Issue 3: the New-Automation modal was taller than the screen and the whole
dialog scrolled. New <x-modal> component: header + footer are fixed (shrink-0),
only the body scrolls, capped to max-h-85dvh so the page never scrolls. Refactored
create-automation (now a responsive 2-column grid, widened to 3xl), add-device,
ring-connect and add-person onto it — the standard for every modal going forward.
Verified: modal fits a 720px viewport with no page scroll; create flow still works.
12/12 tabs clean, suite green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
You were right that HA uses the Shelly LOCAL API, not MQTT. Adds that path
(user chose "both") — control + status over http://<ip>/rpc, no MQTT setup on
the device:
- ShellyRpc (POST /rpc), ShellyHttpDriver (Switch/Light.Set, Reboot).
- ShellyStatusApplier: one shared apply path (normalize + input roles +
monotonic upsert + broadcast) reused by BOTH the MQTT ingest and the HTTP
poll, so transports can't drift. IngestShellyMessage refactored onto it.
- ShellyLocalOnboarder: probe an IP → GetDeviceInfo/GetStatus → create an
http-protocol device with its entities (reuses an MQTT-onboarded row by id,
no duplicate). AssignDevice uses it when a discovered Shelly is reachable;
falls back to MQTT-style if not.
- Manual "Gerät hinzufügen" modal (add by IP). shelly:poll scheduled every 10s
+ a re-poll after each command (PollShellyDevice) for near-live status.
driverFor picks http vs mqtt by protocol.
- Normalizer now drops housekeeping components (sys/wifi/cloud/mqtt/ws/…) so
GetStatus doesn't create junk entities.
6 ShellyHttpTest cases (Http::fake). Suite 68 green, 12/12 clean.
LIVE-VERIFIED against the real Shelly 1 Mini Gen3 at 10.10.30.78: onboarded
over local API (protocol http), entities switch:0 + input:0, kept online by the
10s poll — no MQTT configured on the device.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>