In-App Help Reference

The dashboard’s built-in Help, as one page

This page is the dashboard’s built-in Help (the ? button), generated from the same source as the Help the board shows. It describes a Cruiser with fleet management on. Items about drive and storage status and the per-board values are not listed here.

Dashboard

LIVE indicator
Pulses green ("LIVE"; steady when your device's reduce-motion setting is on) while the dashboard is receiving real-time updates from the board (Server-Sent Events, ~2s cadence). If updates stop, the indicator says so - after ~15s it turns amber and reads "STALE" (the values on screen may be out of date); after ~60s a banner appears: "Lost real-time connection. Reconnecting…" with a Retry button that forces an immediate reconnect; if several reconnect attempts fail it turns red: "Cannot reach the board." During a deliberate reboot the indicator is suppressed (the reboot overlay already explains the expected drop), so it never falsely alarms.
Connecting and reconnecting
When the dashboard opens it asks the board for its name and settings. If the management service does not answer, for example for a few seconds after a restart or an upgrade, the page shows a Reconnecting card in place of a blank screen. The dashboard tries again on its own after 1, 2, 4 and 8 seconds, then every 10 seconds for as long as it takes. The card shows the attempt number and the time to the next try. Retry now tries at once instead of waiting. When the board answers, the card goes away and the page carries on with no reload. A kiosk display that is still stuck on the card after 2 minutes reloads itself once the board answers again, so it comes back without anyone touching it. If the board restarts at the moment the page itself is loading and the page cannot start at all, any browser reloads that page on its own once the board answers, after about 30 seconds. If drawing the page fails, a card says something went wrong and its Reload button reloads the dashboard; a kiosk display does that on its own after 30 seconds, again only once the board answers.
System health bar
CPU temperature, memory usage, and Storage used have visual progress bars that change color at the same points where the board raises an alert: CPU turns red above 80°C and memory turns yellow above 90%. A tile with an open alert takes that alert's color and shows a View alert link to it until you resolve the alert, even after the reading has recovered. Storage used shows the percent used, rounded up, and used of total in GB, counting the system drive and every data drive mounted at /mnt/data* (a drive that shares storage with another is counted once). With data drives, a row for each drive follows, with its type and health from the Drives card; a drive that cannot be read says Usage unavailable, and any drive left out of the total says not in the total. The tooltip adds the space available to normal processes; filesystem-reserved blocks can make used plus available differ from total. The bar color, the alerts and the thresholds below read the system drive only, so a full system drive still shows its warning when a large data drive is empty. Storage used turns yellow above 85% used or below 512 MB available, and red above 95% used or below 256 MB available. Usage warning and critical alert latches re-arm after usage falls to 80% and 90%. Available-space warning and critical latches re-arm at 768 MB and 512 MB. At warning severity, free space before the next package or kernel upgrade. At critical severity, free space now before starting the next package or kernel upgrade. Check for superseded kernel packages and orphaned linux-raspi-headers-* packages, which are the usual culprits. The disk alert reads Storage almost full with the percent used and the space free; open Free up space on the alert row for these steps. A CPU temperature above 80°C raises the alert Running hot with the temperature in whole degrees; it re-arms at 75°C or below. Hover any item for its current values.
PoE Draw
Total power being delivered across all PoE ports right now, glowing in the brand color. If the PoE controller is not responding, the tile stays in place and reads Unavailable.
Dark / Light theme
The dashboard starts in dark mode. Use the button in the header (or press t) to switch to light. The choice is saved on this board, so every browser and the HDMI display use it after their next login.
Reduced motion
When your device's reduce-motion setting is on, dialogs such as Help, Network and TLS settings open without the fade-in, and the PoE total glow and the LIVE indicator pulse stay still.
Header more menu
The ⋮ (more) button in the header opens a dropdown with the less frequent actions: Storage, TLS settings, Alerts delivery config, Home Assistant, Diagnostics, Nearby boards and Logout. Nearby boards shows the number of boards found on the network: with fleet management on it opens the list of boards with links to their dashboards, and with fleet management off it opens the explainer that shows how to turn fleet on. It appears only when boards are found. On a phone the header pill is hidden, so this is where the count lives. The menu opens when a mouse hovers over it, or when you click or tap ⋮. It closes on a second click of ⋮, a click or tap outside it, or Escape. Help stays a dedicated "?" button in the header, next to Network, Reboot and the theme toggle, which are also direct buttons. All have tooltips.
View persistence
The dashboard remembers your last active view (this board or Fleet) across page refreshes.
Repeated alerts
When the same alert is raised again on the same board at the same severity, Active Alerts shows one row with a count such as ×6, the latest value and time, and when it was first seen. Show all lists every occurrence with its time and message. Resolve on that row clears every occurrence of it, including ones too old to be listed, and the activity log records one entry with the count. Different severities and different boards stay separate rows, and critical rows sit above warnings.
Tooltips
Hover over any value or icon for an explanation - what it is, what it means, and the value in context.
What's New
After a software upgrade, a dismissible card lists curated changes since your last visit so you do not miss new fleet, alert, or port features. Dismiss records this package version; the card returns only after the next upgrade. Full notes also live under Help → Release Notes (or the Licenses-adjacent Release Notes entry).
Browser notifications
When a critical alert arrives while this dashboard tab is in the background, the tab title shows a count and the favicon gains a red dot. Optionally enable desktop notifications via the one-time prompt (or never ask again). An optional short beep is off by default and stored as a per-board preference. The prompt is not shown when the browser has blocked notifications for this board, for example in a managed or kiosk browser, because Enable cannot work there. The tab title count and favicon dot still work. To use desktop notifications, allow them for this board in the browser's site settings and reload; the prompt appears if it has not been answered on this board.
Port history
Each PoE port card has a Hist button that opens power and temperature charts for the last 1/6/24 hours (on-board 1-minute samples, retained up to 24h) plus cycle events from SQLite with counts of total and failed cycles. Use this when a camera flaps: look for clusters of cycles or failed outcomes.
Deep links
Shareable URL hashes: #fleet opens Fleet view; #fleet/SERIAL expands that board; #fleet/SERIAL/p3 highlights port index 3; #alerts or #alerts/ID scrolls to Active Alerts (#alerts/ID works for any loaded occurrence of a repeated alert); #audit/ID scrolls to Recent Activity; #storage (or the older #files) opens Storage. Paste into a browser after login to land on the same place.
Keyboard shortcuts
Power-user keys (ignored while typing in a field): ? Help; g then f Fleet view; g then b Board view; / focus fleet filter; r refresh activity; t toggle theme; Esc closes modals. Chord g waits ~0.8s for the second key.
Services
Shows the status of key systemd services on the board (management, kiosk, console, SSH, networking, and the Zigbee radio server on a Cruiser with the Zigbee firmware installed). Kiosk control lives here, and this panel is the single place to start or stop it. Green 'running' means healthy. Red 'failed' raises an alert on any service. Red 'failing (N)' (a crash loop) also raises an alert, but only for the Zigbee radio server. The Zigbee radio server row also shows 'failing (N)' for one minute after it restarts, even while it is running, matching its alert and the status Home Assistant reads. If its restart count has not caught up yet, the pill reads 'failed recently' instead of 'failing (0)'. Red 'failing (N)' indicates a crash-looping service (systemd is restarting it but it keeps exiting); check 'journalctl -u <service>' on the board for the cause. Each managed AND installed row (the kiosk by default, and the Zigbee radio server where it is installed) has Start / Stop / Restart buttons, and the kiosk row also has a Language button that opens the kiosk display language dialog; protected services (management, SSH, networking, anything starting with 'systemd-') render read-only because branding cannot widen the always-protected core. Other managed services that are not installed on this board (e.g. kiosk on a headless Interceptor) render the unit name and 'not installed' status only, with a tooltip suffix explaining why no buttons appear. The Zigbee radio server row is left out when it is not installed or cannot be read, so a board without it shows no row at all. Stop requires an explicit confirm step so an accidental click cannot black-hole the kiosk. While an action runs, the button you clicked (and the status pill) show a spinner with 'Starting…/Stopping…/Restarting…' and the row's buttons disable, so a slow action reads as in-progress rather than unresponsive - no need to click again. Transitional systemd sub-states (e.g. stop-sigterm during a slow shutdown) show as a friendly 'Stopping…' rather than the raw kernel string; a crash-looping unit still shows 'failing (N)' even mid-restart. The action endpoint pre-validates the install state before invoking systemctl: a direct API call to start/stop/restart an uninstalled unit returns 400 SERVICE_NOT_INSTALLED, not 500, so fleet automation gets the right signal. Start = start + enable-on-boot, Stop = stop + disable-on-boot, Restart = restart only. A unit currently disabled that an operator clicks Restart on stays disabled and will not come back on next reboot; the operator must click Start to re-enable boot-persistence. Every action is recorded in the audit log, including rejections; successful start/stop produce two rows (the action + the persistence verb). Kiosk self-heal: a kiosk display that has been running a long time can occasionally drift to a blank screen (browser still alive but the page stopped rendering). The dashboard now reloads the kiosk automatically while it is idle, so a blank kiosk recovers on its own without anyone touching it; the reload only happens when no one is interacting, so it never interrupts an operator mid-task. The same reload covers a kiosk that fails to start: if the board does not answer the dashboard within 2 minutes of the page opening, the kiosk reloads the page, but only once the board answers again, so it never lands on the browser's own error page. A kiosk that is showing the login form (including after a rejected password (401)) or the change-password screen stays where it is; a service error (5xx, network error, too many requests) still reloads once the board answers. The kiosk screen asks for the dashboard password like any browser and stays signed in across its idle reloads. It asks again when the session ends: 24 hours after sign-in, after the management service restarts (an upgrade or reboot), or after Logout. Restarting the kiosk itself (Restart here, or Restart kiosk now in the Language dialog) also asks for the password again, because the kiosk browser starts fresh each time.
Kiosk display language
The Language button on the kiosk row of Services sets the language the HDMI kiosk shows the dashboard in. It is off by default: the kiosk shows English and sends no page text to Google. Choosing a language needs the Google consent tick, because the kiosk browser sends the dashboard text it shows to Google to translate it. The choice applies when the kiosk restarts (use Restart kiosk now in the dialog; the HDMI screen goes blank for a few seconds). It needs a dashboard password that is no longer the factory default, so the setting can only be changed from a signed-in session that has already changed it. It is kept across reboots and upgrades, but it is not part of a backup and a restore does not bring it back. While a language is on, translation is allowed for every Chromium window on the board, because the browser policy that allows it is machine-wide; turning the language Off blocks it again at once; if the board cannot apply the change at once, the dialog says so and restarting the kiosk applies it. Restart kiosk now on a stopped kiosk starts it but does not enable it at boot (use Start in Services for that). Values the kiosk screen shows, such as numbers, addresses, serials, firmware versions, port names and group names, are marked so the translator leaves them alone.
Observability dot
A small indicator in the header showing whether *this* board is currently being scraped by Prometheus. Green = scraping, red = Prometheus has this board as a target but cannot reach it, yellow = this board's IP is not in the Prometheus targets list, gray = checking or Prometheus unreachable, hidden if no URL is configured in branding. When prometheus_url is not set, the dot falls back to a fleet-wide reachability check of the observability_url. Click to open the configured monitoring dashboard; if observability_url_template is set, the link is deep-linked to this board (substituting {instance} with the board's IP and {tail} with the last octet).
Network
Click 'Network' in the header to view and configure network interfaces. Shows all interfaces with IP addresses, DHCP/static method, MAC addresses, and DNS resolvers. Works on both Raspberry Pi OS (NetworkManager) and Ubuntu (systemd-networkd/netplan) boards - the dashboard uses whichever the board runs. Edit interface settings to switch between DHCP and static IP. Static interfaces also accept DNS resolvers (IPv4 addresses, comma or space separated) and a gateway; leaving the DNS field empty clears the resolvers - and for direct API callers, omitting the dns field on a static apply also clears them (absent and empty are equivalent, so an auto-rollback always restores the exact prior state). On DHCP interfaces DNS is supplied automatically by the DHCP server - switch the interface to Static to set specific resolvers. Every interface change is audit-logged with its before and after values. When changing the uplink, the confirmation prompt shows where to reconnect at if this connection drops - the new static address, or the board's hostname.local for a DHCP target (you may need to log in again and accept the certificate warning there). The management interface (the uplink carrying this dashboard) requires explicit confirmation before changes; once confirmed, the change is applied with a timed auto-rollback - if you do not confirm connectivity within the rollback window (90 seconds), the board automatically reverts to the previous configuration, so a bad uplink address can't lock you out. After applying an uplink change, a countdown banner appears at the top of the dashboard showing the seconds remaining and a 'Confirm connectivity' button - click it to keep the change. If the timer runs out the banner resolves to 'reverted to previous configuration'; if the automatic revert itself fails it shows a prominent 'revert FAILED' warning telling you to reconnect via console or SSH. The banner survives a page reload (it re-reads the pending change on load) so you won't lose track of the countdown.
Reboot
Rebooting the board shows a full-screen overlay with an elapsed timer. The dashboard automatically polls the board and transitions to the login screen once it is back online. No need to manually refresh.
Backups
The Backup button (top of the dashboard, near the activity log) downloads a single JSON file containing your port labels, groups, Auto-restart device settings, alerts, audit log, and user prefs. Restore via the Restore button or POST /api/v1/system/restore with the file. The backup is brand-neutral and can be restored onto a board with a different brand. TLS private keys and fleet Ed25519 keys are never included (and a restore rejects them even if a file includes them). First-time boards start with no custom state; the first backup after setup captures your baseline.
Diagnostics
In the header ⋮ (more) menu: 'Diagnostics' downloads a tar.gz support bundle containing the last 24h of relevant journal logs, the current (redacted) management.json, dnsmasq leases, a health snapshot. Structured redaction is applied to the management.json entry (exact-key value masking for secrets like passwords, keys, basic_auth_pass, and webhook headers; only webhooks[].url masked among URLs). journal.txt and dnsmasq.leases are included raw (review contents before sharing with third parties, as they may contain logs or device PII). Filename includes product slug + timestamp. A failed download shows an error message that says whether the request did not reach the board, timed out (after 60 seconds), or the board returned an error. Intended for remote diagnosis, RMA, or integrator support; no dashboard UI surface beyond the download (advanced/ops use today).
Self-healing signals
Minimal last self-heal health is exposed via the existing /system/health.self_heal (last_watchdog_cycle from store cycles, kiosk_self_heal note) and /system/network.pending_rollback. Auto-restart cycles, rollback events (network.interface.rollback), and poe.watchdog-* are in the audit log / Recent Activity panel. Kiosk self-heal is client-only: an invisible idle reload every 60 minutes, plus a reload for a kiosk that failed to start, which waits until the board answers again (see Services). No extra polling or state.
First-use / Getting started
On a fresh board (fleet disabled, zero paired boards), a guidance card or banner appears after the required password change on this board's own view. It explains first steps (label ports, enable fleet if needed, pair via mDNS 'Nearby' chips, see Help for pairing instructions). The card is scoped to this case, has a tooltip, points to Help, and hides automatically once any boards are paired or fleet is enabled and has peers. Existing 'Fleet empty state' help item and guidance card in the Fleet tab cover the fleet case.
Nearby boards pill (fleet off)
If fleet management is off but other Exaviz boards are discovered on the network, the header shows a muted, dotted "N boards" pill with an info glyph (distinct from the normal accent pill, so it does not read as a working control). Clicking it opens an explainer that lists the discovered boards (each links to its own dashboard) and shows how to turn fleet management on: set "enabled": true under "fleet" in /etc/exaviz/management.json, then restart the service with 'sudo systemctl restart exaviz-mgmt'. When fleet is on, the pill is the normal accent style and hovering it lists nearby boards directly.
Factory password
Until the factory password is changed, the board refuses every change and every export (backup, diagnostics, fleet export, storage files, device pages) with 'change the default password first'. Since 1.0.1 it also refuses every signed-in API read (status, settings, live events, metrics), for dashboard sessions, Home Assistant tokens and fleet peers alike; only sign-in, sign-out, the password change, the session check and the public login-page details answer. Change the password on the sign-in screen to unlock the board. The new password must be at least 8 characters and cannot be the current password, the factory default 'password' in any letter case, a common password such as 12345678, or this board's serial number or hostname. The first change also revokes every Home Assistant token made while the board was on the factory password and cancels an open pairing code; pair Home Assistant again afterwards.
Login page
The login page displays the product name, logo, and optional welcome text from your branding configuration. Board name, type, and firmware version are shown for identification.
About and licenses
Click 'About & Licenses' in the footer to see the copyright notice for this product and the third-party software it includes, grouped by license type, with links to each project.
Toast notifications
Brief confirmation messages appear in the bottom-right after actions like enabling a port, saving a label, or pairing a board.

PoE Port Management

Port states
Delivering (green) = powering a device. Searching (gray outline) = looking for a device. Disabled (gray) = manually turned off. Fault (red) = error detected.
Device lost alert
If a port that was powering a device stops delivering power while the port is still enabled (cable unplugged, device failed, power budget exhausted, or device did not come back after a reset), a warning alert is raised within 20 seconds and sent to any configured email or webhook. Turning a port off with Disable (single or group) does not raise this alert; the action is in the activity log instead. Short drops during a reset do not alert.
Power level bar
On delivering ports, shows current draw as a percentage of allocated budget. Animated green gradient.
Power sparkline
On delivering ports, shows the last hour of power usage (1 sample/min). Useful for spotting load spikes or device anomalies. Sparklines need at least 2 minutes of data to appear, so they will be absent briefly after a service restart or reboot.
PoE not responding
The PoE Ports panel says PoE isn't responding when the board has a PoE controller but no port readings are arriving. Port power and status cannot be shown or changed until they return. What to try: 1. Restart the board. 2. Another service, usually the Zigbee integration in Home Assistant, can share the PoE serial port. Stop that service, restart the board, and start it again once PoE readings are back. 3. Only if the firmware mode under the message reads Standard PoE, update the PoE controller firmware from a shell on the board. First stop any service of yours that uses the PoE serial port; the update stops the management service itself but will not stop yours. Then run sudo exaviz-flash update --dry-run, and if it reports no problem, sudo exaviz-flash update. Cameras lose power for about a minute while it runs. If the mode reads Zigbee coordinator or anything else, or no firmware mode is shown, do not update the firmware, because the update can replace Zigbee firmware with standard PoE firmware; contact support instead. 4. On an Interceptor, check that the PoE driver package is installed and up to date, then restart. Details under the message holds the technical reason. If PoE still does not respond, contact support.
Port labels
Click '+ add label' or any existing label to name a port (e.g. 'Camera 1', 'AP Lobby'). Saved automatically. Helps identify devices in deployments.
Enable / Disable
Toggle power to a port. Disabling a delivering or searching port asks for confirmation first (with the port name, label, and manufacturer shown in the prompt) so a misclick does not cut power to an active camera; enabling an idle port fires immediately.
Reset
Power-cycles the port. Resetting a delivering or searching port asks for confirmation first; resetting an idle port fires immediately. The device briefly loses power and reconnects (typically about 3 seconds).
Cycled N×/7d badge
Appears next to the port state when the port has been power-cycled at least once in the last 7 days. Counts every source: operator manual click, bulk group reset, auto-restart cycle, and deep-link tap-on-phone. Turns yellow at 3 cycles and red at 5+ - frequent cycles often indicate a hardware problem with the connected device rather than a network problem. Click the badge to open a drill-down showing each cycle's timestamp, source, and outcome - the field tech who sees 'Cycled 6×/7d' in red can find out who did them and when without SSHing into the board.
Class
PoE power class negotiated with the device (0-4 for PoE, 0-8 for PoE+).
PoE+ vs PoE
PoE+ (802.3at) supports up to 30W per port. PoE (802.3af) supports up to 15.4W. The mode is shown as (at) or (af) in the port header. Click the mode indicator to switch between at and af. The port briefly power-cycles during the switch. Class 4 devices require AT mode and will not power up in AF mode.
Connected device
When a device connected to a PoE/LAN port is detected, the port card shows the manufacturer (from MAC OUI lookup) and hostname or IP. A device seen in the ARP table is reachable now; a device known only from its DHCP lease (no ARP entry yet) is marked 'leased' and may not be reachable, so opening its web UI might not work until it comes online. Click the device IP to open its web interface through the board (reverse proxy). Hover for the full MAC address and discovery source.
Port layout
Ports are displayed in physical board order - evens on top, odds on bottom - matching the hardware when ports show interface names (see Port names). On boards with add-on PoE cards, a visual gap separates native and add-on ports. The Total PoE Ports count in Board Information counts every controller that reports ports, including expansion boards.
Port names
Each PoE port is named after its network interface (poe0, poe1, ...), read from the switch driver, so the name on the card is the one to use with ip link or the PoE tools. If the switch driver has not reported an interface for a port, the card shows the port's controller position instead, for example pse0-0 (controller 0, port 0). That is not an interface name. Cards shown this way are laid out in controller order, which is not the order of the jacks on every board: on a Cruiser, controller 0 is the right-hand bank (the poe4 to poe7 jacks) but shows on the left. Check which jack you mean before you reset or disable a port shown this way. The name changes to the real one within about 30 seconds of the driver coming up.

