question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Device Support Request] SASWELL SAS980SWT-7-Z01 (_TZE200_akjefhj5, TS0601) Smart Irrigation Valve

See original GitHub issue

Discussed 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. image

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

image

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 :

image

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_metering sensor 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 : image image
  • I can also write the duration of next irrigation while valve is off, using the time_left attribute 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:open
  • Created a year ago
  • Comments:6

github_iconTop GitHub Comments

1reaction
javicallecommented, Jul 30, 2022

Water metering

For the water metering, we are using the Metering cluster. And (in your implementation) we are reporting to the current_summ_delivered attribute.

It seems that device is reporting the water_once value, 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.

0reactions
dieneusercommented, Aug 8, 2022

@ScratMan

Did you manage to get the relationship between the “water_once” data point bytes (dp 5) and the real water volume on your valve ?

No, I just added my device signature to your code and restarted HA: image

The valve on/off (Wasserventil) and battery/power level is enough for me for now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

[Device Support Request] Saswell Tuya Thremostat Family ...
It seems like they only open the valve if the set-point is >1 degree over the TRV measured temperature, but I don't know...
Read more >
Saswell smart Irrigation,Best Smart Sprinkler Controller device ...
Saswell smart Irrigation,Best Smart Sprinkler Controller device installation network video.
Read more >
Zigbee garden irrigation device ( Solenoide valve ) not fully ...
[Device Support Request] SASWELL SAS980SWT-7-Z01 (_TZE200_akjefhj5, TS0601) Smart Irrigation Valve · Issue #1668 · zigpy/zha-device-handlers ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found