Skip to content

Add mqttstats: headless Commodity for Home Assistant telemetry - #22

Merged
sidick merged 5 commits into
mainfrom
feat/mqttstats-ha-telemetry
Aug 31, 2026
Merged

Add mqttstats: headless Commodity for Home Assistant telemetry#22
sidick merged 5 commits into
mainfrom
feat/mqttstats-ha-telemetry

Conversation

@sidick

@sidick sidick commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • New mqttstats tool (src/amiga/mqttstats_main.c): a headless AmigaOS Commodity publishing Amiga telemetry (uptime, chip/fast RAM free, CPU model) to Home Assistant via MQTT Discovery, entirely configured through Workbench ToolTypes (amiga.lib's ArgArrayInit) and safe to drop into WBStartup: - no window ever, Commodities Exchange (Enable/Disable/Kill) is its only control surface.
  • New portable src/tools/ha_discovery.[ch] module: builds HA MQTT Discovery topics/payloads, host-unit-tested (tests/test_ha_discovery.c).
  • This is the telemetry piece of I2C/hardware sensor support (scope addition beyond the MQTT proposal) #6, scoped ahead of I2C sensor support per the issue discussion; I2C remains a follow-up.
  • userdocs/mqttstats.md added (ToolTypes reference, Home Assistant setup, WBStartup instructions), wired into mkdocs.yml nav and tools/docs2guide.py for midge.guide.
  • docs/ARCHITECTURE.md updated with the new file, Makefile's dist target now ships mqttstats in the release archive.

Test plan

  • make test - 276 passed, 0 failed (26 new checks for ha_discovery)
  • make lint - clean
  • make m68k-docker - all 6 binaries (including mqttstats) build warning-free
  • make guide + mkdocs build --strict - docs build clean
  • On-target (Copperline, real AmigaOS 3.2.2 boot): verified full happy path (HOST configured) publishes discovery/availability/state topics correctly via mosquitto_sub, and verified the missing-HOST error path returns cleanly with no window and no Shell/Startup-Sequence hang

🤖 Generated with Claude Code

https://claude.ai/code/session_01QWq1CRLCQy9AaD9UtLRSM9

A standalone AmigaOS Commodity publishing Amiga system telemetry
(uptime, chip/fast RAM free, CPU model) to a Home Assistant broker via
mqtt.library, with full MQTT Discovery so sensors appear automatically.
Configured entirely through Workbench ToolTypes (via amiga.lib's
ArgArrayInit), runnable silently from WBStartup, with Commodities
Exchange as its only control surface (Enable/Disable/Kill) - the
telemetry piece of issue #6, scoped ahead of I2C sensor support which
remains a follow-up.

Adds the portable src/tools/ha_discovery.[ch] module (HA MQTT Discovery
topic/payload builder, host-unit-tested) shared with mqttstats, and
userdocs/mqttstats.md covering ToolTypes and Home Assistant setup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWq1CRLCQy9AaD9UtLRSM9
Without a .info icon, mqttstats couldn't actually be double-clicked or
dropped into WBStartup: - a direct requirement from the issue this
tool was built for. tools/mkicons.py (ported from AmiAuth's generator)
produces a classic 4-colour, 2-bitplane DiskObject icon with a few
common Tool Types pre-listed as edit-in-place comments (HOST,
CLIENTID, INTERVAL, CX_PRIORITY).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWq1CRLCQy9AaD9UtLRSM9
@sidick

sidick commented Aug 30, 2026

Copy link
Copy Markdown
Owner Author

Added a Workbench icon (`icons/mqttstats.info`, via a new `tools/mkicons.py` ported from AmiAuth's generator) - without one, `mqttstats` couldn't actually be double-clicked or dropped into `WBStartup:`, which was a direct requirement. Ships alongside the binary in `make dist`; `userdocs/mqttstats.md` and `Installation.md` updated accordingly.

… version sensors

- Icon now lists every ToolType (not just four), all disabled/commented -
  matches every read_config() key so nothing is hidden from the icon.
- Initial MQTT_Connect() failures now retry with capped exponential
  backoff (mco_AutoReconnect only covers post-connect drops, not a failed
  first attempt) - lets mqttstats launch from WBStartup ahead of the
  TCP/IP stack's own startup entry without just quitting once.
- Added MQTT_CONNECT_REFUSED (-102) as a proper public constant in
  mqtt.library's <libraries/mqtt.h> (mqtt.doc updated, api-reference
  regenerated). mqttstats checks for it specifically: unlike a transient
  connect failure, a CONNACK refusal (bad credentials, rejected client
  id, ...) means retrying won't help, so it opens intuition.library
  itself and shows a one-off EasyRequest before quitting - mqtt.library
  itself stays UI-free, this is purely the caller's own choice.
- Added Kickstart version and Workbench version telemetry sensors
  (exec.library's and workbench.library's own lib_Version/lib_Revision).
  Formatting them hit a confirmed m68k-amigaos-gcc -O2 miscompile
  (garbage upper bits when a UWORD struct field reaches sprintf's "%u"
  varargs); worked around with a dedicated noinline manual formatter -
  see format_bcd_version()'s own comment for the full story.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWq1CRLCQy9AaD9UtLRSM9
@sidick

sidick commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

Follow-up round addressing feedback:

  • Icon: now lists every ToolType from `read_config()` (not just four), all disabled/commented by default.
  • Auth/config failures no longer silent: initial `MQTT_Connect()` failures now retry with capped exponential backoff (1s→32s) rather than quitting once - `mco_AutoReconnect` only covers a drop after a successful connect, not a failed first attempt, which matters for a WBStartup daemon racing the TCP/IP stack's own startup. A CONNACK refusal specifically (bad credentials, rejected client id, ...) is different - retrying won't fix it, so `mqttstats` pops a one-off `EasyRequest` (via `intuition.library`, opened only for this) before quitting. `mqtt.library` itself stays completely UI-free - it just returns a new public constant, `MQTT_CONNECT_REFUSED` (-102), added to `<libraries/mqtt.h>` (`mqtt.doc`/api-reference updated too); deciding what to do with it is entirely up to the caller.
  • Two new sensors: Kickstart version and Workbench version (they can genuinely differ).

Also found and worked around a real m68k-amigaos-gcc `-O2` miscompile hit while adding those two sensors (garbage upper bits when a `UWORD` struct field reaches `sprintf`'s `%u` varargs) - tracked separately in #23 since it could affect other code built at `-O2`, not just this file.

All verified on-target under Copperline: retry/backoff timing, discovery+state publish for all 8 sensors now including the two new ones, and the corrected version values (confirmed against the test image's actual Kickstart ROM).

TR_GETSYSTIME doesn't measure time since reset - it returns the same
absolute, calendar-rooted system clock DateStamp() is built on (seconds
since 1978-01-01, set from the battery-backed RTC at boot), just with
sub-second precision. Reported as "uptime" it produced a nonsensical
~48-year value on any machine with a working clock - caught in real use.

Switched to ReadEClock()'s free-running hardware tick counter, which
genuinely resets to 0 at power-on and has no notion of calendar date at
all, while remaining exactly as immune to the DateStamp() clock-jump
hazard issue #8 documents.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWq1CRLCQy9AaD9UtLRSM9
@sidick

sidick commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

Fixed a real bug found by @sidick after checking a live sensor: uptime was reporting ~1,535,701,114s (~48.7 years).

Root cause: `TR_GETSYSTIME` doesn't measure time since reset - it returns the same absolute, calendar-rooted system clock `DateStamp()` is built on (seconds since 1978-01-01, set from the battery-backed RTC at boot), just with sub-second precision. It was picked specifically because it's immune to issue #8's clock-jump hazard, but that reasoning was based on a wrong assumption about what it actually measures.

Switched to `ReadEClock()`'s free-running hardware tick counter instead - genuinely resets to 0 at power-on, no notion of calendar date at all, and is exactly as immune to the clock-jump hazard the original code was trying to avoid. Verified on-target: uptime now reports a sane small value matching actual elapsed time.

… it mid-word

Exchange's list truncates nb_Descr on OS 3.1 well before the end,
cutting "...to Home Assistant via MQTT" down to "...to Home Ass".
Reordered so "Home Assistant" lands safely inside the observed
~37-character cutoff instead of running off the end of the string.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWq1CRLCQy9AaD9UtLRSM9
@sidick

sidick commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

Fixed the Exchange description truncation: reordered "Publishes Amiga telemetry to Home Assistant via MQTT" -> "Amiga telemetry to Home Assistant via MQTT" so "Home Assistant" lands safely inside the ~37-character cutoff Exchange applies on 3.1, instead of running right off the end into "...to Home Ass".

@sidick
sidick merged commit b1f9ac9 into main Aug 31, 2026
11 checks passed
@sidick
sidick deleted the feat/mqttstats-ha-telemetry branch August 31, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant