Royal Gardineer garden water valve

No, I am certain that the values are not correct. I mentioned it some weeks ago already.
Any help/collaboration on getting battery and/or consumption values right is highly appreciated

Ah sorry, I overlooked that.

I managed to get the battery sensor to work with the following quirk, in a new class related to my device. You may need to change the model id for yours. Not convinced about the accuracy of the reading though.

"""Collection of Tuya Valve devices e.g. water valves, gas valve etc."""
from typing import Dict

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import Basic, Groups, Identify, OnOff, Ota, Scenes, Time, PowerConfiguration
from zigpy.zcl.clusters.smartenergy import Metering

from zhaquirks import DoublingPowerConfigurationCluster
from zhaquirks import Bus
from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import (
    TuyaLocalCluster, 
    TuyaPowerConfigurationCluster2AA,
)
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    EnchantedDevice,
    TuyaMCUCluster,
    TuyaOnOff,
    TuyaOnOffNM,
    TuyaPowerConfigurationCluster,
)

class HiHomeValveManufCluster(TuyaMCUCluster):
    """On/Off Tuya cluster with extra device attributes."""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            0xEF01: ("time_left", t.uint32_t, True),
            0xEF02: ("state", t.enum8, True),
            0xEF03: ("last_valve_open_duration", t.uint32_t, True),
            0xEF04: ("dp_6", t.uint32_t, True),
        }
    )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            TuyaOnOff.ep_attribute,
            "on_off",
        ),
        5: DPToAttributeMapping(
            TuyaValveWaterConsumed.ep_attribute,
            "current_summ_delivered",
        ),
        6: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_6",
        ),
        7: DPToAttributeMapping(
            DoublingPowerConfigurationCluster.ep_attribute,
            "battery_percentage_remaining",
        ),
        11: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "time_left",
        ),
        12: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "state",
        ),
        15: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "last_valve_open_duration",
        )
    }

    data_point_handlers = {
        1: "_dp_2_attr_update",
        5: "_dp_2_attr_update",
        6: "_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 HiHomeValve(CustomDevice):
    """HiHome valve device."""
    
    def __init__(self, *args, **kwargs):
        """Init device."""
        self.battery_bus = Bus()
        super().__init__(*args, **kwargs)
    
    signature = {
        MODELS_INFO: [("_TZE200_akjefhj5", "TS0601")],
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    HiHomeValveManufCluster.cluster_id
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaOnOff,
                    TuyaValveWaterConsumed,
                    TuyaPowerConfigurationCluster2AA,
                    HiHomeValveManufCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }

The core idea was to replace the DoublingPowerConfigurationCluster with a TuyaPowerConfigurationCluster2AA.

Edit: I have the feeling that these valves are not very good.

1 Like

Regarding the consumption data, I found this:

Logger: homeassistant.components.sensor
Source: components/sensor/init.py:650
Integration: Sensor (documentation, issues)
First occurred: 19. Juni 2023 um 21:01:23 (1 occurrences)
Last logged: 19. Juni 2023 um 21:01:23

Entity sensor.wasserhahn_summation_delivered (<class ‘homeassistant.components.zha.sensor.SmartEnergySummation’>) is using native unit of measurement ‘L’ which is not a valid unit for the device class (‘energy’) it is using; expected one of [‘kWh’, ‘MJ’, ‘MWh’, ‘GJ’, ‘Wh’]; Please update your configuration if your entity is manually configured, otherwise create a bug report at Issues · home-assistant/core · GitHub

in the logs. Do you have that as well?

Yes, I see similar messages.
And I don’t know why sensor.XXX_summation_delivered is treated as homeassistant.components.zha.sensor.SmartEnergySummation

Has anyone noticed a reduction in flow rate using this device? I had a GIEX QT06 fail on me recently so I replaced it with one of these and my sprinkler only reaches about 75% of the distance it did when on the QT06.

… there are still some occurrences of DoublingPowerConfigurationCluster
did you leave them on purpose?

Cheers

No, just overlooked. The one

should probably be replaced, but I can’t try right now. Will continue on the weekend, currently traveling …

1 Like

Yes, that’s a good question. Not sure either. Could be that there is no proper category for water consumption?

This valve model sold as multiple brands, I own two from SASWELL, and there are some from RTX.
It seems some models lack the water consumed datapoint, that may explain why it remains at 0 for some users. And it appears that some valves reports the consumed water in fl.oz while mine reports in ⅒ of liters. The converter needs to take this into account.

I built my own quirks for ZHA, with working switch and consumed water, but battery value started to be twice the expected value.

I ended up with adding a second ZigBee controller and connect the valve to it via ZigBee2MQTT instead, as it is much more flexible in exposing entities.
I then reused existing converter for the RTX valve and fixed several issues.
Now everything is working fine except a time shift of 6 hours for valve internal timers (but this time shift is also present in Tuya Smart Life app, is it an issue with my valve or common bug for all valves? I don’t know).

I may soon make a pull request to officially add support for the SASWELL valve to Z2M.

@adrien.b would you mind sharing your latest ZHA quirk? Perhaps we could use it to improve ours …

Click on the first link I provided, it’s a post on GitHub with the updated file in the collapsible part at the end of my message.

Hello, guys!

Thanks a lot for your work!
Yesterday I tried my valve to get working and used the quirks from @der-burn . This provided an on/off function. I also replaced DoublingPowerConfigurationCluster with TuyaPowerConfigurationCluster2AA from @nilsreiter configuration. But then had the problem that the battery status was provided as 50% (they are brand new batteries, the device had only been switched on once, so it should be 100%).
It looked to me like the value of both batteries had been added together and then divided by two.
So I removed the 2AA from TuyaPowerConfigurationCluster2AA and now I get the 100% back.

I don’t know if it’s correct, because now I don’t have a dropdown with attributes in the “battery pop-up” (there were two values in it before).

Maybe someone can use this as an idea for a better fix.

Hope I was able to contribute something :slight_smile:

Here’s my full file:

"""Collection of Tuya Valve devices e.g. water valves, gas valve etc."""
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, Identify, OnOff, Ota, Scenes, Time
from zigpy.zcl.clusters.smartenergy import Metering

from zhaquirks import DoublingPowerConfigurationCluster  
from zhaquirks import Bus
from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import (
    TuyaLocalCluster,
    TuyaPowerConfigurationCluster,
)
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    EnchantedDevice,
#    TuyaDPType,
    TuyaMCUCluster,
    TuyaOnOff,
    TuyaPowerConfigurationCluster,
)


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: ("time_left", t.uint32_t, True),
            0xEF02: ("state", t.enum8, True),
            0xEF03: ("last_valve_open_duration", t.uint32_t, True),
            0xEF04: ("dp_6", 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,
        ),
        6: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_6",
          #  TuyaDPType.VALUE,
        ),
        7: DPToAttributeMapping(
             TuyaPowerConfigurationCluster.ep_attribute,
             # 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",
        6: "_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."""
    
    def __init__(self, *args, **kwargs):
        """Init device."""
        self.battery_bus = Bus()
        super().__init__(*args, **kwargs)


    signature = {
        MODELS_INFO: [("_TZE200_2wg5qrjy", "TS0601")],
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184], output_clusters=[25, 10])
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.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,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaOnOff,
                    TuyaValveWaterConsumed,
                    TuyaPowerConfigurationCluster,
                    # DoublingPowerConfigurationCluster,
                    TuyaValveManufCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }


1 Like

Thx for this work, for the quirks and the community :slight_smile:

sinsecond’s hack does not work for me, than i’ve only 50% on my valves, uncommented the entry than i’ve 100%.

But the Valves are switch off after 10min, it is a default setting.
How to connect to the Valves with the Elesium App to change this setting w/o an additional ZHA Gateway?

@RKsHAss which entry did you uncomment?
Would you mind sharing the complete file?
and: does summation work for you?

and I’m sorry, don’t know how to change the max duration of 10min.

image
but after playing around with some DDF Files and Deconz that will not work anymore (4me)

I raised a bug in github:

@RKsHAss sorry for reaching out late. I only look into here sporadically. I „fixed“ the 10 minutes issue with an HA automation which sets a new default time whenever HA detects a valve close event.

alias: water_valve_reset
description: ""
trigger:
  - platform: state
    entity_id:
      - switch.valve_1_on_off
      - switch.valve_2_on_off
    to: "off"
condition: []
action:
  - service: zha.set_zigbee_cluster_attribute
    data:
      ieee: |
        {% set valves = 
          { 'switch.valve_1_on_off': '94:de:b8:ff:xx:xx:xx:xx',
            'switch.valve_2_on_off': '94:de:b8:ff:xx:xx:xx:xx' } %}
        {{ valves[trigger.entity_id] }}
      endpoint_id: 1
      cluster_id: 61184
      attribute: 61185
      value: 3600
mode: single

I didn’t want to fire up the vendors app, foremost as I don’t have another gateway… would be curious how that looks like. Mainly as I don’t get any consumption values as already shared above.
Cheers!

1 Like

thanx, i’m just fighting threw gateways, deconz, user permission, conbee …
But if my beer is empty i will go th esy way :slight_smile:

as expected i didn’t get it cause i can’t find the json files on my Pi4.
I might to dive deeper , but not today.
I schduled now 6*10minutes for the valves :slight_smile: yes, too easy.
And now i try to understand your solution but i do not understand where i found the IEEE?

The IEEE is in the Zigbee Info:
2023-07-16_08h39_53

1 Like