Skip to content

Sese-Schneider/ha-cover-time-based

Repository files navigation

Cover time based integration by @Sese-Schneider

A Home Assistant integration to control your cover based on time.

hacs_badge Active Installations GitHub Release License

Project Maintenance GitHub Activity

This integration is based on davidramosweb/home-assistant-custom-components-cover-time-based.

It improves the original integration by adding tilt control, synchronized travel/tilt movements, and a visual configuration card.

Features:

  • Control the position of your cover based on time.
  • External state monitoring: Detects physical switch presses and keeps the position tracker in sync.
  • Up/down interlock (Switch mode): Never energizes both direction relays at once — when one direction relay turns on, even from outside Home Assistant (a wall switch wired straight to the relays), the opposite relay is switched off — protecting motors with no hardware interlock.
  • Multiple input modes: Latching switches, momentary pulse buttons, or toggle-style relays.
  • Wrap an existing cover: Add time-based position tracking to any cover entity.
  • Control the tilt of your cover based on time with four tilt modes: inline, sequential closes-then-tilts-closed, sequential closes-then-tilts-open, or separate tilt motor.
  • Built-in configuration and calibration: Calibrate travel times directly from the UI, including finer parameters to compensate for the time it takes the motor to startup.
  • Resyncs position at endpoints: Motors with internal limit switches self-stop at the 0%/100% endpoints, which resyncs the position tracker with the physical cover. For latching (Switch-mode) relays a configurable run-on keeps the relay energized until the motor reaches the endpoint.

Install

HACS

This repo is available for install through HACS.

  • Go to HACS
  • Search for "Cover time based"

or

Click here:

Setup

Creating a cover via the UI

  1. Go to Settings → Devices & Services → Helpers
  2. Click Create Helper → Cover Time Based
  3. Enter a name for your cover

Setup the configuration card

The configuration card provides a visual interface for all settings and supports built-in calibration to measure timing parameters automatically.

Create at least one cover first. The configuration card is delivered as a frontend asset of this integration, and Home Assistant only loads an integration's frontend assets once the integration is loaded — which requires at least one config entry to exist. If you add the card to a dashboard before creating any cover, Lovelace will show a red Configuration error ("custom element doesn't exist: cover-time-based-card"). Create a cover via the steps above, then add the card.

  1. Go to Settings → Dashboards.
  2. Click Add dashboard → New dashboard from scratch.
  3. Fill in a name and make sure Add to sidebar is selected.
  4. Click Create.
  5. Click the new dashboard icon in the Home Assistant side bar.
  6. Click the Edit dashboard icon in the top right corner.
  7. Under New section click the + icon to add a new card.
  8. Select the By card tab (in Home Assistant 2026.6+ the card picker opens on the By entity tab, where this configuration card does not appear), then search for and select the Cover time based configuration card and click Save.
  9. Click Done to stop editing the dashboard.

Configuration and Calibration Card

The configuration card provides a visual interface for all settings and supports built-in calibration to measure timing parameters automatically.

The configuration card has two tabs: Device and Calibration. The Device tab must be fully configured before accessing the Calibration tab.

The main items on the Device configure how to interface with the physical cover:

  • Device type: whether this helper talks to the cover via open/close switches or via an existing cover entity
  • Switch type: whether the switches are latching, pulsed, or toggled.
  • Tilting: what type of tilt, if any, is supported.

The Calibration tab is used to configure:

  • Position: sync the position tracker with the physical cover and slat position.
  • Travel: how long it takes to open and close the cover, and how much time it takes to start the motor.
  • Tilt: how long it takes to open and close the slats, and how much time it takes to start the motor.

Device

First configure the Device type. A cover-time-based helper can either:

  • wrap an existing cover entity to add time-based position tracking, or
  • use relay switches to control cover movement, and optionally to control tilt movement.

Wrapped covers

Wrap an existing cover entity to add time-based position tracking. Useful for covers that already have basic open/close/stop functionality but lack position tracking.

Specify the Cover entity.

