Add integration tests and fix 6 behavioral bugs#52
Closed
clintongormley wants to merge 58 commits intoSese-Schneider:mainfrom
Closed
Add integration tests and fix 6 behavioral bugs#52clintongormley wants to merge 58 commits intoSese-Schneider:mainfrom
clintongormley wants to merge 58 commits intoSese-Schneider:mainfrom
Conversation
- Add pyproject.toml with pytest, ruff, and pyright configuration - Add GitHub Actions workflow for tests and linting - Update .gitignore with .coverage and .iml entries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract the core cover logic from the monolithic cover.py into cover_base.py (CoverTimeBased base class) with abstract methods for relay control. Add concrete subclasses for each input mode: - cover_switch_mode.py: separate open/close switches - cover_toggle_mode.py: single toggle switch with directional state - cover_pulse_mode.py: momentary pulse switch control - cover_wrapped.py: wraps an existing HA cover entity - cover_switch.py: helper for switch entity operations Slim cover.py to a thin factory that creates the appropriate subclass based on the input_mode configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a standalone travel_calculator.py that follows HA conventions, removing the xknx library dependency. Handles position tracking, movement timing, and travel state management. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace tilt mode strings with a strategy pattern. Each strategy encapsulates movement planning and command generation: - base.py: TiltStrategy ABC with MovementStep dataclasses - sequential.py: SequentialTilt with phased movement model - dual_motor.py: DualMotorTilt with boundary lock and safety - inline.py: InlineTilt using the main motor for tilt control Factory function creates the appropriate strategy from config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add __init__.py with async_setup_entry for config entry support - Add config_flow.py with UI-based setup wizard - Update manifest.json with config_flow dependency and version bump Enables UI-first setup, deprecating YAML-only configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add calibration.py with automated timing calibration services: - start_calibration/stop_calibration for travel time measurement - Motor overhead calibration with two-phase step test - Min movement time calibration with incremental pulses - Tilt time calibration with travel_moves_with_tilt validation - CalibrationState dataclass for tracking active calibration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add websocket_api.py providing real-time configuration management: - get_config/save_config for cover timing parameters - get_all_covers for listing configured covers with state - start/stop_calibration commands with progress reporting - set_known_position/set_known_tilt_position for position reset - raw_command for direct relay control bypassing position tracker Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update services.yaml with calibration and position reset services using target selectors for UI mode - Update strings.json with config flow, calibration, and service descriptions - Update translations for en, pt; add pl translation - Add translatable strings for all calibration attributes and frontend card labels Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add cover-time-based-card.js (1599 lines) providing a full configuration UI: - Device tab: entity pickers, timing table with save/discard, input mode and tilt mode selectors - Calibration tab: automated calibration with progress feedback, position reset, and per-attribute hints - Tilt Motor tab: strategy-specific entity pickers and config - All strings are translatable via HA's localization system Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 19 test files with ~10,000 lines of tests covering: - Base movement orchestration and position tracking - All input mode subclasses (pulse, switch, toggle, wrapped) - Cover factory and service dispatching - Calibration system with all calibration types - WebSocket API endpoints and config management - Tilt strategy behavior for all strategy types - State monitoring with echo filtering - Travel calculator position/timing logic - Config flow and integration setup - Relay command sequences and motor overhead Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite README for UI-first setup, deprecate YAML-only docs - Add sections for calibration, tilt strategies, state monitoring - Update CHANGELOG with all new features and breaking changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 20 design and plan documents covering: - UI config flow design and implementation plan - Input mode subclasses design and refactor plan - State monitoring design and implementation plan - Calibration APIs design and implementation plan - Configuration card design and plan - Manual position reset design and plan - Tilt strategies design, refactor plan, and config UI plan - Inline tilt design and implementation plan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When travel or tilt position is None (e.g. newly created entity with no restored state), None != 0 evaluates to True, causing set_position(100) to silently force tilt to 100% on unknown state. Add the same None guard that DualMotorTilt already has. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move CONF_*, DOMAIN, and DEFAULT_* constants that were duplicated across cover_base.py, cover.py, websocket_api.py and __init__.py into a single const.py module. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move _resolve_entity from cover.py and websocket_api.py into a shared helpers.py module as resolve_entity (raises) and resolve_entity_or_none (returns None). Update all call sites and test mock paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move 10 calibration methods (337 lines) from CoverTimeBased into CalibrationMixin in cover_calibration.py. CoverTimeBased now inherits from CalibrationMixin, keeping all behavior identical. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract _extract_coupled_tilt, _extract_coupled_travel, and _calculate_pre_step_delay from CoverTimeBased into module-level functions in tilt_strategies/planning.py. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract the ~45-line tilt coupling block duplicated between _async_move_to_endpoint and set_position into _plan_tilt_for_travel. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reorganize definitions across 5 files for top-to-bottom readability: - cover_base.py: group by lifecycle/properties/public API/internals - cover_toggle_mode.py: public overrides → state handlers → relay cmds - dual_motor.py: move can_calibrate_tilt after __init__ - test_websocket_api.py: group unwraps at top, classes match source order - cover.py: group constants, move _register_services after setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pulse/toggle send methods now return immediately after the ON edge, deferring the sleep+turn_off to a background task. This fixes calibration overhead measuring as zero and improves position tracking accuracy. Also adds _send_tilt_open/close/stop overrides to PulseModeCover and ToggleModeCover so tilt buttons use the same pulse/toggle pattern as travel buttons. Fixes ToggleModeCover.async_stop_cover missing the _send_tilt_stop call when tilt restore/pre-step was active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…sections Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ration _async_handle_command dispatches to _send_open/_send_close but never set _last_command. The higher-level methods (async_open/close_cover) set it, but calibration calls _async_handle_command directly. Toggle mode's _send_stop needs _last_command to know which button to re-pulse, so it silently skipped every stop during calibration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… switch for pulse mode Replace the two-field device_type + input_mode system with a single control_mode field (wrapped/switch/pulse/toggle). No migration needed as this code hasn't been released yet. Pulse mode now requires a stop switch entity — the entity shows as unavailable in HA and the calibration tab is disabled until configured. Tilt stop switch is also required for pulse mode with dual_motor tilt. Tilt entity visibility now follows control mode: - wrapped: no tilt entity pickers - switch/toggle: tilt open + close - pulse: tilt open + close + stop (required) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change min=0 to min=0.1 for travel_time_close, travel_time_open, tilt_time_close, and tilt_time_open. Matches the YAML schema's cv.positive_float behavior and prevents division-by-zero in the position calculator and calibration logic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix _async_move_tilt_to_endpoint and set_tilt_position to use tilt motor relays instead of main motor in dual_motor mode - Add tilt motor stops at intermediate cleanup points for safety - Unify _has_tilt_motor() to check tilt_strategy.uses_tilt_motor consistently between base and wrapped classes - Map legacy travel_moves_with_tilt YAML config to inline tilt mode - Fix frontend auto-save entity_id override order - Add assertion for _start_pending_travel command narrowing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Declare host class attributes and methods under TYPE_CHECKING so pyright can resolve them without runtime circular imports. Adds assertions for str | None narrowing where values are guaranteed set by callers. Resolves all 39 reportAttributeAccessIssue pyright errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HACS rejects the non-standard "card" key in strings.json. Move all card UI translations into the JS bundle and look up locale via hass.language. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pytest_homeassistant_custom_component verify_cleanup fixture detects pending _complete_pulse() tasks after tests that intentionally skip draining. Add _cancel_tasks() cleanup to the 6 affected tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Tilt startup delay calibration used hardcoded 0.2 * total_time (correct for 8 travel steps but wrong for 3 tilt steps). Now computed dynamically: (1 - step_count/10) * total_time. 2. _start_tilt_restore cleared _last_command after dispatching the motor command. In toggle mode, _send_stop needs _last_command to know which relay to re-pulse — clearing it left the motor running. Removed the premature clear; auto_stop_if_necessary clears it after the stop is sent. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When calibrating tilt_time_close from the closed_tilt_open position, the card was sending direction="open" based on cover position alone. This overrode the server's correct attribute-based fallback which derives direction from the attribute name (tilt_time_close → close). Now only sends explicit direction for travel attributes; tilt attributes let the server determine direction from the attribute name. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace `kwargs.get("safe_tilt_position") or 100` with
`kwargs.get("safe_tilt_position", 100)` so 0 is no longer treated
as falsy and silently replaced with 100.
- Fix README pulse_time default from 2s to 1s to match code.
- Add tests for safe_tilt_position=0 and timing field validation bounds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
set_known_position and set_known_tilt_position were calling _async_handle_command(SERVICE_STOP_COVER), which in toggle mode re-pulsed the last switch (starting motor movement). Now these methods only update internal tracker state. Also rename log labels from UP/DOWN to OPEN/CLOSE, and fix hardcoded 0.2 * total_time in overhead calibration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents overflow with long entity names by placing the open/stop/close buttons below the position helper text instead of in the blue header bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrapped cover entities fire attribute-only state changes (e.g. closing→closing with position updates) that bypassed echo filtering and triggered redundant async_close_cover calls. During calibration, these overrode the travel calculator's target position. Two guards added to _async_switch_state_changed: - Skip when old_val == new_val (attribute-only, no real transition) - Skip when calibration is active (calibration drives motors directly) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…sult Rewrite overhead calibration to use travel calculator position tracking instead of time-based sleeping. Each step uses calc.start_travel() and polls current_position(), then force-sets position after stopping. - Zero startup delay during test so tracker doesn't compensate - Restore saved delay when calibration ends (success or cancel) - Use correct direction's travel time in result calculation - Subtract pulse_time from continuous phase for pulse/toggle modes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 99 new tests covering dual-motor tilt operations, calibration edge cases, relay echo pending logic, toggle mode tilt handling, legacy YAML migration, and external tilt switch state changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a physical button or remote triggers the cover externally, the tracked position is now set to Unknown (None) instead of attempting inaccurate time-based tracking. Position stays Unknown until set_known_position is called. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove premature validation that blocked changing to pulse mode without a stop switch. The cover will show as unavailable until the stop switch is configured, which is the correct UX — users need to be able to change the mode first, then add the switch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
With max_tilt_allowed_position set, moving the cover to a position above the boundary would incorrectly restore tilt to its pre-move value, then immediately snap it back to safe position. Now the restore is skipped when the target position doesn't allow tilt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Calibration screen open/close/stop buttons now work correctly:
- ws_raw_command stops active lifecycle before sending commands
- New _raw_direction_command method with toggle mode override
(stop-before-reverse for toggle motor controllers)
- Position clears to Unknown when using calibration buttons
- Frontend card resets _knownPosition dropdown on button press
- Physical button / wall switch state changes now tracked correctly:
- _async_switch_state_changed delegates to mode-specific handlers
with _triggered_externally=True (instead of clearing position)
- External movements skip tilt planning (relay already on,
can't sequence pre-steps for physical buttons)
- Pylint cleanup (9.80 → 9.84): class docstring, unused args,
line-too-long, consider-using-in
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Behavioral spec documents expected behavior for all control modes, tilt strategies, and lifecycle phases — reviewed and corrected by maintainer. Integration test design describes hybrid approach: keep unit tests for pure logic, add focused HA integration tests for feedback loop, multi-phase lifecycle, and config wiring. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 tasks across 4 phases: bug fixes (TDD), integration test infrastructure, 12 integration test scenarios, final validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ON signal is the button press; OFF is just the release and should be ignored. Applies to both travel and tilt external state handlers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ON→OFF transitions are just relay releases and should be ignored. Only the rising edge (OFF→ON) indicates a real button press. Applies to both travel and tilt external state handlers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover services (open/close/stop) now behave identically regardless of control mode. No special-casing where same-direction = stop in toggle mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pressing open/close when tracker already shows the endpoint still sends the relay command plus run-on time. This allows physical covers that are out of sync to resync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tilt calibration now derives step size from num_steps (3 steps → 20% each) instead of hardcoding 10%. Travel calibration (8 steps → 10%) is unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses pytest-homeassistant-custom-component for a real HA instance. input_boolean entities simulate physical switches. MockConfigEntry loads the integration through the real config entry lifecycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests open/track/auto-stop, stop-during-movement, set_position, and endpoint resync through real HA service calls, event bus, and switch state changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Feedback: echo filtering and external button press detection - Modes: toggle stop-before-reverse and pulse relay pulsing - Lifecycle: correct entity features from config, position restore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests tilt-before-travel pre-step and tilt rejection when cover is not at an endpoint position. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
Author
|
Damn Claude! Closing... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
pytest-homeassistant-custom-componentBug Fixes
Integration Tests
Test plan
🤖 Generated with Claude Code