Google renders SCENE devices (HA scripts/scenes) as voice/Routine-only, not as
tappable tiles -> the button was invisible. Switched the Google exposure to a
template switch (tiles like the TV). Documents the broken HomeGraph SA key
(invalid_grant) that disables requestSync/reportState until regenerated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deployed script.print_daily_briefing (scripts.yaml) and exposed it in
google_assistant.entity_config on VM HA .146; ha core check passed, restarted,
request_sync OK. Verified end-to-end: HA script -> MQTT -> bridge -> printed.
Corrects the button entity id to button.pos_briefing_print_daily_briefing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Final-review hardening:
- discover_printer falls back to direct IP reachability when printer_mac is
empty (restores legacy behavior; avoids permanent unreachable on misconfig).
Keeps the MAC check when a MAC IS set so we never print to a wrong DHCP tenant.
- bridge subprocess decodes child stdout as utf-8 explicitly, so a LANG=C systemd
locale can't UnicodeDecodeError on the success checkmark and mis-report error.
- add tests for both no-MAC fallback paths (5 passed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Subscribes to posbriefing/button/press; on PRESS runs pos_briefing.py as a
subprocess (debounced via a lock) and reports status/availability. Registers an
HA button via MQTT discovery. Pins paho CallbackAPIVersion.VERSION1 (paho 2.1.0
is installed for claude and warns on the implicit default).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gemma4:26b under format:json ignores the bare-array instruction and returns a
reasoning object ({"thought": ...}), which broke Phase-1 selection (Unterminated
string -> silent fallback to first-5). Selection now uses ollama_select_model
(default qwen2.5:1.5b); summaries stay on gemma4:26b. Also tolerate dict-shaped
selection responses defensively.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
print_receipt now resolves the printer by MAC via discover_printer() instead of
a hardcoded IP. Verified end-to-end: physical receipt printed to 192.168.0.184.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The prior commit only recorded the conftest.py deletion; this adds the actual
fix: tests/pytest.ini (pins rootdir to tests/ so the standard pytest command
no longer crashes on the dead /root/bin symlink) and the PEP8 import move.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The root conftest.py did not prevent pytest's rootdir scandir from following
the dead CREATE_PROJECT.md symlink (-> inaccessible /root/bin), so the standard
'pytest tests/...' command crashed on collection. A minimal tests/pytest.ini
pins rootdir to tests/, so the repo root is never scanned. Also moves the
pathlib import to the top import block (PEP 8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add discover_printer(), _mac_of(), _port_open(), _sweep_arp(), _cache_ip()
with PRINTER_MAC/PRINTER_SUBNET/CACHE_FILE config + unit tests. Also adds
conftest.py to work around broken symlink that blocked pytest collection.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>