This is an old revision of the document!
Changelog
All notable changes to OnAirScreen. Source: OnAirScreen CHANGELOG.md. Narrative release notes: 1.0.0 · 0.9.8.
All notable changes to this project will be documented in this file.
TBA
Added
- Paid builds require a hardware-bound license: 14 days full use, then restricted mode (no fullscreen, GPIO, or audio meters; settings are not saved; window max 1280×800; exit after 15 minutes). Activate online or with a license file. One seat, one year by default, renewable. Return the license in the app to move it.
Changed
- Update check, the update key, and license activation are on their own Settings tab, with one full-width button per action
- The Updates tab says whether this computer can renew online now, or must import a new license file when the current one expires
- The update key is saved as soon as activation succeeds, without pressing Apply
- Shop manuals state that one license covers one PC or one Raspberry Pi
- Manuals point to support when the standard per-computer activation does not fit a use case
- macOS shop builds are signed with an Apple Developer ID and notarized; Gatekeeper no longer blocks the first launch
Fixed
- A paid build checks the update key at startup even when update checks are off. An invalid key removes the local license immediately and switches to restricted mode. Later automatic checks and the deactivation notice are skipped; Check now still runs
- After a license return and a new activation, the window keeps the last size that fit the screen
1.0.7
Changed
- GPIO Custom command uses the same pencil editor as Links (Settings and Web UI)
- Links Custom command is edited from a pencil icon; the icon is highlighted when a command is set
Fixed
- Settings Links no longer leaves a blank gap between the instance hint and the nearby-screen list
- Web Settings Links instance hint stays in place so Add as replica / Use as source no longer shove the form
- Links mapping Custom field is extra API commands when the source is active; Local target Custom only skips LED/AIR/text
- Links Follow all disables Local target and Invert (full status copy does not use them)
- Links replica and source grids fit the Settings width without a horizontal scrollbar
- Add as replica / Use as source fill the next empty row; a notice is shown when all 8 are in use
- Links instance dropdowns no longer show Studio-1 or Studio-2 as the empty placeholder
- Web Settings hints wrap on the full row; Links Replicas/Sources tabs no longer overlap Add as replica / Use as source
- Settings Links instance fields are nearby-screen dropdowns so each replica/source row can pick its own screen
- Link replicas no longer show host-local WARN copy (quit, reboot, shutdown, NTP)
- Link status is pushed on change (replicas and mapped sources); the HTTP poll is only a slow retry, not a per-screen chatter loop
- Replica LEDs and other runtime status push immediately instead of waiting for the 400 ms poll
- Link replicas and sources follow the instance name on the LAN; a stored host is only a fallback if discovery misses them
- Web UI Links matches Settings: Nearby list, Add as replica / Use as source, Replicas and Sources grids
- Settings Links keep the Nearby selection when the peer list refreshes
- Web UI and Settings Apply reject an instance name already used on the LAN and show the collision warning
1.0.6
Added
- Settings Links: discover other OnAirScreens by instance name (multicast) or host/port; add replicas for 1→n full runtime status (LEDs, AIR, NOW/NEXT/WARN) or map individual signals (hallway tallies)
- Settings warn when another OnAirScreen on the LAN uses the same instance name; discovery no longer picks one host at random
- Right-click menu shows the current OnAirScreen version as info
- Raspberry Pi SD-card image allows passwordless host reboot and shutdown from OnAirScreen
Fixed
- Weather widget stays on the AIR LED column width; long city names are elided instead of pushing the clock
- Weather widget shows the searched city name instead of the OpenWeatherMap station or neighborhood name
- Weather widget keeps the current city when switching °C / °F / K (Apply uses the dialog city ID, not a stale settings read)
- Web UI Instance Name accepts at most 32 characters
- HTTP server no longer does reverse DNS on bind or request logging (avoids multi-second stalls)
1.0.5
Added
- Application log starts with a Starting OnAirScreen line (version and distribution)
1.0.4
Fixed
- Linux PTP logs whether the 319/320 bind helper is missing or failed
- Linux PTP bind helper receives the comm socket on stdin
1.0.3
Added
- Web UI and API command
FULLSCREEN:ON/OFF/TOGGLEto switch the main window - Reboot and Shutdown buttons in Settings → About and the Web UI (with confirmation); HTTP
CMD:REBOOT/CMD:SHUTDOWNrequire the Web Settings PIN when one is set - GPIO (Raspberry Pi and Livewire) can map one input to several preset actions plus semicolon-separated custom commands
Changed
- add SNMP enterprise OID IANA PEN 66873 (
.1.3.6.1.4.1.66873); remove placeholder - SNMP MIB is published on the wiki (
onairscreen:mib-en)
Fixed
- Closing the main window while Settings is still open now exits the app
- Linux/Raspberry Pi PTP binds UDP 319/320 via a small helper so the app can run as a desktop user
1.0.2
Added
- SNMPv2c/v3 agent (GET/SET/WALK on port 1161, optional traps) for LEDs, AIR timers, texts, silence, and loudness; MIB in
mibs/ASTRASTUDIO-ONAIRSCREEN-MIB.txt; Settings Network tab shows SNMP beside UDP/MQTT/OSC - Axia Livewire GPIO LWRP: follow GPI/GPO on a device over TCP 93 (read-only), alongside multicast
Changed
- Weather widget backgrounds use a new photographic set for OpenWeatherMap icons 01d–50n
Fixed
- SNMP GET for NOW/NEXT/WARN and other status objects reads the live screen instead of an empty cache
- SNMP agent no longer logs an asyncio error when OnAirScreen quits
- Timer dialog accepts
2:10as well as2,10and2.10 - Timer dialog selects the existing value when opened with Enter
- Weather widget labels stay readable on bright photo backgrounds (soft shadow + overlay)
- Web settings: GPIO Custom Command is disabled unless Action is Custom
- Web settings GPIO row fields are disabled unless that GPI Enable is on
- Desktop GPIO row fields are disabled unless that GPI On checkbox is on
1.0.1
Added
- Axia Livewire GPIO (multicast): follow a source channel’s GPO/GPI pins (e.g. mic ON lamp) in parallel with Raspberry Pi GPIO
- Main-window hotkey overlay (
H, or right-click / long-click → Hotkeys): lists shortcuts; close withH,Esc, or a click outside. Other hotkeys are blocked while it is open
Changed
- PTP: retry UDP 319/320 bind when the ports are in use or permission is denied; log the cause; lock LED and WARN show
PTP ERRORuntil bind succeeds - German manual links to the English GPG wiki page (
gpg-en); the German GPG how-to is removed
1.0.0
First stable 1.0.0. Changes since 0.9.8 are listed in the 1.0.0beta sections below.
1.0.0beta15
Changed
- Require python-osc >=1.10.2
Fixed
- LED and AIR timer on and off color changes take effect immediately after Apply
1.0.0beta14
Added
- Analog clock faces Analog Numbers (1–12 on the classic analog face), Analog Studio (white face with 1–12), Analog Railway (station clock with a red ring second hand), Analog 24h ticking, and Analog 24h smooth (cream face with 1–12 and 13–24)
- Clock face setting
Clock/faceandCONF:Clock:face=for digital and analog styles - README and manuals show screenshots of all clock faces
Changed
- Clock mode in Settings and the Web UI is a dropdown instead of Digital/Analog radio buttons
- Context menu Start/Stop/Reset I+LRA are enabled only when they apply to the current session
CONF:Clock:digital=Falseselects the classic analog face
Fixed
- I/LRA no longer burns a CPU core on long sessions: history stays in a NumPy buffer, blocks below −70 LUFS are not stored, and gated I is refreshed about once per second
1.0.0beta12
Added
- Settings option to always start in fullscreen mode, even if the last session was windowed (
General/always_start_fullscreen, default off)
Changed
- GitHub README presents shop builds as the supported way to run OnAirScreen; the repository is documented as source-available for audit and contributors, not as an installer
- Automatic update checks also run every 24 hours while OnAirScreen is running; the new-version dialog appears only at startup
- Audio meter width can be set up to 201 px (L/R bars were previously capped around 117 px)
- Installation chapter in the manuals covers Windows MSI, macOS Gatekeeper, Linux packages, and flashing the Raspberry Pi SD image
- Manuals use an annotated main-screen screenshot
Fixed
- Long-press on the main screen no longer uses deprecated Qt mouse-position APIs
1.0.0beta11
Added
- Long-click / long-press on the main screen opens the same context menu as right-click
Fixed
- Raspberry Pi GPIO import of system gpiozero no longer fails for missing freeze stdlib modules (
colorsys,fractions)
1.0.0beta10
Fixed
- Raspberry Pi GPIO works in the packaged app by loading system
python3-gpiozero/python3-lgpio(the freeze does not bundle them)
1.0.0beta9
Added
- Raspberry Pi GPIO inputs map mixer GPI contacts to LEDs and AIR timers (Settings → GPIO), with wiring diagrams and pinout links in the manuals
Changed
- GPIO wiring diagrams in the manuals show a PC817 module with silkscreen terminals
IN1–IN8/GNDandOUT1–OUT8/GND
1.0.0beta8
Added
- Left-click on status LEDs and AIR timers toggles them (same as the hotkeys)
- Right-click Quit OnAirScreen on the main screen
- On-screen WARN
QUITTING ONAIRSCREENwhile the app is shutting down - Web UI Add to Home Screen on iPhone/Android uses the OnAirScreen icon
Changed
- Web UI uses a flat studio look: CI color blue, square inputs, and settings tabs on the left like the desktop dialog
- Web UI theme, settings, and version controls scroll with the page instead of staying pinned to the corners
Fixed
- Web UI AIR timer and loudness buttons no longer overflow the viewport on phones
- Web UI home-screen icon is an opaque 180×180 PNG at the site root so iOS picks it up
- Ctrl+C / SIGINT shows the same
QUITTING ONAIRSCREENWARN as Q and the context menu - Opening Settings / Apply no longer segfaults on Raspberry Pi: the Python mouse event filter is gone; main-screen children let double-click and right-click through to the window
- Audio meter heading "LUFS" in the L/R + LUFS layout is no longer clipped on the left and right
1.0.0beta7
Changed
- Settings window opens at 700×800 and can be resized freely (height is no longer capped at 800px)
Fixed
- Settings tabs (except General) scroll vertically in the UI; content stays within the window width instead of shifting sideways
- Audio meters use much less CPU on Raspberry Pi and other software-rendered displays: bars paint from cached pixmaps, and true-peak / BBC PPM / LUFS DSP runs only when the current meter setup needs it
- Opening Settings no longer segfaults: the main-screen mouse filter watches the application instead of installing on every new child widget
- Replaced deprecated
QColor.setNamedColor()withQColor.fromString() - Web UI: Instance/Version/Connection block stays top-right; settings gear sits to its left
Added
- Right-click Start I+LRA and Stop I+LRA on the main screen (when meters are enabled)
- Web UI settings overlay (gear, top right): edit all OnAirScreen settings, optional PIN (
Network/websettingspin), Apply, and preset load/save - Web UI Audio Meters: Livewire Source and AES67 Stream dropdowns with live discovery and Paste SDP, matching the desktop Settings dialog
1.0.0beta6
Changed
- Default TOTH timer label is
TOTHinstead ofTOTH Timer
Fixed
- Windows: opening Settings → Fonts no longer access-violates on first open. The mouse event filter is installed after widgets exist, and the font database is warmed at startup
- Main-screen hotkeys work again. The mouse event filter no longer consumes
ShortcutOverrideand key events, soQShortcutstill reaches Qt
1.0.0beta5
Added
- Persistent log folder with rotating
onairscreen.log, crash reports for uncaught Python exceptions, andfault.logfor native faults; About tab shows the path and can open the folder - After a crash, the next start shows a dialog (open log folder, auto-closes after 30 seconds with a progress bar)
Changed
- Uncaught main-thread exceptions and Qt fatal messages write a crash report, then quit (no dialog at crash time). Thread and asyncio errors are logged without exiting.
Fixed
- Fresh installs without
Audio/layoutnow use L/R + LUFS (both) instead of falling back to L/R only - Settings audio-device Refresh re-scans PortAudio so newly plugged or unplugged inputs appear immediately
1.0.0beta4
Changed
- OnAirScreen Source-Available License (OASL 1.0): source may be used, modified, and redistributed; compiled/binary redistribution requires written permission
- Application file headers point to OASL; Settings License tab shows OASL plus third-party notices
1.0.0beta3
Added
- TOTH Timer label text is configurable (
Timers/TimerTOTHText, defaultTOTH Timer) - Bundled Noto Sans (Regular, Bold, Italic, Bold Italic) as an additional font family alongside Roboto
- Web-UI Loudness I+LRA tile shows live I (LUFS) and LRA (LU);
lufsI/lrain/api/statusand WebSocket; MQTT sensors{base}/lufs/iand/lra; OSC/oas/lufs/iand/oas/lufs/lra
Fixed
- Weather widget text shadows work again under PySide6 (drop-shadow effects are parented so they are not garbage-collected)
- AoIP source change without RTP now drops the meters to the floor instead of freezing on the previous level
Changed
- Settings Network and Time Source tabs align labels and fields in a shared two-column form layout
- License dialog and
THIRD_PARTY_LICENSES.mdnow document PySide6/Qt (LGPLv3), the analog clock BSD example, and Roboto (SIL OFL) instead of PyQt GPL - Application BSD text removed from
LICENSEand the Settings license tab pending the forthcoming source license - Default audio meter layout is L/R plus programme LUFS (
both); default width is 115px and the maximum is 150px
1.0.0beta2
Fixed
- Digital clock no longer aborts when a time sample has no SMPTE frame count
- Startup no longer crashes when listing host addresses under PySide6
Changed
- Qt binding switched from PyQt6 to PySide6
- Settings window opens at 700×800 and is capped at 800px height so it fits smaller screens, audio meters tab uses two columns
- Station and slogan color pickers in Settings no longer show a live preview
- dBTP meter hides the orange ceiling peg when the Too Loud indicator is off
1.0.0beta1
Added
- Meter layouts: L/R only, programme LUFS only, or both (
Audio/layout:lr/lufs/both; BBC PPM stays L/R-only) - Programme LUFS bar (EBU R128): momentary M with a short-term S tick (I and LRA stay off until started)
- Optional gated Integrated I + LRA (off until started):
LUFSI:START/STOP/TOGGLE/RESETvia UDP, HTTP, OSC, MQTT, Web-UI, and Companion - MQTT Home Assistant: Loudness I+LRA switch and reset button (
{base}/lufs/integrated/setand/state);lufsIntegratedin/api/statusand WebSocket - Right-click Reset I+LRA on the main screen (when meters are enabled);
LUFSI:RESETrestarts a running session or hides frozen I/LRA when stopped - Existing configs with
Audio/unit=lufs(nolayoutkey) migrate to layoutlufsand L/R unitdbtp - AIR3 shows ▲ (count-up) or ▼ (count-down) under the timer icon
- AIR3 shows
TOTH Timerwhile top-of-hour countdown is active, then restores the configured label - Web-UI: AIR3 time input (
m:ss,m,ss, or seconds) and count-up vs. countdown in the status tile - Web-UI: silence alarm and loudness I+LRA in live status; keys
1–4toggle LEDs (ignored while typing) - Web-UI: persistent connection badge (Live / Polling / Offline)
countDownin/api/statusfor AIR timers (truewhile AIR3/AIR4 is counting down)- Bitfocus Companion HTTP module (
astrastudio-OnAirScreen) as the recommended Stream Deck path; Generic OSC remains as an alternative - OSC remote control on UDP port 8000 (
/oas/...): set commands, query-reply to the sender, optional status push for Companion Generic OSC - Settings Network tab (after General) for UDP, HTTP, multicast, MQTT, and OSC; General / Advanced tab titles no longer include “Settings”
- Silence Detection on the current audio source (Local / Livewire / AES67): dBFS threshold, duration (default 10 s), recovery time, optional OAS WARN, optional HTTP GET on trigger
- Silence alarm as API boolean (
silencein/api/statusand WebSocket) and MQTT{base}/silence/active(Home Assistant binary sensor) - Option to treat a missing device/stream as silence (on by default)
- DNS-safe instance name (Settings General, default
Studio-1, max 32 characters, LDH hostname label) so each OnAirScreen can be identified by location; shown in the Web-UI,/api/status(instance), MQTT{base}/instance/state, and as a Home Assistant sensor; HA device name becomesOnAirScreen (Studio-1) CONF:General:instancename=TEXTto set the instance name remotely- Double-click on the main screen toggles fullscreen
- Right-click context menu on the main screen: Toggle Fullscreen, Settings
Changed
- Default meter width is 79 px (extra width still thickens the L/R bars)
CONF:Audio:unit=lufsnow switches the layout to programme LUFS instead of using LUFS as an L/R unit- Default audio meter unit is dBTP; TooLoud is enabled by default
Fixed
- Clock no longer freezes after an NTP timeout: NTP results are delivered on the GUI thread, and a watchdog restarts a dead clock timer
- Clock watchdog no longer aborts when a time sample is missing
- Opening Settings no longer paints a running AIR timer (including TOTH) as inactive or resets its displayed time to 0:00
- Web-UI restores the WebSocket after falling back to HTTP polling
- Opening Settings again brings the existing window to the front instead of reloading it
0.9.9beta1
Added
- Stereo audio meters on the left (on by default, Local Input): L/R bars with RMS fill and peak overlay
- Display units: dBFS, dBTP (true peak), LUFS (momentary), BBC PPM (Type IIa, marks 1–7)
- Peak hold marker (default 1.5 s, can be disabled) and display style Solid or Bargraph
- LUFS reference peg via presets (EBU R128 −23, ATSC A/85 −24, AES −16/−18, Custom)
- Adjustable meter width (extra width goes into thicker L/R bars)
- Optional TOO LOUD action: on-screen warning (priority 1) or trigger LED 1–4 when true peak exceeds the threshold; dBTP ceiling peg uses that threshold
- Audio sources: Local Input (PortAudio), Livewire AoIP multicast, AES67 multicast RTP (SAP or pasted SDP)
- Shared AoIP Interface for Livewire/AES67 IGMP join (empty = system route)
- Livewire: advertised sources listed while Settings are open (
239.192.255.3UDP 4001); pick a name or enter channel 1–32767 (channel N →239.192.0.0+NUDP 5004, L24/48 kHz stereo) - AES67: SAP discovery on
239.255.255.255and RFC 2974224.2.127.254UDP 9875 while Settings are open; live stream list (None / SAP / pasted SDP); L16/L24 at 44.1/48/96 kHz, meters use the first two channels - Settings Audio Meters tab and
CONF:Audio:*keys (source, unit, TooLoud, meter width, LUFS reference, peak hold, display style)
Fixed
- Date display follows the configured
Formatting/dateFormatsetting - Digital AM/PM clock: midnight displays as 12 (12-hour mapping)
- NTP lock LED no longer stays green when the server is unreachable
- Autoflash / timedflash LED regression and Web-UI blink
- MQTT reconnect and AES67 capture restart stop during application quit
0.9.8
Added
- Persist windowed position and size across restarts (
Window/geometry); restored when not in fullscreen - OpenWeatherMap city search in Settings: type a city name next to City ID, Find, pick a match
- Mask Update Key, MQTT password, and OpenWeatherMap API key; slashed-eye toggle reveals them
- Time Source settings tab: Local System Clock, NTP Server, PTPv2 IEEE 1588-2008, or LTC
- NTP and PTP steer an independent display clock (monotonic timebase); the OS clock is never set
- PTP: software slave on 224.0.1.129 UDP 319/320, configurable interface (independent of AoIP) and domain 0–255
- LTC: Leo Bodnar LBE-1110 USB-serial SMPTE reader, or SMPTE LTC decoded from a local PortAudio input (Left/Right); display shows
HH:MM:SS:FF, holds last timecode on signal loss - LTC audio uses its own capture device (not Audio Meters / Livewire / AES67); opening the same device for meters and LTC can fail on some hosts
- LTC unlock WARN (
Clock not LTC synchronizedetc.) is optional and off by default; theLTC NOT LOCKEDLED always remains - AES67: SAP discovery on
239.255.255.255and RFC 2974224.2.127.254(UDP 9875) - PTP: apply TAI−UTC only when the master announces the PTP timescale (fixes ~37s offset vs software ptp4l)
- NTP Check settings moved from General to the Time Source tab
- Clock lock LED (bottom right, seconds-LED size): green when the selected time source is locked, red when not; caption
PTP LOCK/NTP LOCK/LTC LOCK(orNOT LOCKED) - NTP Server field stays enabled when Time Source is NTP, even if NTP-Check is off
- Top-of-Hour countdown for Radio Timer (AIR3): wall-clock synchronized countdown to the next full hour (display format M:SS)
- Top-of-Hour: Hotkey
Tto toggle countdown (stop resets display to 0:00) - Top-of-Hour: API command
AIR3TOH:[ON/OFF/TOGGLE]via UDP and HTTP - Top-of-Hour: MQTT topic
{base_topic}/air3/tohand status topicair3/toh/state(Home Assistant button via Autodiscovery) - Top-of-Hour: Web-UI "Top of Hour" button for AIR3
- Top-of-Hour:
topOfHourfield in/api/statusforair[3] - API:
TOGGLEfor LED1–4, AIR1, AIR2, and AIR4 (same ON/OFF/TOGGLE pattern as AIR3) - German and English user manuals (
BEDIENUNGSANLEITUNG.md,USER_MANUAL.md) with README links - Refactoring: Extracted NTP management to ntp_manager.py module
- Refactoring: Extracted font loading to font_loader.py module
- Refactoring: Extracted signal handlers to signal_handlers.py module
- Refactoring: Extracted system operations to system_operations.py module
- Refactoring: Extracted status export to status_exporter.py module
- Refactoring: Extracted UI updates to ui_updater.py module
- Refactoring: Extracted hotkey management to hotkey_manager.py module
- Refactoring: Extracted logging configuration to logging_config.py module
- Error Handling: Unified error handling system with custom exception hierarchy
- Error Handling: Custom exceptions for all error types (Network, Command, Configuration, Validation, API, Encoding, Widget)
- Error Handling: Consistent logging strategy with log_exception() helper function
- Error Handling: HTTP error response mapping based on exception types
- Error Handling: Comprehensive exception handling in network.py, command_handler.py, start.py, weatherwidget.py, mqtt_client.py, settings_functions.py
- Tests: Unit tests for exceptions module (26 tests covering all exception types and logging helper)
- MQTT integration with Home Assistant Autodiscovery support
- MQTT: LED switches (LED1-4) for controlling LEDs via MQTT
- MQTT: AIR timer switches (AIR1-4) for starting/stopping timers
- MQTT: AIR timer sensors (AIR1-4 Time) for displaying elapsed time in seconds
- MQTT: Reset buttons (AIR3/AIR4 Reset) for resetting timers
- MQTT: Text entities (NOW, NEXT, WARN) for setting text fields
- MQTT: Automatic status updates after state changes
- MQTT: Automatic reconnection and autodiscovery re-publishing on reconnect
- Settings: MQTT configuration (Server, Port, Username, Password, Device Name)
- MQTT: Base topic automatically generated from "onairscreen" + unique device ID (last 6 hex characters of MAC address)
- Web-UI: Dark Mode support with theme toggle button and automatic persistence
- Web-UI: Warning priority system with support for NTP warnings (priority -1), normal warnings (priority 0), medium priority (1), and high priority (2)
- Web-UI: Display NTP warnings in Current Status section with blue color coding
- Web-UI: X button to delete warnings directly from status display (for priority 0-2)
- Web-UI: Improved Current Status layout - organized in rows (LED1-4, AIR1-4, NOW/NEXT)
- Web-UI: Compact design for NOW/NEXT status items and input fields
- Web-UI: AIR Timer Controls now show timer labels (Mic, Phone, etc.) directly on buttons
- Web-UI: NOW/NEXT input fields placed side by side (50% width each)
- Settings: Preset/Profile management - save, load, list, and delete configuration presets as JSON files
- Settings: UI buttons for preset management (Save, Load, Delete)
- Settings: Log level configuration (DEBUG, INFO, WARNING, ERROR, CRITICAL, NONE) with ComboBox in General settings
- Command-line: --loglevel option to override log level settings (temporary, not saved)
- Tests: Comprehensive unit test coverage for defaults.py (17 tests for get_default() function)
- Tests: Comprehensive unit test coverage for weatherwidget.py (23 tests for WeatherWidget class)
- Tests: Comprehensive unit test coverage for clockwidget.py (25 tests for ClockWidget class)
- Tests: Extended test coverage for start.py with 11 tests for set_log_level() function
- Security: Comprehensive input validation for all network commands (UDP/HTTP)
- Security: Text input sanitization for NOW, NEXT, WARN commands (removes control characters, dangerous patterns)
- Security: Command value validation for LED, AIR, CMD commands (validates allowed values)
- Security: Length limits for text inputs (500 chars for NOW/NEXT/WARN, 1000 for CONF)
- Security: Input validation for CONF commands (stationname, slogan, LED text, AIR text)
- Refactoring: Extracted NTP management to ntp_manager.py module
- Refactoring: Extracted font loading to font_loader.py module
- Refactoring: Extracted signal handlers to signal_handlers.py module
- Refactoring: Extracted system operations to system_operations.py module
- Refactoring: Extracted status export to status_exporter.py module
- Refactoring: Extracted UI updates to ui_updater.py module
- Refactoring: Extracted hotkey management to hotkey_manager.py module
- Refactoring: Extracted logging configuration to logging_config.py module
Changed
- Fonts settings: family combo (includes bundled Roboto), separate size, bold, and per-row reset instead of the native font dialog
- LED1–4 default font size is 32pt
- Default UI font is now bundled Roboto (FreeSans removed); existing FreeSans settings are mapped to Roboto
- Audio meters are enabled by default with Local Input (
device) as the source - Require Python 3.11 or newer; bump websockets to >=17.1
- Clock: Digital clock second LEDs and colon now repaint aligned to wall-clock second boundaries (removes visible lag at second rollover)
- Refactoring: Reduced start.py from 1711 lines to ~1415 lines by extracting logical components into separate modules
- Refactoring: Improved code modularity and maintainability by separating concerns into dedicated modules
- Refactoring: All tests updated to use new modular structure (583 tests passing)
- Code Quality: Removed unnecessary backward compatibility code after refactoring
- Code Quality: Simplified initialization code using for loops for LED and AIR timer setup
- Error Handling: Replaced generic Exception handling with specific custom exceptions throughout codebase
- Error Handling: Standardized error logging with consistent format and context information
- Error Handling: Improved HTTP error responses with appropriate status codes based on error types
- Web-UI: Fixed dark mode flash on page reload by setting theme immediately in HTML head
- Web-UI: Restructured status display for better organization and space efficiency
- Command Handler: Enhanced WARN command to support priority format (WARN:Prio:Text)
- MainScreen: Implemented priority-based warning system with array index mapping
- MainScreen: Updated process_warnings() to display highest priority warning (excluding NTP if others exist)
- MainScreen: Simplified update_ntp_status() to use priority -1 directly
- API: get_status_json() now returns warnings array with priorities in addition to legacy warn field
0.9.7beta4
Added
- WebSocket support for Web-UI: Real-time status updates via WebSocket connections (replaces HTTP polling)
- Integration tests for network communication (UDP, HTTP, WebSocket)
- Extended unit tests for timer_manager, event_logger, and command_handler modules
- Test tools: cmdtest_multicast.py and diagnose_multicast.py for multicast testing and diagnostics
- Central configuration file (defaults.py) for all default values
- Type hints and docstrings throughout codebase
- Context manager (settings_group) for QSettings group operations
Changed
- Network: Improved multicast support for macOS - UDP server now explicitly joins on loopback interface too
- Network: Improved socket configuration for reliable multicast sending on macOS
- Network: HTTP server now uses ReusableHTTPServer with SO_REUSEADDR to prevent TIME_WAIT issues
- Security: Replaced os.system() with subprocess.run() for secure system command execution
- Error handling: Enhanced error handling for network operations, timer input parsing, and color validation
- Error handling: Graceful degradation when resources (fonts, templates) are missing
- Makefile: Follow symlinks when searching for rcc tool in Homebrew installations
- Fixed: IP addresses now correctly displayed at startup
0.9.7beta3
Added
- Web-UI: Complete web-based remote control interface accessible via HTTP
- Web-UI: Real-time status display for LEDs, AIR timers, and text fields (NOW/NEXT/WARN)
- Web-UI: LED control buttons with toggle functionality
- Web-UI: AIR timer controls with start/stop and reset (for AIR3/AIR4) buttons
- Web-UI: Text input controls for NOW, NEXT, and WARN messages
- Web-UI: REST-style API endpoints (/api/status, /api/command)
- Web-UI: Version and distribution information displayed in top-right corner
- Web-UI: Modal dialog with overlay for connection errors (always visible, dims background)
- Web-UI: Clear buttons for NOW/NEXT text inputs
- Web-UI: Current NOW/NEXT/WARN texts displayed in status panel
- API: Status endpoint now includes version and distribution information
Changed
- Web-UI: HTML template moved from network.py to separate templates/web_ui.html file for better maintainability
- Web-UI: Connection error modal now disables all controls when connection is lost
- Network: HTTP server now supports Web-UI in addition to command API
- Network: Improved thread-safety for GUI operations from HTTP thread using pyqtSignal
0.9.7beta2
Added
- Event logging system for tracking LED changes, AIR timer events, commands, warnings, and system events
- Tooltips for all settings widgets to improve user experience
Changed
- Fixed weather widget API calls when widget is disabled or no API key is configured
- Removed unused font button
0.9.7beta1
Added
- Command test scripts for HTTP and UDP testing (utils/cmdtest_http.sh, utils/cmdtest_udp.sh)
- Show version, distribution and settings path in about dialog
- Fonts/COPYING file
Changed
- Major code refactoring: extracted command handler, network module, and timer manager to separate modules
- Use context manager for QSettings groups
- Consolidated text setters and timer reset methods
- Consolidated AIR reset and start_stop methods
- Consolidated LED toggle methods
- Consolidated set_station_color() and set_slogan_color() methods
- Consolidated set_led1-4() methods into generic method
- Split restore_settings_from_config() into smaller methods
- Optimized led_logic() method
- Optimized font setup in restore_settings_from_config()
- Modernized string formatting to f-strings
- Refactored parse_cmd() using command pattern
- Added logging, type hints, and docstrings throughout codebase
- Fixed crash when UDP/HTTP ports are empty
- Updated copyright strings
- Updated settings.ui
0.9.6 beta2
Added
- options to change icons on all 4 timers
0.9.6 beta1
Added
- option for preferred logo position
0.9.5
Changed
- fixed textclock when hour == 12
- fixed wrong default font size for slogan
- refactored text clock code
- fixed crash when using API to configure boolean fields
- API: you can now use colors in web notation (#00FF00) and hex notation (0x00FF00)
- fixed slogan font in settings
- fixed analog clock style
Added
- french localization for textclock
- left LEDs are now customizable (text/color)
- settings for left LEDs minimum width
- IPs can be automatically replaced with custom text after 10s
- API commands for added functions
- New Hotkey "I" to display IPs for 10 seconds
- added option to select between no/separate/combined seconds display
- added logo to analog clock
0.9.4
Changed
0.9.3
Added
- Alt-S now resets stream timer
- added enable/disable option for timers 1-4
- fixed unit display in weather widget
- fixed crash introduced through a lazy print
- fixed logo size calculation for portrait format logos
- customizable font and size for various elements
0.9.2
Changed
- Fix crash when timer value is not numeric
- Fix show/hide of weather widget
- Fix HTTP API full UTF-8 support
- Fix crash when restoring config on .ini style platforms, boolean type mismatch
- Localized "WEATHER" string in Weather Widget
Added
- HTTP API
- Update check support
- Show/hide LED1-4
- Show/hide TextClock
0.9.1 beta4
Changed
- Fix window resize when displaying long text in NOW/NEXT/WARN
0.9.1 beta3
Added
- this changelog
- selectable blinking/static colon for HH:MM in digital clock mode
Changed
- Fix update of weatherwidget when location is changed