Skip to content

Run modes (music/custom shows, effect state), Fireworks ID, deviceTypes 127/171, metadata guard - #48

Merged
baudneo merged 5 commits into
baudneo:claude-refactorfrom
nathandlawrence:sith/shows-types-birth-guard
Oct 27, 2026
Merged

baudneo merged 5 commits into
baudneo:claude-refactorfrom
nathandlawrence:sith/shows-types-birth-guard

Conversation

@nathandlawrence

@nathandlawrence nathandlawrence commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Rebased onto claude-refactor as asked in #45. Five commits, each with its own tests. Each one passes pytest and ruff on its own, so you can take any of them separately:

  1. Fireworks ID per deviceType: 0x3A stays the default. 0x03 is used on deviceType 75, where 0x3A does nothing, also with 0xDA. See Light show (preset effect) IDs verified on hardware: Fireworks is 0x03, not 0x3A; plus status codes for reporting the active effect #46.

  2. Add deviceTypes 127 and 171 (the Dynamic Effects eave lights and the Matter revision of the Full Color A19). Details in Device not working / Unknown device / Incorrect device / Have better info available / Better white temp handling #12.

  3. parse_entity_state: don't raise for a device without metadata. On an HA birth, the re-announce stopped at the first unknown deviceType, so every device after it kept an unknown state. See MQTT receiver dies on HA birth re-announce when a device type has no metadata ('NoneType' object has no attribute 'capabilities') #45. As @crdson93 found below, the same guard also fixes the 0x73 mesh-info path, where an unknown type dropped the whole mesh packet and stopped status from the known devices in it.

  4. Run modes: music shows, the user's custom show slots, stop_show, and the running show published as the entity's effect (read from status byte 6). The new cync_lan/effects.py holds pure functions and uses the same per-deviceType light-show IDs. set_lightshow uses it, and docs/protocol.md gets a run-mode section with confidence tags. See Light show (preset effect) IDs verified on hardware: Fireworks is 0x03, not 0x3A; plus status codes for reporting the active effect #46 and Feature: music shows (preset + custom) via run mode - same 0xE2 / 0x0E command as set_lightshow #47.

  5. Test for the mesh-info path (the chain _process_73_mesh_info uses): an unknown type's status followed by a known device's status, and both must publish. It fails without commit 3 and passes with it.

Testing

  • uv run pytest -q: 266 passed (198 before + 68 new). uv run ruff check src tests is clean. Both were checked at every commit.
  • Type 171 also confirmed on @crdson93's two bulbs (Matter Full Color A19, RGB + tunable white).
  • Hardware: every effect value was measured one command at a time on a deviceType 75 (24' Cafe Lights, fw 1.0.516). For each one, the command was sent, the status read back, and the Cync app's highlighted tile and the string itself checked. That was done through the Cync cloud relay with the same packet, and since 2026-10-25 also through a local cync-lan build (the python branch plus these changes) on that string. The 0x3A + 0xDA Fireworks packet was re-tested locally on 2026-10-26.
  • Not tested: run modes on other device types (which is why music shows and custom slots are only offered to dynamic devices), the metadata guard through a real HA restart, and this exact branch on hardware.

Notes

🤖 Generated with Claude Code

@crdson93

Copy link
Copy Markdown
Contributor

Hardware confirmation for deviceType 171, and one extra data point on the metadata guard.

Type 171 is the Matter revision of the Full Color A19. I have two of them. In cync_mesh.yaml they export as type: 171 (fw 1.0.222), and Matter reports the product name as "Cync Full Color A19". They are Direct Connect (Wi-Fi + BT) bulbs with Matter support, RGB plus tunable white, so color=True, tunable_white=True matches what the bulbs are. (I haven't run this branch yet. In the meantime I've hand-edited those two entries to type: 153, and on/off control works with that mapping.)

The unknown-type crash isn't limited to the HA-birth re-announce. On a build of claude-refactor (0.0.8b1.dev1, plus the stale-vote/mesh-refresh PRs I sent in #41 to #44), adding two type-171 bulbs to a 19-device mesh made every mesh-info packet fail, not just the birth path:

session.py parse_raw_data -> parse_packet
handlers.py _dispatch_device_request -> _handle_73_mesh_control -> _process_73_mesh_info
device.py handle_entity_update
mqtt_client.py parse_entity_state:
  if hasattr(node.metadata.capabilities, "motion") ...
AttributeError: 'NoneType' object has no attribute 'capabilities'

Each failing packet was dropped (dropping packet that failed to parse, logged for several different devices), so status updates from the existing devices stopped getting through, and no entities were created for the new bulbs. Changing the two entries to type: 153 and restarting cleared it immediately. So the node.metadata is not None guard in commit 3 also fixes this path, which seems worth a line in the PR description, and possibly a test that goes through _process_73_mesh_info rather than only the birth re-announce.

Happy to test this branch against my live mesh (21 devices, mix of BT-relayed and Wi-Fi bridges, both type-171 bulbs included) and report back, if that's useful. I'd run it merged with my fork's mesh-refresh commits.

nathandlawrence added a commit to nathandlawrence/cync-lan that referenced this pull request Oct 26, 2026
…evice

Covers the 0x73 mesh-info path crdson93 hit in baudneo#48 (handlers._process_73_mesh_info -> CyncDevice.handle_entity_update ->
parse_entity_state): with two type-171 bulbs in a 19-device mesh, the AttributeError dropped the whole mesh packet, so status
from the known devices in it stopped too. Fails without the metadata guard (commit 3), passes with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013u4ng89WpKczAqWx9eWCLX
@nathandlawrence

