fix: use the extended protocol for unknown models that answer 0xEA 0x81 - #555
fix: use the extended protocol for unknown models that answer 0xEA 0x81#555dccote wants to merge 1 commit into
Conversation
Protocol probing passes the probe protocol in as the fallback for model
numbers missing from models_db. When a device answers the state query with
the extended 0xEA 0x81 frame, that fallback is ProtocolLEDENET8Byte, which
reports extended responses as valid via is_valid_extended_state_response but
never overrides extended_state_to_state. The abstract stub returns None, so
named_raw_state unpacks None and data_received dies with:
TypeError: LEDENETRawState() argument after * must be an iterable,
not NoneType
Home Assistant surfaces this as "Cannot determine protocol" on repeat.
Select PROTOCOL_LEDENET_EXTENDED_CUSTOM as the fallback when the frame that
identified the device was an extended one, so an unknown model is driven by a
protocol that can parse what it actually sent. Known models are unaffected:
the fallback is only consulted when get_model finds no entry.
Verified against a Surplife AK001-ZJ21413 reporting model_num 0x77, which
never sends the 14-byte response. With this change and no models_db entry it
sets up as LEDENET_EXTENDED_CUSTOM, and power, RGB and brightness all work.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
|
Correcting something I offered in the original description, before anyone spends review time on it. I had said I would happily follow up with a dedicated Cloning the
I think that strengthens the case for the change as it stands. The No code change in this update, description only. CI was green on the current commit. |
Problem
Protocol probing passes the probe protocol in as the
fallback_protocolfor model numbers missing frommodels_db. When a device answers the state query with the extended0xEA 0x81frame, that fallback isProtocolLEDENET8Byte, which reports extended responses as valid viais_valid_extended_state_response()but never overridesextended_state_to_state(). The abstract stub inProtocolBasereturnsNone, sonamed_raw_state()unpacksNoneand the receive callback dies:Home Assistant surfaces this as a setup loop:
Fix
Select
PROTOCOL_LEDENET_EXTENDED_CUSTOMas the fallback when the frame that identified the device was an extended one, so an unknown model is driven by a protocol that can parse what it actually sent.Known models are unaffected:
fallback_protocolis only consulted whenget_model()finds nomodels_dbentry.This is deliberately not a per-model
models_dbaddition.AK001-ZJ21413hardware is already showing up under at least three different model numbers:0xB6(supported since #538/#539),0x82(reported in #547, still unsupported) and0x77(mine). Adding entries one at a time leaves the next variant with the same crash, whereas any device that only speaks the extended format now degrades to a working generic device instead of failing setup.Verification
Hardware. A Surplife
AK001-ZJ21413reportingmodel_num 0x77, firmware77_24_20240423_ZG-BK. It never sends the 14-byte state response, only:With this change and no
models_dbentry:Power, RGB and brightness all verified end to end, each set confirmed by reading the state back, and the original preset pattern restored afterwards.
Tests. Added
test_setup_unknown_model_that_only_speaks_extended_state, built from the real frame above. It fails onmasterwith exactly theTypeErrorshown, and passes with the fix. Full suite goes from 151 to 152 passing.ruff check,ruff formatandmypyare clean.Note on #547
This does not give #547 its white channel back, since that device reports
LEDENET_8BYTEwith a standard state response and needs a proper WRGBmodels_dbentry. I mention it only because it is the sameAK001-ZJ21413hardware string under yet another model number, which is what motivated fixing the generic path rather than adding0x77to the table.Why not a dedicated
models_dbentry for0x77I measured that option too, by cloning the
0xB6entry onto0x77. It does advertise more:{'RGB', 'DIM'}and 22 effects, against{'RGB'}and 21 for the generic fallback. But the extra white channel is not real on this unit. Drivingw=255flipscolor_modetoDIMwhile the white bytes of the extended frame stay flat and the fixture goes dark:raw[14](white temperature) andraw[15](white brightness) never move. So a0xB6-shaped entry would advertise a capability this hardware does not have, and hand users a white mode that silently blanks the light. The generic RGB fallback that this PR produces is the more accurate description of the device.That is a further argument for fixing the generic path rather than growing the table: the variants of this product differ in what they can actually do, so a copied entry is as likely to overstate a device as to help it.