Auto-restart device

What it does
Power-cycles the device if it stops responding. Auto-restart device pings or TCP-connects to a configured target on a 10s cadence. After N consecutive failures (default 3) it automatically cycles the port to recover the device. If the device still does not come back, the port is marked stuck and cycling stops until an operator re-arms it. Solves the 11pm 'a camera locked up again' phone call - power-cycle fixes the device unattended, the operator sees the cycle in /cycle-history and the activity log the next morning.
How to configure
Every PoE port card has an 'Auto-restart device' row with a Set up button (Edit once it is set up); the same row is at the top of the port's History window. Click it to open the Auto-restart device dialog. Set the target IP/host (usually the camera or AP on this port), the TCP fallback ports (it falls back to TCP connect if ICMP is blocked by the device firewall), and the timing knobs. Defaults are tuned per board type: Cruiser uses 5s post-cycle dwell, Interceptor uses 15s for the slower vendor kernel driver. Save persists to /var/lib/exaviz/watchdog.json (atomic write); next 10s tick picks up the change.
Monitor-only mode
Check 'Monitor only (no auto-cycle)' to make Auto-restart device alert when the target stops responding but NOT cycle the port automatically. Useful when you want awareness without intervention - e.g. a device that needs a human to look at it before any power action.
State badges
The Auto-restart device row on each port card shows one status. Off = not set up, or set up but turned off. On = actively checking the device. Restarting = the port was just power-cycled and it is waiting for the device to come back. Paused = the port was turned off by an operator; see Turned off by an operator. Stuck = cycled once, device still down, manual intervention required; it also shows as a red pulsing 'Stuck' badge at the top of the card. The 'Auto-restart devices' list in the Activity panel shows every port that has it set up on this board, with the same statuses.
Turned off by an operator
When you turn off a port that has Auto-restart device set up, by its Disable button or a group Disable, Auto-restart device pauses for that port and stays Paused until you turn the port back on. The pause holds through a restart of the management service and through saving new settings in the Auto-restart device dialog. If the board restarts, the PoE controller brings every port up powered, and the management service turns these ports off again as soon as the controller is reporting, usually within a minute. If it cannot, a warning alert says so.
Stuck alert
When Auto-restart device declares a port stuck, a warning alert is raised and lands in this board's Active Alerts panel. The alert row gets an inline 'Re-arm' button: clicking it re-arms Auto-restart device AND resolves the alert in one action, saving a click for the NOC workflow. Manual operator power-cycle on a stuck port (via the port card Reset button) does NOT re-arm - only the explicit Re-arm action does. Stuck ports also show in the fleet alerts banner across boards so an NOC operator scanning 30 boards sees a single 'Auto-restart device stuck on N ports across <boards>' warning row rather than having to drill into each board's local Active Alerts panel. If the management service cannot turn a Paused port back off after a board restart, a second warning, 'Could not turn port ... back off after restart', lands in the same Active Alerts panel. It has no Re-arm button: turn the port off by hand, which resolves it, or check the PoE controller. A restart does not raise it again while it is still open.
Storm protection
The cooldown_after_cycle_s knob (default 300s, minimum 30s) is the floor on time between cycles, counted across every cycle source - operator clicks, bulk group resets, and auto-restart cycles all count. If the failure threshold is met within the cooldown, auto-restart waits rather than re-cycling, preventing thrashing on a flaky device.
Alerts and webhooks
The dashboard and alert emails say 'Auto-restart device stuck on port ...'. The webhook message field keeps its original wording, so Home Assistant automations that match on it keep working.
Forensics
Every auto-restart cycle writes a cycle_events row with source='watchdog' and an audit_log row with action='poe.watchdog-cycle'. Stuck transitions write 'poe.watchdog-stuck'; recovery writes 'poe.watchdog-recovered'; operator re-arms write 'poe.watchdog-ack'. /api/v1/poe/ports/{pse}/{index}/cycle-history shows the full timeline for any port.

Alert delivery (email + webhook)

What it is
When Auto-restart device declares a port stuck, an alert lands in this board's Active Alerts panel. Alert delivery pushes that same alert OUT to your phone or chat tool, with a one-tap 'Cycle port now' button. Home Assistant can receive alerts through a webhook trigger. The integrator's 2am workflow becomes: alert lands -> tap -> dashboard opens with the right port already focused -> tap Reset. Two taps, end to end.
How to configure
Open the Alerts item under the ⋮ more menu in the header (less-frequent actions like Storage/TLS/Alerts live in the menu to reduce clutter; Network/Reboot/theme and the dedicated "?" help button stay immediate for fast access). You can also click Set up delivery on the Active Alerts banner. In the Email (SMTP) tab fill in Mail server, Port, Encryption, From address and Send to; tick Send alerts by email to turn live delivery on. A board that has never saved email settings starts at port 587 with STARTTLS (recommended); a saved port and encryption mode are shown as saved. Link in alerts opens is the public URL operators use to reach this board's dashboard, so a tap on an alert lands here; leave it blank to turn deep-links off. Each field has a short explanation under it, and From display name sits under More options. The active tab's Save button persists everything in the modal in one click - the link URL is saved alongside the tab's own fields. Send test is reachable as soon as Mail server, From address, and at least one Send to address are filled; you do not need to tick Send alerts by email first. Send test is a dry run - it dials your SMTP server with the on-screen draft and does NOT touch the stored config or the running watcher. The result appears in the form under the buttons: a green line names who it was sent to, a red line gives the server's reason, and it disappears when you edit a field so an old result never sits next to new settings. The Webhooks tab's per-row Test works the same way (its result is a pop-up message): type a URL and Test immediately, before saving - a green test result on an unsaved row reminds you to click Save to keep it. Clicking Save when nothing in a tab changed is a no-op: it writes no config-change audit row, so the audit log stays clean. Saving a real change reconfigures the running watcher atomically; no restart needed.
Secrets handling
SMTP password is never returned by the GET endpoint - the UI shows '(stored - leave blank to keep)' instead. Webhook URLs are returned masked (?... and /secret-path/... redactions). Audit-log rows for delivery-config changes record only field names and indices, never values. If you need to clear the SMTP password, use the 'Clear stored password' button in the Email tab.
Home Assistant (MQTT)
Sending alerts to Home Assistant over MQTT is not available yet; the Home Assistant (MQTT) tab says so. Home Assistant can already receive alerts through a webhook trigger (Webhooks tab), and can pair with this board for live status: the tab's Open Home Assistant pairing button goes to More > Home Assistant.
Deep-link details
The 'Cycle port now' link carries action=cycle, pse, index, alert id, and a source tag (deep-link-email or deep-link-webhook). The dashboard captures these query params before authentication runs (so a login redirect cannot lose them), then scrolls the matching port card into view and focuses its Reset button. On successful cycle, the open auto-restart stuck alert for that port is automatically resolved. Operator's tap-on-phone story leaves an empty alerts panel. Send Test envelopes also carry deep_link when DeepLinkBaseURL is set so the operator can verify their receiver's deep_link branch; the synthetic test uses sentinel port 255-255 so clicking the link from a test envelope cannot land on a real port.
Alert fields
Each alert has a short plain-English message plus two fields for tools. kind is a stable key (for example system.disk_warning, system.disk_critical, system.cpu_temp, system.memory or fleet.config_drift) that never changes when the wording does: key automations on it, never on the message. detail holds the technical steps or setting names kept out of the message. Webhook alerts carry both; email shows detail under Details and leaves kind out. The webhook envelope is schema_version 2: version 1 plus the optional alert.kind and alert.detail, left out when empty. A receiver that validates with the version 1 schema file must take the new one. Alerts raised before this change have neither field.
Retries + state
Pending alerts get a 5s-cadence delivery tick. Failures retry on 1m / 5m / 15m backoff, then mark the alert delivery_state=failed (the alert itself remains active until manually resolved). Each alert row shows a small badge (delivered, delivering, queued, failed). When no email server or webhook is set up, the Active Alerts panel shows one banner, 'Alerts aren't being sent anywhere yet', with a Set up delivery button instead of a badge on every row. The banner goes away as soon as you save an enabled email server or webhook. Alerts raised before that are not re-sent.
Branding footer / webhook hardening
FooterHTML (the email trailer) is filtered through a strict allow-list: paragraph, break, span/div, b/strong/i/em/u, ul/ol/li, and links to http/https/mailto only. Script tags, event handlers, style attributes, javascript: URLs, and protocol-relative URLs are stripped silently. If your footer renders blank after Save, an entry was disallowed. Webhook header field names and values containing CR/LF/NUL are rejected at Save time with a clear error - request-smuggling defense.

