Skip to content

feat: extended timer support for 0xB6 devices#541

Draft
asxzy wants to merge 5 commits into
lightinglibs:masterfrom
asxzy:feat/add-0xb6-timers
Draft

feat: extended timer support for 0xB6 devices#541
asxzy wants to merge 5 commits into
lightinglibs:masterfrom
asxzy:feat/add-0xb6-timers

Conversation

@asxzy

@asxzy asxzy commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merge order: #538#539 → $540 → this → cli. Draft until predecessors land.

Background

The 0xB6 uses a different timer wire format than other LEDENET devices; before this, the CLI
reported "Could not get timers." This adds the device's timer model and protocol.

Changes

File What
timer.py (+280) LedTimerExtended (parse/serialize the 0xB6 timer slots: on/off/color/preset/warmwhite modes, time, repeat mask).
protocol.py (+113) construct_get_timers (E0 06), construct_set_timer (E0 05 <slot> …), is_valid_timers_response, parse_get_timers.
aiodevice.py (+25) Wire get/set timers for the extended protocol.
const.py (+12) Timer action/effect constants.
tests/test_aio.py (+431) Timer parse/build/roundtrip tests.

Testing

  • Unit tests for the timer format + protocol.
  • pytest green, ruff clean, no new mypy errors.

On-device verification (device 192.168.1.78):

Check Command Result
Get clock --getclock ✅ reads device time
Set clock --setclock ✅ syncs (re-read advanced)
Show timers -t ✅ lists 6 slots, parses existing (Timer #1 ON 20:00 daily, #2 OFF 00:30 daily) — this previously returned "Could not get timers"
Set/clear timer -T 3 color "time:1730;repeat:12345;color:red"-t-T 3 inactive "" ✅ set slot #3, read back, cleared; existing #1/#2 preserved

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.53254% with 48 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
flux_led/base_device.py 85.32% 8 Missing and 8 partials ⚠️
flux_led/timer.py 90.66% 6 Missing and 8 partials ⚠️
flux_led/aiodevice.py 69.56% 6 Missing and 1 partial ⚠️
flux_led/protocol.py 96.05% 6 Missing ⚠️
flux_led/device.py 66.66% 5 Missing ⚠️
Files with missing lines Coverage Δ
flux_led/const.py 100.00% <100.00%> (ø)
flux_led/models_db.py 98.90% <ø> (ø)
flux_led/pattern.py 100.00% <100.00%> (ø)
flux_led/device.py 74.75% <66.66%> (+2.26%) ⬆️
flux_led/protocol.py 98.64% <96.05%> (-0.38%) ⬇️
flux_led/aiodevice.py 95.02% <69.56%> (-1.26%) ⬇️
flux_led/timer.py 72.65% <90.66%> (+11.02%) ⬆️
flux_led/base_device.py 94.31% <85.32%> (-1.34%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@asxzy asxzy force-pushed the feat/add-0xb6-timers branch from 75e74e8 to 1845f79 Compare June 30, 2026 16:33
asxzy added 5 commits June 30, 2026 10:39
Introduces a dedicated protocol class for the Surplife 0xB6 device, switches the
model to it, and adds synchronous-path support.

- protocol.py: PROTOCOL_LEDENET_EXTENDED_CUSTOM, LEDENET_EXTENDED_STATE_RESPONSE_LEN,
  and ProtocolLEDENETExtendedCustom (name, 21-byte state length, extended-only
  is_valid_state_response, white-off-aware extended_state_to_state, and
  named_raw_state that converts extended -> standard for the sync path)
- device.py: read the full 21-byte extended state and accept it while probing
- base_device.py: register the protocol and add supports_extended_custom_effects
- models_db.py: point the 0xB6 model at PROTOCOL_LEDENET_EXTENDED_CUSTOM

Stacked on the reuse PR.
- const.py: ExtendedCustomEffectPattern / Direction / Option enums
- pattern.py: EXTENDED_CUSTOM_EFFECT_ID_NAME / NAME_ID maps
- protocol.py: construct_extended_custom_effect (0xE1 0x21),
  construct_custom_segment_colors (0xE1 0x22), construct_levels_change and the
  HSV(+W) byte helpers on ProtocolLEDENETExtendedCustom
- base_device.py: extended_custom_effect_pattern_list, _generate_* helpers and
  pattern-name lookup in _named_effect
- aiodevice.py / device.py: async_set_* and set* entry points

Stacked on the dedicated-protocol PR.
The 0xB6 device uses a distinct timer wire format (e0 05/06 wrapped commands,
variable-length 6-slot list, per-slot set):

- const.py: TIMER_ACTION_* and TIMER_EFFECT_* constants
- protocol.py: MSG_TIMERS_EXTENDED and the timer methods on
  ProtocolLEDENETExtendedCustom
- timer.py: LedTimerExtended dataclass (to_bytes/from_bytes, __str__)
- aiodevice.py: timer types widened, async_set_timers sends 0xB6 timers one at a
  time, new async_set_timer

Stacked on the effect-APIs PR.
@asxzy asxzy force-pushed the feat/add-0xb6-timers branch from 1845f79 to 447c63b Compare June 30, 2026 16:46
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.

1 participant