# Handoff: POS Briefing — Google Home on-demand print button (COMPLETE) ## Session Metadata - Created: 2026-06-11 04:50:21 - Project: /home/claude/bin/POS-Automation - Branch: master - Session duration: long (multi-day: 2026-06-07 build + deploy, 2026-06-10/11 verify/simplify) ### Recent Commits (for context) - 93f6c33 feat: simplify Google switch to on-only (state push restored) - 6607367 docs: Google Home button confirmed working (switch tile); SA key regenerated - 5c8f2d7 chore: gitignore service-account key files - b540d5e docs: expose POS briefing as a switch tile (scenes don't tile in Google Home) - 2691dc4 docs: record HA deployment details + access method in DECISIONS ## Handoff Chain - **Continues from**: None (fresh start) - **Supersedes**: None ## Current State Summary **DONE and verified end-to-end.** The POS daily briefing now prints **on demand from a Google Home button** (no cron). Tapping **"Print Daily Briefing"** in the Google Home app (account `slingshooter08`) → HA `switch.print_daily_briefing` → `button.press` → MQTT → `pos-briefing-mqtt.service` on steel141 → `pos_briefing.py` → printer (resolved by MAC) → Epson TM-m30. Confirmed live: a real Google tap produced a printed receipt. State push to Google is working (HomeGraph SA key was regenerated). Nothing is in-progress; remaining items are optional polish (see Deferred). The original report was "the automation is not firing" — root causes were (1) no cron was ever installed (a prior commit only edited SESSION.md), and (2) `yfinance` was missing on steel141 post-migration. Seth then redirected the whole approach to a Google Home button, which is what got built. ## Codebase Understanding ## Architecture Overview Mirrors the **lgtv** project pattern (steel141 systemd MQTT bridge + HA MQTT discovery + the free manual `google_assistant` integration). ``` Google Home tap → google_assistant integration (VM HA 192.168.0.146, acct slingshooter08) → HA switch.print_daily_briefing (template switch, always-off, on-tap only) → button.press on button.pos_briefing_print_daily_briefing (MQTT-discovery button) → MQTT posbriefing/button/press on broker CT 301 (192.168.0.154) → pos-briefing-mqtt.service on steel141 (systemd, User=claude) → subprocess: /usr/bin/python3 pos_briefing.py → discover_printer() resolves IP by MAC 50:57:9c:eb:0f:07 → ESC/POS over TCP :9100 → status/availability published back to MQTT ``` ## Critical Files | File | Purpose | Relevance | |------|---------|-----------| | `pos_briefing.py` | Main script: fetch FreshRSS, select+summarize, dashboard, build+print receipt | Has `discover_printer()` (MAC-based), gemma4 summary + fast-model selection | | `pos_briefing_mqtt.py` | MQTT bridge → `/usr/local/bin/pos_briefing_mqtt.py` (deployed) | systemd `pos-briefing-mqtt.service`, User=claude | | `pos-briefing-mqtt.service` | systemd unit (repo copy) | EnvironmentFile=/etc/pos-briefing/pos-briefing.env | | `install.sh` | Deploys bridge+unit+env, enable | Re-run to redeploy bridge changes | | `scripts/dryrun.py` | Full pipeline, print suppressed | Use to test without printing/marking-read | | `tests/test_printer_discovery.py` | 5 unit tests for discovery | `python3 -m pytest tests/test_printer_discovery.py` | | `tests/pytest.ini` | Pins pytest rootdir to tests/ | Works around dead /root/bin symlinks that crash collection | | `docs/ha-setup.md` | The HA/Google deployment (as-built) | Read first for the Google side | | `DECISIONS.md` | All decisions w/ rationale | Read first for the why | | `config.json` (gitignored) | Live config incl. real creds | Has printer_mac, ollama_model, ollama_select_model | ### Key Patterns Discovered - **paho-mqtt 2.1.0** is installed for `claude`; bridge pins `CallbackAPIVersion.VERSION1` (matches lgtv; one harmless deprecation warning at startup). - **HA scripts/scenes expose to Google as the Scene trait, which Google Home does NOT render as a tappable tile** (voice/Routine only). A **switch** tiles. This was the key fix — the briefing is exposed as a template switch, not a script/scene. - HA on VM `192.168.0.146` (HAOS 2026.2.3): access via `ssh seth@192.168.0.146` (key auth), `bash -lc "ha core check|restart|logs"`, and call core services via the supervisor token: `curl -H "Authorization: Bearer $SUPERVISOR_TOKEN" http://supervisor/core/api/...`. `/config` is root-owned (write via `sudo tee`); back up to `/config/.backup/` first. - The manual google_assistant integration has a **local fulfillment webhook** that answers SYNC/EXECUTE without Google auth — great for diagnosing what HA reports to Google: `curl -X POST http://127.0.0.1:8123/api/webhook/ -d '{"inputs":[{"intent":"action.devices.SYNC"}],"requestId":"x"}'` (webhook id is in `/config/.storage/google_assistant`). ## Work Completed ### Tasks Finished - [x] Diagnosed "not firing" (no cron + missing yfinance); installed yfinance on steel141. - [x] Verified pipeline runs on steel141 (scripts/dryrun.py). - [x] Committed the in-tree hourly-weather rewrite. - [x] Summaries → gemma4:26b (prompt converged via ask_gemma4 MCP); selection stays on qwen2.5:1.5b (gemma4 broke Phase-1 JSON under format:json). - [x] Printer discovery by MAC (cache + /24 sweep); 5 unit tests; wired into print_receipt. - [x] MQTT bridge + systemd unit + env template + installer; broker user `posbriefing` on CT 301. - [x] Deployed HA side on VM HA: switch + google_assistant exposure; verified via local SYNC. - [x] Regenerated the HomeGraph SA key (old one was invalid); state push now works. - [x] Simplified switch to on-only (turn_off no-op) after state push confirmed. - [x] Confirmed end-to-end: real Google Home tap printed a receipt. ## Files Modified | File | Changes | Rationale | |------|---------|-----------| | `pos_briefing.py` | discovery, gemma4 summaries, fast-model selection, hourly weather | core feature work | | `pos_briefing_mqtt.py` (new) | MQTT bridge | the trigger | | `pos-briefing-mqtt.service`, `install.sh`, `pos-briefing.env.example` (new) | deploy | systemd install | | `tests/test_printer_discovery.py`, `tests/pytest.ini` (new) | tests | discovery coverage | | `config.json`/`config.example.json` | printer_mac, printer_subnet, ollama_select_model, gemma4 model | config | | `docs/ha-setup.md`, `DECISIONS.md`, `CONTEXT.md` (new/edited) | docs | record the build | | VM HA `/config/configuration.yaml` | added template switch + google_assistant exposure | HA side | | VM HA `/config/scripts.yaml` | print_daily_briefing script (alt trigger) | HA side | | VM HA `/config/SERVICE_ACCOUNT.json` | replaced with valid key | fix HomeGraph | ## Decisions Made See `DECISIONS.md` (2026-06-07 entries) for the full list with rationale. Highlights: SWITCH-tile exposure (scenes don't tile); MAC-based printer discovery (DHCP IP churn); gemma4:26b summaries + fast selection model; on-demand MQTT trigger (no cron). ## Pending Work ## Immediate Next Steps The feature is complete. No required next steps. Optional follow-ups only (see Deferred). ### Blockers/Open Questions - [ ] None. Working end-to-end. ### Deferred Items - **Print latency ~1–2 min** (gemma4:26b summarization + yfinance). The button returns immediately; `posbriefing/status` tracks `printing`→`ok`. Optimize later if it annoys (model keep-alive, fewer/shorter summaries, smaller model). - **Router DHCP reservation for the printer** (Seth's router action). MAC discovery makes it optional; a reservation would let us drop the /24 sweep fallback. - **Dashboard fields `zfs`/`reddit`/`grafana` return None on steel141** (it's not the tank host; `cannot open 'tank'`). Out of scope; the receipt prints everything else fine. - **SA key value passed through this session's transcript** when Seth shared the file. It's the live key; rotate once more out-of-band later if desired (then redeploy to HA). ## Context for Resuming Agent ## Important Context - **Don't reintroduce cron.** Trigger is on-demand via Google Home → MQTT only. - **Expose to Google as a SWITCH, never a script/scene** — scenes don't render as tappable tiles in Google Home. - **The printer IP is DHCP-mobile** — always resolve via `discover_printer()` (MAC `50:57:9c:eb:0f:07`); current IP was 192.168.0.184 but expect it to change. - **A manually admin-triggered `google_assistant.request_sync` logs a harmless 404** — it sends the unlinked owner-context id `2c22820…`; HA's automatic reporting uses the linked `f948247…` and succeeds. Do NOT chase that 404; it is not a real failure. - **gemma4 under `format:json` returns reasoning objects** (`{"thought": ...}`), which is why Phase-1 selection uses `qwen2.5:1.5b`, not gemma4. Don't point selection at gemma4. - **lgtv project is the reference** for the HA/Google/MQTT pattern; its `.claude/handoffs/` (2026-06-06) documents the google_assistant linking invariants — do not "re-fix" them. ## Assumptions Made - steel141 stays effectively always-on (hosts seth's desktop for weeks). - Broker CT 301 (192.168.0.154) and HA VM (192.168.0.146) stay put. - The TM-m30 keeps the same MAC (it will; only its DHCP IP moves). ## Potential Gotchas - `pytest` crashes on collection from the repo root unless `tests/pytest.ini` pins rootdir (dead `CREATE_PROJECT.md`/`GITEA_API.md` symlinks → inaccessible /root/bin → PermissionError). Run `python3 -m pytest tests/test_printer_discovery.py`. - The bridge runs `pos_briefing.py` from the **repo path** `/home/claude/bin/POS-Automation/`; editing that file takes effect immediately. The **bridge itself** is the copy at `/usr/local/bin/pos_briefing_mqtt.py` — re-run `./install.sh` (or `sudo install`) + restart after editing `pos_briefing_mqtt.py`. - google_assistant config reload needs a full `ha core restart` (no targeted reload). - Editing `/config/*` on HA requires `sudo tee` (root-owned); always back up to `/config/.backup/`. ## Environment State ### Tools/Services Used - `pos-briefing-mqtt.service` on steel141 (systemd, enabled+active, User=claude). - MQTT broker: Mosquitto CT 301 on pve241 (192.168.0.154); user `posbriefing`. - VM HA 2026.2.3 at 192.168.0.146 (HAOS); SSH add-on (user seth, key auth, sudo root). - steel141 Ollama (192.168.0.141:11434): gemma4:26b (summaries), qwen2.5:1.5b (selection). - Printer: Epson TM-m30, MAC 50:57:9c:eb:0f:07, port 9100 (DHCP IP, was .184). - GCP project `seth-freiberg` (HomeGraph; SA claude@seth-freiberg.iam, key id 8e3e812b6913…). ### Active Processes - `pos-briefing-mqtt.service` (steel141) — running. - HA `google_assistant` integration (VM HA) — loaded; state push working. ### Environment Variables - `MQTT_PASSWORD` via `/etc/pos-briefing/pos-briefing.env` (EnvironmentFile, 0600) — name only. - `HOMELAB_PASSWORD` — name only. - `$SUPERVISOR_TOKEN` (inside HA SSH add-on login shell) — used for HA core API calls. ### Quick health check ```bash sudo systemctl is-active pos-briefing-mqtt.service sudo bash -c 'set -a; . /etc/pos-briefing/pos-briefing.env; set +a; mosquitto_sub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASSWORD" -t posbriefing/status -C 1' python3 -c "import pos_briefing as pb; print(pb.discover_printer())" # current printer IP ``` ## Related Resources - `docs/ha-setup.md` — HA/Google deployment (as-built, read first for the Google side). - `docs/superpowers/specs/2026-06-07-ha-google-home-trigger-design.md` — design. - `docs/superpowers/plans/2026-06-07-ha-google-home-trigger.md` — implementation plan. - `DECISIONS.md` — all decisions with rationale. - `../lgtv/` + its `.claude/handoffs/2026-06-06-*.md` — the reference pattern + Google linking invariants. - Repo: `git.sethpc.xyz/Seth/POS-Automation`. --- **Security Reminder**: No secret values included — credentials referenced by location/name only.