Network Ports

Link state
Connected = a cable is plugged in and the link is up (green dot). No cable = no link on the port; check the cable and the device at the other end. Disabled = the port is turned off on the board. Hover the state for the board's own term (for example lowerlayerdown).
Speed
Negotiated link speed, shown in Mbps below 1 Gbps and in Gbps from 1 Gbps up (for example 2.5 Gbps) - this reading is authoritative. The physical port LEDs are only a coarse indicator: on a 2.5 GbE WAN port, amber alone means 10/100 Mbps, amber+green means 1 GbE, and green alone means 2.5 GbE, so a 100 Mbps fallback can look like a normally lit port. When the uplink negotiates 100 Mbps or less on a faster-capable port, an under-speed badge appears - check the cable, the far-end switch port, and autonegotiation. A 1 GbE link on a 2.5 GbE-capable port is NOT flagged (1 GbE infrastructure is normal); hover the Speed cell to see the negotiated speed against what the port is capable of. Hover the row for duplex info.
Expected uplink speed
If a site's uplink is permanently 10/100 Mbps by design (e.g. a 100 Mbps modem feeding a faster WAN port), set expected_uplink_speed_mbps in management.json to that speed. The under-speed warning is then replaced by a neutral '(expected)' badge - the slow link stays visible in the fleet view as slow-by-design, not a fault. Valid values: 10, 100, 1000, 2500, 10000; 0 or omitted = unset (warn on any 10/100M fallback). The warning clears only when the declared speed exactly matches the negotiated speed, so a mismatched value still warns. Takes effect after an exaviz-mgmt restart - when it does, the Speed cell shows the neutral '(expected)' badge and the daemon logs the override at startup; if you don't see the badge, recheck the value matches the negotiated speed.
RX / TX
Total bytes received and transmitted since boot.
IP Address
The IP address of the device connected to this port, learned from the ARP table. Shows '-' when no device IP is detected.
Role badge
A badge next to the port name shows its role: 'Uplink (WAN)' for the port carrying the board's internet/management connection, and 'Device LAN' (accent-colored) for a port where the board routes traffic for its connected devices and assigns their addresses (DHCP) - the badge shows the served subnet (e.g. 10.100.8.0/24) and, when known, the DHCP pool range handed out on it (e.g. · .100-.200, meaning 10.100.8.100 through 10.100.8.200). Each routed port has its own dedicated /24, allocated in sequence (lan0-2, then poe0 onward), so the subnet number is offset from the port number by design - e.g. poe4 serves 10.100.8.0/24, not 10.100.4.0/24. Hover the badge for the full explanation.
Show internal interfaces
Internal plumbing (the DSA switch conduit eth0, inter-switch cascade ext* links) is hidden by default to reduce clutter. Click 'Show internal interfaces' to reveal them when troubleshooting a cascade link.
PoE ports
On boards with a PoE Ports section, the poe ports fold into one line showing how many have a network link and their total traffic, because the PoE Ports section already shows each port's status and power. Open the line to see each port's row, including its Device LAN subnet. PoE Ports ↑ jumps to that section.
MAC addresses
Switch ports (eth0, ext, poe) share the same MAC address because they are ports on a single hardware switch chip (DSA). This is normal. The WAN port has its own unique MAC because it is a separate network interface.

Remote Access

