Skip to content

Position Verification

Jason Rhubottom edited this page Jun 3, 2026 · 4 revisions

Position Verification

Adaptive Cover Pro runs a background reconciliation loop that checks every configured cover once per minute and resends the last target position if the cover hasn't arrived. This is the mechanism that makes the integration resilient to dropped commands, Z-Wave/Zigbee flakiness, and momentary motor stalls; it's also the mechanism that decides when to stop retrying so the integration doesn't fight a physically blocked cover forever.

How the loop works

  1. Every 1 minute (POSITION_CHECK_INTERVAL_MINUTES = 1, not user-configurable), the loop iterates every entity currently in target_call (the set of positions the integration has asked for).
  2. For each entity it reads the current reported position and compares it to the target using the configurable Position Match Tolerance (position_tolerance, default 3%, range 0–20% β€” see Automation configuration).
  3. If within tolerance β†’ the target is considered reached, retry counter resets, loop moves on.
  4. If outside tolerance β†’ retry counter increments and the same target is resent (unless any of the gates below block it).

The same tolerance also gates the main command path. Before sending any set_cover_position, the integration treats a cover already within Position Match Tolerance of the requested position as a no-op and skips the command. This is a deliberate dead-band: some motors settle a percent or two short of fully open/closed (reporting 98% when commanded to 100%) and, without it, the integration would resend the same target every cycle β€” producing the audible relay clicking some covers make. Raising the tolerance widens the dead-band so those covers stop being re-commanded. The dead-band applies to all callers, including force and weather-safety overrides: if the cover is already within tolerance of a safety target, no command is sent. The one exception is the sun entering/leaving validity, which always re-confirms position regardless of tolerance.

What blocks a retry

Condition Behaviour
wait_for_target is still true and < 120 s since last send Skip (cover is still expected to be moving)
Entity is in the manual-override set Skip (don't fight the user)
Automatic Control OFF and entity is not a safety target Skip
Outside the configured time window and entity is not a safety target Skip
Integration Enabled OFF Skip ALL entities (safety and non-safety)
Retry count has reached max_retries = 3 Log a warning once, add entity to "gave up" set, stop retrying until a new target is set

Worst-case retry sequence

With max_retries = 3 and a 1-minute interval, a cover that refuses to reach its target will see:

  • t+0 s: initial send
  • t+60 s: retry 1
  • t+120 s: retry 2
  • t+180 s: retry 3; the integration logs a warning and backs off

So the integration tries for ~3 minutes maximum before giving up on a stuck target. The retry count resumes when a new target is calculated (e.g. the sun moves, a new handler fires). No motor hammering, no infinite loops.

Safety targets (from Force Override or Weather Override) are tracked separately: reconciliation continues to resend them even when Automatic Control is OFF or the time window has closed, but they too are halted by Integration Enabled OFF.

Diagnostic visibility

The {device}_position_verification and {device}_retry_count diagnostic sensors expose the current retry count per entity, the last reconciliation timestamp, and whether the integration has given up on any target. Use these when troubleshooting a cover that isn't reaching its commanded position.

Clone this wiki locally