Skip to content

Latest commit

 

History

History

posix

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

POSIX port

The eBus core (doc/core.md) on Linux and macOS: a HomieTransport over the Eclipse Paho MQTT C client, the clock and log bindings, a demo device, a demo controller, and end-to-end tests against a real mosquitto. CMake only; PlatformIO never builds this directory, because the root library.json limits a PlatformIO build to mqtt/src/, discovery/src/, homie/src/ and link/src/.

Path Contents
include/ebus_posix/paho_transport.h, src/paho_transport.cpp PahoTransport: connect, reconnect, Last Will, inbound deferral, queue_publish() from any thread
include/ebus_posix/posix_port.h, src/posix_port.cpp Clock (CLOCK_MONOTONIC, nanosleep), log (stderr), settable table storage, ebus_posix_register_settable()
apps/device_main.cpp ebus-posix-device
apps/controller_main.cpp ebus-posix-controller
test/ ebus_posix_e2e (mosquitto)

Build

cmake -S ports/posix -B ports/posix/build
cmake --build ports/posix/build -j
ctest --test-dir ports/posix/build --output-on-failure

Paho MQTT C v1.3.16 is fetched and checked against its SHA-256, and built as a static, plain-TCP library. An installed Paho is used instead when CMake finds its eclipse-paho-mqtt-c package; -DEBUS_POSIX_PAHO=fetch or =system forces one or the other. To build offline, pass -DFETCHCONTENT_SOURCE_DIR_PAHO_MQTT_C=<checkout> (and FETCHCONTENT_SOURCE_DIR_ARDUINOJSON for the core). -DEBUS_POSIX_WERROR=ON makes warnings in the port, demos and tests errors, as CI does.

The end-to-end tests need mosquitto (Homebrew: brew install mosquitto; Debian/Ubuntu: apt-get install mosquitto). Each test starts its own on a free 127.0.0.1 port and leaves its logs in build/e2e/<test>/. Without mosquitto, CMake warns and registers no test.

Run

ports/posix/build/ebus-posix-device --host <broker> --device-id posix-demo
ports/posix/build/ebus-posix-controller --host <broker>
ports/posix/build/ebus-posix-controller --host <broker> --set posix-demo/switch/on=true --duration-s 5

Both take --host, --port (1883), --user, --password (or EBUS_MQTT_PASSWORD, which stays out of ps), --domain (ebus), --reconnect-ms (2000) and --quiet. The device adds --device-id and --period-ms (temperature update period); the controller adds --set DEVICE/NODE/PROPERTY=VALUE and --duration-s. Both take --link SOURCES=>TARGET, repeatable, each followed by optional --link-format, --link-decimals and --link-interval-ms: a property link in the device or in the controller (doc/link.md). Plain TCP only: Paho is built without TLS.

The device publishes <domain>/5/<id> with switch/on (boolean, settable) and sensor/temperature (float, a simulated reading), and a child device <id>-child with status/uptime, which a worker thread publishes through queue_publish(). Ctrl-C sets $state to disconnected and disconnects cleanly; a kill leaves the broker to publish the will, lost. The controller prints one line per change on stdout (state, device, property, set) and the core's log on stderr.

How the port meets the core's contract

Piece Here
Inbound messages Paho's receive thread copies each message into a mutex-guarded arena (EBUS_POSIX_INBOX_BYTES, 64 KB) and returns. PahoTransport::loop(), on the application's thread, hands each one to settable_dispatch() if the settable table claims the topic, else to the fallback (controller_mqtt_callback() for a controller). Nothing that publishes or subscribes runs on Paho's thread.
queue_publish() PahoTransport overrides the generic overload (ebus_mqtt's MqttTransport); a Property reaches it through HomieTransport's adapter. Any thread: copies into a fixed ring (EBUS_POSIX_PUBLISH_QUEUE, 64 entries of Property::VALUE_MAX), which loop() sends. The completion callback is called exactly once per call, from loop(), or at once when the ring is full or the message too long.
Connect Clean session, keepalive 60 s, Last Will <root>/$state = lost, retained, at homie_qos(true). After each connect, mqtt_after_connect() runs, in order: flush the hold, subscribe every settable topic, call the application's on_connected(first). The device publishes the tree on the first; on later ones it calls forgetDescriptionHash() on every device and publishes the tree again, so a broker that lost its retained store gets every $description and value back (doc/core.md).
Link down publish() holds or drops (below) and returns false; loop() reconnects at once, then every --reconnect-ms.
Settable table EBUS_POSIX_SETTABLE_CAPACITY (64) static entries. No NodeEntity on this port, so no driver call is bound; a settable reaches the application through a settable_handler_t, registered with ebus_posix_register_settable(), which also works before the first connect.

While the link is down

publish() passes each message to ebus_mqtt's PublishHold, which applies the rules of ebus-mqtt-client (doc/mqtt.md), and logs what it evicts or drops as too large. The hold is flushed on connect before the subscriptions and before on_connected; a flush the link interrupts keeps what it did not send. disconnect() discards the hold.

Known gaps

  • No TLS.