Remote access card
Shows whether Tailscale or WireGuard is set up on this board and the address to reach it over that network. The dashboard only reads the status; it does not change your VPN.
Tailscale status
Not installed: Tailscale is not on this board. Installed, not running: the tailscaled service is stopped or failed. Needs sign-in: run 'sudo tailscale up' on the board. Waiting for approval: approve the board in your Tailscale admin console. Stopped: someone ran 'tailscale down'. Starting: Tailscale is connecting. Connected: shows the tailnet addresses and name, and a link that opens this dashboard over Tailscale. Unknown: the status could not be read.
Key expiry
Tailscale node keys expire, 180 days by default. When the key expires the board drops off your tailnet until someone signs in on it. Disable key expiry for the board in the Tailscale admin console.
WireGuard
Lists each WireGuard interface as Up or Down, its address, and the latest handshake with its peer. Down means the interface exists but is not brought up. No handshake yet means the tunnel is up but has not reached the other side. The handshake time needs the wireguard-tools package.
Install Tailscale
The Install Tailscale button adds Tailscale's package source (pkgs.tailscale.com) and its signing key, installs the tailscale package and starts its service. It needs internet access and asks you to confirm first. It does not sign in: afterwards, sign in from SSH with 'sudo tailscale up' and follow the remote access guide. While the card shows Installing, the install runs in the background. Install failed names the step that stopped it; the remote access guide has the fixes. If the install stops at starting the service, Retry install appears on the card. If Tailscale shows Installed, not running and there is no Retry button, run 'sudo systemctl enable --now tailscaled' on the board, or remove Tailscale with 'sudo apt remove tailscale' and install it again. If the dashboard restarts during the install, the result still shows on the card and in the system journal, but the Recent Activity row for the outcome can be missing. Once running, Tailscale's service talks to Tailscale's own servers, including log uploads by default. This dashboard never sees your Tailscale account or keys.
No port forwarding
Never forward port 80 or 443 from your network's edge firewall to this board. Use Tailscale, WireGuard or another private network instead. Do not accept a VPN route that overlaps this board's own network.

Fleet Management

Fleet view
Switch between this board's tab and 'Fleet' in the header to see all paired boards in a card grid. The tab shows the board's name, or its serial number (its hostname if it has no serial) until you set a name in Board Info. Each card shows the board name (or its serial when the board is unnamed) with its hostname underneath once the board has reported one. Click a card's header to expand it and see the hostname, IP address and serial. The Filter box matches name, serial, hostname, board type and online/offline.
Nearby boards
Boards on the same network are automatically discovered via mDNS. The badge in the header shows how many are found. On a narrow screen such as a phone, the count is in the ⋮ menu as Nearby boards. It becomes 'Discovery not running' while discovery waits for a network address.
Discovery not running
Boards find each other with mDNS. If the board has no network address yet (for example right after boot, before DHCP answers), discovery waits and retries on its own, up to every 30 seconds, and re-registers when the board's address changes. While it waits, the header shows 'Discovery not running' and nearby boards and pairing are unavailable. No restart is needed.
Fleet empty state
When zero boards are paired, a guidance card (below the 'Nearby:' chips) explains first steps: use the discovered chips to start pairing, ensure fleet.enabled on peers, and that pairing is explicit and mutual. The card is scoped to this case and is hidden as soon as the fleet is non-empty.
Pairing
Click 'Pair' next to a discovered board. Both boards display the same 6-digit confirmation code. Verify the codes match on both screens, then confirm on the initiator and accept on the responder. Trust is mutual and bilateral - each board only sees boards it has directly paired with. Pairing A with B and A with C does not let B see C. For a full mesh, each pair of boards must be paired individually.
Board cards
Each card shows CPU temperature, memory, Storage used (percent and used of total in GB across all drives), uptime, PoE power draw, active ports, and online status. Hover any stat for details. The system drive uses the same warning and critical thresholds as the local health bar. CPU and memory colors follow the alert rules too: CPU turns red above 80°C and memory turns yellow above 90%. Warning and critical disk states add DISK WARNING or DISK CRITICAL text badges, so the signal is not color-only. The card edge follows the highest alert severity: offline boards, PoE faults, critical disk, and HOT (CPU above 80°C, a critical alert) use the danger edge, while offline cards are also dimmed to distinguish an unreachable board from a live fault. Danger states take priority over warnings. Configuration drift adds a DRIFT badge and warning edge, matching the table view and explaining why the board floats when Float issues is enabled. An older remote board that does not report disk usage shows a neutral DISK N/A badge and an unavailable Storage used value until it is upgraded. On this board, the same signal means the filesystem health sample could not be read.
Card reorder
Unlock the padlock icon, then drag and drop board cards to reorder them. The order is saved automatically. Lock again to prevent accidental moves.
Float issues
When enabled (default), boards are ranked by actionable alert severity. Offline boards, faults, warnings, and configuration drift come first. Neutral DISK N/A information from an older remote board that does not report disk usage does not affect problem sorting, so an otherwise healthy fleet still follows the saved card order and dragging a healthy card does not snap back around an older peer. Saved order breaks ties among boards with the same actionable severity.
Fleet alerts
A banner at the top of the fleet view shows fleet-wide problems: offline boards, PoE faults, root disk warning or critical conditions, and high CPU temperatures. Disk rows include each affected board's used percentage and available space. A neutral informational row identifies older remote boards that do not report disk usage and directs the operator to upgrade them. If this board's filesystem health sample could not be read, a separate unavailable row says that instead of recommending an upgrade. Alerts update in real-time as board status changes.
Table view
Toggle between card and table views using the Cards/Table button. Table view shows all boards in a sortable grid - click any column header to sort. CPU and memory values follow the alert rules: CPU turns red above 80°C and memory turns yellow above 90%. The Alerts column shows a badge per condition: OFFLINE (board unreachable), FAULT (a PoE port fault), DISK (root disk warning or critical), DISK N/A (an older remote board does not report disk usage, or this board's filesystem sample could not be read), HOT (CPU above 80°C), MEM (memory above 90%), and DRIFT (this board's config differs from the local board - see the config-drift panel). DISK N/A is neutral and does not participate in the 'Float problems' ranking. Rows with any condition get a colored left edge so they stand out in a long list. While 'Float problems' is on, the table keeps actionable severity groups above healthy rows, then applies the selected table column within each equal-severity group. Saved card order breaks ties in the selected column. Turn Float problems off to apply the selected table column across the whole fleet; Alerts-column sorting then includes every badge weight.
Quick expand
Click a board card's header to expand it to 2x2 size, showing all PoE ports inline with power draw and state. The expanded card also lists the board's hostname, IP address and serial, even when the board is offline (the hostname is missing until the board has reported one). Click again to collapse. Useful for quickly checking individual port status without opening the board's full dashboard.
Remote port control
Enable All, Disable All, and Reset All buttons on each fleet card control all PoE ports on that remote board. Disable All and Reset All ask for confirmation first (with the port count and how many are currently delivering shown in the prompt) so a misclick does not mass-cut power to a remote site; Enable All fires immediately. Actions are proxied through the local board using fleet authentication.
Remote reboot
Click Reboot on a fleet card, then Confirm to reboot that board remotely. The board will go offline briefly and return automatically.
Fleet reboot
Click 'Reboot Fleet' in the fleet header to reboot all online remote boards at once. A two-step confirmation dialog shows which boards will be rebooted. Boards are staggered 2 seconds apart to avoid simultaneous restarts.
Sync Labels
Overwrite port labels on all online fleet boards with this board's labels. A confirmation dialog shows per-target diff first (changing / new / already in sync, plus the destination labels that will be overwritten) so distinct remote labels are not destroyed by accident. Matching is by port position (PSE and index).
Export
Download a CSV or JSON snapshot of all fleet board status (health, power, ports) using the Export buttons in the fleet header. Both formats include root disk total, used, percent, and available-byte fields.
Open Dashboard
Opens that board's full dashboard in a new tab.
Remove
Unpair a board. We send a signed notify to the peer first so their dashboard shows a 'Pairing removed by NAME' banner. If the peer is offline the local unpair still succeeds; the audit log distinguishes notified / offline / failed. A confirmation dialog warns first - re-pairing is the only way to restore trust.
Pairing removed by peer
If another board unpairs this one, a yellow banner appears on every dashboard view (board AND fleet tab) showing the peer name, short serial, and time. The pairing is already cleared on both sides; the banner is purely a notice. Click Dismiss to clear it. Multiple unpair notices stack independently so two peers unpairing in the same window both surface.
Serial collision
A warning chip appears in the fleet alerts when a paired board reports the same hardware serial as this board. Two boards cannot share a serial - the fleet trust model keys every board by serial - so this board's own entry wins and the colliding board is hidden from the grid (along with its alerts). This almost always means a board was imaged with a duplicate serial during provisioning. Fix the duplicate serial on the other board, then re-pair it (TOFU) to restore it to the fleet. The chip names the colliding serial and the hidden board so you know which unit to correct.
Board identity
Each board is known to the fleet by its serial. A Cruiser uses its factory serial (CRU-, CRL- or CRK-). A board without one gets a generated ID that is kept across restarts and compute module swaps: CRX- on a Cruiser, INT- on an Interceptor. A placeholder serial from the PoE controller, such as 12345678, is treated as no serial. Boards that already have a generated ID keep it so their pairings keep working, so an older Cruiser may show an INT- ID; the model shown comes from the board type. A Cruiser that was using a placeholder serial as its ID gets a new CRX- ID, and its peers must pair it again.

