Issue 4: an SMTP add-on for e-mail notifications.
- SmtpSetup modal: server (host/port/encryption/user/pass), from/to, and
individual toggles for the events you want mailed — device offline, low
battery, automation messages. "Send test e-mail" button. Config stored
encrypted on the addon row; a runtime mailer is built from it (no .env edits).
- NotificationService: notify(event, …) sends only if SMTP is set up AND that
event is enabled; send() for the test.
- Triggers: automation "notify" actions e-mail (when enabled);
notifications:sweep (every 5 min) e-mails on NEW device-offline / low-battery
with per-condition dedup + battery hysteresis, so it's one mail per event.
6 tests (gating, per-event toggle, config persist + password-keep, sweep dedup).
Suite 82 green, 12/12 tabs clean; card + modal browser-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Issue 2: Ring sat on "verbinde…" forever because nothing ever connected — the
ring-mqtt bridge (opt-in container) wasn't running, and HomeOS was collecting
Ring credentials it never used. Per the handoff the BRIDGE owns the Ring login
(email/pw/2FA) in its own web UI; HomeOS must not handle Ring credentials.
- Replaced the credential modal with a RingSetup guide: start the bridge
(`docker compose --profile addons up -d ring-mqtt`), open its web UI (linked
at the auto-detected host:port), log in there; devices then appear.
- Status is now honest — it reflects the bridge's REAL MQTT presence
(IngestRingMessage.markStatus), showing "Nicht verbunden" with next-steps
until the bridge actually reports, instead of a stuck "connecting".
- Removed the RingConnect cred modal + fields; reset any stuck status.
Suite green, 12/12 tabs clean; setup modal browser-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First half of the Ring integration (handoff §12: ring-mqtt, cloud token auth):
- Addons registry (static catalogue) + Addon model with encrypted config, so
the Ring refresh token / credentials are never stored in plaintext.
- AddonService: install / uninstall (wipes secrets) / saveConnection (blank
password keeps the stored one) / markStatus (from the bridge over MQTT).
- Addons page (new sidebar tab) with per-addon install, Cloud badge, live
status pill, and a Ring connect modal capturing email/password/2FA — we
never call Ring ourselves; creds are handed to the ring-mqtt sidecar.
- Uninstall behind a wire-elements confirm (R5). Fixed the confirm target:
Livewire names App\Livewire\Addons\Index as "addons" (Index suffix dropped),
and only $wire.$dispatch (not Alpine $dispatch) reaches the modal listener.
- DE/EN localization (R16); doorbell/package/cloud icons.
7 AddonTest cases (registry, install, encryption-at-rest, blank-password
keep, uninstall wipe, status guard). Suite 33 green; 12/12 tabs clean; full
install→connect→connecting→uninstall UI flow browser-verified, 0 console errors.
Backend bridge (ring-mqtt container) + Ring MQTT normalizer land next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>