Files
POS-Automation/.claude/handoffs/2026-06-11-045021-pos-google-home-button.md
T
Mortdecai 1dfe8dadc2 docs: session handoff — Google Home print button (complete)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 04:52:17 -04:00

220 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.