Notable changes to HaMBridge (this repository). Release history for packaging metadata remains in packaging/debian/changelog (Debian) and the RPM spec where required by those formats.
- CI / Debian builds —
Makefilefinds fcl-fpcunit under/usr/lib/*-linux-gnu/fpc/...somake testworks on Ubuntu/Debian (GitHub Actionsubuntu-24.04).
- HaMBridge branding — README, Specification, packaging text; clone paths use
hambridge; README summary table covers VISCA over serial and UDP. - Config — removed pre-release legacy JSON mapping paths, flat serial bus fields, and
/etc/hambridge/hambridge.yamldiscovery (no external releases yet).
- GitHub Actions —
.github/workflows/ci.ymlrunsmakeandmake teston pull requests andmain;verify-release-pinschecksrelease-pins.jsonagainst the Makefile and RPM spec..github/workflows/release.ymlon tagsv*.*.*verifies version alignment, buildshambridge-{version}-linux-x86_64.tar.gz+SHA256SUMS, Debian.deb(amd64 and arm64 runners), and Fedora RPM (fedora:42container), then publishes a GitHub Release withCHANGELOG.mdnotes.
- MQTT TLS (optional) —
bridge.mqtt.tlsmay be a boolean (legacy) or an object withenabled,caFile,caPath,clientCertFile,clientKeyFile,verifyPeer,serverName,minVersion,maxVersion,ciphers(seeSpecification.md§3.0). Trust anchors and verification are applied before the TLS handshake via a build-time patch onprof7bit/fpc-mqtt-clientmqtt.pas(seepatches/; zip pin unchanged for other units). Startup validates paths, warns on verifyPeer: false and on private keys readable by group/other, and warns once if minVersion / maxVersion are set (not enforced; use ciphers / OpenSSL defaults).
- Automated tests (FPCUnit) —
make testbuilds and runs./build/hambridge_tests(plain report). Fixtures live undertests/fixtures/: minimalhambridge.yamlslices fordevicesconfigvalidation (duplicate slugs, UDP triple and cross-bus rules, missing UDP controller, duplicate VISCA controllers) and a smallvisca-min.yamlforviscamappinggolden encode/decode (including a controller power/on frame aligned with common Sony VISCA / Bitfocus-style bytes per Specification §10.4).
- Bus schema enforcement —
buses.<id>requirestransport+protocol, validatesprotocol_config(if present) is an object, and reads serial settings fromtransport_configuration.
- Endpoints loader — VISCA devices are loaded from
endpoints[]withmatch.endpoint_type: device, usingmatch.busandmatch.deviceID(replacing the legacydevices[]stanza). Evdev inputs are loaded asmatch.endpoint_type: controllerwithmatch.protocol: evdevand default publish topiccontroller/<slug>/event.
- Evdev endpoints enforcement — Linux input is configured via an
evdevbus (transport: none,protocol: evdev,protocol_config.enabled: true) andendpoints[]controller rows (match.protocol: evdev). Validation now enforcesprotocol_config.enabled: truefor evdev buses.
- VISCA over UDP —
busesmay usetransport: udp+protocol: viscawithtransport_configuration.bindHost/bindPort. Device endpoints resolveudpHost/udpPort(or busdefaultUdpHost/defaultUdpPort). Replies are correlated using(bus, remoteHost, remotePort, deviceID)with strict must-match semantics. Controller ingest publishes oncontroller/<slug>/event(onematch.protocol: viscacontroller endpoint per UDP bus).
- Unified YAML configuration — One file
hambridge.yamlreplacesbridge.json+devices.json. Top-levelbridgeholds MQTT and logging;device_mappings.viscapoints at the VISCA mapping file (paths relative to the main config directory).busesmay usetransport: serialand nestedtransport_configuration(port,baud,rs485, …).--devicesandBRIDGE_DEVICESare removed; pass the same path to--config/BRIDGE_CONFIGfor everything. - Config discovery — Matches
docs/user/ConfigurationGuide.md(no implicit./config/probe): CLI,BRIDGE_CONFIG,.local/etc/config/hambridge.yaml,/etc/hambridge/config/,/etc/hambridge/hambridge.yaml. - VISCA mapping —
mappings/visca.yaml(and.yml) supported via in-tree minimal YAML parsing;.jsonmapping files still work.
- Device reply decode —
device/<slug>/telemetryandlastReplyondevice/<slug>/statusmay include adecodeobject (generic VISCA: replyClass, socket, payload / code as applicable) viaviscareplydecode. controller/<bus>/status— JSON snapshot withlastControllerandlastDeviceReply(objects ornull), published aftercontroller/<bus>/eventand after device replies on that bus.
devices.json—devices[].scheduler.coalesce: array of first path segments (pan,tilt,zoom, …). Before enqueueing, older queued commands for the same device and segment are removed (the item waiting for ACK is not dropped).- Redundant VISCA skip — Per-device, per-command-path last successful wire cache (bridge ACK/completion and controller semantic re-encode). Matching MQTT control is answered with
commandAck(reason: redundant,viscaKind: skipped) without enqueueing or sending; duplicates already queued are dropped at send time the same way. device/<slug>/status— Optionalstateobject with last JSON forpan,tilt,zoom, and preset-family commands, updated from bridge successes and controller decodes.
- VISCA command lifecycle (
commandrouter): per-bus state machine — drain TX queue, wait for device ACK / completion / error (orscheduler.ackTimeoutMstimeout),commandRetryMaxresends withretryBackoffMs.ackTimeoutMs: 0 skips wait and publishescommandAckwithviscaKindimmediate. - MQTT
device/<slug>/commandAck: JSON withok,reason,attempts,mqttTopic,command,viscaKind,viscaHex. - Serial (
serialport): software TX queue (up to 8 KiB),PumpTransmitfor partialwrite/EAGAIN; reopen with backoff after hard read/write errors; optionalTIOCSRS485fromdevices.jsonbuses.<id>.rs485. visca-mapping.json: template slots as string (one byte) or objectslot+width(1..8); MQTT /variablesvalue as integer (big-endian) or JSON array of bytes. Controller reverse-decode updated.
- Serial RX: non-blocking reads, VISCA frames terminated by
0xFF. - Controller traffic: reverse-map packets against
visca-mapping.json; publishcontroller/<bus>/event(semantic or rawevent). - Device replies: classify ACK / completion / error; publish
device/<slug>/telemetryand mergelastController/lastReplyintodevice/<slug>/status.
- Framed VISCA encoding in
visca-mapping.json(bytes+ optionaltemplate/variables+ MQTT JSON for slots).
- MQTT
device/<slug>/<command>→visca-mapping.json→ serial TX; per-bus queue and inter-command spacing.
- Linux evdev → MQTT JSON;
bridge.json/devices.json; MQTT reconnect, LWT/birth.