Skip to content

Add TS0601 _TZE284_5m4nchbm RCBO quirk#4835

Open
alvarogl wants to merge 4 commits intozigpy:devfrom
alvarogl:feat/ts0601-tze284-5m4nchbm-rcbo
Open

Add TS0601 _TZE284_5m4nchbm RCBO quirk#4835
alvarogl wants to merge 4 commits intozigpy:devfrom
alvarogl:feat/ts0601-tze284-5m4nchbm-rcbo

Conversation

@alvarogl
Copy link
Copy Markdown

@alvarogl alvarogl commented Mar 18, 2026

Proposed change

Add support for the Tuya RCBO variant _TZE284_5m4nchbm / TS0601.

This PR adds a new v2 quirk entry in zhaquirks/tuya/ts0601_rcbo.py that maps the datapoints from a working Zigbee2MQTT converter, including the composite raw datapoints 48 and 49 used for the alarm/breaker threshold payloads. The implementation preserves the reserved bytes in those payloads when writing updated thresholds back to the device.

The PR also adds tests to verify:

  • datapoint report parsing for the new variant
  • serialized write payloads for normal enum writes and composite raw writes
  • no regressions in quirks v2 registration

Additional information

This is additive only and should not be a breaking change.

The device diagnostics used for this work show the unsupported device before this quirk is applied:

  • manufacturer: _TZE284_5m4nchbm
  • model: TS0601
  • power source: Mains
  • device type: Router
  • quirk_applied: false

Validation run locally:

  • uv run pytest tests/test_tuya_rcbo.py -q
  • uv run pytest tests/test_quirks_v2.py -q
  • uv run pre-commit run --all-files

Device diagnostics

zha-01KKZ1NW5GS19MYYHNAPKR43FC-_TZE284_5m4nchbm TS0601-bb977f4b1014ef6e4cf4f7a3f15e139a.json

Checklist

  • The changes are tested and work correctly
  • pre-commit checks pass / the code has been formatted using Black
  • Tests have been added to verify that the new code works
  • Device diagnostics data has been attached

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.78%. Comparing base (c5634ab) to head (af6c946).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #4835      +/-   ##
==========================================
+ Coverage   92.76%   92.78%   +0.02%     
==========================================
  Files         385      385              
  Lines       12818    12868      +50     
==========================================
+ Hits        11890    11940      +50     
  Misses        928      928              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TheJulianJES TheJulianJES added the Tuya Request/PR regarding a Tuya device label Mar 18, 2026
Comment on lines +779 to +788
under_voltage_threshold: Final = ZCLAttributeDef(
id=0xEF21, type=t.uint16_t, is_manufacturer_specific=True
)

dp_to_attribute: dict[int, list[DPToAttributeMapping]] = {
1: [DPToAttributeMapping(TuyaMCUCluster.ep_attribute, "state")],
17: [DPToAttributeMapping(TuyaMCUCluster.ep_attribute, "energy")],
18: [DPToAttributeMapping(TuyaMCUCluster.ep_attribute, "current")],
19: [DPToAttributeMapping(TuyaMCUCluster.ep_attribute, "power")],
20: [DPToAttributeMapping(TuyaMCUCluster.ep_attribute, "voltage")],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also have methods, like tuya_dp, in the TuyaQuirkBuilder to both create the local attributes and the mappings. Is there a reason why you've done it like this instead?
For reference, see:

def tuya_dp_attribute(
self,
dp_id: int,
attribute_name: str,
ep_attribute: str = TuyaMCUCluster.ep_attribute,
converter: Callable[[Any], Any] | None = None,
dp_converter: Callable[[Any], Any] | None = None,
endpoint_id: int | None = None,
dp_handler: str = "_dp_2_attr_update",
type: type = t.uint16_t,
access: foundation.ZCLAttributeAccess = foundation.ZCLAttributeAccess.NONE,
is_manufacturer_specific=True,
) -> Self:
"""Add an Tuya DataPoint and corresponding AttributeDef."""
self.tuya_attribute(
dp_id=dp_id,
attribute_name=attribute_name,
type=type,
access=access,
is_manufacturer_specific=is_manufacturer_specific,
)
self.tuya_dp(
dp_id=dp_id,
ep_attribute=ep_attribute,
attribute_name=attribute_name,
dp_converter=dp_converter,
converter=converter,
endpoint_id=endpoint_id,
dp_handler=dp_handler,
)
return self

and: https://github.com/zigpy/zha-device-handlers/blob/dev/tuya.md#tuya_dp_attribute.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored this to use the v2 TuyaQuirkBuilder DP helpers instead of the hand-written AttributeDefs / dp_to_attribute block.

Concretely:

  • single-DP entities now use tuya_switch, tuya_sensor, and tuya_enum
  • the composite DP48/DP49 payloads now use tuya_attribute + tuya_dp_multi with the same reserved-byte-preserving write converters as before
  • the custom TuyaRCBO2ManufCluster class is gone, so the manufacturer-cluster attributes/mappings are now declared the way tuya.md and the builder API recommend

I reran:

  • uv run pytest tests/test_tuya_rcbo.py -q
  • uv run pytest tests/test_quirks_v2.py -q
  • uv run pre-commit run --files zhaquirks/tuya/ts0601_rcbo.py tests/test_tuya_rcbo.py

Thanks, that is a better fit for this v2 quirk.

@alvarogl alvarogl requested a review from TheJulianJES March 18, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Tuya Request/PR regarding a Tuya device

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants