Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add segment effect support for RGBIC light strips#1702

Open
shiner66 wants to merge 3 commits into
python-kasa:masterpython-kasa/python-kasa:masterfrom
shiner66:feat/l930-segment-effectsshiner66/python-kasa:feat/l930-segment-effectsCopy head branch name to clipboard
Open

Add segment effect support for RGBIC light strips#1702
shiner66 wants to merge 3 commits into
python-kasa:masterpython-kasa/python-kasa:masterfrom
shiner66:feat/l930-segment-effectsshiner66/python-kasa:feat/l930-segment-effectsCopy head branch name to clipboard

Conversation

@shiner66
Copy link
Copy Markdown

@shiner66 shiner66 commented May 29, 2026

Summary

RGBIC light strips such as the L930 (also L920 / L430) expose a dedicated
segment_effect SMART component for the per-segment custom effects created in
the Tapo app
(breathe, circulating, chasing, flicker, bloom, stacking, and the
static "none" paint). These
are a separate subsystem from the lighting_effect system handled by
LightStripEffect, and are activated with the apply_segment_effect_rule
method rather than set_lighting_effect. python-kasa currently has no support
for them.

This PR adds a SegmentEffect module:

  • REQUIRED_COMPONENT = "segment_effect"
  • reads the active rule via get_segment_effect_rule and the saved-effect list
    from get_preset_rules (already fetched by LightPreset, so no extra query)
  • effect / effect_list / is_active / brightness / has_custom_effects
  • set_effect(name | "Off"), set_custom_effect(rule), set_brightness()
  • test(rule) / stop_test() for a churn-free live preview via
    start_segment_effect_test / stop_segment_effect_test — plays a rule without
    rewriting the device preset table (saving an effect makes the firmware/app
    rewrite the preset list and evict effects no longer present)
  • payload includes deviceType: "strip" (required for custom effects) and
    preserves speed (the firmware resets it to 0 / no animation if omitted)

The rule builder is hardened against the documented SegmentEffectData ranges
(decompiled from the Tapo Android app v3.18.506, cross-checked on a live L930):

  • validates type against the seven segment types (raises on anything else)
  • clamps brightness to 1-100 and speed to 1-10; speed: 0 is permitted only
    for the static "none" paint (it freezes an animated type otherwise)
  • normalises per-segment colours to the device's 4-int [h, s, v, w] form and
    reduces display_colors to the unique palette — start_segment_effect_test
    rejects 3-int [h, s, v] colours with PARAMS_ERROR(-1008) (apply tolerates
    them), so normalising keeps both code paths working
  • the segments field is dual-encoded by type: group sizes for the six
    animated types, explicit LED indices for the static "none" paint

Also adds a FakeSmartTransport handler for apply_segment_effect_rule, tests,
and an L930 fixture (fw 1.4.3) that contains real saved segment effects.

Open question for maintainers

LightStripEffect names itself "LightEffect" on the assumption that a device
supports only one effect system, but RGBIC strips expose both
light_strip_lighting_effect and segment_effect. This PR therefore registers
the new module under its own name (Module.SegmentEffect) so the two coexist.
I'm happy to change the approach — e.g. unify both into the LightEffect
interface and route set_effect to the correct subsystem — if you prefer.

Notes on the fixture

The L930-5(EU)_1.0_1.4.3 fixture was captured from a real device. The region
suffix is assumed; the device brightness was normalised to a resting value and
the active segment rule set to enable: 0 (the two custom effects remain in the
preset slots). Happy to regenerate it with dump_devinfo if you'd rather.

Test plan

  • uv run pytest tests/smart/modules/test_segment_effect.py
  • uv run pytest -k "1.4.3" (full suite against the new fixture)
  • pre-commit run -a (ruff / mypy / generate-supported)

🤖 Generated with Claude Code

RGBIC strips such as the L930/L920/L430 expose a `segment_effect` component
for the per-segment custom effects created in the Tapo app (breathe,
circulating, chasing, flicker, bloom, stacking). These are separate from the
`lighting_effect` system handled by LightStripEffect and are activated with
the `apply_segment_effect_rule` method.

Add a SegmentEffect module exposing the saved-effect list (from preset rules),
the active effect, and set_effect/set_custom_effect, plus a fake-transport
handler for apply_segment_effect_rule and an L930 1.4.3 fixture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

Codecov Report

❌ Patch coverage is 98.33333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.30%. Comparing base (76d9f68) to head (56a7065).

Files with missing lines Patch % Lines
kasa/smart/modules/segmenteffect.py 98.30% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1702      +/-   ##
==========================================
+ Coverage   93.22%   93.30%   +0.08%     
==========================================
  Files         157      158       +1     
  Lines        9815     9935     +120     
  Branches     1003     1018      +15     
==========================================
+ Hits         9150     9270     +120     
  Misses        472      472              
  Partials      193      193              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

Add tests for set_custom_effect (with and without speed/carousel),
set_brightness (active and idle), the Off no-op path, the module
properties, and non-dict preset entries — bringing the module to 100%
coverage so the codecov patch check passes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@shiner66 shiner66 marked this pull request as ready for review May 29, 2026 18:23
Harden the segment effect rule builder using the decompiled Tapo app
v3.18.506 `SegmentEffectData` bean (cross-checked on a live L930):

* Validate `type` against the seven segment types (now incl. the static
  "none" paint) and raise on anything else.
* Clamp brightness to 1-100 and speed to 1-10; speed 0 is permitted only
  for the static "none" paint (it freezes an animated type otherwise).
* Normalise per-segment colours to the device's 4-int [h, s, v, w] form
  and reduce display_colors to the unique palette. start_segment_effect_test
  rejects 3-int [h, s, v] colours with PARAMS_ERROR(-1008); apply tolerates
  them, so normalising keeps both paths working.

Add test()/stop_test() backed by start/stop_segment_effect_test for a
churn-free live preview that does not rewrite the device preset table.

Expand the module docstring with the type/range table and the dual
`segments` encoding (group sizes for animated types, explicit LED indices
for "none"). Cover the new behaviour with four tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shiner66
Copy link
Copy Markdown
Author

Update — pushed 56a7065 hardening the rule builder against the documented SegmentEffectData ranges (decompiled from the Tapo Android app v3.18.506, cross-checked on a live L930):

  • Validation & rangestype is validated against the seven segment types (now incl. the static none paint); brightness is clamped to 1–100 and speed to 1–10. speed: 0 is permitted only for none (it freezes an animated type otherwise).
  • 4-int colours — per-segment colours are normalised to the device's [h, s, v, w] form and display_colors is reduced to the unique palette. start_segment_effect_test rejects 3-int [h, s, v] colours with PARAMS_ERROR(-1008) while apply_segment_effect_rule tolerates them, so normalising keeps both code paths working.
  • Live preview — new test(rule) / stop_test() backed by start_segment_effect_test / stop_segment_effect_test. These play a rule without rewriting the device preset table, avoiding the churn where saving an effect makes the firmware/app rewrite the preset list and evict effects no longer present.
  • Docs — the module docstring gains the type/range table and documents the dual segments encoding: group sizes for the six animated types vs explicit LED indices for the static none paint.

+4 tests (clamping/normalisation, the none speed-0 exception, invalid-type, and the preview path). uv run ruff check & mypy clean; pytest tests/smart/modules/test_segment_effect.py → 72 passed, 12 skipped.

The PR description above has been updated to match.

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

Morty Proxy This is a proxified and sanitized view of the page, visit original site.