Config Drift

What config drift means
Boards in a fleet should agree on a few security and monitoring settings. Each board compares those settings with every paired board it can reach. Config drift means a paired board has a different value from the board whose dashboard you are on. There is no fleet master value: the comparison is always "This board" against each peer, so two boards can show the same drift from opposite sides. Other settings, such as board name, branding, certificates and network, belong to each board and are never compared. Why it matters: metrics auth that differs makes Prometheus get 401 errors on one board; a different TLS mode, redirect or HSTS value makes browsers treat boards differently.
Settings compared
Each board compares these settings with every paired board it can reach: tls.hsts_max_age_seconds (HSTS max-age): fixed for you. tls.redirect_http (HTTP to HTTPS redirect): changed by hand. Needs a restart of the management service to take effect, so a pushed value would read as fixed while the board still behaves the old way. Steps: 1) Open that board's dashboard, ⋮ menu, TLS 2) Under HSTS & HTTP Redirect, set Redirect HTTP → HTTPS (it saves when you change it) 3) When the TLS dialog shows Restart required, click Restart now tls.mode (TLS mode: self-signed, upload or ACME): changed by hand. The certificate, ACME domain and upload belong to each board, and entering ACME needs a restart. Steps: 1) Open that board's dashboard, ⋮ menu, TLS 2) Under TLS Mode, choose the mode and click Apply Mode; for ACME set that board's own domain metrics.basic_auth (metrics login on for one board and off for the other is reported once as metrics.basic_auth; shown as "enabled" or "disabled"): changed by hand. The metrics password is a secret and must not travel between boards, and there is no settings page for it. Steps: 1) On that board, set metrics.basic_auth_user and metrics.basic_auth_pass in management.json 2) Restart the management service 3) Update the Prometheus scrape job to match metrics.basic_auth_user (a different user with login on both boards): changed by hand. The metrics password is a secret and must not travel between boards, and there is no settings page for it. Steps: 1) On that board, set metrics.basic_auth_user and metrics.basic_auth_pass in management.json 2) Restart the management service 3) Update the Prometheus scrape job to match metrics.basic_auth_pass (a different password with login on both boards; the password shows only as set or differs): changed by hand. The metrics password is a secret and must not travel between boards, and there is no settings page for it. Steps: 1) On that board, set metrics.basic_auth_user and metrics.basic_auth_pass in management.json 2) Restart the management service 3) Update the Prometheus scrape job to match fleet.enabled (a board with fleet turned off cannot answer the check, so it is listed under "Unreachable peers:" instead): changed by hand. Never changed remotely: turning fleet off on a board cuts it off from the fleet, and a board with fleet off cannot answer this check. Steps: 1) Open that board itself and change fleet enabled there
Reading the drift panel
The panel appears on the Fleet view only when something differs, a peer could not be checked, or the check itself failed. The header reads "Config drift: N issue(s) across M peer(s) (K finding(s))": issues are distinct settings, findings are rows (one per setting per board). "cannot verify N peer(s)" means those boards did not answer, so they may or may not match. "Config drift check failed" means the check itself did not run. Click the header to expand the table: "Peer" (the board name, else its hostname, else its serial), "Setting", "This board", "Peer", "Correct value" and "Action". Boards with drift also get a "DRIFT" badge on their card and in the table view. The check runs every 5 minutes while the Fleet view is open, and every 5 minutes in the background on every board.
Fixing drift
For each row pick the "Correct value": "This board's value" copies it to the peer; "Peer's value" takes it here, and also on any other board that still had this board's old value, so a fix does not create new drift. "Fix drift" handles one row, "Fix all" every fixable row. Both show every change (board, setting, from, to) and apply nothing until you click "Apply". "Fix all" is off while rows for one setting choose different values. Only HSTS max-age is fixed automatically; a value above 0 is not applied to a board with the redirect off: it is listed under "Not changed:" with the reason when other changes are confirmed in the same dialog, and shown as the reason alone when nothing else can change. Settings that are changed by hand show the reason and steps in the row. For the redirect and the TLS mode, open that board's dashboard, the ⋮ menu, then "TLS": the redirect is the "Redirect HTTP → HTTPS" checkbox under "HSTS & HTTP Redirect" (then click "Restart now" when the dialog asks), and the mode is chosen under "TLS Mode" with "Apply Mode". The metrics login is set in management.json on that board, and fleet is turned on or off on that board itself. A board that does not answer is not changed. Repeating a fix is safe. After applying, the check runs again and the panel shows what is left.
Fix results
"Result of the last fix:" lists each change with one of: applied (saved on that board), unchanged (it already had the value), conflict (it changed since the preview; nothing written, the current value is shown), failed (the message says why), not_fixable (change it by hand), unreachable (it did not answer), unsupported (it runs older software; update it or change the setting by hand).
Drift alert and activity log
When a board first sees drift it raises one warning alert, "Fleet settings don't match: ...", not one per check. The alert row has a Show differences button that opens the Fleet view with the drift table expanded. Every board with peers runs the check, so both boards in a pair can raise it. The alert is resolved automatically the next time a check finds no drift and every peer answered, whether after a fix or a hand change; an alert you already dismissed is left as it is. A check where a peer did not answer does not resolve it. In Recent Activity, the board you used writes "Fixed fleet drift" for each change it sent to another board, with the result, even when it failed or the board did not answer. Each board whose setting changed, this one included, writes "Setting changed by drift fix".

