docs: session handoff — Google Home print button (complete)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mortdecai
2026-06-11 04:52:17 -04:00
parent 93f6c33cd3
commit 1dfe8dadc2
@@ -0,0 +1,219 @@
# 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/<local_webhook_id> -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 ~12 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.