================================================================================
SitRepNet Scheduler v1.0.0 — Program Overview

Designed and developed by Stephen Clay McGehee, KN4AM
Coding done using Claude Code AI
See SitRepNet.com for more information
================================================================================


PURPOSE
-------
SitRepNet Scheduler lets an unattended or lightly attended station keep
monitoring its usual frequency — the primary frequency — in JS8Call or
FLDIGI, while still catching bulletins and nets that happen on other
frequencies at known times each week.

At each scheduled time it switches the program to the bulletin's
frequency, audio offset, and JS8Call speed or FLDIGI mode. When the
window ends, it puts the program back exactly as it was just before the
switch. The operator doesn't have to be there, and doesn't have to
remember to change back.

It is a companion to the other SitRepNet programs: SitRepMapper and
JS8Spotter read and display the traffic that JS8Call receives, and the
Scheduler makes sure JS8Call is on the right frequency to receive it.


HOW IT WORKS
------------
The schedule is a list of entries. Each entry is one day of the week, a
start time (UTC or local), a duration, an optional early start, and the
settings to switch to. An entry repeats every week; for a net that meets
on several days, there is one entry per day (Copy to Other Days makes
them).

The day is always the operator's local day, even when the time is given
in UTC — that matches how nets announce themselves ("Monday night,
0200Z" is Monday evening in the US). The program works out each entry's
actual dates and times from that rule, including daylight-saving
changes, and shows the next few in the entry editor so they can be
checked.

When a window starts, the Scheduler:
  1. Waits until the program isn't transmitting.
  2. Reads the program's current settings — these are the primary
     settings — and saves them to disk (state.json) before changing
     anything.
  3. Applies the entry's settings and reads them back to confirm they
     took.

When the window ends, it waits again for any transmission to finish,
puts the primary settings back, reads them back, and deletes state.json.

If a second window starts while the first is still running, the
Scheduler goes straight from one to the other and keeps the original
primary settings — it never mistakes a bulletin frequency for the
primary one.

Because the primary settings are taken at switch time rather than
entered anywhere, an operator who changes their monitoring frequency by
hand doesn't need to tell the Scheduler.


KEY FEATURES
------------
- Controls JS8Call (standard, and the JS8Call-improved fork) or FLDIGI —
  one at a time, chosen in Settings
- Weekly schedule with UTC or local start times, local day of the week,
  optional early start (up to 2 hours), and duration (up to 24 hours)
- JS8Call entries set frequency, offset and speed (Normal, Fast, Turbo,
  Slow); FLDIGI entries set frequency, offset and mode, with the mode
  list read from FLDIGI itself
- Status panel: ON PRIMARY or ON SCHEDULE (with what it will return to),
  the program's current settings, the next switch with a countdown, and
  a local/UTC clock
- Overlap warnings when an entry is saved or enabled, compared over the
  coming year so that UTC and local entries that collide only part of
  the year are caught. Two kinds: a full overlap (the later entry takes
  over at its start time) and an early-start overlap (the later entry
  doesn't start early)
- Copy to Other Days: independent per-day copies, skipping days that
  already have the same entry
- Copy Table: the schedule as aligned or tab-separated text, for pasting
  into a document or spreadsheet and printing
- Return to Primary, Pause Scheduling, and Test Selected Entry Now (try an
  entry for a few minutes)
- Activity pane and rotating log file, all times in UTC
- Settings > Time Zone for computers whose clock is set to UTC (common on
  a Raspberry Pi)
- Update check, the same as SitRepMapper's
- Runs on Raspberry Pi, Linux and Windows with nothing to install beyond
  Python itself


RELIABILITY
-----------
The Scheduler changes a radio's frequency without anyone watching, so it
is built to fail safe:

- Never mid-transmission. It waits for the program to stop transmitting
  before any change (JS8Call: 8 seconds after the last frame, since
  JS8Call drops PTT between frames). At switch time it gives up after a
  set limit and skips the window; when returning to primary it goes
  ahead after the limit, since staying away is worse.
- Survives restarts. The primary settings are on disk before the first
  change. If the Scheduler or the computer stops mid-window, the next
  start either stays on the window until it ends or returns to primary
  at once. If the settings can't be saved, it doesn't switch.
- Checks its work. Every change is read back. A switch that only partly
  took (for example, the program was still starting) is retried while
  the window lasts; a failed return to primary is retried until it
  works.
- Waits for the program. If JS8Call or FLDIGI isn't running, it warns a
  minute before a switch and keeps retrying, logging the first failure
  and then a summary every 10 minutes rather than flooding the log.
  When the program comes back, it waits 20 seconds for it to finish
  starting before changing anything.
- Catches up after sleep. A window that started while the computer was
  asleep is joined if enough of it remains.
- One copy at a time. A second copy refuses to start, so two Schedulers
  can't fight over the radio.
- Protects the schedule. A schedule file that can't be read is never
  overwritten; damaged entries are skipped or disabled with a warning,
  and the original is kept as a backup.


PROGRAM CONTROL
---------------
JS8Call
  JS8Call's TCP API (port 2442), one persistent connection that
  reconnects automatically. Uses RIG.GET_FREQ / RIG.SET_FREQ for
  frequency and offset, MODE.GET_SPEED / MODE.SET_SPEED for speed, and
  JS8Call's PTT and frame messages plus its TX text to tell when it is
  transmitting. Works with both the standard JS8Call (2.2–2.3) and
  JS8Call-improved (3.0 and later), which answer some requests
  differently; JS8Call-improved also reports its version.
  Requires "Enable TCP Server API" and "Accept TCP Requests" in JS8Call.

FLDIGI
  FLDIGI's XML-RPC interface (port 7362). Reads and sets the rig
  frequency, the modem (mode) by name, and the audio carrier (offset);
  checks the transmit/receive state before any change.

In both cases the program itself must have working rig control (CAT) —
the Scheduler asks JS8Call or FLDIGI to change, and they change the
radio.


FILES
-----
Program folder (from the release ZIP):
  main.py and the other .py modules, assets/ (icons),
  sitrepnetscheduler.desktop, requirements.txt, and the documentation.

Config folder — ~/.config/sitrepnetscheduler/ (Linux/Pi) or
C:\Users\<username>\.config\sitrepnetscheduler\ (Windows):
  config.json      Settings
  schedule.json    The schedule (plain JSON; one record per entry)
  state.json       Only during a scheduled window: the primary settings
  scheduler.log    Activity log, times in UTC, rotated at 1 MB
  scheduler.lock   Single-copy lock

Updating the program never touches the config folder.


TECHNOLOGY
----------
- Python 3.9 or newer with Tkinter — the standard library only; no pip
  packages
- JS8Call TCP API over standard-library sockets (newline-delimited JSON)
- FLDIGI XML-RPC via the standard library's xmlrpc.client
- zoneinfo (standard library) for the optional Time Zone setting; the
  computer's own zone needs no time zone database
- A scheduling engine driven by the GUI's timer every couple of seconds,
  with the slow work (waiting for TX, talking to the program) on a
  background thread so the window never freezes
- Unit tests (not shipped) cover the time rules across daylight saving,
  the overlap rules, the engine against a simulated program and a fake
  clock, and both clients against fake JS8Call and FLDIGI servers

Main modules:
  app.py               Main window
  engine.py            When to switch and return; snapshot and recovery
  timecalc.py          Local day / UTC rule, early start, daylight saving
  overlap.py           Overlap detection and warning text
  js8call_client.py    JS8Call API client
  fldigi_client.py     FLDIGI XML-RPC client
  schedule_store.py    Reading and writing schedule.json
  (plus the dialogs, settings, Copy Table, and update check)


SEE ALSO
--------
  SitRepNetScheduler_Installation_Guide.txt   Installing; setting up
                                              JS8Call and FLDIGI
  SitRepNetScheduler_User_Manual.txt          Using the program
  SitRepNetScheduler_CHANGELOG.txt            Version history


================================================================================
  End of Program Overview
================================================================================