Port Groups

Port groups
Named collections of PoE ports. Create groups like 'Cameras', 'APs', or 'Floor 2' to manage multiple ports together.
Bulk enable/disable/reset
Apply an action to every port in the group at once. Useful for site-wide maintenance or controlled power cycling. Disable All, Reset All, and Delete each ask for confirmation first (with the group name and port count in the prompt); Enable All fires immediately.
Group management
Click '+ New Group' to create a group. Name the group, then click ports to add them; a selected port shows a check mark and an outline in the accent color. The Select ports label shows how many are selected. Save, then edit or delete groups from their cards.

TLS / HTTPS

Current certificate
Shows the active TLS certificate details: subject, issuer, validity dates, covered DNS names and IP addresses.
Hostname mismatch warning
If the URL hostname does not appear in the certificate's DNS names or IP list, the panel surfaces a warning banner. Browsers will reject the connection in that case; either regenerate the self-signed cert with the right SANs or upload a cert that covers this hostname.
TLS mode picker
Three modes: Self-Signed (board auto-generates a cert), Upload (you supply a cert from your own CA or external ACME tooling), and ACME (board talks to Let's Encrypt or another ACME provider directly). Switching modes saves the choice to management.json; mode flips that involve ACME require a board restart.
ACME configuration
Directory URL, contact email, and domain. The board requests a certificate only when the mode is ACME and both a directory URL and a domain are set; there is no default directory. Challenge type is HTTP-01. The board needs to be publicly reachable on port 80 for HTTP-01 to validate.
SAN editor + Regenerate
When mode is Self-Signed, you can edit the cert's Subject Alternative Names (hostnames + IPs) and click Regenerate. A confirmation dialog shows old SANs vs new SANs side-by-side before the new cert is generated. Hot-swaps immediately; no restart.
Upload certificate
Replace the current certificate with your own. Provide a PEM-encoded certificate file and its matching private key. Hot-swaps immediately.
HSTS max-age
Strict-Transport-Security max-age in seconds. 0 disables. Once browsers see this header they refuse plain HTTP for the entire window - even if the cert breaks later. A foot-gun confirmation dialog explains this on both enable and disable (disabling does NOT retroactively unlock browsers that saw the prior header). Requires HTTP redirect to be enabled (or i_know_what_im_doing for reverse-proxy setups).
CSP
Baseline Content-Security-Policy is set on all responses (default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'self'). This hardens against injection while allowing the dashboard's own startup script. Fonts and images load from the board; remote logo or favicon origins are added only when configured. Proxies (/device/*) inherit the policy.
HTTP-to-HTTPS redirect
When enabled, the HTTP listener redirects every request to HTTPS. Restart required to apply because the listener mux is configured at boot. The Restart Required banner at the top of the panel surfaces this.
Certificate details did not load
If the panel cannot read the certificate it says why, with a Retry button. 'The request did not complete' means the browser never got an answer from the board; 'timed out' means the board did not answer in time; 'The board returned an error (HTTP n)' means the board answered with an error. 'HTTPS may not be enabled on this board' appears only when the board itself reports that TLS is not configured. If only the settings fail to load, the certificate stays visible and the settings are hidden until Retry works. If the board uses a self-signed certificate that the browser has not trusted, background requests such as the panel or Diagnostics may fail while another browser works; a trusted certificate (Upload or ACME mode) avoids this.
Download certificate
Returns the public cert.pem (NOT the private key) as a download. Useful for loading into other tools or escalating to support.

Home Assistant

Pairing
Connect Home Assistant to this board without any cloud account. Start pairing on the HDMI console (type h, press Enter, pick an access level) or here in More > Home Assistant. In Home Assistant, enter the https:// address shown and the 8-character code. The code lasts 5 minutes, works once, and five wrong tries end it. Compare the certificate fingerprint Home Assistant shows with the one on this screen.
Signed out while pairing
If the dashboard session ends while a pairing code is showing, the login screen says so. The code expires on its own within its normal 5 minutes. If you sign in again without reloading the page, the dashboard also asks the board to cancel it sooner, and stops asking about 5.5 minutes after the code was shown. If the board does not confirm a cancel, the Home Assistant window shows the error and keeps retrying until the board confirms or that time passes, then stops and the window can close.
Access levels
Read only lets Home Assistant see ports, health, switch and fleet status. Read + PoE control also lets it turn ports on, off and power-cycle them. Neither can change settings, passwords or other boards. On a board still on the factory password, PoE control from Home Assistant is refused until the dashboard password is changed, and since 1.0.1 so are its reads. Tokens made before the first password change stop working at that change; pair again after it.
Revoke
Each paired Home Assistant is listed in More > Home Assistant with its access level and when it last connected (since the service started). Revoke takes effect at once and closes its live connections; Home Assistant must then be paired again. Deleting the integration in Home Assistant does not revoke its token; revoke it here.
HTTPS
Home Assistant tokens work only over HTTPS, and only in the Authorization header. Pairing is refused when HTTPS is off on this board; turn it on in TLS settings first.
Password changes
The first change away from the factory password unpairs every Home Assistant; pair again after it. Later password changes do not unpair Home Assistant. Revoke its token here to disconnect it.
Backups
Home Assistant tokens are not in backups. After restoring a backup onto another board, pair again.
Live connections
A dashboard session's live updates close when logging out of the dashboard, when the session expires and on a password change. Revoking a Home Assistant token closes Home Assistant's. Neither affects the other.

Privacy

What leaves the board
This dashboard sends nothing off your network by default. Fonts, icons and images load from the board. Data leaves the board only for services you turn on: ACME certificates, webhook alerts, email alerts, Auto-restart device probes (sent to the target host you enter for each port), a Prometheus URL you configure, and remote logo or favicon URLs. An observability URL is also contacted by the board: when it is set and no Prometheus URL is, the board sends an HTTP HEAD request to it at most every 25 seconds while a dashboard is open. Support and documentation links are only links: nothing is sent unless you click one. If you install Tailscale, Tailscale's own service connects to Tailscale's servers; this dashboard sends nothing about it. If you turn on a kiosk display language, the kiosk browser sends the dashboard text it shows to Google to translate it, and translation is then allowed for every Chromium window on the board, not only the kiosk; it is off by default. With the language Off, the kiosk browser is also kept from reaching Google's sign-in and push-messaging servers, which Chromium otherwise contacts on its own when it starts; with a language on it can contact them too.

Last modified October 18, 2026