Reacting to physical wall switches. When the wrapped cover is operated externally (physical wall switch, remote, or another integration), the time-based tracker can only follow the movement if the wrapped entity emits an opening / closing state during travel. Some wrapped entities — notably certain Tuya / ZHA cover modules — stay in their current open or closed state the entire time the motor runs, only reporting the final settled state once the movement completes. In that case the time-based position cannot be tracked during the physical movement, but it will snap to the wrapped entity's reported position once it settles (or once you click the wrapped cover's stop button, if the wrapped entity reports its current position at that point). If your device instead reports closed (or unknown) the moment a command is issued — so a manual stop mid-travel is wrongly reported as fully closed — enable Reports commands, not endpoints (below) to track it purely by time.

Ignore reported position. Enable this option when the wrapped cover reports an unreliable position. The integration then tracks the position purely by time and ignores the current_position the wrapped entity reports (the fully-closed endpoint is still trusted). This is also what lets time-based tilt work cleanly on a wrapped cover whose reported position would otherwise interfere.

Reports commands, not endpoints. Some covers (for example single-DP Tuya shutters) have no position feedback and never emit an opening / closing state — their reported state simply echoes the last command: open when opening was commanded, closed when closing was commanded, and unknown when stopped. For these, a closed state does not mean the cover reached the bottom; pressing stop halfway is reported identically to a full close, so the default behaviour wrongly snaps the position to 0%. Enable this option to treat the wrapped entity's state as an open / close / stop command and track the position entirely by time: open starts a timed open, closed starts a timed close, and unknown (stop) freezes the cover at its current time-based position. Leave it off for any cover that reports a real position or a genuine opening / closing transition.

Setting a position. If the wrapped cover natively supports set_cover_position, the integration forwards the set-position command straight to it, so the cover stops at the requested position even if the underlying device has no stop service. The time-based tracker still animates the position live during the move (handy for covers that only report their position once they finish moving). On such a cover, the integration's Stop is implemented by setting the wrapped cover to the current calculated position. If the wrapped cover doesn't support set_cover_position, the integration falls back to driving it with timed open / close / stop. The Force time-based positioning option forces that timed behaviour even when native set-position is available — use it if the wrapped cover's own set-position is unreliable.

Tilt on a wrapped cover. The Inline and Sequential tilt modes drive the wrapped cover's normal open / close commands, so they work on any wrapped cover regardless of whether it reports tilt support. Only the Separate tilt motor mode requires the wrapped cover to expose its own tilt commands, so it is offered only when the wrapped entity reports native tilt support.

Switch-based covers

Control a cover using two relay switches (one for open, one for close), with an optional third stop switch.

Specify the Open switch, Close switch, and optionally the Stop switch entities.

Input Mode for switch-based covers

Three input modes are available to describe how the switch entities for switch-based covers function:

Mode Description
Switch Latching relays. The direction switch stays ON for the entire movement. Movement stops when the switch is turned OFF
Pulse Momentary pulse buttons. A brief ON-OFF pulse latches the motor on. Requires a stop button to stop movement, or movement stops when the hardware reaches its endpoint.
Toggle Toggle-style relays. A brief ON-OFF pulse latches the motor on. A second pulse on the same direction button stops the motor.

Scripts in Pulse mode. In Pulse mode the Open / Close / Stop entities (and the dual-motor tilt entities) may be script entities as well as switch entities — for example, IR-remote-controlled covers where each script fires an open / close / stop IR command. Switch and Toggle modes require switch entities: they rely on the entity reporting a held/latched on-state, which a script (which auto-returns to off) cannot provide. Keep the scripts short: after Pulse time elapses the integration turns the entity off again, which cancels any script still running — so a script whose own internal delay is longer than the pulse time would be cut short.

Pulse time

With the Pulse input mode, the Pulse time configures how long the switch should send the ON signal before it turns OFF. Defaults to 1s. Toggle mode does not use it — toggle relays are momentary, so the integration sends a single ON pulse and lets the relay release itself.

Relay reports its own OFF (Toggle mode)

Toggle mode only. Leave it on (the default) for normal toggle relays — they switch themselves off after the pulse and report that OFF back to Home Assistant, so the integration can drive a still-ON relay OFF first to guarantee a clean ON edge.

Turn it off for hardware-managed pulse modules — for example an Aqara T2 in its 200 ms internal-pulse mode — that pulse the contact themselves but never report the OFF to Home Assistant, leaving the switch entity stuck on. On such hardware a turn_off is not an idempotent "off" but another activation pulse, so the integration's attempt to force a clean edge (turn_off then turn_on) lands as a doubled command and the motor's toggle counter drifts — the symptom is Stop reversing the cover and Up driving it down. With the option off, toggle mode only ever sends a single turn_on per command and never a turn_off, giving exactly one clean activation per press. A repeated turn_on still pulses the motor even while the entity reads on.

Send stop signal at endpoints (Pulse mode)

Pulse mode only. Leave it on (the default) for controllers that latch the direction command and keep running until they receive a separate stop pulse. Without the endpoint stop they stay stuck "moving" — the cover only responds after several clicks and the physical wall/PLC buttons appear blocked. With the option on, the integration pulses the dedicated stop relay when the cover reaches an endpoint (deferred by the Endpoint run-on time, see below); because the stop is a separate relay it can never restart the motor.

Turn it off for controllers with automatic end-stop detection: the motor halts itself at its 0%/100% limit switches, and a stop pulse received while it is already stopped is read as "go to favourite/preset position" (the classic Somfy my behaviour), repositioning the cover on every limit hit. With the option off, no stop is sent at the endpoints. The same flag governs a separate tilt motor's tilt-stop relay at the tilt endpoints. Switch, Toggle and wrapped-cover modes are unaffected.

Assumed state

Available for every device type. A time-based cover calculates its position from travel time without feedback, so by default it reports an assumed state and Home Assistant keeps both the open and close buttons active at all times. Turn Assumed state off if you trust the time-based calculation and want the UI to behave like a position-aware cover — greying out actions that can't apply (for example the close button once the cover is already fully closed). Leave it on if the calculation can drift (motor slip, manual operation, power loss mid-travel), since the always-active buttons let you re-issue a command to re-converge.

Tilt Mode

The Tilt Mode setting controls how tilt and travel interact:

  • None: Tilt is disabled. Only position tracking is used.
  • Inline: Tilt and travel use the same motor. Tilting can happen with the cover in any position. When closing the cover, the closing movement first causes the slats to tilt closed before the cover starts closing. When opening the cover, the opening movement first causes the slats to tilt open before the cover starts opening.
  • Sequential (closes then tilts closed): Tilting can only happen in the fully closed position. First the cover closes then the slats tilt closed (motor drives further down past cover-closed to close the slats). When opening, the slats first tilt open (motor up) then the cover opens.
  • Sequential (closes then tilts open): Mirror image of the above — for covers where slats articulate open when the motor drives further down past cover-closed, not closed. First the cover closes then the slats tilt open (motor continues down). When opening, the slats first tilt closed (motor up) then the cover opens.
  • Separate tilt motor (dual_motor): A separate motor controls the tilt. Requires dedicated tilt open/close/stop switches. Tilt is only allowed when the cover is in a safe position (configurable).

How close/open behaves under sequential tilt modes

HA's cover entity exposes close/open for travel and close-tilt/open-tilt for articulation. The integration handles each slightly differently depending on who invoked it:

  • HA UI close (cover.close_cover): drives travel only — the cover closes and slats remain at the resting position. Use the tilt-close button separately to articulate.
  • HA UI open (cover.open_cover): restores slats to the resting position if needed, then travels to fully open. This is a single motor motion.
  • HA UI close-tilt / open-tilt: drives tilt only (with a travel pre-step if tilt is only allowed at travel=0).
  • External close (physical switch or automation firing the close relay): the integration assumes the motor runs the full journey — it closes the cover and then continues to articulate the slats past cover-closed to the opposite extreme. Tracking follows both phases.
  • External open: the integration restores slats to the resting position and then travels to fully open (same as the HA UI open path).

External-switch assumption. External close on sequential modes assumes a motor controller that latches on a pulse and runs to a mechanical end without stopping at the cover-closed position (common with pulse-mode relays and many off-the-shelf blind motors). If your external switch stops the motor at cover-closed instead — for example a latching switch that you release partway, or a motor that naturally halts at travel=0 — the reported tilt position will drift until the next sync. Please open an issue describing your hardware so we can support it.

Tilt Motor

For covers with a dedicated tilt motor, configure:

  • Tilt open/close/stop switches: The relay switches controlling the tilt motor (unless this is a wrapped cover entity which doesn't require extra switches).
  • Safe tilt position: The tilt moves to this position before travel starts (default: 100 = fully open).
  • Max tilt allowed position: Tilt is only allowed when the cover position is at or below this value (e.g., 0 = only when fully closed).

Calibration

The Calibration tab is used to synchronise the position tracker with the position of the physical cover and slats, and to configure the timings that allow this integration to track the physical hardware.

Current Position

Use the open/stop/close buttons to move the cover (and slats, if tilting is enabled) into a known position and then change the Current Position dropdown from Unknown to that position. The position must be specified in order to access the calibration tests further down the page.

Timing Calibration

Select the attribute that you wish to calibrate. The available attributes depend on the current position of the cover and slats, and which other attributes have already been configured. For instance, in position Fully open you can only calibrate Travel time (close) and Minimum movement time. Travel startup delay becomes configurable once Travel time (open) or Travel time (close) has been configured.

  1. Set the Current position of the cover and slats.
  2. Select the attribute you wish to configure.
  3. Read the description of what needs to be measured.
  4. Click Start.
  5. Once the cover or slats reach the position described in the description, click Finish. Alternatively, click Cancel to abort the calibration.

Calibration Attributes for Travel

Option Description Default
Travel time (close) Time in seconds for the cover to fully close
Travel time (open) Time in seconds for the cover to fully open
Travel startup delay Motor startup compensation for travel (see below) None
Endpoint run-on time Extra relay time at endpoints to reset position (Switch mode; Pulse when it sends the stop) 2.0
Min movement time Minimum movement duration - blocks shorter movements to prevent drift None

Calibration Attributes for Tilt

Option Description Default
Tilt time (close) Time in seconds to tilt the cover fully closed None
Tilt time (open) Time in seconds to tilt the cover fully open None
Tilt startup delay Motor startup compensation for tilt None

Travel/Tilt startup delay

Compensates for motor inertia by delaying position tracking after relay activation. This improves position accuracy, especially for short movements.

The problem: Motors have startup inertia. After the relay turns ON, there's a brief delay before the cover starts moving. For long movements (e.g., 30s) this is negligible, but for short movements (e.g. 0.5s) it can cause 20-30% position error that accumulates over time.

How it works:

  1. Relay turns ON immediately
  2. Waits for the configured startup delay (motor is starting up)
  3. Only then starts counting position change
  4. Can be cancelled at any time (stop or direction change)

Recommended values: 0.05 - 0.15 seconds. Can be configured separately for travel and tilt.

Endpoint Run-on Time

Position tracking is not exact and can drift over time, so the tracker resyncs itself whenever the cover is sent fully to the 0% or 100% endpoint.

Most cover motors have internal limit switches and stop themselves at the endpoints. In Toggle and wrapped-cover modes the integration therefore sends no stop command at an endpoint — it lets the motor run into its own limit. This avoids an unwanted extra movement (in Toggle mode a stop pulse on an already-stopped motor would restart it) and resyncs the tracker for free, as the motor always reaches its true endpoint. Pulse mode is configurable (see Send stop signal at endpoints above): by default it pulses its dedicated stop relay at the endpoint, which a latching controller needs, but that can be turned off for controllers that self-stop at their own limits.

In Switch mode the direction relay is latched ON for the whole movement, so it must be actively switched off at the endpoint. Because tracking is approximate, the relay is held on for an extra Endpoint Run-on Time (default 2s) so the motor reaches the physical endpoint before power is cut. This setting applies to Switch mode, and to Pulse mode when it sends the endpoint stop (it defers that stop pulse by the run-on so the motor seats against its limit first).

The same self-stop handling applies to a separate tilt motor (separate-tilt-motor mode): no stop is sent when tilt reaches its 0%/100% endpoints — the tilt motor self-stops on its own limit — except in Switch mode (which de-energizes the latched tilt relay) and in Pulse mode when Send stop signal at endpoints is on (which pulses the tilt-stop relay). Mid-tilt positions are always stopped (nothing self-stops there).

Under the sequential closes-then-tilts-closed and sequential closes-then-tilts-open tilt modes, run-on is skipped at the closed (0%) endpoint, because the motor is already driven past cover-closed for the tilt phase. Run-on still applies at the open (100%) endpoint.

Min movement time

Prevents position drift by blocking relay activations too brief to physically move the cover. Movements to 0% or 100% are always allowed. Recommended values: 0.5 - 1.5 seconds.

Services

cover_time_based.set_known_position

Manually set the internal position of a cover. Useful for correcting drift.

Field Description
entity_id The cover entity
position The position to set (0-100)

cover_time_based.set_known_tilt_position

Manually set the internal tilt position of a cover.

Field Description
entity_id The cover entity
tilt_position The tilt position to set (0-100)

cover_time_based.start_calibration

Start a calibration test to measure a timing parameter.

Field Description
entity_id The cover entity
attribute The timing parameter to calibrate
timeout Safety timeout in seconds - motor auto-stops if stop_calibration is not called
direction Direction to move (open or close). Auto-detects if not set

cover_time_based.stop_calibration

Stop an active calibration test and save the result.

Field Description
entity_id The cover entity
cancel If true, discard the results without saving

Debugging

If something isn't working as expected, you can enable debug logging to see detailed information about what the integration is doing.

Via Developer Tools

  1. Go to Developer Tools → Actions.
  2. Search for Logger: Set level and select it.
  3. Switch to YAML mode and enter:
action: logger.set_level
data:
  custom_components.cover_time_based: debug
  1. Click Perform action.
  2. Reproduce the issue — debug messages will appear in the Home Assistant log.

To turn off debug logging, repeat the steps above but change debug to info.

Via YAML

Add the following to your configuration.yaml:

logger:
  default: info
  logs:
    custom_components.cover_time_based: debug

Restart Home Assistant to apply.

Reporting Issues

If you encounter a bug or have a feature request, please open an issue on GitHub. Include debug logs if possible — they help diagnose problems much faster.

YAML configuration (deprecated)

Note: YAML configuration is deprecated and will be removed in a future version. Please use the UI method described above instead. Existing YAML configurations will continue to work, and a deprecation notice will appear in your Home Assistant repairs panel.

Show YAML configuration (deprecated)

Basic configuration with individual device settings:

cover:
  - platform: cover_time_based
    devices:
      room_rolling_shutter:
        name: Room Rolling Shutter
        open_switch_entity_id: switch.wall_switch_right
        close_switch_entity_id: switch.wall_switch_left
        travel_moves_with_tilt: false
        travelling_time_down: 23
        travelling_time_up: 25
        tilting_time_down: 2.3
        tilting_time_up: 2.7
        travel_delay_at_end: 2.0
        min_movement_time: 0.5
        travel_startup_delay: 0.1
        tilt_startup_delay: 0.08

YAML options

Name Type Requirement Description Default
name string Required Name of the created entity
open_switch_entity_id entity Required or cover_entity_id Entity ID of the switch for opening the cover. Accepts a script entity when input_mode: pulse
close_switch_entity_id entity Required or cover_entity_id Entity ID of the switch for closing the cover. Accepts a script entity when input_mode: pulse
stop_switch_entity_id entity Optional Entity ID of the switch for stopping the cover. Accepts a script entity when input_mode: pulse None
cover_entity_id entity Required or open_|close_switch_entity_id Entity ID of an existing cover entity
is_button boolean Optional Set to true for momentary pulse buttons (same as input_mode: pulse) false
travelling_time_down float Optional Time in seconds to close the cover 30
travelling_time_up float Optional Time in seconds to open the cover 30
tilting_time_down float Optional Time in seconds to tilt the cover fully closed None
tilting_time_up float Optional Time in seconds to tilt the cover fully open None
travel_moves_with_tilt boolean Optional Whether tilt movements also cause proportional travel changes false
travel_delay_at_end float Optional Additional relay time (seconds) at endpoints for position reset None
min_movement_time float Optional Minimum movement duration (seconds) - blocks shorter movements None
travel_startup_delay float Optional Motor startup time compensation (seconds) for travel movements None
tilt_startup_delay float Optional Motor startup time compensation (seconds) for tilt movements None
pulse_time float Optional Duration in seconds for button press in pulse mode 1.0
relay_reports_off boolean Optional Toggle mode: set false for pulse modules that never report their OFF true
send_endpoint_stop boolean Optional Pulse mode: set false for auto-stop controllers that reposition on a stop received while stopped true

About

Integration which allows cover control based on time.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors