Found while assessing IKEA's new Matter-over-Thread range for support. Verified against the real handler registry, not yet against hardware (no ALPSTUGA in hand).
What happens
The IKEA ALPSTUGA air-quality sensor exposes, on one endpoint: AirQuality (0x005B), CO₂ (0x040D), PM2.5 (0x042A), Temperature (0x0402), Humidity (0x0405), OnOff (0x0006), plus node-scoped PowerSource. The OnOff cluster does not switch power — it toggles the sensor's front display (a "dead front" control).
Running an ALPSTUGA-shaped node through HandlerRegistry.handlers_for_endpoint yields:
['matterAirQualitySensor', 'matterCO2Sensor', 'matterHumiditySensor',
'matterPM25Sensor', 'matterRelay', 'matterTemperatureSensor']
The five sensor devices are correct and wanted. The matterRelay is the wrinkle — OnOffHandler.is_primary_for returns True because none of the lighting/ENDPOINT_OWNER_CLUSTERS are present, so a generic relay is created for the display toggle. It's not broken (the relay genuinely toggles the display), but it's an unexpected, generically-labelled extra device. Home Assistant has the same confusion — it mis-classifies ALPSTUGA as an Outlet (HA core #158943).
This is a cousin of #58 (the duplicate-device class): an OnOff that is a secondary control of a sensor, not the endpoint's primary purpose.
Why it's not auto-fixed (and the decision to make)
Suppressing OnOff "whenever sensors are present" would be wrong — legitimate sensor+switch combos could exist. The Matter-correct signals to distinguish a display toggle from a real switch are:
- OnOff
FeatureMap (attr 0xFFFC) bit 2 = DeadFrontBehavior (DF). ALPSTUGA's display OnOff is expected to set this; a real plug/switch does not. This is the clean, spec-defined tell (and the one the HA issue points to).
- The endpoint's DeviceTypeList (Descriptor 0x001D) — an Air Quality Sensor device type (0x002C) means OnOff is auxiliary; an On/Off Plug-in Unit (0x010A) means it's primary.
Either requires data the pipeline doesn't currently consult (FeatureMap isn't parsed; device-type-driven dispatch is a larger change than cluster-driven). Deliberately not implemented blind — there's no ALPSTUGA on hand to verify the DF flag against, and a wrong suppression rule could break real combos.
Captured for now
tests/test_device_zoo.py gains an alpstuga entry that characterises current behaviour (expects the matterRelay), so the wrinkle is pinned and any future change is deliberate. When this is fixed (likely: OnOffHandler.is_primary_for returns False when the OnOff FeatureMap advertises DeadFront), the fix updates that expected-types list in the same change.
Refs
- HA core #158943 — ALPSTUGA mis-classified as Outlet (DeadFrontBehavior is the tell)
Found while assessing IKEA's new Matter-over-Thread range for support. Verified against the real handler registry, not yet against hardware (no ALPSTUGA in hand).
What happens
The IKEA ALPSTUGA air-quality sensor exposes, on one endpoint: AirQuality (0x005B), CO₂ (0x040D), PM2.5 (0x042A), Temperature (0x0402), Humidity (0x0405), OnOff (0x0006), plus node-scoped PowerSource. The OnOff cluster does not switch power — it toggles the sensor's front display (a "dead front" control).
Running an ALPSTUGA-shaped node through
HandlerRegistry.handlers_for_endpointyields:The five sensor devices are correct and wanted. The
matterRelayis the wrinkle —OnOffHandler.is_primary_forreturns True because none of the lighting/ENDPOINT_OWNER_CLUSTERSare present, so a generic relay is created for the display toggle. It's not broken (the relay genuinely toggles the display), but it's an unexpected, generically-labelled extra device. Home Assistant has the same confusion — it mis-classifies ALPSTUGA as an Outlet (HA core #158943).This is a cousin of #58 (the duplicate-device class): an OnOff that is a secondary control of a sensor, not the endpoint's primary purpose.
Why it's not auto-fixed (and the decision to make)
Suppressing OnOff "whenever sensors are present" would be wrong — legitimate sensor+switch combos could exist. The Matter-correct signals to distinguish a display toggle from a real switch are:
FeatureMap(attr 0xFFFC) bit 2 = DeadFrontBehavior (DF). ALPSTUGA's display OnOff is expected to set this; a real plug/switch does not. This is the clean, spec-defined tell (and the one the HA issue points to).Either requires data the pipeline doesn't currently consult (FeatureMap isn't parsed; device-type-driven dispatch is a larger change than cluster-driven). Deliberately not implemented blind — there's no ALPSTUGA on hand to verify the DF flag against, and a wrong suppression rule could break real combos.
Captured for now
tests/test_device_zoo.pygains analpstugaentry that characterises current behaviour (expects thematterRelay), so the wrinkle is pinned and any future change is deliberate. When this is fixed (likely:OnOffHandler.is_primary_forreturns False when the OnOff FeatureMap advertises DeadFront), the fix updates that expected-types list in the same change.Refs