| title | sma2mqtt operations and validation |
|---|---|
| summary | Network, MQTT, signals, secrets, container publishing, and test boundaries. |
| applies_to | Runtime configuration, tests, Dockerfile, and deployment scripts |
| last_verified | 2026-07-27 |
The process needs simultaneous access to:
- the SMA multicast group, default
239.12.255.254:9522; - device HTTP/HTTPS endpoints for bootstrap where available;
- device UDP endpoints for inverter queries;
- the configured MQTT broker.
Multicast normally stays inside one LAN/VLAN. Validate interface selection and container network mode on the deployment host. Port publishing alone does not guarantee multicast membership or delivery.
- Release defaults are
noticelogging and base topicsma/; debug defaults aredebugandexample/sma/. - The inverter password priority is CLI, environment, then
0000. --mqtt-unchanged-publish-intervalmust be finite and non-negative.- Interesting paths use
path:seconds. Malformed entries are currently discarded during parsing; duplicate keys are not a supported configuration. --json-outputis an additional stdout sink, not an MQTT-offline mode.SIGUSR1cyclesdebug -> trace -> info -> debug; any other starting level moves todebug.- Signal sources must remain retained for the process lifetime.
Two exposed options are not wired through in the current development revision:
MQTTPublisher.initignores its password parameter and always passes an empty password to MQTTNIO.SMALighthouse.initignores its bind-port parameter and configures the receiver with the multicast port.
Treat password-authenticated MQTT and an independently selected local bind port as unsupported until implementation and tests prove otherwise. Keep this warning synchronized with code changes.
MQTT topic shape and JSON type are downstream contracts:
- normalize one trailing base-topic slash before joining paths;
- preserve logical path names unless a migration is intentional;
- keep topics that have emitted arrays as arrays on subsequent single-value updates, including across normalized device-name keys;
- suppress unchanged retained publications;
- reset publication history on broker disconnect so state is republished after reconnect;
- do not confuse publication throttling with SMA polling frequency.
Run the deterministic suite first:
swift package dump-package
swift build
swift test
swift build -c release --product sma2mqttOn 2026-07-22 with Apple Swift 6.4, these checks passed. The default test run executed 36 tests in six suites and skipped three gated tests: two live-device tests and one missing pcap fixture.
Optional fixture validation:
swift test -- --pcap-file /absolute/path/to/capture.pcapOptional live-device validation:
SMA_INTEGRATION_TESTS=1 swift testThe current live tests contain local/default device addresses. Inspect them and ensure the target network is correct before opting in. Never commit real inverter or broker passwords.
For runtime changes, also verify multicast discovery, HTTP-to-UDP fallback, broker reconnect, retained and non-retained topics, JSON stdout framing, and both signals in a controlled environment.
The product Dockerfile uses matching Swift 6.3 builder/runtime images, resolves dependencies in a cacheable layer, dynamically finds the release binary/resource bundle, and copies both into a slim image.
docker build . --file sma2mqtt.product.dockerfile --tag sma2mqtt
docker run --rm --network host --env INVERTER_PASSWORD sma2mqtt sma2mqtt --mqtt-servername 127.0.0.1The image uses CMD ["sma2mqtt"], not an entrypoint. Supplying arguments after the image replaces that default command, so repeat sma2mqtt before any options.
On 2026-07-22, a local-architecture Docker build and sma2mqtt --help container smoke test passed. Linux compilation emitted a deprecation warning for MQTTNIO's event-loop provider but completed and copied the resource bundle. A controlled run with reachable devices and broker is still required for network behavior.
The Dockerfile copies only Package.swift before resolution and does not copy Package.resolved. It therefore resolves the newest compatible dependency graph, which can differ substantially from a developer's local checkout. Treat dependency updates observed only inside Docker as deliberate inputs to validation, not as proof that the locked/local graph is equivalent.
.github/workflows/docker-publish.yml publishes multi-architecture GHCR images from GitHub branch/tag events. ghcrupload.sh is a manual publisher that reads a token from the macOS Keychain and mutates GHCR. build.sh is a legacy deployment-specific Docker launcher.
Only the main branch workflow publishes latest; semantic-version tag workflows publish the version tag without also racing to update latest. GitHub Actions cache export is best-effort because an unavailable cache backend must not turn a successfully built and published image into a failed release. A cache-export warning can therefore be non-fatal, but an image build or registry-push error must still fail the workflow.
Do not run publishing scripts as validation. Before publishing, verify the intended registry, tag, architectures, credentials, and whether the source commit exists on the server that triggers the workflow.
Temp/ contains separate reverse-engineering/reference repositories. They are not root project source and may intentionally be partial or dirty. Never stage, repair, clean, or commit them as part of sma2mqtt work.