Add Shelly Power Strip (Gen4) support, independent on/off colors, and reliability fixes - #2
Open
radioactive-bbs wants to merge 8 commits into
Open
Add Shelly Power Strip (Gen4) support, independent on/off colors, and reliability fixes#2radioactive-bbs wants to merge 8 commits into
radioactive-bbs wants to merge 8 commits into
Conversation
- api.py: auto-detect the LED RPC component (PLUGS_UI vs POWERSTRIP_UI) so the same client works on single-outlet plugs and the 4-outlet Power Strip. - light.py: create one LED light entity per outlet, discovered from the switch:N keys in the device's LED color config, instead of a single hardcoded switch:0 entity. Single-outlet devices keep their original entity name/unique_id for backward compatibility. - config_flow.py: broaden the device picker filter to also include power strip models, not just plugs. - button.py: generalize the reset button label since it now resets LEDs across multiple outlets on a Power Strip. - Update translations (en/de) and README for multi-outlet wording, and note the firmware limitation that LED mode is shared across all outlets while color/brightness stays per-outlet. - Bump manifest version to 1.2.0.
On a real Shelly Power Strip Gen4, PLUGS_UI.GetConfig also answers (with only switch:0) alongside POWERSTRIP_UI.GetConfig (with all 4 channels). The previous 'first success wins' probe locked onto PLUGS_UI, so only a single LED Ring entity was created instead of one per outlet. Now all LED_UI_COMPONENTS are probed and the one whose config reports the most switch:N keys is kept and cached. Also: - manifest.json: point documentation/issue_tracker at this fork, credit original creator @ishiharas alongside @radioactive-bbs in codeowners. - README.md: GitHub badge linking to this fork, Credits section for the original creator.
Real Power Strip Gen4 firmware confirmed: each outlet's physical LED
independently tracks its own relay state (native switch mode), but the
config only exposes ONE on/off color pair per LED - and the previous
light entity wrote the same RGB to both 'on' and 'off' on every
turn_on, silently clobbering any asymmetric on/off color scheme (e.g.
red-when-on / green-when-off) the moment the entity was touched again.
light.py: split ShellyPlugLedRing by a new color_key ('on'/'off') so
each LED gets two entities, e.g. 'LED Ring' + 'LED Ring Off Color',
each writing only its own color slot. The 'on' entity keeps its
original name/unique_id for backward compatibility; only a new 'Off
Color' entity is added.
README: document the on/off split and that a Power Strip's outlets
currently share one color slot in firmware while still tracking their
own relay state independently - so per-outlet colors work without any
HA automation once set.
Bump manifest version to 1.3.0.
…olor Was just 'LED Ring' before, which read oddly next to 'LED Ring Off Color'. Display name only - unique_id/entity_id unchanged, so this doesn't create new entities or orphan existing ones.
…mode
Previously both entities' is_on read the same device-wide leds.mode, so
they always showed the same state and turning either off ('mode: off')
silently killed the other's color too - the toggle was effectively
meaningless as a per-entity control.
Now each entity's is_on is switch-mode-engaged AND its own slot's
brightness > 0. turn_on engages switch mode and writes its own
rgb/brightness (falling back to full brightness instead of a stale 0
when the slot was previously off). turn_off only dims its own slot to
0 brightness - it no longer touches leds.mode at all, so the sibling
entity is completely unaffected.
Updated README to describe the new independent on/off/off behavior.
… header sanitization, credential redaction - config_flow.py: stop picking entry_devices[0] blindly. The official Shelly integration can register multiple devices per config entry on multi-outlet devices (a root device + one child per output); resolve the root device explicitly by identifier shape instead of list position, and fall back to sibling devices for a model string when the root device doesn't carry one itself. Confirmed live this session that list-position selection could land on a modelless device and behave inconsistently. - light.py: fix a real race between the on-color/off-color sibling entities that share one coordinator. A refresh triggered by one entity's write no longer clears the other entity's still-in-flight optimistic state - each entity now tracks its own pending-write count and only clears its optimistic overrides once its own writes have settled. - button.py: reset button no longer swallows every exception silently. Failures are now logged and raised as HomeAssistantError so a failed reset is visible in the UI instead of looking like it succeeded. - api.py: sanitize realm/nonce/opaque values taken from the device's WWW-Authenticate challenge before interpolating them into our own outgoing Digest Authorization header (defense-in-depth against header-value injection from a malicious/compromised device or LAN MITM). Also simplified get_config()'s component probing back to first-success-wins now that real-world testing confirmed a device only ever answers one of PLUGS_UI/POWERSTRIP_UI successfully - the 'probe all, keep the one with more outlets' comparison never had more than one candidate in practice. - diagnostics.py (new): redact the integration's own stored username/password copy from Home Assistant's diagnostics download, matching how the official Shelly integration already redacts its copy. Bump manifest version to 1.5.0.
Swaps the old custom_components/shelly_plug_led/brand/banner.png for two real screenshots showing the On Color / Off Color toggles on the device's control card, and the Off Color picker set to green.
…am PR Only self-referential branding changes on top of main - all functional changes (Power Strip support, on/off color entities, audit fixes, diagnostics, screenshots) are carried over as-is.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thanks for this integration - it's been very useful. This PR adds Shelly Power Strip (Gen4) support on top of it, plus independent on/off color entities and a handful of reliability/security fixes found during a focused audit. Happy to adjust anything to fit your preferred style/scope - split into smaller PRs on request.
New features
PLUGS_UI(Plug S) orPOWERSTRIP_UI(Power Strip).LED Ring On ColorandLED Ring Off Color- matching the device's native switch-mode LED, which already shows a different color depending on the relay's own state. Set red-on/green-off once and the device handles it entirely in firmware, no automation needed, and it keeps working even while Home Assistant is offline.turn_onwrote the same RGB to both slots.diagnostics.py, new) - redacts the stored username/password on download.Fixes (from a focused audit)
config_flow.pyno longer picksentry_devices[0]blindly. Newer multi-outlet devices register a physical "root" device plus one child device per output, and picking by list position could land on the wrong one (reproduced against real Power Strip Gen4 hardware, where it selected a device with no model info). The root device is now resolved deterministically by identifier shape, with sibling devices checked for a model string as a fallback.realm/nonce/opaquevalues from the device'sWWW-Authenticatechallenge are now sanitized before being interpolated into the outgoing Authorization header (defense-in-depth against header-value injection from a compromised device or LAN MITM).PLUGS_UI/POWERSTRIP_UIsuccessfully (the other 404s outright), soget_config()uses first-success-wins instead of probing every component and comparing results.Also included
Testing
Manually tested against real hardware over the course of this work:
POWERSTRIP_UIpath, multi-device config-entry resolution, on/off color independence, digest-auth-disabled device)All commits and more detail are also visible on the fork this PR comes from: https://github.com/radioactive-bbs/shelly_plug_led