Codex R15 on the local transport:
- [P2] A light command set brightness/rgb but the normalizer stored only `on`,
so the poll dropped them and the UI/automations went stale. The light state
now carries brightness + rgb when the device reports them.
- [P2] ShellyLocalOnboarder matched an existing row by IP BEFORE the Shelly id,
so a DHCP-reassigned IP could let one Shelly overwrite an unrelated device.
Now matches by stable Shelly id first and reuses an IP row only when it's the
same (or an unidentified) device.
+3 tests (light attrs, housekeeping dropped, IP-reuse no hijack). Suite 71 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>