Repository navigation
Installation
Important
Choose the target that matches how you want to run sdsctl. Home Assistant
and container users do not need to install the Python package on the host.
| Goal | Recommended path |
|---|---|
| Run inside Home Assistant OS | Install the Home Assistant App |
| Use a terminal UI on Linux or Raspberry Pi OS | Install sds200[tui,playback]
|
| Run a web dashboard or MQTT service on a Linux server | Install sds200[web,mqtt]
|
| Install every optional Python runtime interface | Install sds200[all]
|
| Use only the CLI or Python library | Install the base sds200 package |
| Run a managed container | Follow the container deployment guide |
Develop or contribute to sdsctl
|
Install the source checkout with .[dev,all]
|
Continue with First connection after a Python or container installation. Home Assistant users should finish the App setup first.
- Python 3.11 or newer
- A Uniden SDS100, SDS150, or SDS200 scanner
- A USB serial connection for any supported model, or a trusted local network for native SDS200 Ethernet features
- A working PortAudio runtime for optional local playback
FFmpeg with libmp3lame is needed only for the optional Broadcastify adapter.
Install the library and sdsctl command:
python -m pip install sds200Install the optional Textual full-screen interface:
python -m pip install "sds200[tui]"Install optional local audio playback:
python -m pip install "sds200[playback]"Install the optional loopback web dashboard:
python -m pip install "sds200[web]"Install optional daemon MQTT support:
python -m pip install "sds200[mqtt]"Install every optional Python runtime interface:
python -m pip install "sds200[all]"The all extra is exactly the union of tui, web, mqtt, and playback.
It does not install development tools, operating-system packages, Home
Assistant, Docker or Podman, an audio server, or FFmpeg. Individual extras can
still be combined, such as sds200[tui,playback] or sds200[web,mqtt].
Verify the installation:
sdsctl --version
sdsctl --helpA virtual environment keeps the package and optional dependencies isolated:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install "sds200[all]"Activate the environment again before using its sdsctl command:
source .venv/bin/activategit clone https://github.com/stevenboyd78/sdsctl.git
cd sdsctl
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev,all]"Run the project checks before contributing:
ruff check .
mypy src/sds200
pytest
python scripts/check_docs.py
git diff --checkSome Linux systems do not automatically grant the active user access to the
scanner serial port. The project includes an optional udev rule that uses
systemd-logind uaccess, retains a dialout fallback, and prevents
ModemManager from probing matching scanners.
Follow the canonical Linux udev guide rather than making scanner devices globally writable.
Inspect stable device paths with:
ls -l /dev/serial/by-id/The playback extra installs the Python binding, but Linux must also provide
the PortAudio runtime. On Debian or Raspberry Pi OS:
sudo apt update
sudo apt install libportaudio2List the audio devices visible to sdsctl:
sdsctl audio-devicesIf playback still fails, use Troubleshooting.
Check that FFmpeg exposes the MP3 encoder required by the Broadcastify adapter:
ffmpeg -version | head -n 1
ffmpeg -hide_banner -encoders 2>/dev/null | grep -F libmp3lameThe encoder listing should contain libmp3lame.
Continue with First connection for USB, SDS200 Ethernet, multiple-scanner selection, expected success output, and safe discovery limits.
Home Assistant OS users should follow Home Assistant. The
published App does not require pip, a source checkout, or a Local App under
/addons.
Version 0.31.0 publishes the Mimic-SDS presentation and installed display-profile
administrator workflow while preserving one daemon-owned scanner connection,
existing MQTT identities, persistent recordings, credentials, ports and advanced
service defaults. It also publishes one disabled-by-default SDS200 Menu boundary
limited to firmware Version 1.26.01 and fresh Trunk Scan / trunk_scan
context. It does not add another key, held gesture, sequence, retry or
post-acknowledgement state claim.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Activate the existing virtual
environment and install the exact release only after PyPI shows both the reviewed
wheel and source distribution:
python -m pip install --upgrade "sds200==0.31.0"
python -m pip check
sdsctl --versionInstall or upgrade every optional Python runtime interface with:
python -m pip install --upgrade "sds200[all]==0.31.0"
python -m pip check
sdsctl --versionFor the generic container, prefer the exact published multi-architecture image:
docker pull theboyd78/sdsctl:0.31.0Verify the reviewed manifest digest before treating that mutable registry tag as
an immutable deployment input. theboyd78/sdsctl:latest follows the newest
successfully published release, but the exact version is preferred for a
controlled upgrade.
The Home Assistant App version also tracks 0.31.0. Save a private copy of its
options, Network mappings and complete digest-qualified dashboard resource URL
before updating. The matching image and catalog add
qualified_sds200_menu_control_enabled: false and
scanner_display_config: "". Do not manually add those fields to a v0.30.0 or
older installed App; its strict parser expects the previous seven-field schema.
After Home Assistant offers the matching v0.31.0 update:
- update through the normal repository-managed App workflow;
- confirm the installed App version/image and both new defaults before opting into either feature;
- open Ingress and confirm the expected scanner, existing MQTT entities and persistent recordings;
- replace the dashboard aggregate resource with the exact URL shown by the installed App, then reload all open dashboard tabs; and
- configure
scanner_display_configonly after preparing the private deployment/profile manifests and accepted state with the documented administrator workflow.
The profile path never causes startup to search, initialize, import, repair or change state. Mimic-SDS is read-only, and this release does not implement automatic Favorites List synchronization. The qualified Menu option remains off unless the exact model/firmware/context procedure is deliberately required.
For rollback, first turn both new options off. Preserve recordings, credentials, profile manifests, accepted state and original profile copies. Restore the prior reviewed Python/container/App version through its normal package, registry or Home Assistant backup/repository workflow, and restore only that release's matching options and aggregate resource URL. Do not uninstall the Home Assistant Core integration, delete App data or remove profile state merely to make rollback succeed. If a new resource was registered, replace it with the exact older URL instead of retaining mixed Waterfall/Mimic module generations.
The independently versioned Home Assistant Core integration remains optional; the App does not install, activate, reload, remove or restart it automatically. A release upgrade does not authorize a Home Assistant Core restart, scanner command, profile import/reload or recording mutation.
Version 0.30.0 adds local dates, a numeric timezone offset and 24-hour time to
the TUI header and status changes. The timezone is the TUI host's; Status since
is an observed label transition, not a measured socket connection start. Upgrade
each TUI client to get the new presentation. Scanner model/firmware stays in its
own panel, and the connected daemon's application version is not yet displayed.
Web Diagnostics shows connected-client ages as hours/minutes/seconds with elapsed days. The LCARS theme keeps scanner text and header controls clear of decoration, and First Responder and Amateur Radio separate the overview label from the header divider.
The daemon also fixes false missing-event errors in remote TUIs when another interface starts or stops a recording. Upgrade the Home Assistant App or other daemon installation to receive that server-side correction; it does not require replacing client credentials. Client-side date presentation still requires upgrading each TUI client.
Experimental browser-device commands and continuation/sign-out foundations stay opt-in; an upgrade does not enable enrollment, migrate existing profiles or qualify unattended production sign-in. The repository App's seven-field schema, credentials, mappings, cards and recording locations remain unchanged.
It retains v0.29.5's managed remote TUI waiting screen while its daemon is unavailable. The screen shows the target and retry countdown, then returns to live data after fresh authorization. That client-side waiting-screen feature also works with an existing 0.29.4 daemon. It does not require changing fonts, service files, passwords or port mappings.
It includes the certificate-test corrections from 0.29.4. Version 0.29.3 was published as containers but did not reach PyPI; use a fully published version.
The TUI shows sdsctl and the application version in its top header.
Scanner model and firmware remain in Scanner, and Connection retains the
endpoint and remote target. Short terminals keep a single-line Scanner summary;
the 100-by-30 display gives it a compact full-width panel without scrolling the
normal dashboard. Change console fonts only while the display is stopped.
It retains v0.29.1's wide Textual TUI refinements: Live PSI sits directly beneath Scanner State, Logs occupies a full-width row, and Keyboard Reference can stay open alongside Logs. These refinements apply at 120 or more columns and at least 32 rows; the compact display's space-saving drawers remain unchanged. An existing 0.29.0 daemon is compatible with the updated TUI, so the layout fix requires only a client upgrade, not new credentials or a Home Assistant App upgrade.
It builds on v0.29.0, which published Milestones 33.1 through 33.3. The TUI
adapts to the physically qualified 100-column by 30-row Raspberry Pi console,
keeps network-audio controls only when the selected transport supplies that
service, and proactively renews finite direct-USB PSI pushes without reopening
scanner control. Scanner-owned recording state is labeled Scanner recording; the
separate daemon-owned WAV workflow remains Audio recording.
The v0.29.0 release also added an opt-in managed Raspberry Pi TUI deployment. A
display-client-preflight command verifies the exact console, observe-only
authorization, remote services, runtime contract, and optional local playback
without printing private connection or identity details. The packaged
sdsctl-display@.service template starts the physical /dev/tty1 display at
boot under a dedicated unprivileged account, retries only temporary connection
loss, and stops for revoked credentials, permanent configuration failures,
unexpected local failures, or an intentional quit.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Activate the existing virtual
environment first; do not recreate it for an ordinary upgrade. For a managed
service, follow its deployment guide
so the command updates the environment used by that service. Upgrade the base
package with:
python -m pip install --upgrade "sds200==0.30.0"
sdsctl --versionInstall or upgrade every optional Python runtime interface with:
python -m pip install --upgrade "sds200[all]==0.30.0"
python -m pip check
sdsctl --versionLinux local playback still needs a working PortAudio runtime. See Audio and recordings for the required operating-system package and verification procedure.
For the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.30.0theboyd78/sdsctl:latest follows the newest successfully published release,
but the exact version tag is recommended for controlled deployments. The
ordinary repository-root compose.yaml and compose.usb.yaml paths remain
source-built and local-only. The separate compose.remote.yaml topology is
documented in Containers and requires deliberate private-LAN TLS,
identity, address, port, and firewall configuration.
The Home Assistant App version tracks 0.30.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, persistent recordings, aggregate and individual card resource
paths, and independently versioned card modules. Upgrade the repository-managed
App only after the matching release images have published.
Upgrading does not expose an advanced Home Assistant service. The
authenticated daemon-client and native HTTPS dashboard mappings remain
disabled and null by default. Existing Ingress-only users do not need to
create a server identity, dashboard password, client credential, firewall rule,
or TCP mapping. The App continues to expose only authenticated Ingress and the
existing scanner-to-App RTP input unless an operator deliberately completes the
advanced configuration.
After an observe-only remote TUI works interactively, follow Managed Raspberry Pi display for the dedicated account, private file placement, preflight, service activation, recovery, credential rotation or revocation, upgrade, disablement, and exact removal workflow. Browser kiosks remain separate because they use the native HTTPS dashboard, browser certificate trust, a dashboard password, and a browser session instead of a daemon-client credential.
The optional Home Assistant Core integration remains independently versioned at 0.1.5 and does not need replacement, bridge-key rotation, reauthentication, Core restart, or Core reload for this release.
v0.28.1 publishes Milestones 32.1 through 32.6. It lets one scanner-owning
daemon serve explicitly authenticated private-LAN CLI, TUI, Raspberry Pi,
container, browser, and advanced Home Assistant clients. Each daemon client
receives an independent observe or control identity for its authorized
status, events, accepted-PCMU audio, Waterfall, and typed controls. Recording
content is not granted by either daemon-client scope; the same daemon continues
to own recordings without opening another scanner connection.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the base package with:
python -m pip install --upgrade "sds200==0.28.1"
sdsctl --versionInstall or upgrade every optional Python runtime interface with:
python -m pip install --upgrade "sds200[all]==0.28.1"
python -m pip check
sdsctl --versionLinux local playback still needs a working PortAudio runtime. See Audio and recordings for the required operating-system package and verification procedure.
For the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.28.1theboyd78/sdsctl:latest follows the newest successfully published release,
but the exact version tag is recommended for controlled deployments. The
ordinary repository-root compose.yaml and compose.usb.yaml paths remain
source-built and local-only. The separate compose.remote.yaml topology is
documented in Containers and requires deliberate private-LAN TLS,
identity, address, port, and firewall configuration.
The Home Assistant App version tracks 0.28.1 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, persistent recordings, aggregate and individual card resource
paths, and independently versioned card modules. Upgrade the repository-managed
App only after the matching release images have published.
v0.28.1 also corrects the v0.28.0 native-dashboard login response so an ordinary browser preserves the exact same-origin value required by the dashboard's CSRF protection. It does not broaden listener exposure, client scope, or the supported private-LAN boundary.
Upgrading does not expose an advanced Home Assistant service. The
authenticated daemon-client and native HTTPS dashboard mappings remain
disabled and null by default. Existing Ingress-only users do not need to
create a server identity, dashboard password, client credential, firewall rule,
or TCP mapping. The App continues to expose only authenticated Ingress and the
existing scanner-to-App RTP input unless an operator deliberately completes the
advanced configuration.
Operators who need one App-owned daemon to serve Raspberry Pi or workstation clients should follow Advanced Home Assistant. That guide explains Supervisor's host-wide mapping limitation, private-LAN firewall direction, certificate trust, per-device enrollment, least-privilege scopes, revocation, rotation, restart recovery, rollback, and cleanup. Do not expose either service to the Internet, forward it through a router, use a wildcard listener, share one client identity across displays, or copy the server private key to a client.
The optional Home Assistant Core integration remains independently versioned at 0.1.5 and does not need replacement, bridge-key rotation, reauthentication, Core restart, or Core reload for this release.
v0.27.0 publishes Milestones 31.1 and 31.2. It adds bounded 15-, 30-, and 60-second Waterfall history modes to the authenticated web dashboard and the first-party Home Assistant Waterfall card while retaining compatible 60-, 120-, and 240-frame configurations. It also adds an optional display-only frequency pointer that interpolates the scanner-reported span for inspection. The pointer does not tune, hold, search, change scanner span, or turn the relative and uncalibrated Waterfall into an RF measurement instrument.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the base package with:
python -m pip install --upgrade "sds200==0.27.0"
sdsctl --versionInstall or upgrade every optional Python runtime interface with:
python -m pip install --upgrade "sds200[all]==0.27.0"
python -m pip check
sdsctl --versionLinux local playback still needs a working PortAudio runtime. See Audio and recordings for the required operating-system package and verification procedure.
For the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.27.0theboyd78/sdsctl:latest follows the newest successfully published release,
but the exact version tag is recommended for controlled deployments.
Repository-root compose.yaml and compose.usb.yaml remain source-built and do
not switch automatically to the Docker Hub image.
The Home Assistant App version tracks 0.27.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, persistent recordings, aggregate and individual card resource
paths, and independently versioned card modules. Upgrade the repository-managed
App only after the matching release images have published. The optional Core
integration remains independently versioned at 0.1.5 and does not need
replacement for this release.
v0.26.1 publishes Milestones 30.1 and 30.2: the concise package README,
deployment- and task-oriented beginner documentation, and the sds200[all]
optional dependency extra. The all extra is the exact union of tui, web,
mqtt, and playback; it does not install development tools, operating-system
packages, Home Assistant, containers, audio servers, or external encoders.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the base package with:
python -m pip install --upgrade "sds200==0.26.1"
sdsctl --versionInstall or upgrade every optional Python runtime interface with:
python -m pip install --upgrade "sds200[all]==0.26.1"
python -m pip check
sdsctl --versionLinux local playback still needs a working PortAudio runtime. See Audio and recordings for the required operating-system package and verification procedure.
For the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.26.1theboyd78/sdsctl:latest follows the newest successfully published release,
but the exact version tag is recommended for controlled deployments.
Repository-root compose.yaml and compose.usb.yaml remain source-built and do
not switch automatically to the Docker Hub image.
The Home Assistant App version tracks 0.26.1 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, persistent recordings, and independently versioned card modules.
Upgrade the repository-managed App only after the matching release images have
published. The optional Core integration remains independently versioned at
0.1.5 and does not need replacement for this patch release.
v0.26.0 freezes Milestones 29.4 through 29.7: one aggregate first-party Home
Assistant card resource with retained individual compatibility URLs, a phase-
stable 250 ms text-GWF schedule, bounded timing telemetry, independently
refreshed typed GST span data, Home Assistant editor and section-layout
compatibility, and the bounded GW2 research conclusion. The qualified text
PWF/GWF path remains authoritative; the tested SDS200 firmware 1.26.01 LAN
GW2 candidate returned ERR\r and established no binary framing or production
negotiation contract.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the Python package with:
python -m pip install --upgrade "sds200==0.26.0"
sdsctl --versionFor the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.26.0theboyd78/sdsctl:latest follows the newest successfully published release, but
the exact version tag is recommended for controlled deployments. Repository-root
compose.yaml and compose.usb.yaml remain source-built and do not switch
automatically to the Docker Hub image.
The Home Assistant App version tracks 0.26.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, persistent recordings, and independently versioned card modules.
Upgrade the repository-managed App only after the matching release images have
published. The optional Core integration remains independently versioned at
0.1.5; this release does not require replacing its artifact. Existing
digest-confirmed integration lifecycle, Core restart or reload,
reauthentication, and media-target URL reachability requirements remain
unchanged.
v0.25.0 freezes Milestones 29.1 through 29.3: the responsive first-party Home
Assistant Waterfall card, the standard media-source://sdsctl/live workflow,
the versioned optional Core integration, authenticated private App transports,
bounded waterfall and playback leases, System palette choices for the web and
all three cards, compact workspace controls, the Ingress-only integration
lifecycle pane, SHA-qualified card resources, and visible two-step destructive
confirmations. The daemon remains the only scanner, waterfall, and RTSP/RTP
owner. Home Assistant media players receive a bounded Home Assistant-owned URL,
not an Ingress identifier, App capability, scanner address, or public stream.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the Python package with:
python -m pip install --upgrade "sds200==0.25.0"
sdsctl --versionFor the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.25.0theboyd78/sdsctl:latest follows the newest successfully published release, but
the exact version tag is recommended for controlled deployments. Repository-root
compose.yaml and compose.usb.yaml remain source-built and do not switch
automatically to the Docker Hub image.
The Home Assistant App version tracks 0.25.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, persistent recordings, and bundled cards. Upgrade the repository-
managed App only after the matching release images have published. The optional
Core integration remains independently versioned at 0.1.5 and requires explicit
digest-confirmed install or update from the authenticated Ingress workspace,
followed by the documented Core restart or reload and any required
reauthentication. A target player must be able to reach Home Assistant's selected
internal or external URL for live media playback.
v0.24.0 freezes Milestones 28.1 through 28.4: one explicit credentialed RadioReference refresh in the local Favorites Workspace editor, an exact read-only preview, reviewed assisted field and record decisions, deterministic write planning, and full-token-confirmed copied-tree or freshly qualified USB execution with verified readback, conditional provenance publication, and exact cross-store recovery. Synchronization remains local, explicit, user-initiated, and one-shot; it is not automatic, scheduled, silent, or exposed through the web dashboard, Home Assistant, or MQTT. The release also provides complete current target context and Previous, Hold/Release, and Next controls for System, Department, Site, and Channel in the responsive web Controls pane.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the Python package with:
python -m pip install --upgrade "sds200==0.24.0"
sdsctl --versionFor the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.24.0theboyd78/sdsctl:latest follows the newest successfully published release, but
the exact version tag is recommended for controlled deployments. Repository-root
compose.yaml and compose.usb.yaml remain source-built and do not switch
automatically to the Docker Hub image.
The Home Assistant App version tracks 0.24.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, and bundled card custom elements. Upgrade the repository-managed App
through Home Assistant after the matching release images have published. The
local RadioReference-assisted Favorites workflow is not an App or Ingress
feature.
v0.23.0 freezes Milestones 27.1 through 27.4: adaptive scanner-screen presentation, the qualified private text-waterfall service, protocol and audio lifecycle hardening, the responsive six-pane web workspace, the original Pip-Boy-inspired web theme, managed-theme source-snapshot hardening, and the authenticated relative spectrum and rolling-waterfall pane. Waterfall values are explicitly uncalibrated, the web pane creates demand only while visible, and no Home Assistant waterfall card, scanner tuning, public waterfall transport, or persistent waterfall history is included.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the Python package with:
python -m pip install --upgrade "sds200==0.23.0"
sdsctl --versionFor the generic container, prefer the exact release image:
docker pull theboyd78/sdsctl:0.23.0theboyd78/sdsctl:latest follows the newest successfully published release, but
the exact version tag is recommended for controlled deployments. Repository-root
compose.yaml and compose.usb.yaml remain source-built and do not switch
automatically to the Docker Hub image.
The Home Assistant App version tracks 0.23.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, and bundled card custom elements. Upgrade the repository-managed App
through Home Assistant after the matching release images have published.
v0.22.0 freezes Milestones 26.1 through 26.16: authenticated direct-TLS LAN dashboard access, the capability and field-parity audit, the local interactive Favorites Workspace editor, complete web snapshot presentation, bounded battery lifecycle handling, expanded Home Assistant state and responsive scanner-style cards, exact semantic controls, Tone-Out parity, and modular built-in and managed themes for web, Home Assistant, and terminal interfaces.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the Python package with:
python -m pip install --upgrade "sds200==0.22.0"
sdsctl --versionFor the generic container, prefer the immutable exact release image:
docker pull theboyd78/sdsctl:0.22.0theboyd78/sdsctl:latest follows the newest successfully published release, but
the exact version tag is recommended for reproducible deployments.
Repository-root compose.yaml and compose.usb.yaml remain source-built and do
not switch automatically to the Docker Hub image.
The Home Assistant App version tracks 0.22.0 while preserving its
compatibility-sensitive sds200 name, slug, GHCR image identity, MQTT entity
identities, and bundled card custom elements. Upgrade the repository-managed App
through Home Assistant after the matching release images have published.
v0.21.0 is the first release after v0.20.2 and freezes the completed Milestones
21 through 25 release scope: Favorites Workspace and verified storage workflows,
assisted RadioReference synchronization, advanced protocol and analysis
foundations, the user-facing sdsctl repository/product identity, and the
generic Docker/Compose/Podman deployment foundation.
The compatibility-sensitive Python distribution and import package remain
sds200, while the command remains sdsctl. Upgrade the Python package with:
python -m pip install --upgrade "sds200==0.21.0"
sdsctl --versionThe v0.21.0 release is also the first release using the generic Docker Hub publication path. After the genuine matching release tag has published successfully, prefer the immutable exact image:
docker pull theboyd78/sdsctl:0.21.0theboyd78/sdsctl:latest follows the newest successfully published release, but
the exact version tag is recommended for reproducible deployments.
Repository-root compose.yaml and compose.usb.yaml remain source-built and do
not switch automatically to the Docker Hub image.
The Home Assistant App version tracks 0.21.0 for the release while preserving
its compatibility-sensitive sds200 name, slug, and GHCR image identity. The
single-owner daemon, MQTT Discovery/control, Ingress, browser audio, and
recording architecture remain unchanged by release preparation.
v0.20.2 publishes the three Home Assistant slices completed after v0.20.1 while preserving the existing single-owner daemon architecture.
The Home Assistant Configuration page now has user-facing names and descriptions
for scanner_host, mqtt_topic_prefix, and recording_directory. The recording
directory remains media-relative and the default still resolves to:
/media/sdsctl/recordings
The App installs the unchanged compact, responsive display, and authenticated
waterfall card modules plus one aggregate entry point. For a new installation,
register
/local/sds200/sds200-cards.js?v=dbbb246abbf82fff9040c2d3a4ccb7f94ef634bf56795c0c356737bb5faac37f
once under Settings > Dashboards > Resources as a JavaScript Module. The
three complete digest-qualified individual URLs remain supported for selective
registration and existing installations. Add and verify the aggregate before
explicitly removing old individual resource records; the App never edits those
records. If the App had to
create Home Assistant's www directory for the first time, restart Home
Assistant Core once before registering the /local resources. Add SDS200
Scanner, SDS200 Display, or SDS200 Waterfall from the picker and use
its graphical editor to
choose the SDS200 Discovery state entities. The display card also selects one of
five layouts, three palettes, and Card or viewport-bounded 4:3 fit.
The waterfall card requires no entities, URL, credentials, App slug, private Ingress identifier, or scanner address. It discovers exactly one running SDS200 App through Home Assistant, uses authenticated App Ingress, and renders bounded relative, uncalibrated spectrum history. Stop or uninstall obsolete Local Apps if the card reports that multiple SDS200 Apps are running.
The MQTT-discovered SDS200 device now contains twenty-one components: fourteen state/diagnostic components, including optional Site, Frequency, Modulation, and Service Type sensors, plus System, Department, Site, and Channel Hold switches and Previous Channel, Next Channel, and Reconnect Scanner buttons. The seven controls use a dedicated bounded Home Assistant adapter; the App still does not enable the generic daemon MQTT request-envelope command topic.
Existing v0.20.1 recordings and configuration remain in the same Home Assistant media/configuration locations. Back up important configuration and recordings before any upgrade.
See the canonical Home Assistant App guide for the Lovelace registration, entity, storage, networking, control, and security contracts.
v0.20.1 is a corrective Home Assistant App release. It keeps the distribution
and Python import package named sds200, the executable named sdsctl, and the
existing single-owner daemon architecture.
Home Assistant recordings now use writable media storage instead of the
App-private legacy recording directory. The default recording_directory value
sdsctl/recordings resolves to:
/media/sdsctl/recordings
When upgrading a v0.20.0 Home Assistant App installation, startup migrates files
from /data/recordings into the configured media library before starting the
daemon. Nested paths and metadata sidecars are preserved. Migration preflights
destination conflicts, never overwrites a differing file, verifies copied file
contents before removing the legacy source, and can resume when an identical
destination already exists.
The dashboard also separates active Capture from Recent recordings, moves Reconnect scanner into Scanner connection, groups daemon runtime with scanner connection, and gives the finalized recording library its own responsive panel.
Existing standalone scanner profiles, remote-audio profiles, daemon configuration, and other non-App data are not moved by this Home Assistant recording migration. Back up important configuration and recordings before any upgrade.
See the canonical Home Assistant App guide for exact storage, migration, networking, and security behavior.
The foreground daemon is intended for process-manager ownership. It exposes private local API, event, PCMU, and finalized-recording sockets and can activate saved playback, recording, and remote-profile destinations.
sdsctl --log-level INFO --host SCANNER_IP daemon
sdsctl daemon-client status
sdsctl tui --daemon-clientStandalone scanner commands and the standalone TUI remain the default. Daemon client mode is explicit.
To run the loopback web dashboard in another terminal:
sdsctl webOpen http://127.0.0.1:8000/ locally. The web service remains a daemon client
and does not open scanner hardware directly.
- Complete First connection.
- Choose a CLI, TUI, web, daemon, MQTT, control, or theme workflow in Using sdsctl.
- Configure audio and recordings.
- Review operations and diagnostics before installing a persistent service.
- Open Troubleshooting when discovery or startup fails.