AlertDisplay v1.1.0
By Stephen Clay McGehee, KN4AM
Coding done using Claude Code AI

Purpose:        Watches JS8Call's DIRECTED.TXT for messages that match
                the triggers in your alert profiles, and shows them on
                SitRepMapper's banner and toolbar. SitRepNet's profile,
                SitRepNet (@SITREP), is installed and turned on for
                every station. More profiles can come from your group
                (read-only, issued by the coordinator) or be your own;
                any number can be on at once.
                Also watches SitRepMapper's Status Board (SitRepMapper
                v1.18.0 or later) for stations that become flagged,
                get worse, improve or clear, and for many stations
                flagged at once, and can keep a summary line on the
                banner.
                Full instructions are in AlertDisplay_User_Manual.txt,
                in the program folder.

Code:           ALR (alerts and the toolbar block) and NTF
                (notifications). No Expect codes.

Display:        Red ALERT strip (ALR.banner): one item per active
                alert. You can't close it in SitRepMapper; it clears
                when its time runs out, or when you clear it in
                AlertDisplay (Active Alerts tab, or alertdisplay.py
                --clear).
                Pale yellow strip (NTF.banner): notifications, still or
                scrolling (set on the Settings tab). You can close it in
                SitRepMapper. With the Status Board summary line on
                (Status Board tab), its first line is always the board
                summary, ending "(stale)" if SitRepMapper hasn't
                updated the board for over 12 minutes.
                Toolbar block ALR:
                  GREEN  "Watching"   running normally
                  RED    "ALERT"      an alert is showing
                  YELLOW "No calls"   "Ignore all except" is checked
                                      but its list is empty: no station
                                      can trigger alerts
                  YELLOW "List err"   a callsign list can't be read: no
                                      station can trigger alerts
                  YELLOW "No log"     DIRECTED.TXT isn't set or can't
                                      be read
                  YELLOW "No profile" no triggers are turned on
                  GRAY   "Stopped"    the monitor was stopped
                  GRAY   (dot)        the monitor stopped updating
                                      (crashed or computer off)
                A relayed message shows "(via CALL)" after its text.
                A message that wasn't fully received still triggers;
                the Active Alerts tab marks it "partial".
                No sound of any kind (audio can upset the radio
                interface on a Pi).

Transmits:      Never.

Updates:        When the settings window opens, checks SitRepNet.com
                for a newer version and offers to open the download
                page (silent if offline; the monitor never checks).
                Turn it off, or Check for Updates Now, on the Settings
                tab. Nothing is downloaded or installed for you.

Callsign lists: Callsign Lists tab in the settings window:
                  Always Ignore       never act on these stations
                  Ignore all except   act only on these stations
                                      (* means everyone)
                  Also ignore SitRepMapper's IGNORE.TXT
                With neither of the first two checked, every station
                can trigger alerts. An empty "Ignore all except" list
                means NOBODY can trigger alerts. A callsign on a list
                also covers it with a /P or other suffix. JS8 callsigns
                aren't verified, so a list keeps out noise and
                mistakes but can't prove who sent something.
                Status Board triggers follow Always Ignore and
                IGNORE.TXT, but not "Ignore all except".

Triggers:       Matching ignores case and takes the text literally:
                  Contains              anywhere in the message
                  Whole word or phrase  not touching a letter or digit
                                        on either side (MAGNET matches
                                        @MAGNET but not MAGNETIC)
                  Starts with           right after the TO callsign
                A group's own alert code takes the standard form
                (group)-ALERT, e.g. SITREP-ALERT for @SITREP, matched
                as a whole word (also when sent with MSG).
                Banner text placeholders: {FROM} {TO} {TEXT} {AFTER}
                {TIME} {TRIGGER} {GRID} {DIST} {DIR} {RANGE}. {AFTER}
                is the text after the match, so a trigger code doesn't
                show on the banner.
                {GRID} is the grid reported as GR[...] in the message
                (? if the message has none).
                Use the "Test a Message" tab to try a trigger without
                waiting for real traffic. Test shows the result in the
                window only. Show on SitRepMapper also puts it on
                SitRepMapper's banner, marked "TEST:", for 2 minutes
                (the monitor must be running). A test alert turns the
                toolbar block RED while it shows.
                Status Board triggers (Add Status Board... in the
                profile editor): station newly flagged, got worse,
                improved or cleared, or flagged count / share reaches
                a level.
                "Flagged" is SitRepMapper's own Sub-Optimal Thresholds;
                a trigger can only narrow it. Nothing fires for
                stations already flagged when the monitor starts. An
                ALR clears by itself when the station sends a newer
                report that isn't flagged. A message and a Status Board
                event for the same station and report show once.

Reads:          JS8Call's DIRECTED.TXT (path from SitRepMapper's
                settings, or set on the Settings tab), read-only.
                ~/.config/sitrepmapper/config.json (read-only), for
                the DIRECTED.TXT path, your station callsign and your
                Station grid.
                IGNORE.TXT in SitRepMapper's program folder, if that
                box is checked.
                ~/.config/sitrepmapper/statusboard.statusboard.json
                (read-only), SitRepMapper's Status Board.

Writes:         ~/.config/sitrepmapper/companions/ALR.banner,
                NTF.banner and ALR.indicator.
                Its own files in ~/.config/alertdisplay/: settings.json,
                profiles/*.json, always_ignore.txt,
                ignore_all_except.txt, active.json, status.json,
                monitor.pid, alertdisplay.log, and briefly
                clear.request, stop.request and test.request.

Start:          Settings window:  python3 alertdisplay.py
                Monitor (no window): the Start Monitor button, or
                python3 alertdisplay.py --monitor. To start the monitor
                by itself at login, tick "Start the monitor
                automatically when I log in" on the Settings tab.
                Needs Python 3.9 or newer with tkinter; nothing else to
                install.

Stop:           The Stop Monitor button, or
                python3 alertdisplay.py --stop.
                Clear everything showing: python3 alertdisplay.py --clear

Remove:         Stop the monitor and untick the login option (or delete
                ~/.config/autostart/alertdisplay.desktop on Linux, or
                AlertDisplay.cmd in the Windows Startup folder). Delete
                the AlertDisplay program folder and
                ~/.config/alertdisplay/. Delete ALR.banner, NTF.banner
                and ALR.indicator from ~/.config/sitrepmapper/companions/
                if they're still there.
