onairscreen:manual-en

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
onairscreen:manual-en [05.09.2026 15:55] – external edit 127.0.0.1onairscreen:manual-en [27.09.2026 02:22] (current) – external edit 127.0.0.1
Line 2: Line 2:
 # OnAirScreen – User Manual # OnAirScreen – User Manual
  
-**Version:** 1.0.0beta11  +**Version:** 1.0.10  
 **Author:** Sascha Ludwig, [astrastudio.de](http://www.astrastudio.de)   **Author:** Sascha Ludwig, [astrastudio.de](http://www.astrastudio.de)  
 **Project:** [OnAirScreen](https://www.astrastudio.de/en/onairscreen/)   **Project:** [OnAirScreen](https://www.astrastudio.de/en/onairscreen/)  
Line 11: Line 11:
 ## Table of Contents ## Table of Contents
  
-1. [Overview](#1-overview) +1. [Overview](#overview) 
-2. [Installation and Startup](#2-installation-and-startup) +2. [Installation and Startup](#installation_and_startup) 
-3. [Main Screen](#3-main-screen) +3. [Main Screen](#main_screen) 
-4. [Keyboard Shortcuts (Hotkeys)](#4-keyboard-shortcuts-hotkeys) +4. [Keyboard Shortcuts (Hotkeys)](#keyboard_shortcuts_hotkeys) 
-5. [Settings Dialog](#5-settings-dialog) +5. [Settings Dialog](#settings_dialog) 
-6. [Features in Detail](#6-features-in-detail) +6. [Features in Detail](#features_in_detail) 
-7. [Remote Control and API](#7-remote-control-and-api) +7. [Remote Control and API](#remote_control_and_api) 
-8. [Presets (Profiles)](#8-presets-profiles) +8. [Presets (Profiles)](#presets_profiles) 
-9. [Command-Line Options](#9-command-line-options) +9. [Command-Line Options](#command-line_options) 
-10. [Configuration Storage Location](#10-configuration-storage-location) +10. [Configuration Storage Location](#configuration_storage_location) 
-11. [Troubleshooting](#11-troubleshooting)+11. [Troubleshooting](#troubleshooting)
  
 --- ---
Line 39: Line 39:
 - **Text lines** NOW, NEXT, and WARN (with priority system) - **Text lines** NOW, NEXT, and WARN (with priority system)
 - **Weather widget** (OpenWeatherMap) - **Weather widget** (OpenWeatherMap)
-- **Remote control** via keyboard, mouse (double-click/right-click/long-click), UDP, HTTP, Web UI, MQTT, OSC, REST API, and Bitfocus Companion+- **Remote control** via keyboard, mouse (double-click/right-click/long-click), UDP, HTTP, Web UI, MQTT, OSC, SNMP, REST API, and Bitfocus Companion
 - **Home Assistant integration** via MQTT Autodiscovery - **Home Assistant integration** via MQTT Autodiscovery
-- **GPIO inputs** on Raspberry Pi (mixer GPI via optocoupler → LEDs and AIR timers)+- **GPIO inputs** on Raspberry Pi (mixer GPI via optocoupler), **Axia Livewire GPIO** (multicast or LWRP TCP 93, e.g. mic ON lamp), and **MIDI** (Note/CC from one interface) 
 +- **Instance links**: 1→n replicas (full LED/AIR/NOW/NEXT/WARN status) and per-signal mappings (e.g. hallway tallies from several studios)
  
 The application starts in **fullscreen mode** by default with the mouse cursor hidden, making it suitable for dedicated studio monitors, Raspberry Pi setups, and touch-free operation. The application starts in **fullscreen mode** by default with the mouse cursor hidden, making it suitable for dedicated studio monitors, Raspberry Pi setups, and touch-free operation.
Line 53: Line 54:
 ## 2. Installation and Startup ## 2. Installation and Startup
  
 +Ready-to-run builds for Windows, macOS, Linux, and Raspberry Pi are available from the [astrastudio shop](https://www.astrastudio.de/shop/). One license covers one PC or one Raspberry Pi. Each additional computer needs its own license. The same license can be moved to a replacement computer when the previous one is no longer in use.
  
 +OnAirScreen starts in **fullscreen** with the mouse cursor hidden. Open Settings with `Ctrl+S` (macOS: `Cmd+S`). Changes apply only after **Apply**.
  
-### Requirements+### Windows
  
-- **Python 3.11+** with PySide6 (when installing from source) +1. Download `OnAirScreen_*_Win_x64.msi` (inside `OnAirScreen_Win_x64.zip`). 
-- Dependencies: see `requirements.txt` +2. Double-click the MSI and follow the installer. A per-machine install needs administrator rights. 
-- Network access for UDP/HTTP/MQTT/OSC remote control (optional)+3. OnAirScreen is installed to `C:\Program Files\OnAirScreen`. 
 +4. Start it from the **Start** menu or the desktop shortcut.
  
 +The Start menu folder also contains **OAS Send** (command sender) and **OAS Send (no console)**. Settings live in the Windows Registry; logs under `%LOCALAPPDATA%\astrastudio\OnAirScreen\logs\`.
  
 +An older portable `.exe` is **not** removed by the MSI. Delete that copy yourself after installing.
  
-### Starting from Source+Windows only syncs internet time about once a week by default, which can show the wrong clock if the time source is **Local**. Shorten the OS sync interval, or use NTP / PTP / LTC in OnAirScreen (see [5.8 Time Source](#time_source)). 
 + 
 +### macOS 
 + 
 +1. Download `OnAirScreen_*_macOS.dmg`. 
 +2. Open the DMG and drag **OnAirScreen.app** into **Applications**. Do not run it from the DMG. 
 +3. Start OnAirScreen from Applications, Launchpad, or Spotlight. 
 + 
 +Shop builds are signed with an Apple Developer ID and notarized. After you copy the app to Applications, start it from Applications, Launchpad, or Spotlight. For local audio meters, grant **Microphone** permission. 
 + 
 +### Linux (Debian / Ubuntu / Raspberry Pi OS) 
 + 
 +Official builds are a `.deb`. After install the app lives in `/opt/onairscreen`, starts as `onairscreen`, and appears in the application menu. 
 + 
 + 
 +| Shop ZIP                    | Package inside                       | Architecture | For                    | 
 +| --------------------------- | ------------------------------------ | ------------ | ---------------------- | 
 +| `OnAirScreen_Linux_x64.zip` | `OnAirScreen_*_Linux_x64.deb`        | `amd64`      | Debian/Ubuntu PCs      | 
 +| `OnAirScreen_PiOS_x64.zip`  | `OnAirScreen_*_RaspberryPiOSx64.deb` | `arm64`      | Raspberry Pi OS 64-bit | 
 + 
 + 
 +Check with `dpkg --print-architecture`. The two packages are not interchangeable. 
 + 
 +Raspberry Pi: 64-bit OS on Zero 2 W, Pi 3 / 4 / 400, CM4, Pi 5 / 500, CM5. Not supported: Pi 1 and classic Zero. You need a graphical desktop, not Lite without a GUI. 
 + 
 +Unzip the download, then install with **apt** (not `dpkg -i` alone) so PortAudio, OpenGL, and Xcb are pulled in. The `./` in front of the file is required:
  
 ```bash ```bash
-python start.py+unzip OnAirScreen_Linux_x64.zip 
 +cd ~/Downloads 
 +sudo apt update 
 +sudo apt install ./OnAirScreen_*.deb
 ``` ```
  
 +Start from the application menu or run `onairscreen`. Updates: install the new `.deb` the same way; settings are kept. Uninstall with `sudo apt remove onairscreen` (config in `~/.config` stays).
 +
 +If you used `dpkg -i` and dependencies are missing: `sudo apt -f install`.
 +
 +Packages are OpenPGP-signed. Optional verification: [Package signing (GPG)](https://www.astrastudio.de/wiki/gpg-en).
 +
 +### Fedora
 +
 +The Fedora RPM is built on Fedora 44 (Fedora 44+). Older RHEL, Rocky, or Alma may fail because of glibc.
 +
 +```bash
 +sudo rpm --import https://www.astrastudio.de/GPG-KEY-astrastudio
 +sudo dnf install ./OnAirScreen_*_Fedora_x64.rpm
 +```
 +
 +`dnf` pulls in PortAudio and other system libraries. Check the signature with `rpm -K OnAirScreen_*_Fedora_x64.rpm` (expected: `digests signatures OK`).
 +
 +### Raspberry Pi SD-card image
 +
 +The [SD-card image](https://www.astrastudio.de/en/shop/onairscreen-raspberry-pi-sd-card-image/) is a ready-to-boot 64-bit Raspberry Pi OS with OnAirScreen already installed (desktop autologin, GPIO included). Unzip the download; inside is `OnAirScreen_*_RaspberryPiOS_Image.img`.
 +
 +Use [Raspberry Pi Imager](https://www.raspberrypi.com/software/):
 +
 +- [macOS](https://downloads.raspberrypi.org/imager/imager_latest.dmg)
 +- [Windows](https://downloads.raspberrypi.org/imager/imager_latest.exe)
 +- [Ubuntu x86](https://downloads.raspberrypi.org/imager/imager_latest_amd64.deb)
 +
 +1. Insert a microSD card.
 +2. Start Raspberry Pi Imager.
 +3. **Choose OS** → **Use custom** → select the OnAirScreen `.img` file (not the `.zip`).
 +4. **Choose storage** (or **Choose SD Card**) and select the card.
 +5. **Write**.
  
 +Default user: `pi` / password `OnAirScreen1!`. Hostname: `onairscreen`. Change the password after first boot. SSH is enabled. Host reboot and shutdown from OnAirScreen (Settings, Web UI, or `CMD:REBOOT` / `CMD:SHUTDOWN`) work without a password on this image.
  
-### Precompiled Versions+On the desktop: **OnAirScreen**, **OAS Pi Settings** (optional autostart), on-screen keyboard, network icon. First boot grows the root filesystem to fill the card.
  
-Ready-to-run binaries for Windows, Linux, macOS, and Raspberry Pi are available at [astrastudio.de/shop](https://www.astrastudio.de/shop/).+If you already run Raspberry Pi OS 64-bit with a desktop, install the Pi `.deb` instead (see Linux above).
  
 ### First Startup ### First Startup
Line 87: Line 154:
 The main screen is divided into the following areas: The main screen is divided into the following areas:
  
-![OnAirScreen Hauptbildschirm](https://www.astrastudio.de/wp-content/uploads/2026/08/OAS_Screenshot_1.0.0.png) +![OnAirScreen main screen, annotated](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Screenshot_annotated_1_0_0beta8.png)
  
 ### Areas in Detail ### Areas in Detail
Line 98: Line 164:
 | **Slogan**          | `labelSlogan`             | Station tagline / claim                                  | | **Slogan**          | `labelSlogan`             | Station tagline / claim                                  |
 | **Status LEDs 1–4** | `buttonLED1`–`buttonLED4` | Large colored status indicators (ON AIR, PHONE, …)       | | **Status LEDs 1–4** | `buttonLED1`–`buttonLED4` | Large colored status indicators (ON AIR, PHONE, …)       |
-| **Audio meters**     | `audioMeterWidget`       | L/R and/or programme LUFS on the left edge (optional)    |+| **Audio meters**    | `audioMeterWidget`        | L/R and/or programme LUFS on the left edge (optional)    |
 | **Clock**           | `clockWidget`             | Digital or analog, with logo and optional weather widget | | **Clock**           | `clockWidget`             | Digital or analog, with logo and optional weather widget |
-| **Lock LED**        | Clock lock                | Bottom right: `PTP/NTP/LTC LOCK` or `LOCAL`               | +| **Lock LED**        | Clock lock                | Bottom right: `PTP/NTP/LTC LOCK` or `LOCAL`              | 
-| **AIR Timers 1–4**  | `AirLED_1`–`AirLED_4`     | Stopwatch timers with icon, label, MM:SS; AIR3 with ▲/▼ |+| **AIR Timers 1–4**  | `AirLED_1`–`AirLED_4`     | Stopwatch timers with icon, label, MM:SS; AIR3 with ▲/▼  | 
 +| **Date**            | `labelTextLeft`           | Bottom left: weekday and date                            |
 | **NOW**             | `labelCurrentSong`        | First footer line (e.g. current song title)              | | **NOW**             | `labelCurrentSong`        | First footer line (e.g. current song title)              |
 | **NEXT**            | `labelNews`               | Second footer line (e.g. next title)                     | | **NEXT**            | `labelNews`               | Second footer line (e.g. next title)                     |
 | **WARN**            | `labelWarning`            | Warning message; hides NOW/NEXT when active              | | **WARN**            | `labelWarning`            | Warning message; hides NOW/NEXT when active              |
 +| **Text clock**      | `labelTextRight`          | Bottom right: time in words (wordclock)                  |
  
  
Line 115: Line 183:
 - Default: fullscreen with hidden mouse cursor - Default: fullscreen with hidden mouse cursor
 - Toggle: `F` or `Ctrl+F` (macOS: `Cmd+F`), **double-click** an empty area of the main screen, or right-click / long-click → **Toggle Fullscreen** - Toggle: `F` or `Ctrl+F` (macOS: `Cmd+F`), **double-click** an empty area of the main screen, or right-click / long-click → **Toggle Fullscreen**
-- **Right-click / long-click menu:** Toggle Fullscreen, Settings, Quit OnAirScreen; when meters are enabled also **Start I+LRA**, **Stop I+LRA**, and **Reset I+LRA**+- **Right-click / long-click menu:** Toggle Fullscreen, Settings, Hotkeys, Quit OnAirScreen; when meters are enabled also **Start I+LRA**, **Stop I+LRA**, and **Reset I+LRA**
 - Fullscreen state is saved in settings (`General/fullscreen`) - Fullscreen state is saved in settings (`General/fullscreen`)
 +- Settings → General → **Always start in fullscreen mode** (`General/always_start_fullscreen`, default off) forces fullscreen on every start, even if the last session was windowed. Apply takes effect on the next start.
 - In windowed mode, position and size are saved (`Window/geometry`) and restored on the next start - In windowed mode, position and size are saved (`Window/geometry`) and restored on the next start
  
Line 134: Line 203:
 | Key(s)                            | Function                                        | | Key(s)                            | Function                                        |
 | --------------------------------- | ----------------------------------------------- | | --------------------------------- | ----------------------------------------------- |
 +| `H`                               | Show or hide the hotkey overlay                 |
 | `F` / `Ctrl+F`                    | Toggle fullscreen                               | | `F` / `Ctrl+F`                    | Toggle fullscreen                               |
 | `Ctrl+S` / `Ctrl+,`               | Open settings dialog                            | | `Ctrl+S` / `Ctrl+,`               | Open settings dialog                            |
 | `Q` / `Ctrl+Q` / `Ctrl+C` / `ESC` | Quit OnAirScreen                                | | `Q` / `Ctrl+Q` / `Ctrl+C` / `ESC` | Quit OnAirScreen                                |
 | `I`                               | Display IP addresses in NOW/NEXT for 10 seconds | | `I`                               | Display IP addresses in NOW/NEXT for 10 seconds |
- 
-While quitting, the main screen shows WARN `QUITTING ONAIRSCREEN` until the window closes. 
  
  
 +The overlay lists these shortcuts on the main screen. Close it with `H`, `Esc`, or a click on the dimmed background. Other main-window hotkeys are blocked while it is open; `Esc` does not quit until the overlay is closed. Right-click / long-click → **Hotkeys** opens the same overlay.
  
 +While quitting, the main screen shows WARN `QUITTING ONAIRSCREEN` until the window closes.
  
 ### Status LEDs ### Status LEDs
Line 153: Line 223:
 | `3` | LED 3 on/off | | `3` | LED 3 on/off |
 | `4` | LED 4 on/off | | `4` | LED 4 on/off |
 +
  
 Left-click on a status LED toggles it as well. Left-click on a status LED toggles it as well.
- 
- 
- 
  
 ### AIR Timers ### AIR Timers
Line 172: Line 240:
 | `T`                 | Top-of-Hour countdown on/off | AIR3                | | `T`                 | Top-of-Hour countdown on/off | AIR3                |
 | `Enter` / `Return`  | Open timer input dialog      | AIR3                | | `Enter` / `Return`  | Open timer input dialog      | AIR3                |
 +
  
 Left-click on an AIR timer starts or stops it (same as `M` / `P` / Space / `S`). Reset, TOTH, and the timer dialog stay keyboard or remote. Left-click on an AIR timer starts or stops it (same as `M` / `P` / Space / `S`). Reset, TOTH, and the timer dialog stay keyboard or remote.
- 
- 
- 
  
 ### OAS USB Keyboard (Special Mapping) ### OAS USB Keyboard (Special Mapping)
Line 196: Line 262:
  
  
-| Tab                   | Content                                  | +| Tab              | Content                                                                     | 
-| --------------------- | ---------------------------------------- | +| ---------------- | --------------------------------------------------------------------------- | 
-| **General**           | Instance name, station, LEDs, clock, logo, updates | +| **General**      | Instance name, station, LEDs, clock, logo, fullscreen start                 | 
-| **Network**           | UDP, HTTP, multicast, MQTT, OSC         | +| **Updates**      | Update check, update key, hardware activation                               | 
-| **Time Source**       | Local / NTP / PTPv2 / LTC clock, NTP check | +| **Network**      | UDP, HTTP, multicast, MQTT, OSC, SNMP                                       | 
-| **Advanced**          | Formatting, weather                      | +| **Links**        | Discover other OnAirScreens; replicas (1→n full status) and source mappings | 
-| **Timers**            | AIR timers 1–4                           | +| **Advanced**     | Formatting, weather                                                         | 
-| **Fonts**             | Fonts for all elements                   | +| **Timers**       | AIR timers 1–4                                                              | 
-| **Audio Meters**      | Level meters, source, TooLoud, Silence Detection | +| **Fonts**        | Fonts for all elements                                                      | 
-| **GPIO**              | Raspberry Pi GPIO inputs for mixer GPI           | +| **Time Source**  | Local / NTP / PTPv2 / LTC clock, NTP check                                  | 
-| **About**             | Version, license info, log level, log folder, reset  | +| **Audio Meters** | Level meters, source, TooLoud, Silence Detection                            | 
-| **License**           | OASL 1.0 plus third-party notices (PySide6/Qt, fonts, examples) |+| **GPIO**         | Raspberry Pi, Axia Livewire, and MIDI inputs (parallel)                     | 
 +| **About**        | Version, license info, log level, log folder, reset, host reboot/shutdown   | 
 +| **License**      | OASL 1.0 plus third-party notices (PySide6/Qt, fonts, examples)             |
  
  
Line 236: Line 304:
  
  
-| Setting       | Key                    | Default    | Description | +| Setting       | Key                    | Default    | Description                                                                                                      | 
-| ------------- | ---------------------- | ---------- | ----------- |+| ------------- | ---------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------- |
 | Instance Name | `General/instancename` | `Studio-1` | DNS-safe label (1–32 characters, letters/digits/hyphen, no leading or trailing `-`) identifying this OnAirScreen | | Instance Name | `General/instancename` | `Studio-1` | DNS-safe label (1–32 characters, letters/digits/hyphen, no leading or trailing `-`) identifying this OnAirScreen |
  
  
 The instance name appears in the Web UI (title and status), in `/api/status` (`instance`), on MQTT `{base}/instance/state`, and as a Home Assistant sensor. The HA device name becomes `OnAirScreen (Studio-1)` unless the instance name is already part of the device name. Remote: `CONF:General:instancename=TEXT`. The instance name appears in the Web UI (title and status), in `/api/status` (`instance`), on MQTT `{base}/instance/state`, and as a Home Assistant sensor. The HA device name becomes `OnAirScreen (Studio-1)` unless the instance name is already part of the device name. Remote: `CONF:General:instancename=TEXT`.
 +
 +**The name must be unique on the LAN.** If another OnAirScreen announces the same name, Settings → General, Settings → Links, and the Web UI show a warning with the other host(s). Nearby lists each colliding host separately (`name collision`). Linking does not guess which IP to use — set the host, or rename one instance. Apply is rejected while the name still collides.
  
 #### Station Name and Slogan #### Station Name and Slogan
Line 307: Line 377:
  
  
-| Setting               | Key                          | Default          | Description                        | +| Setting               | Key                          | Default   | Description                                                                                                                                       | 
-| --------------------- | ---------------------------- | ---------------- | ---------------------------------- | +| --------------------- | ---------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | 
-| Digital / Analog      | `Clock/digital`              | `true` (Digital) | Clock mode                         | +| Clock Face            | `Clock/face`                 | `digital` | `digital`, `analog`, `analog_numbers`, `analog_studio`, `analog_railway`, `analog_24h_smooth`, `analog_24h_ticking` (`analog_24h` aliases smooth) | 
-| Hours LEDs            | `Clock/digitalhourcolor`     | `#3232FF`        | Hour digit color                   | +| Digital (legacy)      | `Clock/digital`              | `true`    | Kept in sync with `Clock/face` (`true` = digital)                                                                                                 | 
-| Seconds LEDs          | `Clock/digitalsecondcolor`   | `#FF9900`        | Seconds color                      | +| Hours LEDs            | `Clock/digitalhourcolor`     | `#3232FF` | Hour digit color                                                                                                                                  | 
-| Digits LEDs           | `Clock/digitaldigitcolor`    | `#3232FF`        | All digit color                    | +| Seconds LEDs          | `Clock/digitalsecondcolor`   | `#FF9900` | Seconds color                                                                                                                                     | 
-| Show seconds          | `Clock/showSeconds`          | `false`          | Show seconds                       | +| Digits LEDs           | `Clock/digitaldigitcolor`    | `#3232FF` | All digit color                                                                                                                                   | 
-| Seconds Layout        | `Clock/showSecondsInOneLine` | `false`          | `separate` or `in one line`        | +| Show seconds          | `Clock/showSeconds`          | `false`   | Show seconds                                                                                                                                      | 
-| Static colon          | `Clock/staticColon`          | `false`          | Static colon (non-blinking)        | +| Seconds Layout        | `Clock/showSecondsInOneLine` | `false`   | `separate` or `in one line`                                                                                                                       | 
-| Use textclock         | `Clock/useTextClock`         | `true`           | Text clock (e.g. "it's 3 o'clock") | +| Static colon          | `Clock/staticColon`          | `false`   | Static colon (non-blinking)                                                                                                                       | 
-| Replace IPs after 10s | `General/replacenow`         | `false`          | Replace text after IP display      | +| Use textclock         | `Clock/useTextClock`         | `true`    | Text clock (e.g. "it's 3 o'clock")                                                                                                                | 
-| Replace with text     | `General/replacenowtext`     | *(empty)*        | Replacement text for NOW line      |+| Replace IPs after 10s | `General/replacenow`         | `false`   | Replace text after IP display                                                                                                                     | 
 +| Replace with text     | `General/replacenowtext`     | *(empty)* | Replacement text for NOW line                                                                                                                     |
  
 +
 +
 +
 +#### Display
 +
 +
 +| Setting                         | Key                               | Default | Description                                                      |
 +| ------------------------------- | --------------------------------- | ------- | ---------------------------------------------------------------- |
 +| Always start in fullscreen mode | `General/always_start_fullscreen` | `false` | Always open in fullscreen, even if the last session was windowed |
 +
 +
 +Apply does not switch the current window; the option applies on the next start. Without it, OnAirScreen still restores the last fullscreen state (`General/fullscreen`, default on).
 +
 +### 5.2 Updates
  
  
Line 335: Line 420:
 > The update feature is intended for **precompiled (paid) versions**. > The update feature is intended for **precompiled (paid) versions**.
 > >
-> To use update checking in the paid version, an **Update Key** must be entered. You can find it in the customer portal at [customer.astrastudio.de](https://customer.astrastudio.de) after placing your order. The field is masked; use the slashed-eye icon to show it.+> To use update checking in the paid version, an **Update Key** must be entered. You can find it in the customer portal at [customer.astrastudio.de](https://customer.astrastudio.de) after placing your order. One license covers one PC or one Raspberry Pi. The field is masked; use the slashed-eye icon to show it. 
 + 
 + 
 + 
 +#### Activation (paid builds) 
 + 
 +Shop builds must be activated. Self-built OpenSource builds are not. 
 + 
 +1. Copy the update key from the customer portal into **Update Key**. 
 +2. **Activate** (needs internet) or copy the **Hardware ID**, download a license file in the portal, and **Import license file**. 
 +3. The activation is valid for one year unless your order is set differently. The Updates tab shows whether this computer can renew online now. If the license server is not reachable, download a new license file in the portal and import it before the activation expires. The update key stays the same. You do not buy a new key. 
 +4. To move the license, choose **Return license**, then redeem the return code in the portal (or it is redeemed automatically when this computer is online). Activate the new computer. A dead computer can only be released by astrastudio support. 
 +5. Without a license, OnAirScreen runs fully for 14 days. After that it stays visible but cannot go fullscreen, use GPIO or audio meters, or save settings. The window is limited to 1280×800 and the app closes after 15 minutes. The same limits apply when a license has expired. 
 +6. At startup the update key is checked with the license server even when **Check for Updates** is off. If the server rejects the key, the license on this computer is removed at once and the same limits apply. Later starts do not repeat that automatic check or the notice. **Check now** still runs. A missing network connection does not remove the license. A new activation checks the key again. 
 + 
 +If this activation does not fit your use case, contact us via the [contact form](https://www.astrastudio.de/kontakt/). We will work out a custom solution. 
 + 
 +The same actions are in the Web UI settings overlay.
  
 --- ---
  
-### 5.2 Network+ 
 + 
 +### 5.3 Network
  
  
Line 346: Line 450:
  
  
-| Setting           | Key                         | Default       | Description               | +| Setting           | Key                         | Default       | Description                                                                                                                                                                                                                                     | 
-| ----------------- | --------------------------- | ------------- | ------------------------- | +| ----------------- | --------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 
-| UDP Port          | `Network/udpport`           | `3310`        | Port for UDP commands     | +| UDP Port          | `Network/udpport`           | `3310`        | Port for UDP commands                                                                                                                                                                                                                           | 
-| HTTP Port         | `Network/httpport`          | `8010`        | Port for HTTP/Web UI      | +| HTTP Port         | `Network/httpport`          | `8010`        | Port for HTTP/Web UI                                                                                                                                                                                                                            | 
-| Multicast Address | `Network/multicast_address` | `239.194.0.1` | Multicast address for UDP | +| Multicast Address | `Network/multicast_address` | `239.194.0.1` | Multicast address for UDP                                                                                                                                                                                                                       | 
-| Web Settings PIN  | `Network/websettingspin`    | *(empty)*     | Optional PIN for the Web UI settings overlay (stored hashed). Empty = no PIN. Leave the field empty to keep the current PIN; enter `-` to remove it. Remote Control stays unprotected. |+| Web Settings PIN  | `Network/websettingspin`    | *(empty)*     | Optional PIN for the Web UI settings overlay and for HTTP `CMD:REBOOT` / `CMD:SHUTDOWN` (stored hashed). Empty = no PIN. Leave the field empty to keep the current PIN; enter `-` to remove it. Other Remote Control commands stay unprotected. | 
 + 
  
  
Line 374: Line 480:
  
  
-| Setting            | Key                | Default   | Description                                              | +| Setting            | Key               | Default   | Description                                              | 
-| ------------------ | ------------------ | --------- | -------------------------------------------------------- | +| ------------------ | ----------------- | --------- | -------------------------------------------------------- | 
-| enable OSC support  | `OSC/enableosc`    | `false`   | Enable OSC remote control                                | +| enable OSC support | `OSC/enableosc`   | `false`   | Enable OSC remote control                                | 
-| OSC Listen Port    | `OSC/oscport`      | `8000`    | UDP port for incoming OSC                               | +| OSC Listen Port    | `OSC/oscport`     | `8000`    | UDP port for incoming OSC                                | 
-| OSC Send Host      | `OSC/oscsendhost`  | *(empty)* | Destination for status push (Companion IP); empty = none | +| OSC Send Host      | `OSC/oscsendhost` | *(empty)* | Destination for status push (Companion IP); empty = none | 
-| OSC Send Port      | `OSC/oscsendport`  | `9000`    | Destination UDP port (Companion feedback port)             |+| OSC Send Port      | `OSC/oscsendport` | `9000`    | Destination UDP port (Companion feedback port)           |
  
  
 Send Host is only needed for unsolicited status push (Companion button feedback). Queries always reply to the UDP sender. Send Host is only needed for unsolicited status push (Companion button feedback). Queries always reply to the UDP sender.
  
----+#### SNMP
  
-### 5.3 Time Source 
  
-The display clock can follow the local system clock, an NTP server, a PTPv2 (IEEE 1588-2008) master, or SMPTE LTC (Leo Bodnar LBE-1110 USB serial **or** decoded from a local audio input). **OnAirScreen never changes the operating-system clock.** NTP and PTP steer an independent timebase (`time.monotonic()`), so a jump of the system clock does not move the studio clock. LTC may jump, freeze, and includes frames (`HH:MM:SS:FF`).+| Setting             | Key                       | Default   | Description                                          | 
 +| ------------------- | ------------------------- | --------- | ---------------------------------------------------- | 
 +| enable SNMP support | `SNMP/enablesnmp`         | `false`   | Enable the SNMPv2c/v3 agent                          | 
 +| SNMP Listen Port    | `SNMP/snmpport`           | `1161`    | UDP port. 161 needs OS privileges                    | 
 +| sysContact          | `SNMP/syscontact`         | *(empty)* | MIB-2 sysContact                                     | 
 +| sysLocation         | `SNMP/syslocation`        | *(empty)* | MIB-2 sysLocation                                    | 
 +| v2c Read Community  | `SNMP/snmpcommunity`      | `public`  | Empty disables v2c. Masked                           | 
 +| v2c Write Community | `SNMP/snmpwritecommunity` | *(empty)* | Empty makes v2c read-only. Masked                    | 
 +| v3 User             | `SNMP/snmpv3user`         | *(empty)* | Empty disables v3                                    | 
 +| v3 Auth Password    | `SNMP/snmpv3authpass`     | *(empty)* | SHA-256. Empty = noAuthNoPriv (testing only). Masked | 
 +| v3 Priv Password    | `SNMP/snmpv3privpass`     | *(empty)* | AES-128. Empty = authNoPriv when auth is set. Masked | 
 +| enable SNMP traps   | `SNMP/enabletraps`        | `false`   | Send traps to the NMS                                | 
 +| Trap Host           | `SNMP/snmptraphost`       | *(empty)* | NMS hostname/IP                                      | 
 +| Trap Port           | `SNMP/snmptrapport`       | `162`     | NMS trap port                                        | 
 +| Trap Version        | `SNMP/snmptrapversion`    | `v2c`     | `v2c` or `v3`                                        | 
 +| Trap Community      | `SNMP/snmptrapcommunity`  | `public`  | Community for v2c traps. Masked                      | 
 +| trap on silence     | `SNMP/trap_silence`       | `true`    | Trap when silence starts or clears                   | 
 +| trap on warning     | `SNMP/trap_warning`       | `true`    | Trap when WARN text changes                          | 
 +| trap on LED change  | `SNMP/trap_leds`          | `false`   | Trap when an LED turns on or off (can be noisy)      |
  
-Date, text clock, and AIR3 top-of-hour follow the same wall time as the large clock when the source is Local, NTP, or PTP. With LTC they keep using the system date/time, because LTC has no calendar date. 
  
 +At least a v2c community or a v3 user must be set, or the agent will not start. Community and v3 passwords are masked.
  
-| Setting          | Key                    | Default        | Description | +---
-| ---------------- | ---------------------- | -------------- | ----------- | +
-| Time Source      | `TimeSource/source`    | `local`        | `local`, `ntp`, `ptp`, or `ltc` | +
-| Enable NTP-Check | `NTP/ntpcheck`         | `true`         | Warning if time diverges from the NTP server or the server is unreachable | +
-| NTP Server       | `NTP/ntpcheckserver`   | `pool.ntp.org` | NTP server for NTP as time source **and** for the optional NTP check | +
-| PTP Interface    | `TimeSource/ptp_iface` | *(empty)*      | IPv4 address of the PTP network interface (independent of AoIP) | +
-| PTP Domain       | `TimeSource/ptp_domain`| `0`            | IEEE 1588 domain (0–255) | +
-| LTC Input        | `TimeSource/ltc_input` | `serial`       | `serial` (LBE-1110) or `audio` (local PortAudio decode) | +
-| LTC Serial Port  | `TimeSource/ltc_port`  | *(empty)*      | USB serial device of the LBE-1110; empty = Auto | +
-| LTC Audio Device | `TimeSource/ltc_audio_device` | *(empty)* | Local capture device; empty = system default | +
-| LTC Channel      | `TimeSource/ltc_audio_channel` | `0`     | `0` = Left, `1` = Right | +
-| LTC unlock warning | `TimeSource/ltc_warn` | `false` | WARN text when LTC drops; the `LTC NOT LOCKED` LED always remains |+
  
  
-**Local System Clock:** The display uses the OS clock. With NTP-Check enabled, the OS clock is compared to the NTP server (deviation > 0.3 s or errors → warning, priority -1). 
  
-**NTP Server:** OnAirScreen queries the NTP Server field and steers its own clock. The OS time is not used after the first successful sample. The field stays editable even when NTP-Check is off. Loss of NTP: last time keeps running and a warning is shown.+### 5.4 Links
  
-**PTPv2 IEEE 1588-2008:** Software slave on multicast `224.0.1.129` UDP 319/320 (event/general), delay mechanism E2E. Typical accuracy is milliseconds (no hardware timestamping). Choose the studio/AoIP VLAN interface independently of the Audio Meters AoIP interface. Loss of Sync: last time keeps running plus warning.+Link several OnAirScreens on the LAN (multicast discovery by **instance name**) or by typing a host and HTTP port. Instance names must be unique; a collision is flagged in Settings and the Web UI, and Apply is rejected. There are no exclusive master/slave roles: any instance can publish replicas **and** subscribe to sources.
  
-**LTC:** One time source with two inputs. Frame rate is inferred from incoming frames (24 / 25 / 30). Loss of LTC: last timecode is frozen (`LTC NOT LOCKED`). The large WARN messages (`waiting for LTC lock`, `Clock not LTC synchronized`, `LTC reader not connected`) are **off by default** so video scrubbing does not flood WARN; enable **Show LTC unlock warning** if you want them. The lock LED always shows `LTC LOCK` / `LTC NOT LOCKED`. NTP-Check still compares the OS clock to the NTP server, not the timecode.+**Replicas** (this screen is the source): add nearby instances. Apply writes a Follow on each target and pushes the full **runtime** status: LED1–4 (state, caption, autoflash/timedflash), AIR1–4 (state, seconds, ToH/countdown), NOW / NEXT / WARN (including the warning stack). Clock, meters, GPIO wiring, network ports, and the instance name stay local. Configure 1→n once on the source — you do not walk to each replica.
  
-**LBE-1110 Serial:** USB CDC virtual serial port of a [Leo Bodnar LBE-1110](https://www.leobodnar.com/shop/index.php?main_page=product_info&cPath=120&products_id=374); no drivers. Auto selects a Leo Bodnar device (USB VID `0x1DD2`) or an LBE-1110 / CDC port.+**Sources** (this screen is the destination): map `Studio-1 / LED1 → LED1` and `Studio-2 / LED1 → LED2` for a hallway tally. Signals: LED1–4, AIR1–4, NOW, NEXT, WARN, silence, or **Follow all**. Follow all copies the full runtime status, so Local target and Invert are unused. Invert applies to boolean signals. **Custom** is extra API commands (semicolon-separated) that fire when the source is active; they run in addition to Local target. Choose Local target **Custom only** if you want those commands without driving a local LED, AIR, or text field.
  
-**Audio Input:** Decodes SMPTE LTC (biphase-mark) from a **local** PortAudio capture device, independent of Audio Meters (not Livewire/AES67). Choose Left or Right (default Left). On some hosts the same device cannot be opened twice — if meters already use that input, pick a different device for LTC.+A screen may have only **one** full Follow. If it is already a replica of Studio-1, Studio-2 cannot add it as a replica (HTTP 409). Mappings from other instances are allowed for fields the Follow does not occupy. Offline sources keep the last state (no automatic all-off). Removing a replica clears Follow on the target and leaves lamps as they are.
  
-The clock lock LED (bottom right) is green when the selected source is locked and red when it is not. Next to it: `PTP LOCK` / `PTP NOT LOCKED`, `NTP LOCK` / `NTP NOT LOCKED`, `LTC LOCK` / `LTC NOT LOCKED`, or `LOCAL`.+Discovery uses multicast `239.194.0.2` UDP **3311** (not the command group `239.194.0.1:3310`). Runtime status is **pushed on change** to replicas and to screens that mapped this instance; there is no continuous HTTP poll of every peer. Host-local WARN text (`QUITTING ONAIRSCREEN`, reboot/shutdown, NTP) stays on that screen. HTTP `/api/link/follow`, `/api/link/unfollow`, `/api/link/snapshot`, and `/api/link/watch` do not use the Web Settings PIN (same model as UDP/HTTP commands). 
 + 
 + 
 +| Setting                 | Key                     | Default   | Description                                                                                                                                                                                                                                  | 
 +| ----------------------- | ----------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 
 +| Enable instance linking | `Links/enabled`         | `false`   | Push replicas and apply mappings. Name discovery for uniqueness always runs.                                                                                                                                                                 | 
 +| Replica *n*             | `Links/replicaN_`*      | off       | Target instance (dropdown of nearby screens, or type a name). Leave Host empty to resolve the current IP from the name (DHCP-safe). Host is only a fallback when multicast does not reach them, or to pick one machine if the name collides. | 
 +| Map *n*                 | `Links/mapN_`*          | off       | Source instance (nearby dropdown per row), signal, local target, invert, custom command. Host empty = discover by name.                                                                                                                      | 
 +| Replica of              | `Links/follow_instance` | *(empty)* | Written when another screen adds this one as a replica                                                                                                                                                                                       |
  
-> **Recommendation:** Use a local NTP server on your studio network, as `pool.ntp.org` can be unreliable at times. 
  
 --- ---
  
-### 5.4 Advanced+ 
 + 
 +### 5.5 Advanced
  
  
Line 463: Line 583:
  
  
-Type a city name next to **City ID**, press **Find** (or Return), and pick a match from the dropdown. The City ID is filled automatically; you can still enter an ID by hand. The API key is masked; use the slashed-eye icon to show it.+Type a city name next to **City ID**, press **Find** (or Return), and pick a match from the dropdown. The City ID is filled automatically; you can still enter an ID by hand. The widget shows the searched city name, not the OpenWeatherMap station or neighborhood name. The API key is masked; use the slashed-eye icon to show it.
  
 **Test API:** Button to test the API connection with current settings. **Test API:** Button to test the API connection with current settings.
Line 475: Line 595:
  
  
-### 5.5 Timers+### 5.6 Timers
  
 For each AIR timer (group `Timers`): For each AIR timer (group `Timers`):
Line 501: Line 621:
  
  
-| Setting         | Key                | Default       | Description                                              | +| Setting         | Key                | Default      | Description                                          | 
-| --------------- | ------------------ | ------------- | -------------------------------------------------------- | +| --------------- | ------------------ | ------------ | ---------------------------------------------------- | 
-| TOTH Timer Text | `TimerTOTHText`    | `TOTH Timer`  | AIR3 label while the top-of-hour countdown is active     | +| TOTH Timer Text | `TimerTOTHText`    | `TOTH Timer` | AIR3 label while the top-of-hour countdown is active | 
-| AIR Min Width   | `TimerAIRMinWidth` | `200`         | Minimum width of AIR displays (pixels)                   |+| AIR Min Width   | `TimerAIRMinWidth` | `200`        | Minimum width of AIR displays (pixels)               |
  
  
Line 511: Line 631:
  
  
-### 5.6 Fonts+### 5.7 Fonts
  
 Font family, size, and weight can be set individually for each UI element: Font family, size, and weight can be set individually for each UI element:
  
  
-| Element      | Group `Fonts`                     | Default              | +| Element      | Group `Fonts`                     | Default            | 
-| ------------ | --------------------------------- | -------------------- |+| ------------ | --------------------------------- | ------------------ |
 | LED1–4       | `LED{n}FontName/Size/Weight`      | Roboto, 32pt, Bold | | LED1–4       | `LED{n}FontName/Size/Weight`      | Roboto, 32pt, Bold |
 | AIR1–4       | `AIR{n}FontName/Size/Weight`      | Roboto, 24pt, Bold | | AIR1–4       | `AIR{n}FontName/Size/Weight`      | Roboto, 24pt, Bold |
Line 532: Line 652:
  
  
-### 5.7 About+### 5.8 Time Source
  
 +The display clock can follow the local system clock, an NTP server, a PTPv2 (IEEE 1588-2008) master, or SMPTE LTC (Leo Bodnar LBE-1110 USB serial **or** decoded from a local audio input). **OnAirScreen never changes the operating-system clock.** NTP and PTP steer an independent timebase (`time.monotonic()`), so a jump of the system clock does not move the studio clock. LTC may jump, freeze, and includes frames (`HH:MM:SS:FF`).
  
-| Element            | Description                                             | +Date, text clock, and AIR3 top-of-hour follow the same wall time as the large clock when the source is Local, NTP, or PTP. With LTC they keep using the system date/time, because LTC has no calendar date.
-| ------------------ | ------------------------------------------------------- | +
-| Version            | Current OnAirScreen version                             | +
-| Distribution       | `OpenSource` or commercial distribution                 | +
-| Settings Path      | Path to the configuration file on this system           | +
-| Log Folder         | Folder with `onairscreen.log` and crash reports         | +
-| Open log folder    | Opens that folder in the system file manager            | +
-| Loglevel           | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`, `NONE` | +
-| Enable Reset       | Checkbox to enable the reset button                     | +
-| Reset all settings | Resets **all** settings to defaults (cannot be undone)  |+
  
 +
 +| Setting            | Key                            | Default        | Description                                                               |
 +| ------------------ | ------------------------------ | -------------- | ------------------------------------------------------------------------- |
 +| Time Source        | `TimeSource/source`            | `local`        | `local`, `ntp`, `ptp`, or `ltc`                                           |
 +| Enable NTP-Check   | `NTP/ntpcheck`                 | `true`         | Warning if time diverges from the NTP server or the server is unreachable |
 +| NTP Server         | `NTP/ntpcheckserver`           | `pool.ntp.org` | NTP server for NTP as time source **and** for the optional NTP check      |
 +| PTP Interface      | `TimeSource/ptp_iface`         | *(empty)*      | IPv4 address of the PTP network interface (independent of AoIP)           |
 +| PTP Domain         | `TimeSource/ptp_domain`        | `0`            | IEEE 1588 domain (0–255)                                                  |
 +| LTC Input          | `TimeSource/ltc_input`         | `serial`       | `serial` (LBE-1110) or `audio` (local PortAudio decode)                   |
 +| LTC Serial Port    | `TimeSource/ltc_port`          | *(empty)*      | USB serial device of the LBE-1110; empty = Auto                           |
 +| LTC Audio Device   | `TimeSource/ltc_audio_device`  | *(empty)*      | Local capture device; empty = system default                              |
 +| LTC Channel        | `TimeSource/ltc_audio_channel` | `0`            | `0` = Left, `1` = Right                                                   |
 +| LTC unlock warning | `TimeSource/ltc_warn`          | `false`        | WARN text when LTC drops; the `LTC NOT LOCKED` LED always remains         |
 +
 +
 +**Local System Clock:** The display uses the OS clock. With NTP-Check enabled, the OS clock is compared to the NTP server (deviation > 0.3 s or errors → warning, priority -1).
 +
 +**NTP Server:** OnAirScreen queries the NTP Server field and steers its own clock. The OS time is not used after the first successful sample. The field stays editable even when NTP-Check is off. Loss of NTP: last time keeps running and a warning is shown.
 +
 +**PTPv2 IEEE 1588-2008:** Software slave on multicast `224.0.1.129` UDP 319/320 (event/general), delay mechanism E2E. Typical accuracy is milliseconds (no hardware timestamping). Choose the studio/AoIP VLAN interface independently of the Audio Meters AoIP interface. Loss of Sync: last time keeps running plus warning. If UDP 319/320 cannot be bound (another stack already holds the ports), the slave retries every few seconds; the lock LED and WARN show `PTP ERROR` until the ports are free. Details stay in the log. On Linux and Raspberry Pi OS, shop `.deb`/`.rpm`/SD images install the `/usr/lib/onairscreen/oas-ptp-bind` helper for UDP 319/320.
 +
 +**LTC:** One time source with two inputs. Frame rate is inferred from incoming frames (24 / 25 / 30). Loss of LTC: last timecode is frozen (`LTC NOT LOCKED`). The large WARN messages (`waiting for LTC lock`, `Clock not LTC synchronized`, `LTC reader not connected`) are **off by default** so video scrubbing does not flood WARN; enable **Show LTC unlock warning** if you want them. The lock LED always shows `LTC LOCK` / `LTC NOT LOCKED`. NTP-Check still compares the OS clock to the NTP server, not the timecode.
 +
 +**LBE-1110 Serial:** USB CDC virtual serial port of a [Leo Bodnar LBE-1110](https://www.leobodnar.com/shop/index.php?main_page=product_info&cPath=120&products_id=374); no drivers. Auto selects a Leo Bodnar device (USB VID `0x1DD2`) or an LBE-1110 / CDC port.
 +
 +**Audio Input:** Decodes SMPTE LTC (biphase-mark) from a **local** PortAudio capture device, independent of Audio Meters (not Livewire/AES67). Choose Left or Right (default Left). On some hosts the same device cannot be opened twice — if meters already use that input, pick a different device for LTC.
 +
 +The clock lock LED (bottom right) is green when the selected source is locked and red when it is not. Next to it: `PTP LOCK` / `PTP NOT LOCKED` / `PTP ERROR`, `NTP LOCK` / `NTP NOT LOCKED`, `LTC LOCK` / `LTC NOT LOCKED`, or `LOCAL`.
 +
 +> **Recommendation:** Use a local NTP server on your studio network, as `pool.ntp.org` can be unreliable at times.
  
 --- ---
Line 551: Line 693:
  
  
-### 5.8 Audio Meters+### 5.9 Audio Meters
  
 Stereo level meters on the left side of the screen: L/R (sample peak, true peak, or BBC PPM), a single programme LUFS bar (EBU R128), or both. L/R bars fill with RMS and overlay the current peak. Programme LUFS is one bar (momentary M, short-term S tick). Integrated I and loudness range (LRA) are off by default and start with `LUFSI:START` (Web UI, MQTT Home Assistant switch, Companion, OSC, UDP/HTTP, or right-click / long-click). `LUFSI:RESET` restarts a running session; if the session is stopped it hides I and LRA on the meter. Right-click or long-click the main screen → **Start I+LRA**, **Stop I+LRA**, or **Reset I+LRA**. Configure under **Settings → Audio Meters**. Stereo level meters on the left side of the screen: L/R (sample peak, true peak, or BBC PPM), a single programme LUFS bar (EBU R128), or both. L/R bars fill with RMS and overlay the current peak. Programme LUFS is one bar (momentary M, short-term S tick). Integrated I and loudness range (LRA) are off by default and start with `LUFSI:START` (Web UI, MQTT Home Assistant switch, Companion, OSC, UDP/HTTP, or right-click / long-click). `LUFSI:RESET` restarts a running session; if the session is stopped it hides I and LRA on the meter. Right-click or long-click the main screen → **Start I+LRA**, **Stop I+LRA**, or **Reset I+LRA**. Configure under **Settings → Audio Meters**.
Line 558: Line 700:
  
  
-| Setting               | Key                          | Default      | Description                                         | +| Setting                              | Key                            | Default    | Description                                                         | 
-| --------------------- | ---------------------------- | ------------ | --------------------------------------------------- | +| ------------------------------------ | ------------------------------ | ---------- | ------------------------------------------------------------------- | 
-| Enable Audio Meters   | `Audio/enabled`              | `true`       | Show meter column                                   | +| Enable Audio Meters                  | `Audio/enabled`                | `true`     | Show meter column                                                   | 
-| Audio Source          | `Audio/source`               | `device`     | `device`, `livewire`, or `aes67`                    | +| Audio Source                         | `Audio/source`                 | `device`   | `device`, `livewire`, or `aes67`                                    | 
-| Audio Input           | `Audio/input_device`         | *(empty)*    | PortAudio device name (when source = Local Input)   | +| Audio Input                          | `Audio/input_device`           | *(empty)*  | PortAudio device name (when source = Local Input)                   | 
-| Livewire Channel      | `Audio/livewire_channel`     | `1`          | Livewire channel 1–32767 (also via Livewire Source combo) | +| Livewire Channel                     | `Audio/livewire_channel`       | `1`        | Livewire channel 1–32767 (also via Livewire Source combo)           | 
-| AoIP Interface        | `Audio/livewire_iface`       | *(empty)*    | IPv4 for Livewire/AES67 IGMP join; empty = default  | +| AoIP Interface                       | `Audio/livewire_iface`         | *(empty)*  | IPv4 for Livewire/AES67 IGMP join; empty = default                  | 
-| AES67 Stream ID       | `Audio/aes67_id`             | *(empty)*    | SDP origin hash of the selected stream              | +| AES67 Stream ID                      | `Audio/aes67_id`               | *(empty)*  | SDP origin hash of the selected stream                              | 
-| AES67 Address         | `Audio/aes67_addr`           | *(empty)*    | Multicast address used for RTP capture              | +| AES67 Address                        | `Audio/aes67_addr`             | *(empty)*  | Multicast address used for RTP capture                              | 
-| AES67 Port            | `Audio/aes67_port`           | `5004`       | RTP UDP port                                        | +| AES67 Port                           | `Audio/aes67_port`             | `5004`     | RTP UDP port                                                        | 
-| AES67 Name            | `Audio/aes67_name`           | *(empty)*    | Display name from SDP `s=`                          | +| AES67 Name                           | `Audio/aes67_name`             | *(empty)*  | Display name from SDP `s=`                                          | 
-| AES67 Codec           | `Audio/aes67_codec`          | `L24`        | `L16` or `L24`                                      | +| AES67 Codec                          | `Audio/aes67_codec`            | `L24`      | `L16` or `L24`                                                      | 
-| AES67 Sample Rate     | `Audio/aes67_rate`           | `48000`      | `44100`, `48000`, or `96000`                        | +| AES67 Sample Rate                    | `Audio/aes67_rate`             | `48000`    | `44100`, `48000`, or `96000`                                        | 
-| AES67 Channels        | `Audio/aes67_channels`       | `2`          | Stream channel count (meter uses first two)         | +| AES67 Channels                       | `Audio/aes67_channels`         | `2`        | Stream channel count (meter uses first two)                         | 
-| AES67 Pasted SDP      | `Audio/aes67_manual`         | `false`      | `true` if the stream was added via Paste SDP        | +| AES67 Pasted SDP                     | `Audio/aes67_manual`           | `false`    | `true` if the stream was added via Paste SDP                        | 
-| Meter Layout          | `Audio/layout`               | `both`       | `lr`, `lufs`, or `both`                             | +| Meter Layout                         | `Audio/layout`                 | `both`     | `lr`, `lufs`, or `both`                                             | 
-| Display Unit          | `Audio/unit`                 | `dbtp`       | L/R unit: `dbfs`, `dbtp`, `bbc_ppm` (PPM only in `lr`) | +| Display Unit                         | `Audio/unit`                   | `dbtp`     | L/R unit: `dbfs`, `dbtp`, `bbc_ppm` (PPM only in `lr`)              | 
-| Display Style         | `Audio/display_style`        | `bargraph`   | `solid` or `bargraph`                               | +| Display Style                        | `Audio/display_style`          | `bargraph` | `solid` or `bargraph`                                               | 
-| Meter Width           | `Audio/meter_width`          | `115`        | Overall width in pixels (53–150); extra width thickens visible bars | +| Meter Width                          | `Audio/meter_width`            | `115`      | Overall width in pixels (53–201); extra width thickens visible bars | 
-| LUFS Reference Preset | `Audio/lufs_reference_preset`| `ebu_r128`   | `ebu_r128`, `atsc_a85`, `aes_16`, `aes_18`, `custom` | +| LUFS Reference Preset                | `Audio/lufs_reference_preset`  | `ebu_r128` | `ebu_r128`, `atsc_a85`, `aes_16`, `aes_18`, `custom`                | 
-| LUFS Reference        | `Audio/lufs_reference`       | `-23.0`      | Target level in LUFS (peg on the scale)             | +| LUFS Reference                       | `Audio/lufs_reference`         | `-23.0`    | Target level in LUFS (peg on the scale)                             | 
-| Peak Hold             | `Audio/peak_hold`            | `true`       | Hold peak marker                                    | +| Peak Hold                            | `Audio/peak_hold`              | `true`     | Hold peak marker                                                    | 
-| Peak Hold Seconds     | `Audio/peak_hold_seconds`    | `1.5`        | Peak hold duration                                  | +| Peak Hold Seconds                    | `Audio/peak_hold_seconds`      | `1.5`      | Peak hold duration                                                  | 
-| TooLoud               | `Audio/tooloud`              | `true`       | Action when true peak exceeds threshold             | +| TooLoud                              | `Audio/tooloud`                | `true`     | Action when true peak exceeds threshold                             | 
-| TooLoud Text          | `Audio/tooloudtext`          | `TOO LOUD`   | Warning text                                        | +| TooLoud Text                         | `Audio/tooloudtext`            | `TOO LOUD` | Warning text                                                        | 
-| TooLoud Threshold     | `Audio/tooloud_threshold_dbtp` | `-1.0`     | Threshold in dBTP                                   | +| TooLoud Threshold                    | `Audio/tooloud_threshold_dbtp` | `-1.0`     | Threshold in dBTP                                                   | 
-| TooLoud Action        | `Audio/tooloud_action`       | `warning`    | `warning` or `led`                                  | +| TooLoud Action                       | `Audio/tooloud_action`         | `warning`  | `warning` or `led`                                                  | 
-| TooLoud LED           | `Audio/tooloud_led`          | `1`          | LED 1–4 when action = LED                           | +| TooLoud LED                          | `Audio/tooloud_led`            | `1`        | LED 1–4 when action = LED                                           | 
-| Enable Silence Detection | `Audio/silence`          | `false`      | Watch the current audio source for silence         | +| Enable Silence Detection             | `Audio/silence`                | `false`    | Watch the current audio source for silence                          | 
-| Show WARN in OAS      | `Audio/silence_warn`         | `true`       | Show the silence alarm as an on-screen WARN       | +| Show WARN in OAS                     | `Audio/silence_warn`           | `true`     | Show the silence alarm as an on-screen WARN                         | 
-| Trigger when Device/Stream is absent | `Audio/silence_on_absent` | `true` | Count missing capture (no device / no stream) as silence | +| Trigger when Device/Stream is absent | `Audio/silence_on_absent`      | `true`     | Count missing capture (no device / no stream) as silence            | 
-| Silence Message       | `Audio/silence_text`         | `SILENCE`    | WARN text (only used when Show WARN is on)        | +| Silence Message                      | `Audio/silence_text`           | `SILENCE`  | WARN text (only used when Show WARN is on)                          | 
-| Silence Threshold     | `Audio/silence_threshold_dbfs` | `-50.0`   | Sample-peak threshold in dBFS (−90…0)            | +| Silence Threshold                    | `Audio/silence_threshold_dbfs` | `-50.0`    | Sample-peak threshold in dBFS (−90…0)                               | 
-| Max. Silence duration | `Audio/silence_duration_s`  | `10.0`       | Seconds below threshold before the alarm latches  | +| Max. Silence duration                | `Audio/silence_duration_s`     | `10.0`     | Seconds below threshold before the alarm latches                    | 
-| Recovery time         | `Audio/silence_recovery_s`  | `2.0`        | Seconds above threshold before the alarm clears  | +| Recovery time                        | `Audio/silence_recovery_s`     | `2.0`      | Seconds above threshold before the alarm clears                     | 
-| HTTP GET URL          | `Audio/silence_http_url`    | *(empty)*    | Optional URL called once when silence becomes true |+| HTTP GET URL                         | `Audio/silence_http_url`       | *(empty)*  | Optional URL called once when silence becomes true                  | 
  
 Silence Detection uses the **same audio source** as the meters (Local Input, Livewire, or AES67). The threshold is always **sample-peak dBFS**, independent of the meter display unit. Capture keeps running when Silence Detection is on, even if the meters are hidden. Silence Detection uses the **same audio source** as the meters (Local Input, Livewire, or AES67). The threshold is always **sample-peak dBFS**, independent of the meter display unit. Capture keeps running when Silence Detection is on, even if the meters are hidden.
Line 608: Line 751:
  
 **Local input:** on macOS grant microphone permission to OnAirScreen. **Local input:** on macOS grant microphone permission to OnAirScreen.
- 
  
 --- ---
Line 614: Line 756:
  
  
-### 5.9 GPIO+### 5.10 GPIO / MIDI 
 + 
 +GPIO maps contacts, Livewire source pins, and MIDI messages to the same LED and AIR commands as the network API. Configure under **Settings → GPIO**. Inner tabs at the top: **Raspberry Pi**, **Axia Livewire**, **MIDI**, and **Logic**. Pi, Livewire, and MIDI can be enabled at the same time. Logic combines On/Off levels from all three. 
 + 
 +#### Raspberry Pi
  
-Raspberry Pi GPIO inputs map mixer GPI contacts to the same LED and AIR commands as the network API. Configure under **Settings → GPIO**. Available on Raspberry Pi only.+Raspberry Pi GPIO inputs map mixer GPI contacts. Available on Raspberry Pi only; other platforms show “not available” on this sub-tab.
  
 Pi GPIO is **3.3 V**. Mixer GPI is often 5–24 V or open collector — **always use a PC817 isolation module**. Dry relay contacts to GND may be wired directly (internal pull-up, Invert on). Pi GPIO is **3.3 V**. Mixer GPI is often 5–24 V or open collector — **always use a PC817 isolation module**. Dry relay contacts to GND may be wired directly (internal pull-up, Invert on).
  
-| Setting        | Key                    | Default | Description | 
-| -------------- | ---------------------- | ------- | ----------- | 
-| Enable GPIO    | `GPIO/enabled`         | `false` | Watch configured BCM pins | 
-| Debounce       | `GPIO/debounce_ms`     | `50`    | Ignore bounce shorter than this (ms) | 
-| GPI*n* Enable  | `GPIO/gpiN_enabled`    | GPI1–2 on, 3–8 off | Use this input | 
-| GPI*n* BCM pin | `GPIO/gpiN_pin`        | 17, 27, 5, 6, 12, 13, 16, 22 | Safe BCM pins only | 
-| GPI*n* Invert  | `GPIO/gpiN_invert`     | `true`  | On: contact to GND is active (pull-up) | 
-| GPI*n* Mode    | `GPIO/gpiN_mode`       | `level` | `level`, `rising`, `falling`, `both` | 
-| GPI*n* Action  | `GPIO/gpiN_action`     | LED1 / AIR3 | LED1–4, AIR1–4, AIR3/AIR4 Reset, Custom | 
-| GPI*n* Command | `GPIO/gpiN_command`    | *(empty)* | API command for Custom action | 
  
-**Level** (typical tally / fader): closed sends `LED1:ON` / `AIR3:ON`, open sends `OFF`. **Rising / Falling / Both** send `TOGGLE` (or Reset / the custom command) on that edge.+| Setting        | Key                 | Default                      | Description                                                      | 
 +| -------------- | ------------------- | ---------------------------- | ---------------------------------------------------------------- | 
 +| Enable GPIO    | `GPIO/enabled`      | `false`                      | Watch configured BCM pins                                        | 
 +| Debounce       | `GPIO/debounce_ms`  | `50`                         | Ignore bounce shorter than this (ms)                             | 
 +| GPI*n* Enable  | `GPIO/gpiN_enabled` | GPI1–2 on, 3–8 off           | Use this input                                                   | 
 +| GPI*n* Name    | `GPIO/gpiN_name`    | *(empty)*                    | Short label for Logic rules, e.g. MIC1                           | 
 +| GPI*n* BCM pin | `GPIO/gpiN_pin`     | 17, 27, 5, 6, 12, 13, 16, 22 | Safe BCM pins only                                               | 
 +| GPI*n* Invert  | `GPIO/gpiN_invert`  | `true`                       | On: contact to GND is active (pull-up)                           | 
 +| GPI*n* Mode    | `GPIO/gpiN_mode`    | `level`                      | `level`, `rising`, `falling`, `both`                             | 
 +| GPI*n* Actions | `GPIO/gpiN_action`  | LED1 / AIR3                  | One or more of LED1–4, AIR1–4, AIR3/AIR4 Reset (comma-separated) | 
 +| GPI*n* Command | `GPIO/gpiN_command` | *(empty)*                    | Extra API commands, separated by semicolon                       | 
 + 
 + 
 +**Level** (typical tally / fader): closed sends `LED1:ON` / `AIR3:ON` for each selected action, open sends `OFF`. Custom commands fire only while the contact is closed. **Rising / Falling / Both** send `TOGGLE` (or Reset / the custom commands) on that edge. Legacy `CUSTOM` in the action field still means “custom commands only”.
  
 Factory mapping for a two-wire mixer GPI: GPI1 BCM 17 → LED1 (ON AIR), GPI2 BCM 27 → AIR3 (radio timer). Enable GPIO and connect the contacts through a PC817 module (or dry relays to GND). Factory mapping for a two-wire mixer GPI: GPI1 BCM 17 → LED1 (ON AIR), GPI2 BCM 27 → AIR3 (radio timer). Enable GPIO and connect the contacts through a PC817 module (or dry relays to GND).
Line 653: Line 802:
 </mermaid> </mermaid>
 <markdown> <markdown>
 +
 +
  
  
Line 667: Line 818:
 </mermaid> </mermaid>
 <markdown> <markdown>
 +
 +
  
  
Line 673: Line 826:
 **Factory defaults on the header** (board oriented with the USB/Ethernet ports down, pin 1 is the corner 3.3 V next to the SD card / power end on most boards): **Factory defaults on the header** (board oriented with the USB/Ethernet ports down, pin 1 is the corner 3.3 V next to the SD card / power end on most boards):
  
-| OAS input | BCM | Header pin | Typical use | + 
-| --------- | --- | ---------- | ----------- | +| OAS input | BCM | Header pin                   | Typical use        | 
-| GPI1      | 17  | 11         | ON AIR (LED1) | +| --------- | --- | ---------------------------- | ------------------ | 
-| GPI2      | 27  | 13         | Radio timer (AIR3) | +| GPI1      | 17  | 11                           | ON AIR (LED1)      | 
-| Ground    | —   | 6, 9, 14, 20, 25, 30, 34, 39 | Common GND |+| GPI2      | 27  | 13                           | Radio timer (AIR3) | 
 +| Ground    | —   | 6, 9, 14, 20, 25, 30, 34, 39 | Common GND         | 
  
 Safe BCM pins and their header pins (use these in **BCM pin**): Safe BCM pins and their header pins (use these in **BCM pin**):
 +
  
 | BCM | Header | BCM | Header | BCM | Header | | BCM | Header | BCM | Header | BCM | Header |
Line 687: Line 843:
 | 16  | 36     | 17  | 11     | 24  | 18     | | 16  | 36     | 17  | 11     | 24  | 18     |
 | 26  | 37     | 27  | 13     | 25  | 22     | | 26  | 37     | 27  | 13     | 25  | 22     |
 +
  
 **Pinout references** (40-pin header, BCM numbering): **Pinout references** (40-pin header, BCM numbering):
Line 694: Line 851:
 - Pi 5 overview: [Raspberry Pi 5](https://www.raspberrypi.com/documentation/computers/raspberry-pi-5.html) - Pi 5 overview: [Raspberry Pi 5](https://www.raspberrypi.com/documentation/computers/raspberry-pi-5.html)
 - Compute Module IO boards: [Compute Module](https://www.raspberrypi.com/documentation/computers/compute-module.html) - Compute Module IO boards: [Compute Module](https://www.raspberrypi.com/documentation/computers/compute-module.html)
 +
 +
 +
 +#### Axia Livewire
 +
 +Axia Livewire GPIO follows source pins (Operator Mic, Guest Mic, Line, …) and maps them to the same LED and AIR commands. OnAirScreen only **reads** GPIO (it does not write GPI back to the console). Available on all platforms. Use the **Axia Livewire** inner tab.
 +
 +Two modes:
 +
 +- **Multicast** (default): CMsg2 on `239.192.255.4`. The mapping **Channel** is the Livewire **audio channel** of that source. Put the machine on the AoIP / Livewire VLAN with IGMP, and pick the same interface as the Livewire audio meters (empty = default route).
 +- **LWRP (TCP)**: connect to a device (xNode GPIO, iPort, console, …) at **IP:93**. The mapping column is **Port** — the GPIO port on that device, not a Livewire audio channel. No IGMP join; the host must be reachable on the Livewire/AoIP network.
 +
 +Typical microphone ON-AIR profile: **GPO pin 1** is the ON lamp (latched while the channel is ON; often off during TALK/MUTE). GPI 1 would be the ON command *to* the console — OAS does not send that.
 +
 +
 +| Setting              | Key                    | Default            | Description                                                             |
 +| -------------------- | ---------------------- | ------------------ | ----------------------------------------------------------------------- |
 +| Enable Livewire GPIO | `GPIO/lw_enabled`      | `false`            | Follow Livewire GPIO (multicast or LWRP)                                |
 +| Mode                 | `GPIO/lw_transport`    | `multicast`        | `multicast` or `lwrp`                                                   |
 +| Host                 | `GPIO/lw_host`         | *(empty)*          | Device IPv4 (LWRP)                                                      |
 +| Port                 | `GPIO/lw_port`         | `93`               | LWRP TCP port                                                           |
 +| Password             | `GPIO/lw_password`     | *(empty)*          | Optional LWRP `LOGIN` password                                          |
 +| AoIP interface       | `Audio/livewire_iface` | *(empty)*          | IPv4 interface for IGMP (multicast mode; same as Audio Meters)          |
 +| Debounce             | `GPIO/lw_debounce_ms`  | `50`               | Ignore bounce shorter than this (ms)                                    |
 +| GPI*n* Enable        | `GPIO/lw_gpiN_enabled` | rows 1–2 on        | Use this mapping row                                                    |
 +| GPI*n* Name          | `GPIO/lw_gpiN_name`    | *(empty)*          | Short label for Logic rules, e.g. MIC1                                  |
 +| GPI*n* Channel/Port  | `GPIO/lw_gpiN_channel` | 1, 2, then row *n* | Livewire channel (multicast) or GPIO port on the device (LWRP), 1–32767 |
 +| GPI*n* Direction     | `GPIO/lw_gpiN_dir`     | `gpo`              | `gpo` (from console) or `gpi` (to console)                              |
 +| GPI*n* Pin           | `GPIO/lw_gpiN_pin`     | `1`                | Pin 1–5 on that channel/port                                            |
 +| GPI*n* Invert        | `GPIO/lw_gpiN_invert`  | `false`            | Off: Livewire low (L/l) is active                                       |
 +| GPI*n* Mode          | `GPIO/lw_gpiN_mode`    | `level`            | `level`, `rising`, `falling`, `both`                                    |
 +| GPI*n* Actions       | `GPIO/lw_gpiN_action`  | LED1 / AIR3        | One or more of LED1–4, AIR1–4, AIR3/AIR4 Reset (comma-separated)        |
 +| GPI*n* Command       | `GPIO/lw_gpiN_command` | *(empty)*          | Extra API commands, separated by semicolon                              |
 +
 +
 +Factory mapping (master **Enable Livewire GPIO** stays off): row 1 channel/port 1 GPO pin 1 → LED1, row 2 channel/port 2 GPO pin 1 → AIR3.
 +
 +Multicast is `239.192.255.4` UDP **2055** (GPIO node → console) and **2060** (console → node). OAS joins both. After the join, OAS requests the current pin state so a microphone that is already ON at start lights the LED.
 +
 +**LWRP:** OAS opens TCP 93, sends `LOGIN` (with password if set), `ADD GPI`, `ADD GPO`, then queries each watched port so a microphone that is already ON at start lights the LED. Reconnects if the socket drops.
 +
 +**Level** (typical ON lamp): GPO 1 low sends `LED1:ON`, high sends `OFF`. Invert stays **off** unless the console polarity is reversed.
 +
 +#### MIDI
 +
 +**MIDI** reads one input interface (Settings → GPIO → MIDI) and maps Note or CC messages to the same LED and AIR commands. **Learn** waits up to 10 seconds for the next Note or CC and fills channel, type, and number. Clock, Active Sensing, and SysEx are ignored.
 +
 +
 +| Setting           | Key                     | Default   | Description                                                         |
 +| ----------------- | ----------------------- | --------- | ------------------------------------------------------------------- |
 +| Enable MIDI       | `GPIO/midi_enabled`     | `false`   | Listen on the selected interface                                    |
 +| Interface         | `GPIO/midi_port`        | *(empty)* | Input port name. A missing device stays listed as not connected     |
 +| Debounce          | `GPIO/midi_debounce_ms` | `20`      | Oneshot and Toggle treat a burst closer than this as one press (ms) |
 +| MIDI*n* Enable    | `GPIO/midiN_enabled`    | `false`   | Use this row                                                        |
 +| MIDI*n* Name      | `GPIO/midiN_name`       | *(empty)* | Short label for Logic, e.g. PAD                                     |
 +| MIDI*n* Channel   | `GPIO/midiN_channel`    | `1`       | MIDI channel 1–16                                                   |
 +| MIDI*n* Type      | `GPIO/midiN_kind`       | `note`    | `note` or `cc`                                                      |
 +| MIDI*n* Number    | `GPIO/midiN_number`     | `0`       | Note or CC number, 0–127                                            |
 +| MIDI*n* Threshold | `GPIO/midiN_threshold`  | `64`      | CC at or above this is active                                       |
 +| MIDI*n* Behavior  | `GPIO/midiN_behavior`   | `follow`  | `follow` (On/Off), `oneshot`, or `toggle`                           |
 +| MIDI*n* Invert    | `GPIO/midiN_invert`     | `false`   | On/Off swaps the held level. Oneshot sends OFF instead of ON        |
 +| MIDI*n* Actions   | `GPIO/midiN_action`     | *(empty)* | LED1–4, AIR1–4, AIR3/AIR4 Reset                                     |
 +| MIDI*n* Command   | `GPIO/midiN_command`    | *(empty)* | Extra API commands, semicolon-separated                             |
 +
 +
 +**On/Off** holds the level: Note On (velocity > 0) or a CC at the threshold sends `LED1:ON`, Note Off or a CC below the threshold sends `OFF`. **Oneshot** sends `LED1:ON` once per press, or `LED1:OFF` when Invert is on. **Toggle** sends `LED1:TOGGLE` once per press. Reset and custom commands fire once for both, including an inverted Oneshot. Both fire again even when the controller never sends Note Off. A fader that keeps sending CCs above the threshold stays one burst. Two enabled rows on the same channel, type, and number both fire, and the tab shows a warning. While Settings is open, an enabled row flashes when a Note or CC arrives on its channel, type, and number.
 +
 +**Only On/Off rows appear in Logic.** Oneshot and Toggle are missing from the Logic input menu even when the row is enabled and named, because they do not hold a level. Every On/Off row is listed, including rows whose Enable box is off. That disabled input counts as off inside a rule. Unnamed On/Off rows are labeled MIDI1 … MIDI8. A name is shown as `PAD (MIDI1)`. To use a MIDI row in Logic, set Behavior to On/Off.
 +
 +#### Logic
 +
 +**Logic** combines Raspberry Pi, Livewire, and MIDI On/Off inputs. Each rule has one operator, one or more inputs, and one or more outputs. The outputs follow the combined level: a command is sent only when that result changes. The input menu lists every Pi input, every Livewire input, and every MIDI row set to On/Off. MIDI Oneshot and Toggle rows are left out. A MIDI On/Off row stays in the menu when Enable is off.
 +
 +
 +| Operator | Outputs turn on                | Outputs turn off                 |
 +| -------- | ------------------------------ | -------------------------------- |
 +| OR       | any selected input is active   | every selected input is inactive |
 +| AND      | every selected input is active | any selected input is inactive   |
 +
 +
 +Example: name Pi GPI1 `MIC1` and Pi GPI2 `MIC2`. Rule `OR` with those two inputs and outputs LED1 and AIR1 stays on while either microphone is open, and turns both off only when both are closed.
 +
 +Inputs that are disabled, missing, or not yet seen count as off. An empty input list stays off. Resets and custom commands fire when the rule becomes true, not when it becomes false. Direct row actions (including edge modes) keep working beside the rules. If the same LED or AIR timer is also set on a row or on another rule, that Logic row shows a warning.
 +
 +
 +| Setting           | Key                   | Default   | Description                                   |
 +| ----------------- | --------------------- | --------- | --------------------------------------------- |
 +| Rule *n* Enable   | `GPIO/logicN_enabled` | `false`   | Use this rule                                 |
 +| Rule *n* Operator | `GPIO/logicN_op`      | `or`      | `or` or `and`                                 |
 +| Rule *n* Inputs   | `GPIO/logicN_inputs`  | *(empty)* | `pi:1`, `lw:2`, `midi:3`, comma-separated     |
 +| Rule *n* Outputs  | `GPIO/logicN_action`  | *(empty)* | LED1–4, AIR1–4, AIR3/AIR4 Reset               |
 +| Rule *n* Command  | `GPIO/logicN_command` | *(empty)* | Extra API commands when the rule becomes true |
 +
 +
 +Eight rules. A microphone that is already on when OnAirScreen starts turns a matching rule on as soon as that input level is known.
 +
 +---
 +
 +
 +
 +### 5.11 About
 +
 +
 +| Element            | Description                                                 |
 +| ------------------ | ----------------------------------------------------------- |
 +| Version            | Current OnAirScreen version                                 |
 +| Distribution       | `OpenSource` or commercial distribution                     |
 +| Settings Path      | Path to the configuration file on this system               |
 +| Log Folder         | Folder with `onairscreen.log` and crash reports             |
 +| Open log folder    | Opens that folder in the system file manager                |
 +| Loglevel           | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`, `NONE`     |
 +| Enable Reset       | Checkbox to enable the reset button                         |
 +| Reset all settings | Resets **all** settings to defaults (cannot be undone)      |
 +| Reboot             | Reboot the host operating system (asks for confirmation)    |
 +| Shutdown           | Shut down the host operating system (asks for confirmation) |
  
  
Line 746: Line 1018:
  
  
-| Input            | Meaning                           | +| Input                    | Meaning                           | 
-| ---------------- | --------------------------------- | +| ------------------------ | --------------------------------- | 
-| `2,10` or `2.10` | 2 minutes 10 seconds (count-down) | +| `2:10`, `2,10` or `2.10` | 2 minutes 10 seconds (count-down) | 
-| `30`             | 30 seconds (count-down)           | +| `30`                     | 30 seconds (count-down)           | 
-| `0`              | Count-up mode                     |+| `0`                      | Count-up mode                     |
  
  
Line 809: Line 1081:
  
 - **Digital:** LED-style digit display with configurable colors - **Digital:** LED-style digit display with configurable colors
-- **Analog:** Classic clock face+- **Analog:** Classic ticks and hands without numerals 
 +- **Analog Numbers:** Classic analog face with 1–12 
 +- **Analog Studio:** White face, black ticks, numerals 1–12 
 +- **Analog Railway:** White station face without numerals, pointed black hands, sweeping red second hand with a ring 
 +- **Analog 24h smooth:** Cream face, black 1–12 and red 13–24, sweeping second hand 
 +- **Analog 24h ticking:** Same cream 24h face with a ticking second hand 
 + 
 +![Digital clock face](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Clockfaces_digital.png) 
 + 
 +![Analog clock face](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Clockfaces_analog.png) 
 + 
 +![Analog Numbers clock face](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Clockfaces_analog_numbers.png) 
 + 
 +![Analog Studio clock face](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Clockfaces_analog_studio.png) 
 + 
 +![Analog Railway clock face](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Clockfaces_analog_railway.png) 
 + 
 +![Analog 24h clock face (smooth or ticking second hand)](https://www.astrastudio.de/wp-content/uploads/2026/09/OAS_Clockfaces_analog_24h.png) 
 - **Text clock:** Spoken time display (e.g. "it's a quarter past three") - **Text clock:** Spoken time display (e.g. "it's a quarter past three")
-- **Time source:** Local, NTP, PTPv2, or LTC — see [5.3 Time Source](#53-time-source); the OS clock is never set+- **Time source:** Local, NTP, PTPv2, or LTC — see [5.8 Time Source](#time_source); the OS clock is never set
 - **Lock LED** bottom right: green = locked, red = not locked (`PTP LOCK` / `NTP LOCK` / `LTC LOCK`, or `LOCAL`) - **Lock LED** bottom right: green = locked, red = not locked (`PTP LOCK` / `NTP LOCK` / `LTC LOCK`, or `LOCAL`)
 - **Weather widget:** Optionally displayed next to the clock (OpenWeatherMap) - **Weather widget:** Optionally displayed next to the clock (OpenWeatherMap)
Line 817: Line 1107:
  
  
-### 6.6 System Commands (API only)+### 6.6 System Commands
  
  
Line 827: Line 1117:
  
  
-> These commands are **not** available through the settings UI, only via API/MQTT.+Reboot and Shutdown are also in **Settings → About** and the Web UI **System** section. Both ask for confirmation. HTTP `CMD:REBOOT` / `CMD:SHUTDOWN` require the Web Settings PIN when one is set (`X-Settings-Token`). UDP, MQTT, OSC, GPIO, and SNMP stay unauthenticated. `CMD:QUIT` remains API-only.
  
-### 6.7 GPIO Inputs (Raspberry Pi)+### 6.7 GPIO Inputs
  
-Mixer GPI (contact closure) can drive LEDs and AIR timers through Raspberry Pi GPIO. See [5.9 GPIO](#59-gpio) for the wiring diagram, PC817 module, header pins, and pinout links. GPIO is local hardware, not a network API.+Mixer GPI (contact closure) can drive LEDs and AIR timers through **Raspberry Pi** GPIO. Axia consoles can drive the same LED and AIR actions through **Livewire GPIO** (multicast source channel or LWRP TCP 93, e.g. mic ON lamp). A MIDI controller can drive them from Note and CC messages on one input. All three can run at the same time. See [5.10 GPIO](#510-gpio) for Pi wiring, Livewire channel/port mapping, MIDI Learn, and the AoIP interface. Pi GPIO is local hardware; Livewire GPIO is multicast or a TCP session on the AoIP network; MIDI is the selected input port.
  
 --- ---
Line 839: Line 1129:
 ## 7. Remote Control and API ## 7. Remote Control and API
  
-OnAirScreen supports remote control via UDP, HTTP, Web UI, MQTT, OSC, REST API, and Bitfocus Companion.+OnAirScreen supports remote control via UDP, HTTP, Web UI, MQTT, OSC, SNMP, REST API, and Bitfocus Companion.
  
 ### 7.1 UDP (Port 3310) ### 7.1 UDP (Port 3310)
Line 887: Line 1177:
 - Persistent connection badge (Live / Polling / Offline) plus error modal - Persistent connection badge (Live / Polling / Offline) plus error modal
 - Settings gear (top right): tabbed overlay for all editable settings, optional PIN, Apply, and preset load/save - Settings gear (top right): tabbed overlay for all editable settings, optional PIN, Apply, and preset load/save
 +- Links in the overlay: same Nearby list, Add as replica / Use as source, and Replicas / Sources grids as the desktop Settings
 - Audio Meters in the overlay: Livewire Source and AES67 Stream dropdowns (live discovery while the overlay is open) plus Paste SDP - Audio Meters in the overlay: Livewire Source and AES67 Stream dropdowns (live discovery while the overlay is open) plus Paste SDP
 +
  
  
Line 911: Line 1203:
   "lra": null,   "lra": null,
   "instance": "Studio-1",   "instance": "Studio-1",
-  "version": "1.0.0beta11", +  "version": "1.0.10", 
-  "distribution": "OpenSource"+  "distribution": "OpenSource", 
 +  "link": { "enabled": false, "follow": null, "replicas": [], "peers": 0 }
 } }
 ``` ```
Line 923: Line 1216:
 curl "http://127.0.0.1:8010/api/command?cmd=LED1:ON" curl "http://127.0.0.1:8010/api/command?cmd=LED1:ON"
 ``` ```
 +
 +**Instance links** (no Web Settings PIN):
 +
 +```bash
 +curl http://127.0.0.1:8010/api/link/peers
 +curl -X POST http://127.0.0.1:8010/api/link/follow -H 'Content-Type: application/json' \
 +  -d '{"source_instance":"Studio-1","source_http_port":8010}'
 +curl -X POST http://127.0.0.1:8010/api/link/unfollow -H 'Content-Type: application/json' \
 +  -d '{"source_instance":"Studio-1"}'
 +```
 +
 +`link` in `/api/status` shows whether this screen is a replica (`follow`) and which instances it pushes to (`replicas`).
  
 **Web settings** (optional PIN via `X-Settings-Token` after `POST /api/settings/auth`): **Web settings** (optional PIN via `X-Settings-Token` after `POST /api/settings/auth`):
Line 935: Line 1240:
  
 Secrets (`updatekey`, MQTT password, OpenWeatherMap API key) are returned in plaintext so the settings overlay can show them. The PIN is returned as `__unchanged__` (only a hash is stored). Send that sentinel to keep the PIN, or `-` to clear it. UDP/HTTP port changes are stored immediately but need an application restart. Secrets (`updatekey`, MQTT password, OpenWeatherMap API key) are returned in plaintext so the settings overlay can show them. The PIN is returned as `__unchanged__` (only a hash is stored). Send that sentinel to keep the PIN, or `-` to clear it. UDP/HTTP port changes are stored immediately but need an application restart.
- 
  
 ### 7.5 MQTT ### 7.5 MQTT
Line 942: Line 1246:
  
  
-| Topic            | Payload                 | Function         | +| Topic                   | Payload                           | Function               | 
-| ---------------- | ----------------------- | ---------------- | +| ----------------------- | --------------------------------- | ---------------------- | 
-| `led{1-4}/set`   | `ON` / `OFF` / `TOGGLE` | Switch LED       | +| `led{1-4}/set`          | `ON` / `OFF` / `TOGGLE`           | Switch LED             | 
-| `air{1-4}/set`   | `ON` / `OFF` / `TOGGLE` | Start/stop timer | +| `air{1-4}/set`          | `ON` / `OFF` / `TOGGLE`           | Start/stop timer       | 
-| `air{3-4}/reset` | `PRESS`                 | Reset timer      | +| `air{3-4}/reset`        | `PRESS`                           | Reset timer            | 
-| `air3/toh`       | `ON` / `OFF` / `TOGGLE` | Top-of-Hour      | +| `air3/toh`              | `ON` / `OFF` / `TOGGLE`           | Top-of-Hour            | 
-| `lufs/integrated/set` | `ON` / `OFF` / `TOGGLE` / `RESET` | Start/stop/reset I+LRA | +| `lufs/integrated/set`   | `ON` / `OFF` / `TOGGLE` / `RESET` | Start/stop/reset I+LRA | 
-| `lufs/integrated/reset` | `PRESS` | Reset I+LRA | +| `lufs/integrated/reset` | `PRESS`                           | Reset I+LRA            | 
-| `text/now/set`   | `TEXT`                  | Set NOW text     | +| `text/now/set`          | `TEXT`                            | Set NOW text           | 
-| `text/next/set`  | `TEXT`                  | Set NEXT text    | +| `text/next/set`         | `TEXT`                            | Set NEXT text          | 
-| `text/warn/set`  | `TEXT`                  | Set WARN text    |+| `text/warn/set`         | `TEXT`                            | Set WARN text          |
  
  
Line 958: Line 1262:
  
  
-| Topic              | Payload           | +| Topic                        | Payload                     | 
-| ------------------ | ----------------- | +| ---------------------------- | --------------------------- | 
-| `led{1-4}/state`   | `ON` / `OFF`      | +| `led{1-4}/state`             | `ON` / `OFF`                | 
-| `air{1-4}/state`   | `ON` / `OFF`      | +| `air{1-4}/state`             | `ON` / `OFF`                | 
-| `air{1-4}/time`    | Seconds (integer) | +| `air{1-4}/time`              | Seconds (integer)           | 
-| `air3/toh/state`   | `true` / `false`  | +| `air3/toh/state`             | `true` / `false`            | 
-| `text/{now,next,warn}/state` | Text    | +| `text/{now,next,warn}/state` | Text                        | 
-| `warning/active`  | `true` / `false`  | +| `warning/active`             | `true` / `false`            | 
-| `silence/active`   | `true` / `false`  | +| `silence/active`             | `true` / `false`            | 
-| `lufs/integrated/state` | `ON` / `OFF` | +| `lufs/integrated/state`      | `ON` / `OFF`                | 
-| `lufs/i`           | I in LUFS (`""` if unknown) | +| `lufs/i`                     | I in LUFS (`""` if unknown) | 
-| `lufs/lra`         | LRA in LU (`""` if unknown) | +| `lufs/lra`                   | LRA in LU (`""` if unknown) | 
-| `instance/state`   | Instance name     |+| `instance/state`             | Instance name               |
  
  
Line 988: Line 1292:
  
 The Home Assistant device name becomes `OnAirScreen (Studio-1)` unless the instance name is already part of the MQTT Device Name. The Home Assistant device name becomes `OnAirScreen (Studio-1)` unless the instance name is already part of the MQTT Device Name.
- 
- 
  
 ### 7.6 Bitfocus Companion (recommended) ### 7.6 Bitfocus Companion (recommended)
Line 1006: Line 1308:
 Drag presets for LED1–4 (toggle + colour), AIR1–4 with live caption and time on the button (MIC = AIR1), TOTH, Reset AIR3/4, NOW / NEXT / WARN, Silence, Loudness I+LRA, and Reset I+LRA. Drag presets for LED1–4 (toggle + colour), AIR1–4 with live caption and time on the button (MIC = AIR1), TOTH, Reset AIR3/4, NOW / NEXT / WARN, Silence, Loudness I+LRA, and Reset I+LRA.
  
-Variables such as `$(oas:air1_time)`, `$(oas:lufs_i)`, and `$(oas:lra)` and feedbacks (LED on, AIR running, TOTH, Silence, WARN, Loudness I+LRA) update from WebSocket or the status poll. Set the connection Label to `oas` so those examples match. The connection status shows instance name and version, for example `Studio-1 · 1.0.0beta11`. The module `HELP.md` lists every action, feedback, and variable.+Variables such as `$(oas:air1_time)`, `$(oas:lufs_i)`, and `$(oas:lra)` and feedbacks (LED on, AIR running, TOTH, Silence, WARN, Loudness I+LRA) update from WebSocket or the status poll. Set the connection Label to `oas` so those examples match. The connection status shows instance name and version, for example `Studio-1 · 1.0.10`. The module `HELP.md` lists every action, feedback, and variable.
  
 If you cannot load a custom module, **Generic OSC** remains available (next section). Status push over OSC is slower (every 5 seconds) than the HTTP poll / WebSocket. If you cannot load a custom module, **Generic OSC** remains available (next section). Status push over OSC is slower (every 5 seconds) than the HTTP poll / WebSocket.
Line 1017: Line 1319:
  
  
-| Address              | Argument                         | Function              | +| Address                      | Argument                    | Function           | 
-| -------------------- | -------------------------------- | --------------------- | +| ---------------------------- | --------------------------- | ------------------ | 
-| `/oas/led{1-4}`      | `i` 0/1, or none for toggle       | LED                   | +| `/oas/led{1-4}`              | `i` 0/1, or none for toggle | LED                | 
-| `/oas/air{1-4}`      | `i` 0/1, or none for toggle        | AIR timer             | +| `/oas/air{1-4}`              | `i` 0/1, or none for toggle | AIR timer          | 
-| `/oas/air{3-4}/reset` | none                             | Reset AIR3/AIR4       | +| `/oas/air{3-4}/reset`        | none                        | Reset AIR3/AIR4    | 
-| `/oas/air3/toh`      | `i` 0/1                          | Top-of-Hour           | +| `/oas/air3/toh`              | `i` 0/1                     | Top-of-Hour        | 
-| `/oas/air3/time`     | `i` seconds (omit to query)       | Set AIR3 time         | +| `/oas/air3/time`             | `i` seconds (omit to query) | Set AIR3 time      | 
-| `/oas/text/now`      | `s` text                         | NOW                   | +| `/oas/text/now`              | `s` text                    | NOW                | 
-| `/oas/text/next`     | `s` text                         | NEXT                  | +| `/oas/text/next`             | `s` text                    | NEXT               | 
-| `/oas/text/warn`     | `s` text                         | WARN                  | +| `/oas/text/warn`             | `s` text                    | WARN               | 
-| `/oas/command`       | `s` `COMMAND:VALUE`              | Raw API command       | +| `/oas/command`               | `s` `COMMAND:VALUE`         | Raw API command    | 
-| `/oas/lufs/integrated` | `i` 0/1, or none for toggle     | Start/stop I + LRA    | +| `/oas/lufs/integrated`       | `i` 0/1, or none for toggle | Start/stop I + LRA | 
-| `/oas/lufs/integrated/reset` | none                       | Reset I + LRA         |+| `/oas/lufs/integrated/reset` | none                        | Reset I + LRA      |
  
  
Line 1046: Line 1348:
 python3 utils/oas_osc_send.py /oas/led2/state python3 utils/oas_osc_send.py /oas/led2/state
 ``` ```
 +
 +
  
 #### Alternative: Generic OSC #### Alternative: Generic OSC
Line 1065: Line 1369:
 Query-reply to the command socket is **not** used by Companion (it listens on a different UDP port). Query-reply to the command socket is **not** used by Companion (it listens on a different UDP port).
  
 +### 7.8 SNMP (Port 1161)
  
-### 7.8 Command Reference+Enable SNMP under **Settings → Network**. The agent speaks **SNMPv2c** and **SNMPv3** (USM, SHA-256, AES-128). The default listen port is **1161** (unprivileged). Port 161 is possible but needs OS privileges on Linux/macOS. 
 + 
 +The MIB is `mibs/ASTRASTUDIO-ONAIRSCREEN-MIB.txt` and [on the wiki](https://www.astrastudio.de/wiki/onairscreen:mib-en) for download. Enterprise OID `.1.3.6.1.4.1.66873` (IANA PEN 66873, astrastudio broadcast solutions). MIB-2 `system` (sysDescr, sysUpTime, sysName, …) is included. 
 + 
 +**GET / WALK** (same status as `/api/status`): LEDs, AIR timers, NOW/NEXT/WARN, silence, loudness I+LRA, version, instance. 
 + 
 +**SET** (same semantics as OSC): LED state `0/1/2` = OFF/ON/TOGGLE, AIR state `0/1/2/3` = OFF/ON/TOGGLE/RESET, AIR3 seconds, AIR3 TOTH, texts, `oasLufsIntegrated`, or `oasCommand` with a raw `COMMAND:VALUE`. v2c SET needs a write community. v3 SET is allowed once an auth password is set. 
 + 
 +**Traps:** silence, WARN text change, optional LED change. Version `v2c` or `v3` (v3 uses the same USM user). 
 + 
 +```bash 
 +# Status walk (v2c) 
 +snmpwalk -v2c -c public localhost:1161 .1.3.6.1.4.1.66873 
 + 
 +# Turn LED1 on 
 +snmpset -v2c -c private localhost:1161 .1.3.6.1.4.1.66873.1.2.1.2.1 i 1 
 + 
 +# Walk with SNMPv3 authPriv 
 +snmpwalk -v3 -l authPriv -u nms -a SHA-256 -A 'auth-secret' -x AES -X 'priv-secret' localhost:1161 .1.3.6.1.4.1.66873 
 +``` 
 + 
 +With an empty write community (the default), v2c is read-only. noAuthNoPriv is for testing only. 
 + 
 +### 7.9 Command Reference
  
  
Line 1073: Line 1401:
  
  
-| Command                      | Function                         | +| Command                           | Function                                                                      | 
-| ---------------------------- | -------------------------------- | +| --------------------------------- | ----------------------------------------------------------------------------- | 
-| `LED{1-4}:[ON/OFF/TOGGLE]`   | Switch LED                       | +| `LED{1-4}:[ON/OFF/TOGGLE]`        | Switch LED                                                                    | 
-| `NOW:TEXT`                   | Set NOW text                     | +| `NOW:TEXT`                        | Set NOW text                                                                  | 
-| `NEXT:TEXT`                  | Set NEXT text                    | +| `NEXT:TEXT`                       | Set NEXT text                                                                 | 
-| `WARN:TEXT`                  | Set warning (priority 0)         | +| `WARN:TEXT`                       | Set warning (priority 0)                                                      | 
-| `WARN:1:TEXT`                | Set warning (priority Medium)    | +| `WARN:1:TEXT`                     | Set warning (priority Medium)                                                 | 
-| `WARN:2:TEXT`                | Set warning (priority High)      | +| `WARN:2:TEXT`                     | Set warning (priority High)                                                   | 
-| `WARN:`                      | Clear warning priority 0         | +| `WARN:`                           | Clear warning priority 0                                                      | 
-| `WARN:1:`                    | Clear warning priority 1         | +| `WARN:1:`                         | Clear warning priority 1                                                      | 
-| `WARN:2:`                    | Clear warning priority 2         | +| `WARN:2:`                         | Clear warning priority 2                                                      | 
-| `AIR1:[ON/OFF/TOGGLE]`       | Microphone timer                 | +| `AIR1:[ON/OFF/TOGGLE]`            | Microphone timer                                                              | 
-| `AIR2:[ON/OFF/TOGGLE]`       | Phone timer                      | +| `AIR2:[ON/OFF/TOGGLE]`            | Phone timer                                                                   | 
-| `AIR3:[ON/OFF/RESET/TOGGLE]` | Radio timer                      | +| `AIR3:[ON/OFF/RESET/TOGGLE]`      | Radio timer                                                                   | 
-| `AIR3TIME:seconds`           | Set radio timer to seconds value | +| `AIR3TIME:seconds`                | Set radio timer to seconds value                                              | 
-| `AIR3TOH:[ON/OFF/TOGGLE]`    | Top-of-Hour countdown            | +| `AIR3TOH:[ON/OFF/TOGGLE]`         | Top-of-Hour countdown                                                         | 
-| `AIR4:[ON/OFF/RESET/TOGGLE]` | Stream timer                     |+| `AIR4:[ON/OFF/RESET/TOGGLE]`      | Stream timer                                                                  |
 | `LUFSI:[START/STOP/TOGGLE/RESET]` | Programme I + LRA session (reset restarts if running, hides I+LRA if stopped) | | `LUFSI:[START/STOP/TOGGLE/RESET]` | Programme I + LRA session (reset restarts if running, hides I+LRA if stopped) |
-| `CMD:REBOOT`                 | OS reboot                        | +| `FULLSCREEN:[ON/OFF/TOGGLE]`      | Main window fullscreen                                                        | 
-| `CMD:SHUTDOWN`               | OS shutdown                      | +| `CMD:REBOOT`                      | OS reboot (HTTP requires Web Settings PIN when set)                           | 
-| `CMD:QUIT`                   | Quit OnAirScreen                 |+| `CMD:SHUTDOWN`                    | OS shutdown (HTTP requires Web Settings PIN when set)                         | 
 +| `CMD:QUIT`                        | Quit OnAirScreen                                                              |
  
  
Line 1105: Line 1434:
  
  
-| Command                                         | Description           | +| Command                                         | Description                                                                                                                                                   | 
-| ----------------------------------------------- | --------------------- | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | 
-| `CONF:General:stationname=TEXT`                 | Station name          | +| `CONF:General:stationname=TEXT`                 | Station name                                                                                                                                                  | 
-| `CONF:General:instancename=TEXT`              | Instance name (DNS label) | +| `CONF:General:instancename=TEXT`                | Instance name (DNS label)                                                                                                                                     | 
-| `CONF:General:slogan=TEXT`                      | Slogan                | +| `CONF:General:slogan=TEXT`                      | Slogan                                                                                                                                                        | 
-| `CONF:General:stationcolor=COLOR`               | Station color         | +| `CONF:General:stationcolor=COLOR`               | Station color                                                                                                                                                 | 
-| `CONF:General:slogancolor=COLOR`                | Slogan color          | +| `CONF:General:slogancolor=COLOR`                | Slogan color                                                                                                                                                  | 
-| `CONF:General:replacenow=[True/False]`          | Enable IP replacement | +| `CONF:General:replacenow=[True/False]`          | Enable IP replacement                                                                                                                                         | 
-| `CONF:General:replacenowtext=TEXT`              | Replacement text      | +| `CONF:General:replacenowtext=TEXT`              | Replacement text                                                                                                                                              | 
-| `CONF:LED[1-4]:used=[True/False]`               | Enable LED            | +| `CONF:LED[1-4]:used=[True/False]`               | Enable LED                                                                                                                                                    | 
-| `CONF:LED[1-4]:text=TEXT`                       | LED text              | +| `CONF:LED[1-4]:text=TEXT`                       | LED text                                                                                                                                                      | 
-| `CONF:LED[1-4]:activebgcolor=COLOR`             | LED active background | +| `CONF:LED[1-4]:activebgcolor=COLOR`             | LED active background                                                                                                                                         | 
-| `CONF:LED[1-4]:activetextcolor=COLOR`           | LED active text       | +| `CONF:LED[1-4]:activetextcolor=COLOR`           | LED active text                                                                                                                                               | 
-| `CONF:LED[1-4]:autoflash=[True/False]`          | Autoflash             | +| `CONF:LED[1-4]:autoflash=[True/False]`          | Autoflash                                                                                                                                                     | 
-| `CONF:LED[1-4]:timedflash=[True/False]`         | 20-second flash       | +| `CONF:LED[1-4]:timedflash=[True/False]`         | 20-second flash                                                                                                                                               | 
-| `CONF:Clock:digital=[True/False]`               | Digital/Analog        | +| `CONF:Clock:face=FACE`                          | Clock face: `digital`, `analog`, `analog_numbers`, `analog_studio`, `analog_railway`, `analog_24h_smooth`, `analog_24h_ticking` (`analog_24h` aliases smooth) | 
-| `CONF:Clock:showseconds=[True/False]`           | Show seconds          | +| `CONF:Clock:digital=[True/False]`               | Digital / classic analog (legacy)                                                                                                                             | 
-| `CONF:Clock:secondsinoneline=[True/False]`      | Seconds on one line   | +| `CONF:Clock:showseconds=[True/False]`           | Show seconds                                                                                                                                                  | 
-| `CONF:Clock:staticcolon=[True/False]`           | Static colon          | +| `CONF:Clock:secondsinoneline=[True/False]`      | Seconds on one line                                                                                                                                           | 
-| `CONF:Clock:digitalhourcolor=COLOR`             | Hour color            | +| `CONF:Clock:staticcolon=[True/False]`           | Static colon                                                                                                                                                  | 
-| `CONF:Clock:digitalsecondcolor=COLOR`           | Seconds color         | +| `CONF:Clock:digitalhourcolor=COLOR`             | Hour color                                                                                                                                                    | 
-| `CONF:Clock:digitaldigitcolor=COLOR`            | Digit color           | +| `CONF:Clock:digitalsecondcolor=COLOR`           | Seconds color                                                                                                                                                 | 
-| `CONF:Clock:logopath=PATH`                      | Logo path             | +| `CONF:Clock:digitaldigitcolor=COLOR`            | Digit color                                                                                                                                                   | 
-| `CONF:Clock:logoupper=[True/False]`             | Logo on top           | +| `CONF:Clock:logopath=PATH`                      | Logo path                                                                                                                                                     | 
-| `CONF:Network:udpport=PORT`                     | UDP port              | +| `CONF:Clock:logoupper=[True/False]`             | Logo on top                                                                                                                                                   | 
-| `CONF:Network:tcpport=PORT`                     | HTTP port             | +| `CONF:Network:udpport=PORT`                     | UDP port                                                                                                                                                      | 
-| `CONF:Audio:enabled=[True/False]`               | Audio meters on/off   | +| `CONF:Network:tcpport=PORT`                     | HTTP port                                                                                                                                                     | 
-| `CONF:Audio:source=[device/livewire/aes67]`     | Audio source          | +| `CONF:Audio:enabled=[True/False]`               | Audio meters on/off                                                                                                                                           | 
-| `CONF:Audio:input_device=DEVICE_NAME`           | Local input device    | +| `CONF:Audio:source=[device/livewire/aes67]`     | Audio source                                                                                                                                                  | 
-| `CONF:Audio:livewire_channel=N`                 | Livewire channel      | +| `CONF:Audio:input_device=DEVICE_NAME`           | Local input device                                                                                                                                            | 
-| `CONF:Audio:livewire_iface=IP_OR_EMPTY`         | AoIP interface IP     | +| `CONF:Audio:livewire_channel=N`                 | Livewire channel                                                                                                                                              | 
-| `CONF:Audio:aes67_id=ORIGIN_HASH`               | AES67 stream id       | +| `CONF:Audio:livewire_iface=IP_OR_EMPTY`         | AoIP interface IP                                                                                                                                             | 
-| `CONF:Audio:aes67_addr=MULTICAST`               | AES67 multicast       | +| `CONF:Audio:aes67_id=ORIGIN_HASH`               | AES67 stream id                                                                                                                                               | 
-| `CONF:Audio:aes67_port=PORT`                    | AES67 RTP port        | +| `CONF:Audio:aes67_addr=MULTICAST`               | AES67 multicast                                                                                                                                               | 
-| `CONF:Audio:aes67_name=NAME`                    | AES67 display name    | +| `CONF:Audio:aes67_port=PORT`                    | AES67 RTP port                                                                                                                                                | 
-| `CONF:Audio:aes67_codec=[L16/L24]`              | AES67 codec           | +| `CONF:Audio:aes67_name=NAME`                    | AES67 display name                                                                                                                                            | 
-| `CONF:Audio:aes67_rate=48000`                   | AES67 sample rate     | +| `CONF:Audio:aes67_codec=[L16/L24]`              | AES67 codec                                                                                                                                                   | 
-| `CONF:Audio:aes67_channels=2`                   | AES67 channel count   | +| `CONF:Audio:aes67_rate=48000`                   | AES67 sample rate                                                                                                                                             | 
-| `CONF:Audio:aes67_manual=[True/False]`          | AES67 pasted SDP      | +| `CONF:Audio:aes67_channels=2`                   | AES67 channel count                                                                                                                                           | 
-| `CONF:Audio:unit=[dbfs/dbtp/bbc_ppm]`          | L/R display unit      | +| `CONF:Audio:aes67_manual=[True/False]`          | AES67 pasted SDP                                                                                                                                              | 
-| `CONF:Audio:layout=[lr/lufs/both]`             | Meter layout          | +| `CONF:Audio:unit=[dbfs/dbtp/bbc_ppm]`           | L/R display unit                                                                                                                                              | 
-| `CONF:Audio:display_style=[solid/bargraph]`     | Meter style           | +| `CONF:Audio:layout=[lr/lufs/both]`              | Meter layout                                                                                                                                                  | 
-| `CONF:Audio:meter_width=79`                     | Meter width (pixels)  | +| `CONF:Audio:display_style=[solid/bargraph]`     | Meter style                                                                                                                                                   | 
-| `CONF:Audio:lufs_reference_preset=PRESET`       | LUFS preset           | +| `CONF:Audio:meter_width=79`                     | Meter width (pixels)                                                                                                                                          | 
-| `CONF:Audio:lufs_reference=-23.0`               | LUFS target           | +| `CONF:Audio:lufs_reference_preset=PRESET`       | LUFS preset                                                                                                                                                   | 
-| `CONF:Audio:peak_hold=[True/False]`             | Peak hold on/off      | +| `CONF:Audio:lufs_reference=-23.0`               | LUFS target                                                                                                                                                   | 
-| `CONF:Audio:peak_hold_seconds=1.5`              | Peak hold duration    | +| `CONF:Audio:peak_hold=[True/False]`             | Peak hold on/off                                                                                                                                              | 
-| `CONF:Audio:tooloud=[True/False]`               | TooLoud on/off        | +| `CONF:Audio:peak_hold_seconds=1.5`              | Peak hold duration                                                                                                                                            | 
-| `CONF:Audio:tooloudtext=TEXT`                   | TooLoud text          | +| `CONF:Audio:tooloud=[True/False]`               | TooLoud on/off                                                                                                                                                | 
-| `CONF:Audio:tooloud_threshold_dbtp=-1.0`        | TooLoud threshold     | +| `CONF:Audio:tooloudtext=TEXT`                   | TooLoud text                                                                                                                                                  | 
-| `CONF:Audio:tooloud_action=[warning/led]`       | TooLoud action        | +| `CONF:Audio:tooloud_threshold_dbtp=-1.0`        | TooLoud threshold                                                                                                                                             | 
-| `CONF:Audio:tooloud_led=[1/2/3/4]`              | TooLoud LED           | +| `CONF:Audio:tooloud_action=[warning/led]`       | TooLoud action                                                                                                                                                | 
-| `CONF:Audio:silence=[True/False]`                | Silence Detection    | +| `CONF:Audio:tooloud_led=[1/2/3/4]`              | TooLoud LED                                                                                                                                                   | 
-| `CONF:Audio:silence_warn=[True/False]`          | Silence WARN on/off | +| `CONF:Audio:silence=[True/False]`               | Silence Detection                                                                                                                                             | 
-| `CONF:Audio:silence_on_absent=[True/False]`      | Absent as silence    | +| `CONF:Audio:silence_warn=[True/False]`          | Silence WARN on/off                                                                                                                                           | 
-| `CONF:Audio:silence_text=TEXT`                  | Silence WARN text    | +| `CONF:Audio:silence_on_absent=[True/False]`     | Absent as silence                                                                                                                                             | 
-| `CONF:Audio:silence_threshold_dbfs=-50.0`      | Silence threshold    | +| `CONF:Audio:silence_text=TEXT`                  | Silence WARN text                                                                                                                                             | 
-| `CONF:Audio:silence_duration_s=10.0`            | Silence duration (s) | +| `CONF:Audio:silence_threshold_dbfs=-50.0`       | Silence threshold                                                                                                                                             | 
-| `CONF:Audio:silence_recovery_s=2.0`             | Silence recovery (s) | +| `CONF:Audio:silence_duration_s=10.0`            | Silence duration (s)                                                                                                                                          | 
-| `CONF:Audio:silence_http_url=URL`                | Silence HTTP GET URL | +| `CONF:Audio:silence_recovery_s=2.0`             | Silence recovery (s)                                                                                                                                          | 
-| `CONF:Timers:TimerAIR[1-4]Enabled=[True/False]` | Enable AIR            | +| `CONF:Audio:silence_http_url=URL`               | Silence HTTP GET URL                                                                                                                                          | 
-| `CONF:Timers:TimerAIR[1-4]Text=TEXT`            | AIR label             | +| `CONF:Timers:TimerAIR[1-4]Enabled=[True/False]` | Enable AIR                                                                                                                                                    | 
-| `CONF:Timers:TimerTOTHText=TEXT`                | TOTH timer label      | +| `CONF:Timers:TimerAIR[1-4]Text=TEXT`            | AIR label                                                                                                                                                     | 
-| `CONF:Timers:AIR[1-4]activebgcolor=COLOR`       | AIR active background | +| `CONF:Timers:TimerTOTHText=TEXT`                | TOTH timer label                                                                                                                                              | 
-| `CONF:Timers:AIR[1-4]activetextcolor=COLOR`     | AIR active text       | +| `CONF:Timers:AIR[1-4]activebgcolor=COLOR`       | AIR active background                                                                                                                                         | 
-| `CONF:Timers:AIR[1-4]iconpath=PATH`             | AIR icon path         | +| `CONF:Timers:AIR[1-4]activetextcolor=COLOR`     | AIR active text                                                                                                                                               | 
-| `CONF:Timers:TimerAIRMinWidth=PIXELS`           | AIR minimum width     | +| `CONF:Timers:AIR[1-4]iconpath=PATH`             | AIR icon path                                                                                                                                                 | 
-| `CONF:CONF:APPLY=TRUE`                          | Apply configuration   |+| `CONF:Timers:TimerAIRMinWidth=PIXELS`           | AIR minimum width                                                                                                                                             | 
 +| `CONF:CONF:APPLY=TRUE`                          | Apply configuration                                                                                                                                           | 
  
 `CONF:Audio:unit=lufs` is still accepted as an alias that sets layout to `lufs` (L/R unit stays `dbtp`). `CONF:Audio:unit=lufs` is still accepted as an alias that sets layout to `lufs` (L/R unit stays `dbtp`).
Line 1209: Line 1540:
 python start.py --loglevel DEBUG python start.py --loglevel DEBUG
 python start.py -l WARNING python start.py -l WARNING
 +python start.py --start-time 2026-09-14T12:00:00
 ``` ```
  
  
-| Option             | Values                                          | Description                    | +| Option             | Values                                          | Description                                          | 
-| ------------------ | ----------------------------------------------- | ------------------------------ | +| ------------------ | ----------------------------------------------- | ---------------------------------------------------- | 
-| `-l`, `--loglevel` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` | Override log level (not saved) |+| `-l`, `--loglevel` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` | Override log level (not saved)                       | 
 +| `--start-time`     | ISO-8601 (`datetime.fromisoformat`)             | Set display start time for this run only (not saved) |
  
  
Line 1243: Line 1576:
  
  
-| Platform | Log folder                                      | +| Platform | Log folder                                     | 
-| -------- | ----------------------------------------------- |+| -------- | ---------------------------------------------- |
 | Linux    | `~/.local/share/astrastudio/OnAirScreen/logs/` | | Linux    | `~/.local/share/astrastudio/OnAirScreen/logs/` |
-| macOS    | `~/Library/Logs/OnAirScreen/`                   | +| macOS    | `~/Library/Logs/OnAirScreen/`                  | 
-| Windows  | `%LOCALAPPDATA%\astrastudio\OnAirScreen\logs\`   |+| Windows  | `%LOCALAPPDATA%\astrastudio\OnAirScreen\logs\` |
  
  
Line 1257: Line 1590:
  
 Crash files are always written, even if the log level is `NONE`. Send the log folder to support when asked; do not post it publicly (DEBUG logs may contain host names or commands). After a process crash, the next start shows a dialog with **Open log folder**; it closes automatically after 30 seconds. Crash files are always written, even if the log level is `NONE`. Send the log folder to support when asked; do not post it publicly (DEBUG logs may contain host names or commands). After a process crash, the next start shows a dialog with **Open log folder**; it closes automatically after 30 seconds.
- 
  
 --- ---
Line 1276: Line 1608:
 ### Remote control not working ### Remote control not working
  
-- Check firewall rules for UDP/HTTP/OSC ports+- Check firewall rules for UDP/HTTP/OSC/SNMP ports
 - Use correct IP address and ports - Use correct IP address and ports
 - Test locally with `curl http://127.0.0.1:8010/api/status` - Test locally with `curl http://127.0.0.1:8010/api/status`
Line 1284: Line 1616:
 ### GPIO not switching LEDs or timers ### GPIO not switching LEDs or timers
  
-- GPIO works on Raspberry Pi only. Check **Settings → GPIO** status +**Raspberry Pi** (inner tab **Raspberry Pi**): 
-- Status "gpiozero library not available": `sudo apt install python3-gpiozero python3-lgpio python3-rpi-lgpio` (already on the OnAirScreen Pi image)+ 
 +- Pi GPIO works on Raspberry Pi only. Other platforms show “not available” on that sub-tab 
 +- Check **Settings → GPIO → Raspberry Pi** status
 - Use a PC817 module; never feed mixer 5–24 V into Pi pins - Use a PC817 module; never feed mixer 5–24 V into Pi pins
 - Confirm Invert (default on for contacts to GND) and Level vs edge mode - Confirm Invert (default on for contacts to GND) and Level vs edge mode
-- Enable GPIO and the individual GPI row, then Apply`+- Enable GPIO and the individual GPI row, then Apply 
 + 
 +**Axia Livewire** (inner tab **Axia Livewire**): 
 + 
 +- Enable Livewire GPIO and the mapping row, then Apply 
 +- Typical mic ON lamp: direction **GPO**, pin **1**, Invert **off**, mode **level** 
 +- **Multicast:** use the same Livewire **channel number** as the source’s audio (GPIO is not advertised). Machine must be on the AoIP / Livewire VLAN with IGMP; pick the same interface as Audio Meters. Status “join failed”: wrong interface or no multicast route 
 +- **LWRP:** set Mode to **LWRP (TCP)**, enter the device **Host** (TCP 93). Mapping **Port** is the GPIO port on the device, not a Livewire audio channel. Status “host is empty” / “LWRP failed”: missing IP or the device is not reachable. VLAN still applies; IGMP is not used 
 +- No packets / LED stays off: confirm the console/device is sending GPIO, the channel or port number, and that OAS is on the Livewire network 
 +- Mic already ON at OAS start: OAS requests the current state after join/connect; if the LED stays dark, check that the device answers that read (or toggle the channel once)
  
  
Line 1368: Line 1711:
  
 The reports do not include settings, MQTT passwords, or API keys. Prefer `--loglevel DEBUG` only for a short reproduction run before sending logs. After a crash, OnAirScreen also shows this dialog on the next start (auto-closes after 30 seconds). The reports do not include settings, MQTT passwords, or API keys. Prefer `--loglevel DEBUG` only for a short reproduction run before sending logs. After a crash, OnAirScreen also shows this dialog on the next start (auto-closes after 30 seconds).
- 
  
 --- ---
Line 1380: Line 1722:
 - LED changes (source: manual, autoflash, timedflash, API) - LED changes (source: manual, autoflash, timedflash, API)
 - AIR timer start/stop/reset - AIR timer start/stop/reset
-- Received commands (UDP/HTTP/OSC)+- Received commands (UDP/HTTP/OSC/SNMP)
 - Warnings added/removed - Warnings added/removed
 - Settings changes - Settings changes
  • onairscreen/manual-en.1788623757.txt.gz
  • Last modified: 01.10.2026 17:43
  • (external edit)