Copy link
Copy Markdown
Contributor Author

Thanks, this is really useful, both the type 171 confirmation from your own bulbs and the mesh-info trace.

I've added a test for that path: a status for a type the table doesn't know goes through CyncDevice.handle_entity_update -> parse_entity_state (the same chain as _process_73_mesh_info), followed by a status for a known device, and both have to publish. It fails without the guard in commit 3 and passes with it. That's the new 5th commit. I've also added a line to the PR description that the guard fixes the mesh-info path, not only the HA-birth re-announce.

And yes, please test it on your mesh, merged with your mesh-refresh commits. 21 devices with a mix of BT-relayed and Wi-Fi bridges is a much wider check than my setup. I'd especially like to hear whether the type-171 bulbs come up as lights with color and white once you switch them back from 153.

On a type 75 (24' Cafe Lights, fw 1.0.516) 0x3A did nothing, also with the table's own last byte 0xDA, while 0x03 ran Fireworks (status 0x82). 0x3A works on the devices FACTORY_EFFECTS_BYTES was built from, so it stays the default and LIGHT_SHOW_ID_OVERRIDES picks the ID by deviceType (suggested in baudneo#46). The other nine IDs matched on type 75.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… A19, Matter)

127: GE Cync Dynamic Effects Outdoor Smart Eave Lights, CEV100CDOD, fw 1.0.510 (color, tunable white, dynamic per the Cync cloud's own capability data). 171: GE CYNC Full Color A19, CLEDA199CD1MS, Matter logo, 800 lm, 9.5 W, 2000-7000 K, fw 1.1.204; color, temperature and brightness verified working. Details in issue baudneo#12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A deviceType that model_info does not know has metadata None, and the motion check read node.metadata.capabilities. On an HA birth the re-announce loop stopped at the first such device, so every device after it kept an unknown state (baudneo#45).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ct in state

set_lightshow sends op E2 / cmd 0E 11 02 07 <mode> <index> <any> for every run-mode effect: the factory light shows (mode 1, IDs per deviceType via light_show_id), the 8 music shows (mode 2), the user's custom show slots (index 10 up in both modes) and stop_show (mode 0). Dynamic devices get the music shows and custom slots in the HA effect list. Status byte 6 names the running show (80+index-1 light, A0+index-1 music, E3 Cyber), decoded with the device's type and published as the entity's effect. Values measured one by one on a deviceType 75; see docs/protocol.md and baudneo#46 / baudneo#47.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…evice

Covers the 0x73 mesh-info path crdson93 hit in baudneo#48 (handlers._process_73_mesh_info -> CyncDevice.handle_entity_update ->
parse_entity_state): with two type-171 bulbs in a 19-device mesh, the AttributeError dropped the whole mesh packet, so status
from the known devices in it stopped too. Fails without the metadata guard (commit 3), passes with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants