Skip to content

Tuya cover (category cl): state never updates because motor only pushes percent_control, not percent_state #168493

@jl1990

Description

@jl1990

The problem

On two A-OK AM45 Plus Wi-Fi tubular motors (product_id b9oa3zocv4qq47iy, category cl), HA's cover state never updates current_position is frozen at 100 regardless of physical position.
The Tuya/SmartLife app reflects the motor position correctly in real time (including when driven by the RF remote), so the motor is reporting to the cloud as expected.

Debug logs show the firmware only pushes percent_control (dpId 2) changes over MQTT. percent_state (dpId 3) is exposed in status_range but is never emitted after startup. It is stuck at 0 forever.

The DeviceCategory.CL cover description at homeassistant/components/tuya/cover.py:89 prefers PERCENT_STATE via the tuple:

current_position=(DPCode.PERCENT_STATE, DPCode.PERCENT_CONTROL)

get_default_definitionDPCodeInvertedPercentageWrapper.find_dpcode binds the entity to percent_state at setup (it exists in status_range), so live percent_control pushes are ignored for position tracking. Inverted percent_state=0 renders as HA current_position=100, state=open . Which matches the existing snapshot for fixture cl_g1cp07dsqnbdbbki (same DP shape), so the integration is behaving as coded; the coded assumption just doesn't match this firmware.

Possibly related: #156543 (state not updating after close), #159800 (reversed position), unmerged #161223 (options flow to invert).

What version of Home Assistant Core has the issue?

core-2026.4.3

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant Container

Integration causing the issue

Tuya

Link to integration documentation on our website

Tuya

Diagnostics information

In the attached diagnostics dumps (for EstorIzquierdo and EstorDerecho. product_id b9oa3zocv4qq47iy). Both show:

status_range contains: percent_state, percent_control
status:            control=stop, percent_control=100, percent_state=0,
                   work_state=opening, fault=0
HA entity state:   state=open, current_position=100
last_changed:      2026-04-18T01:03:13
last_reported:     2026-04-18T11:30:09   (10+ h of heartbeats, no state change)

debug log captured while moving the right blind via RF remote between 13:48 and 13:50 local time

tuya-cf1a7e4f547fffeba5bbc377c439ee5a-AM45 Plus Wi-Fi Derecho-6074fbc7c44569a9fe04ec01b2aaadb1.json
tuya-cf1a7e4f547fffeba5bbc377c439ee5a-AM45 Plus Wi-Fi Izquierdo-f994c4879f5fe897bb501762be5e9b68.json

tuya-am45-debug.log

Example YAML snippet

Anything in the logs that might be useful for us?

Moving one blind with the RF remote produces only `control` and `percent_control` updates. Never `percent_state`:


Received update for device bfb511584971be8c8cfsby: {... percent_control: 100, percent_state: 0 ...}  (updated properties: ['control'],          dp_timestamps: {'control': 1776512980822})
Received update for device bfb511584971be8c8cfsby: {... percent_control: 99,  percent_state: 0 ...}  (updated properties: ['percent_control'], dp_timestamps: {'percent_control': 1776512980894})
Received update for device bfb511584971be8c8cfsby: {... percent_control: 99,  percent_state: 0 ...}  (updated properties: ['control'],          dp_timestamps: {'control': 1776512987701})
Received update for device bfb511584971be8c8cfsby: {... percent_control: 75,  percent_state: 0 ...}  (updated properties: ['percent_control'], dp_timestamps: {'percent_control': 1776512987785})


Raw MQTT payloads confirm `dpId:3` never appears across the entire debug capture (zero occurrences); only `dpId:1` (control) and `dpId:2` (percent_control) are pushed.

Additional information

Suggested direction: for DeviceCategory.CL entities where percent_state is present in status_range but never reported via MQTT, the entity should either (a) fall back to percent_control, or (b) allow per-device override. A blanket flip of the tuple would break motors that do report percent_state reliably (e.g. snapshot cl_zah67ekd expects position derived from percent_state=52, not percent_control=100), so a naïve reorder isn't safe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions