Repository navigation
arch(light,cover): default to native light transitions and extract bus-truthful cover kinematics strategies #730
Copy link
Copy link
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Architectural Assessment & Severity
- Critique Point: Sending multiple commands will fail #1 — Software-stepped fades and virtual cover positioning
- Severity: P0 (Critical — Rank Sending multiple commands will fail #1)
- Related Issues: Covers: end a timed run at the stop status, not the stop write (#466) #705, Covers: per-cover motor start-up floor instead of one 0.4 s constant (#466) #704, Send queue: let a cover's stop frame overtake queued frames #645, feat(cover): support venetian blind slat / louvre tilt positioning (WHO 2 Dimension 11) #492, Community Call for Real-World Gateway Traces: Help Us Eliminate Hardware Blind Spots! 📡 #466, feat(cover,lock): impulse garage/gate control, multi-factor safety approval, and intercom events #667, RFC: timed covers, what I measured on a MyHOMEServer1 (latencies, frame order, non-linear position) #302
Problem Statement
1. Software Fade Engine (custom_components/myhome/light_fade.py, light.py, const.py)
DEFAULT_TRANSITION_MODEis currently set toTRANSITION_MODE_SOFTWARE("software_stepped") atcustom_components/myhome/const.py:175(andTRANSITION_MODE_AUTOalso resolves toTRANSITION_MODE_SOFTWAREatcustom_components/myhome/light.py:603-604).- Consequently, every
light.turn_on(..., transition=T)call by default spawns a software loop sending up to 25 instant-brightness frames (*#1*WHERE*#1*level*0##) at0.3sintervals (SOFTWARE_TRANSITION_STEP_INTERVAL = 0.3,light_fade.py:159-188) at Tier-0 command priority. - On a shared, low-bandwidth SCS bus, this floods the gateway during multi-light scenes or
adaptive_lightingupdates, fights actuators that natively support hardware transition speeds (*#1*WHERE*#1*level*speed##), can reorder steps whencommand_worker_count > 1(light_fade.py:132-141), and requires an optimistic echo-suppression rule (abs(reported - current_opt) >= 10atlight.py:1100-1108) that ignores real bus state during active fades.
2. Virtual Travel-Time Covers (custom_components/myhome/cover.py, cover_motion.py, cover_calibration.py)
- Standard WHO=2 actuators (
F411U2,F411/4,LN4660M2) do not report percentage position on the bus (onlyF430/ Dimension 10*#2*WHERE*10##actuators do). - However,
MyHOMECover(cover.py:195-1353) forces virtual travel-time estimation (DEFAULT_TRAVEL_TIME = 25atconst.py:105) and a fabricated startup position of_attr_current_cover_position = 50(cover.py:280) onto every uncalibrated standard cover by default. - All cover behaviors—native hardware position (
advanced=True), virtual travel-time dead-reckoning, interactive bus calibration (cover_calibration.py), echo-window tracking (ECHO_WINDOW = 2.0), delivery-confirmation futures, motor start-up lag (MOTOR_START_DELAY), stop-status re-anchoring (Covers: end a timed run at the stop status, not the stop write (#466) #705), per-cover motor pulse floor (Covers: per-cover motor start-up floor instead of one 0.4 s constant (#466) #704), deadband protection (Community Call for Real-World Gateway Traces: Help Us Eliminate Hardware Blind Spots! 📡 #466), Venetian slat tilt (feat(cover): support venetian blind slat / louvre tilt positioning (WHO 2 Dimension 11) #492), and impulse gate/garage timers (feat(cover,lock): impulse garage/gate control, multi-factor safety approval, and intercom events #667)—are entangled inMyHOMECover(1,353 lines on base, growing past 2,200+ lines across 5 concurrent cover branches).
Proposed Solution (PR Scope)
Part A — Lights (const.py, light.py, light_fade.py)
- Default to Native Hardware Transitions:
- Change
DEFAULT_TRANSITION_MODEincustom_components/myhome/const.py:175fromTRANSITION_MODE_SOFTWAREtoTRANSITION_MODE_NATIVE("native"). - Map
TRANSITION_MODE_AUTOincustom_components/myhome/light.py:603-604toTRANSITION_MODE_NATIVE.
- Change
- Demote & Isolate Opt-In Software Fades:
- Keep
TRANSITION_MODE_SOFTWAREstrictly opt-in for legacy dimmers that ignore hardware speed parameters. - Enqueue intermediate software fade steps at a lower priority tier (
_TIER_FADE_STEPS = 1, below interactive Tier-0 commands) so fades never delay wall-switch or coverSTOPcommands. - Remove the
<10%optimistic echo suppression during native transitions, and immediately cancel an opt-in software fade if an external physical switch event arrives.
- Keep
Part B — Covers (cover.py, cover_strategies/)
- Extract Pluggable
CoverKinematicsStrategyClasses (custom_components/myhome/cover_strategies/):SimpleUpDownStopStrategy(new default for uncalibrated/unconfigured standard covers): ExposesOPEN | CLOSE | STOPonly, reportsis_opening/is_closing/is_closedtruthfully from bus frames (*2*1/2/0*WHERE##), setscurrent_cover_position = None(no fabricated50%startup state), and runs zero background stopwatch timers.NativePositionStrategy: Foradvanced=Trueactuators or any cover auto-promoted on receiving a Dimension 10 (*#2*WHERE*10##) frame.TimedCurtainStrategy: Enabled only whentravel_timeis explicitly configured or calibration data exists inCONF_COVER_TRAVEL_TIMES. Encapsulates dead-reckoning,min_motor_pulse(Covers: per-cover motor start-up floor instead of one 0.4 s constant (#466) #704),cover_deadband_pct(Community Call for Real-World Gateway Traces: Help Us Eliminate Hardware Blind Spots! 📡 #466), and stop-status re-anchoring (Covers: end a timed run at the stop status, not the stop write (#466) #705).VenetianTiltStrategy: Encapsulates slat tilt pulse math (feat(cover): support venetian blind slat / louvre tilt positioning (WHO 2 Dimension 11) #492).ImpulseDoorStrategy: Encapsulates gate/garage impulse timers (feat(cover,lock): impulse garage/gate control, multi-factor safety approval, and intercom events #667).
- Slim
MyHOMECover(cover.py):- Reduce
MyHOMECoverto a thin Home AssistantCoverEntityadapter (~350 lines) that delegates kinematics toself._strategy.
- Reduce
Verification Plan
- Unit tests in
tests/test_cover_strategies.pycoveringSimpleUpDownStopStrategy(uncalibrated default, no fake 50%),NativePositionStrategy,TimedCurtainStrategy,VenetianTiltStrategy, andImpulseDoorStrategy. - Unit tests in
tests/test_light.pyverifyingDEFAULT_TRANSITION_MODE == "native"sends a single native transition command instead of stepped frames. - Full WSL test suite (
pytest tests -q --cov=custom_components/myhome),ruff check, andscripts/verify_ha_standards.py.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
feat(cover,light): default native transitions and extract cover kinem…
feat(cover,light): default native transitions and extract cover kinem…
feat(cover,light): default native transitions and extract cover kinem…
feat(cover,light): pluggable CoverKinematicsStrategy hierarchy and lo…
feat(cover,light): pluggable CoverKinematicsStrategy hierarchy and lo…
feat(cover,light): pluggable CoverKinematicsStrategy hierarchy and lo…
Merge pull request #739 from OpenWebNet-HA/arch/issue-730-native-fade…
GreenGrassBlueOcean commentedon Oct 21, 2026
Resolved in PR #739 (
10405032), PR #760 (8acea4f9), and PR #762 (43bdc070):CoverKinematicsStrategyhierarchy intocustom_components/myhome/cover_strategies/(SimpleUpDownStopStrategy,NativePositionStrategy,TimedCurtainStrategy,VenetianTiltStrategy,ImpulseDoorStrategy)._TIER_FADE_STEPS = 1onFrameScheduler.tests/test_cover_strategies.py,tests/test_cover_strategy_contract.py).