cb7ad8b0ff
Replaces the never-installed cron approach with an MQTT bridge mirroring the lgtv pattern: Google Home button -> HA script/scene -> MQTT -> steel141 prints. Adds MAC-based printer discovery (printer IP is DHCP-unstable) and a gemma4 summarizer swap. Includes scripts/dryrun.py (non-printing pipeline harness). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.8 KiB
6.8 KiB
POS Briefing — Home Assistant / Google Home Trigger (Design)
Date: 2026-06-07 Status: Proposed — awaiting Seth's review
Goal
Replace the (never-installed) cron schedule with an on-demand trigger: tap a button in Google Home → the daily briefing prints on the Epson TM-m30. No cron.
Background / findings (this session)
- "Not firing" had two causes, both now moot under this design: (1) no cron entry
was ever installed on steel141 — the "schedule 4:58am/3pm" commit only edited
SESSION.md; (2)
yfinancewas missing from steel141's system python3 → installed (pip --user --break-system-packages, matching lgtv's PEP-668 approach). - The pipeline itself works end-to-end on steel141 (verified via non-printing
dry run,
scripts/dryrun.py): FreshRSS 100 items, weather (the uncommitted hourly rewrite), finance (yfinance), and summarization all produce a ~2.4 KB ESC/POS receipt.zfs/reddit/grafanareturnNoneon steel141 (non-fatal; out of scope here — see Out of Scope). - Printer changes IP on every restart (router DHCP, no reservation). Currently
192.168.0.184:9100, MAC50:57:9c:eb:0f:07(Epson). Always on.
Architecture
Mirrors the proven lgtv chain (steel141 systemd MQTT bridge + HA MQTT discovery +
free manual google_assistant integration).
[Google Home tap]
→ google_assistant integration (already wired; acct slingshooter08; exposes LG TV switch today)
→ HA script "Print Daily Briefing" (exposed to Google as a Scene → momentary button)
→ MQTT publish to broker CT 301 (192.168.0.154:1883)
→ pos-briefing-mqtt.service on steel141 (systemd, User=claude)
→ pos_briefing.py → printer discovery (by MAC) → ESC/POS over TCP :9100
→ status/availability published back to MQTT (HA shows success/fail)
Components
1. MQTT bridge — pos_briefing_mqtt.py + pos-briefing-mqtt.service (new, steel141)
- systemd
Type=simple,User=claude,EnvironmentFile=/etc/pos-briefing/pos-briefing.env(holdsMQTT_PASSWORD, root-owned 0600, never committed).Restart=on-failure. - Connects to broker
192.168.0.154:1883, userposbriefing(or reuse an existing broker user — TBD at install; lgtv uses a per-device user). - On connect: publishes MQTT discovery for an HA button entity
(
homeassistant/button/pos_briefing/config) + availabilityonline; LWT →offline. - Subscribes command topic
posbriefing/button/press(payloadPRESS). - On press: runs the briefing as a subprocess
(
/usr/bin/python3 /home/claude/bin/POS-Automation/pos_briefing.py) so a slow/long print never blocks the MQTT loop and a script crash can't kill the bridge. Publishesposbriefing/status=printing→ok/error:<msg>. - Debounce: ignore a new press while one is already in flight (prevents double prints).
Topics:
| Topic | Dir | Payload |
|---|---|---|
homeassistant/button/pos_briefing/config |
pub (retain) | discovery JSON |
posbriefing/availability |
pub (retain) | online / offline (LWT) |
posbriefing/button/press |
sub | PRESS |
posbriefing/status |
pub (retain) | idle / printing / ok / error:<msg> |
2. Printer discovery (new, in pos_briefing.py) — kills the DHCP-IP problem
- Resolve current printer IP by MAC
50:57:9c:eb:0f:07instead of trusting a hardcodedprinter_ip. - Algorithm (lgtv "cached IP, sweep on miss"):
- Read cached IP from
~/.cache/pos-briefing/last_ip(seed = configprinter_ip). ping -c1it, checkip neighlladdr == target MAC, and:9100open → use it.- On miss: ARP-prime sweep the /24 (
ping -c1 -W1fan-out), then scanip neighfor the MAC → its IP. Re-cache. - Still not found → raise a clear error (bridge reports
error:printer-not-found).
- Read cached IP from
- Config gains
printer_mac;printer_ipbecomes a seed/fallback only. - Belt-and-suspenders (Seth's action, router-side): add a DHCP reservation for the printer MAC so the IP stops moving. Discovery makes this optional for correctness.
3. HA script + Google Home exposure (Seth's HA side; I provide exact YAML/steps)
- MQTT discovery auto-creates
button.pos_briefing(no hand YAML for the entity). - Google's
google_assistantintegration doesn't support HAbuttonentities → wrap: an HAscript.print_daily_briefingthat presses the button. Scripts map to Google's Scene trait → appear as a tappable button in the Google Home app (momentary). - Add the script to the same
google_assistantexpose list that already exposes the TV switch; re-sync. (Per lgtv DECISIONS 2026-06-06: manual integration, scopes must include email+name, "HTTP basic auth header" OFF, Test activated by slingshooter08.)
4. gemma4 summarizer swap (in pos_briefing.py)
- Point summarization at a gemma4 model on steel141 Ollama (candidate
gemma4:26borgemma4:31b-it-q4_K_M) via the existing direct Ollama HTTP call — changeollama_modelin config + the prompt string. - Prompt convergence: done by Claude now, interactively, via the
ask_gemma4MCP tool against real FreshRSS article samples, iterating until summaries are tight (30–50 words, factual, no preamble). The finalized prompt string is then baked intopos_briefing.py(which calls Ollama directly — it cannot call the MCP at runtime).
5. Deps / install
yfinance— installed (done).paho-mqtt— present forclaude. Confirm both pinned/persisted.install.shmirrors lgtv: copies bridge to/usr/local/bin, unit to/etc/systemd/system, env to/etc/pos-briefing/,daemon-reload, enable.
Error handling
- Printer not found / unreachable →
error:printer-not-found; no partial print. - Briefing subprocess nonzero exit or timeout (cap ~180s) →
error:<rc>; bridge stays up. - MQTT disconnect → paho auto-reconnect; LWT marks
offlineso HA/Google show it down. - Data-source failures inside the briefing remain non-fatal (dashboard prints what it has).
Testing
scripts/dryrun.py— full pipeline, print suppressed (already used to verify).- Bridge unit: publish
PRESSto the command topic by hand (mosquitto_pub) → observestatustransitions and a real receipt; confirmbutton.pos_briefingappears in HA. - Discovery: unit-test MAC→IP resolution with cache hit, cache miss+sweep, and not-found.
- End-to-end: tap the button in Google Home → receipt prints.
Out of scope (noted, not fixed here)
zfs(steel141 isn't the tank host —cannot open 'tank'),reddit,grafanareturningNoneon steel141. Track separately.- Committing the in-tree weather rewrite is folded into this work (it's verified).
Open items for Seth
- Broker MQTT user for the bridge: new
posbriefinguser vs reuse existing? (install-time) - gemma4 model choice:
26bvs31b-it-q4_K_M(I'll recommend after convergence).