Meshtasticator's requirements.txt pins meshtastic~=2.6.1, which predates the
meshtastic/meshtasticd image it drives; with the old client the simulator
never observed node TX packets (both e2e directions timed out). The official
meshtastic firmware_harness uses the current client against the same
simulator-mode meshtasticd, so install the sim deps with meshtastic floating
instead of the pinned requirements file.
Both e2e directions time out: nothing is delivered between nodes although
the adapter connects fine and bridging code is equivalent to meshtastic's own
firmware_harness. Before concluding, instrument the pinned meshtasticator:
- on_receive now prints every observed packet (topic keys) to sim.log,
- a [sim-text] listener prints any text packet any sim interface sees,
- cleanup sends 'exit' through the cmdloop (graceful, no EOF-spam flood that
was drowning the log tail),
- workflow failure step prints 400 sim-log lines + the node logs dump.
First dispatch (run 10535) failed instantly with Permission denied on the
orchestrator: the file lost its executable bit in the branch move. Set mode
100755 and call through bash so a future mode regression cannot break the job.
Adds .gitea/workflows/meshtasticator-e2e.yaml (workflow_dispatch until
validated green, pull_request trigger commented out): builds the pinned
Hermes contract env like release.yaml, installs the plugin with deps,
checks out Meshtasticator at a pinned commit, installs the simulator's
own (conflicting-version) requirements in an isolated venv, then runs
scripts/meshtasticator_e2e/run_e2e.sh --mode docker.
Supporting changes:
- run_e2e.sh: SIM_VENV support; automatic localhost->daemon TCP forwards
(scripts/meshtasticator_e2e/tcp_forward.py) when DOCKER_HOST is a tcp://
daemon, because Meshtasticator hardcodes localhost for its node control
connections; node-boot settle wait; fixed docker cleanup (container
'Meshtastic', volume 'Meshtasticator').
- e2e tests: connect via a module-long event loop in a background thread
(adapter requires a running loop for watchdog + inbound dispatch, so
per-call asyncio.run was wrong) with retry while the node TCP API boots.
- README: sim-venv guidance, remote-daemon forwarding, CI section.
Docker access follows the deployment examples in
eric/actions-docker (docker is available to runner jobs).
curl drops the Authorization header when -L follows Gitea's 308 redirect from
http server_url to https, so the API replied 'token is required' and publish
failed with no release id. Add --location-trusted to every publish curl.
server_url resolves to http and Gitea answers the create-release POST with a
308 redirect; curl without -L returned an empty body and the grep-based id
extraction failed under set -e/pipefail, failing v0.1.3 publish. Add -L,
reuse an existing release on retry, and parse with python3.
- Resolve the Hermes gateway API lazily via get_adapter_class() so the adapter
always inherits the real gateway.platforms.base.BasePlatformAdapter instead
of the ImportError fallback stub (root cause of the AttributeError:
'set_message_handler' crash at gateway startup).
- Pass Platform('meshtastic') enum to super().__init__ and align
connect(*, is_reconnect=False) -> bool with the gateway contract.
- Split pure formatting utils into formatting.py; remove the stub fallback.
- Add tests/contract (L0-L3): real-base binding, ABC instantiation, gateway
run.py wiring replay, signature and event-shape conformance, run against
hermes-agent pinned to the deployed image source (v2026.8.31).
- Add scripts/contract-test.sh and a contract-test CI job; release publish
now requires contract tests to pass.
- Untrack stray __pycache__ artifacts.