[Device Support Request] SASWELL SAS980SWT-7-Z01 (_TZE200_akjefhj5, TS0601) Smart Irrigation Valve
See original GitHub issueDiscussed in https://github.com/zigpy/zha-device-handlers/discussions/1660
<div type='discussions-op-text'>Originally posted by ScratMan July 25, 2022 Hello,
I need some help to develop the quirk for the SASWELL SAS980SWT-7-Z01 irrigation timer valve, with the vendor ID _TZE200_akjefhj5 and model TS0601.

https://www.saswell.com/smart-irrigation-wifi-water-timer-sas980swt-7-z01_p147.html
I own two units, and I can control it through Tuya SmartLife app, but I’d like to get rid of Tuya app and use Home Assistant instead through ZHA integration.
I’ve seen that this valve is already available with different vendors (RTX ZVG1 for example), and I could find in ZHA that there is a quirk that looks very similar to the result the scan of my valves but with different vendor ID :
MODELS_INFO: [("_TZE200_81isopgh", "TS0601")], https://github.com/zigpy/zha-device-handlers/issues/1556
This valve exists in the ts0601_valve.py file in ZHA device handlers, but unfortunately it seems it doesn’t fully matches my valve’s description, changing only the vendor ID didn’t work, and I had to make some modifications based on some extractions from Tuya logs.
I could grab the following data from my valves :
{
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>,
complex_descriptor_available=0, user_descriptor_available=0, reserved=0,
aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>,
mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>,
manufacturer_code=4098, maximum_buffer_size=82,
maximum_incoming_transfer_size=82, server_mask=11264,
maximum_outgoing_transfer_size=82,
descriptor_capability_field=<DescriptorCapability.NONE: 0>,
*allocate_address=True, *is_alternate_pan_coordinator=False,
*is_coordinator=False, *is_end_device=True, *is_full_function_device=False,
*is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False,
*is_security_capable=False)",
"endpoints": {
"1": {
"profile_id": 260,
"device_type": "0x0051",
"in_clusters": [
"0x0000", # Basic
"0x0001", # Power configuration
"0x0004", # Groups
"0x0005", # Scenes
"0x0006", # OnOff
"0x0702", # Smart Energy: Metering
"0xef00" # TuyaNewManufCluster
],
"out_clusters": [
"0x000a",
"0x0019"
]
}
},
"manufacturer": "_TZE200_akjefhj5",
"model": "TS0601",
"class": "ts0601_TZE200_akjefhj5_valve.TuyaValve"
}
In the tuya logs I could extract the DP codes using Chrome developers tool, but unfortunately, it doesn’t indicates in which cluster the data are available (in bold those showing data received from valves in Tuya developers platform):
- 1: “switch”,
- 3: “flow_state”, # No data in tuya logs
- 4: “failure_to_report”, # No data in tuya logs
- 5: “water_once”, # last irrigation volume
- 7: “battery”, # indicates the level of the battery in % in Tuya logs
- 8: “battery_state”, # No data in tuya logs
- 9: “accumulated_usage_time”, # No data in tuya logs
- 10: “weather_delay”, # No data in tuya logs
- 11: “irrigation_time”, # Corresponds to remaining time
- 12: “work_state”, # idle or manual
- 13: “smart_weather”, # No data in tuya logs
- 14: “smart_weather_switch”, # No data in tuya logs
- 15: “once_using_time”, # last irrigation duration
- 16: “cycle_irrigation”, # No data in tuya logs
- 17: “normal_timer”, # No data in tuya logs
and in the debug tool from the Tuya developers platform, I could get the data types

I made some trials copying the TuyaValve class from ts0601_valve.py and made some changes, on the
0xEF0B: ("time_left", t.uint32_t, True), # changed from 0xEF01, as irrigation_time is at data point 11.
0xEF0C: ("state", t.enum8, True), # changed from 0xEF02, corresponds to the work_state data point 12
0xEF0F: ("last_valve_open_duration", t.uint32_t, True), # changed from 0xEF03, matches the once_using_time on DP 15
The full file
"""Tuya Valve."""
from typing import Dict
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time, OnOff, PowerConfiguration
from zigpy.zcl.clusters.smartenergy import Metering
from zhaquirks import DoublingPowerConfigurationCluster
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaDPType,
TuyaMCUCluster,
TuyaOnOff,
)
class TuyaValveWaterConsumed(Metering, TuyaLocalCluster):
"""Tuya Valve Water consumed cluster."""
VOLUME_LITERS = 0x0007
"""Setting unit of measurement."""
_CONSTANT_ATTRIBUTES = {0x0300: VOLUME_LITERS}
class TuyaValveManufCluster(TuyaMCUCluster):
"""On/Off Tuya cluster with extra device attributes."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
# 0xEF01: ("on_off", t.uint8_t, True),
# 0xEF05: ("current_summ_delivered", t.Single, True),
# 0xEF07: ("battery_percentage_remaining", t.uint8_t, True),
0xEF0B: ("time_left", t.uint32_t, True),
0xEF0C: ("state", t.enum8, True),
0xEF0F: ("last_valve_open_duration", t.uint32_t, True),
}
)
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOnOff.ep_attribute,
"on_off",
dp_type=TuyaDPType.BOOL,
),
5: DPToAttributeMapping(
TuyaValveWaterConsumed.ep_attribute,
"current_summ_delivered",
TuyaDPType.VALUE,
),
7: DPToAttributeMapping(
DoublingPowerConfigurationCluster.ep_attribute,
"battery_percentage_remaining",
TuyaDPType.VALUE,
),
11: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"time_left",
TuyaDPType.VALUE,
),
12: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"state",
TuyaDPType.VALUE,
),
15: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"last_valve_open_duration",
TuyaDPType.VALUE,
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
5: "_dp_2_attr_update",
7: "_dp_2_attr_update",
11: "_dp_2_attr_update",
12: "_dp_2_attr_update",
15: "_dp_2_attr_update",
}
class TuyaValve(CustomDevice):
"""Tuya valve device."""
signature = {
MODELS_INFO: [("_TZE200_akjefhj5", "TS0601")],
# SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=81, device_version=1,
# input_clusters=[0, 1, 4, 5, 6, 1794, 61184], output_clusters=[25, 10])
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
# PowerConfiguration.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
# OnOff.cluster_id,
TuyaValveManufCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
}
},
}
replacement = {
ENDPOINTS: {
1: {
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
# PowerConfiguration.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaOnOff,
TuyaValveWaterConsumed, # attr 0 = last volume delivered
DoublingPowerConfigurationCluster,
# OnOff.cluster_id,
TuyaValveManufCluster,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
}
}
}
With the file as shown above I can get the valve in HA as below :

And regarding what works and what doesn’t work :
- I can switch on and off the valve using the on_off switch entity.
- The battery level doesn’t work and reports unknown.
- The
smartenergy_meteringsensor is supposed to report the volume of water during the last opening of the valve, but it reports garbage. I could fill 5 liters in a bucket, and it indicated 114, then I added 5 more liters and it said 55 ; while it said 615 and 543 when I added some water in my pool (around 150/160 liters both time, in 30mn). - I can read the time left while the valve is open using the cluster management tool in HA with
TuyaValveManufCluster:

- I can also write the duration of next irrigation while valve is off, using the
time_leftattribute by writing the value in the field and using 1 in the replacement code before performing the write. Once the new time value written, it remains set up when reading the attribute, and this value is used when switching the valve on. Once the valve is switched off (either manually or after timer end), the value is then reset to 600 seconds. - The last valve open duration reported in clusters manager works correctly.
- The state of the valve is reported correctly in clusters manager (1 = on, 2 = off)
The doubling power management cluster doesn’t seem to have the correct battery level configured, but I can’t figure where this data is located in the clusters available in the data from the valve to change it in the quirk.
Could someone please help me to understand how to find the correct data point for battery level and water volume consumed and how to make the attributes be reported as sensor entities in HA ? When looking at the python code from the quirks, it looks really abstract to me, despite my knowledge in python. The behavior of the quirk looks strange, when I try to enable the clusters 1 (power configuration) and 6 (on_off) it breaks the quirk, and the modified clusters like TuyaValveManufCluster disappear from the interface. But it seems the PowerConfiguration cluster should be closer to the one used in the valve, or am I wrong ?
Thanks for your help.</div>
Issue Analytics
- State:
- Created a year ago
- Comments:6

Top Related StackOverflow Question
Water metering
For the water metering, we are using the
Meteringcluster. And (in your implementation) we are reporting to thecurrent_summ_deliveredattribute.It seems that device is reporting the
water_oncevalue, but depending on how it is doing the report, it may not be calculating correctly. If the device reports the value several times, it could be that we are adding the same value multiple times. To better understand the behavior of the device and the meaning of the reports, once again, it is best to go to the source, which is the ZHA logs. There we would see how the device is reporting attributes and its raw values.@ScratMan
No, I just added my device signature to your code and restarted HA:
The valve on/off (Wasserventil) and battery/power level is enough for me for now.