Thx, but i have no Zigbee Info? My Valve is connected via Conbee/Deconz.
So i should switch back to Sonoff ZHA.
Now switched to ZHA but does not work, i’m assuming your Cluster ID will not work on my ZHA?
Installed ZHA Toolkit and got this values
"0x0006": {
"cluster_id": "0x0006",
"title": "On/Off",
"name": "on_off",
"attributes": {},
"commands_received": {},
"commands_generated": {}
},
looks different to yours
Short question in between - I read somewhere that the water pressure does not go well through Royal Gardineer Zigbee valve - does someone use the valve with a rain water irrigation from a higher point? Got a water barrel on the balcony that should water plants below (2 meter difference). Will the pressure be enough?
I used last year the Parkside _TZE200_htnnfasr version of this Tuya smart water valve, it worked great. This year, after connecting it to the ZHA network, it just doesn’t respond at all. It seems like it doesn’t get a good answer from the zigbee network as recognised or joined or what, because it flashes for another few minutes (pairing mode), but it appears in Home Assistant including all the control options, however nothing gets synced afterwards.
I used it last year without any special quirks or so and had no problem, this year after noticing it won’t answer to anything I deleted and then reconnected it to the ZHA network, without any result, than loaded the Quirk and try again, but sadly same result, it shows up, but won’t respond.
Anyone had a similar error or have an idea, what I could do? (Changed the batteries, removed the valve completely, than added it again multiple times even with pressing the button every now and then during connection…)
Thanks for this, this saved me a lot of time! This worked for me with my ieee address. First, I did not get why one must set this every time the valve is closed again. But yeah, the value gets reset to 600 seconds every time the valve is closed again.
I didn’t notice any issues, and the watering line jumps up to two meters. But my valve is directly connected to the main water supply.
Does the sensor summation_delivered
should count the overall water consumption?
The sensor only shows values while the valve is open. I would like to get an idea how many water passed through the valve. Any suggestions?
This sensor never returned anything for me.
Just fyi - the valve does not work with low water pressure. Just returned it a few days ago. 2-3 meters in hight difference.
On the main line it worked, but also did not return any values (bool, water flow etc.)
Useless IMO at the moment.
Hi! Just bought this valve and thanks to this thread I managed to make it work in zha.
I’m sharing here my quirk using v2 api:
"""Royal Gardineer Tuya Water Valve device."""
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.quirks.v2 import add_to_registry_v2
from zigpy.quirks.v2.homeassistant import EntityPlatform, UnitOfTime, EntityType
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.smartenergy import Metering
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaMCUCluster,
TuyaOnOff,
TuyaPowerConfigurationCluster,
)
# Timer time left to auto-off.
TIMER_TIME_LEFT_ATTR_ID = 0xEF01
TIMER_TIME_LEFT_ATTR_NAME = "timer_time_left"
# Timer state.
TIMER_STATE_ATTR_ID = 0xEF02
TIMER_STATE_ATTR_NAME = "timer_state"
# Last valve open duration.
LAST_VALVE_OPEN_DURATION_ATTR_ID = 0xEF03
LAST_VALVE_OPEN_DURATION_ATTR_NAME = "last_valve_open_duration"
# Weather delay.
WEATHER_DELAY_ATTR_ID = 0xEF04
WEATHER_DELAY_ATTR_NAME = "weather_delay"
class RoyalGardineerWeatherDelay(t.enum8):
"""Royal Gardineer weather delay enum."""
Disabled = 0x00
Delayed_24h = 0x01
Delayed_48h = 0x02
Delayed_72h = 0x03
class RoyalGardineerTimerState(t.enum8):
"""Royal Gardineer timer state enum."""
Disabled = 0x00
Active = 0x01
Enabled = 0x02
class RoyalGardineerValveWaterConsumed(Metering, TuyaLocalCluster):
"""Royal Gardineer Tuya Water Valve - water consumed cluster."""
UNIT_VOLUME_LITERS = 0x0007
TYPE_WATER_METERING = 0x02
"""Setting unit of measurement."""
_CONSTANT_ATTRIBUTES = {
0x0300: UNIT_VOLUME_LITERS,
0x0306: TYPE_WATER_METERING,
}
class RoyalGardineerValveManufCluster(TuyaMCUCluster):
"""On/Off Royal Gardineer Tuya cluster with extra device attributes."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
TIMER_TIME_LEFT_ATTR_ID: (TIMER_TIME_LEFT_ATTR_NAME, t.uint32_t, True),
TIMER_STATE_ATTR_ID: (TIMER_STATE_ATTR_NAME, RoyalGardineerTimerState, True),
LAST_VALVE_OPEN_DURATION_ATTR_ID: (LAST_VALVE_OPEN_DURATION_ATTR_NAME, t.uint32_t, True),
WEATHER_DELAY_ATTR_ID: (WEATHER_DELAY_ATTR_NAME, RoyalGardineerWeatherDelay, True)
}
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOnOff.ep_attribute,
"on_off",
),
5: DPToAttributeMapping(
RoyalGardineerValveWaterConsumed.ep_attribute,
"current_summ_delivered",
lambda x: x // 10,
),
7: DPToAttributeMapping(
TuyaPowerConfigurationCluster.ep_attribute,
"battery_percentage_remaining",
),
10: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"weather_delay",
lambda x: RoyalGardineerWeatherDelay(x),
),
11: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"timer_time_left",
lambda x: x // 60,
lambda x: x * 60,
),
12: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"timer_state",
lambda x: RoyalGardineerTimerState(x),
),
15: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"last_valve_open_duration",
lambda x: x // 60,
),
#16 - cycle timer,
#17 - normal timer,
}
data_point_handlers = {
1: "_dp_2_attr_update",
5: "_dp_2_attr_update",
7: "_dp_2_attr_update",
10: "_dp_2_attr_update",
11: "_dp_2_attr_update",
12: "_dp_2_attr_update",
15: "_dp_2_attr_update",
}
(
add_to_registry_v2("_TZE200_2wg5qrjy", "TS0601")
.replaces(RoyalGardineerValveManufCluster)
.adds(TuyaOnOff)
.adds(RoyalGardineerValveWaterConsumed)
.adds(TuyaPowerConfigurationCluster)
# Timer time left/remaining.
.number(
TIMER_TIME_LEFT_ATTR_NAME,
RoyalGardineerValveManufCluster.cluster_id,
min_value=1,
max_value=600,
step=1,
unit=UnitOfTime.MINUTES,
translation_key="timer_time_left",
)
# Weather delay.
.enum(
WEATHER_DELAY_ATTR_NAME,
RoyalGardineerWeatherDelay,
RoyalGardineerValveManufCluster.cluster_id,
translation_key="weather_delay",
)
# Timer state - read-only.
.enum(
TIMER_STATE_ATTR_NAME,
RoyalGardineerTimerState,
RoyalGardineerValveManufCluster.cluster_id,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.DIAGNOSTIC,
translation_key="timer_state",
)
# Last valve open duration - read-only.
.sensor(
LAST_VALVE_OPEN_DURATION_ATTR_NAME,
RoyalGardineerValveManufCluster.cluster_id,
entity_type=EntityType.DIAGNOSTIC,
unit=UnitOfTime.MINUTES,
translation_key="last_valve_open_duration",
)
)
This will add:
- 2 sensors to the diagnostics section, one for the last valve open duration (in minutes) and one for the timer state.
- 1 number editor for the timer time left/remaining (in minutes).
- 1 combobox with values for the weather delay (pause).
This presents the water consumption in liters, assuming my variant reports it in deciliters.
Unfortunately, the new entity names and their respective display names must be updated manually due to lack of support in ZHA quirks v2 API (or at least I haven’t yet figured it out).
hello all,
just for a check, my valve (_TZE200_akjefhj5) is working for what concerns toggling and battery and times and bla bla bla, but i can’t see any flow meter result. So could you confirm the data model is correct?
I just got this for the flowmeter sensor, i’m gonna fight Aliexpress on this…
My “current_summ_delivered” is fixed to zero while watering and after watering, just 0.
"0x0702": {
"endpoint_attribute": "smartenergy_metering",
"attributes": {
"0x0000": {
"attribute_name": "current_summ_delivered",
"value": 0
},
"0x0306": {
"attribute_name": "metering_device_type",
"value": 2
},
"0x0300": {
"attribute_name": "unit_of_measure",
"value": 7
}
},
"unsupported_attributes": {}
},
Edit: what is “timer mode” intended to do?
Thanks for sharing @mrrstux. I wonder what steps are required to integrate this or another solution from this thread into home assistant, so that many can benefit from the ZHA integration without the need continuously monitor this thread for new versions of this code.
A MR can be created on GitHub - zigpy/zha-device-handlers: ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.. If it gets accepted and merged, it will end-up into zha and then home-assistant.
This broke for me with 2024.8.x. Do you already fixed that for you? I used the version from @sinsecond now instead, which seem to work.
@Tribune Here is the version adapted for 2024.8.x (quirks 2 API was changed inside zigpy):
"""Royal Gardineer Tuya Water Valve device."""
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.quirks.v2 import QuirkBuilder
from zigpy.quirks.v2.homeassistant import EntityPlatform, UnitOfTime, EntityType
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.smartenergy import Metering
from zhaquirks.tuya import TuyaLocalCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaMCUCluster,
TuyaOnOff,
TuyaPowerConfigurationCluster,
)
# Timer time left to auto-off.
TIMER_TIME_LEFT_ATTR_ID = 0xEF01
TIMER_TIME_LEFT_ATTR_NAME = "timer_time_left"
# Timer state.
TIMER_STATE_ATTR_ID = 0xEF02
TIMER_STATE_ATTR_NAME = "timer_state"
# Last valve open duration.
LAST_VALVE_OPEN_DURATION_ATTR_ID = 0xEF03
LAST_VALVE_OPEN_DURATION_ATTR_NAME = "last_valve_open_duration"
# Weather delay.
WEATHER_DELAY_ATTR_ID = 0xEF04
WEATHER_DELAY_ATTR_NAME = "weather_delay"
class RoyalGardineerWeatherDelay(t.enum8):
"""Royal Gardineer weather delay enum."""
Disabled = 0x00
Delayed_24h = 0x01
Delayed_48h = 0x02
Delayed_72h = 0x03
class RoyalGardineerTimerState(t.enum8):
"""Royal Gardineer timer state enum."""
Disabled = 0x00
Active = 0x01
Enabled = 0x02
class RoyalGardineerValveWaterConsumed(Metering, TuyaLocalCluster):
"""Royal Gardineer Tuya Water Valve - water consumed cluster."""
UNIT_VOLUME_LITERS = 0x0007
TYPE_WATER_METERING = 0x02
"""Setting unit of measurement."""
_CONSTANT_ATTRIBUTES = {
0x0300: UNIT_VOLUME_LITERS,
0x0306: TYPE_WATER_METERING,
}
class RoyalGardineerValveManufCluster(TuyaMCUCluster):
"""On/Off Royal Gardineer Tuya cluster with extra device attributes."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
TIMER_TIME_LEFT_ATTR_ID: (TIMER_TIME_LEFT_ATTR_NAME, t.uint32_t, True),
TIMER_STATE_ATTR_ID: (TIMER_STATE_ATTR_NAME, RoyalGardineerTimerState, True),
LAST_VALVE_OPEN_DURATION_ATTR_ID: (LAST_VALVE_OPEN_DURATION_ATTR_NAME, t.uint32_t, True),
WEATHER_DELAY_ATTR_ID: (WEATHER_DELAY_ATTR_NAME, RoyalGardineerWeatherDelay, True)
}
)
dp_to_attribute: dict[int, DPToAttributeMapping] = {
1: DPToAttributeMapping(
TuyaOnOff.ep_attribute,
"on_off",
),
5: DPToAttributeMapping(
RoyalGardineerValveWaterConsumed.ep_attribute,
"current_summ_delivered",
lambda x: x // 10,
),
7: DPToAttributeMapping(
TuyaPowerConfigurationCluster.ep_attribute,
"battery_percentage_remaining",
),
10: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"weather_delay",
lambda x: RoyalGardineerWeatherDelay(x),
),
11: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"timer_time_left",
lambda x: x // 60,
lambda x: x * 60,
),
12: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"timer_state",
lambda x: RoyalGardineerTimerState(x),
),
15: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"last_valve_open_duration",
lambda x: x // 60,
),
#16 - cycle timer,
#17 - normal timer,
}
data_point_handlers = {
1: "_dp_2_attr_update",
5: "_dp_2_attr_update",
7: "_dp_2_attr_update",
10: "_dp_2_attr_update",
11: "_dp_2_attr_update",
12: "_dp_2_attr_update",
15: "_dp_2_attr_update",
}
(
QuirkBuilder("_TZE200_2wg5qrjy", "TS0601")
.replaces(RoyalGardineerValveManufCluster)
.adds(TuyaOnOff)
.adds(RoyalGardineerValveWaterConsumed)
.adds(TuyaPowerConfigurationCluster)
# Timer time left/remaining.
.number(
TIMER_TIME_LEFT_ATTR_NAME,
RoyalGardineerValveManufCluster.cluster_id,
min_value=1,
max_value=600,
step=1,
unit=UnitOfTime.MINUTES,
translation_key="timer_time_left",
)
# Weather delay.
.enum(
WEATHER_DELAY_ATTR_NAME,
RoyalGardineerWeatherDelay,
RoyalGardineerValveManufCluster.cluster_id,
translation_key="weather_delay",
)
# Timer state - read-only.
.enum(
TIMER_STATE_ATTR_NAME,
RoyalGardineerTimerState,
RoyalGardineerValveManufCluster.cluster_id,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.DIAGNOSTIC,
translation_key="timer_state",
)
# Last valve open duration - read-only.
.sensor(
LAST_VALVE_OPEN_DURATION_ATTR_NAME,
RoyalGardineerValveManufCluster.cluster_id,
entity_type=EntityType.DIAGNOSTIC,
unit=UnitOfTime.MINUTES,
translation_key="last_valve_open_duration",
)
.add_to_registry()
)