Adding TS0049 Irrigation Valve to Zigbee Home Automation

Adding TS0049 Irrigation Valve to Zigbee Home Automation

The TS0049 irrigation valve, also known as TS0049 by _TZ3210_0jxeoadc, is a handy device for automating your irrigation system. However, out of the box, it is not recognized by the Zigbee Home Automation (ZHA) component in Home Assistant. Follow this guide to get it recognized and fully controlled.

Steps to Recognize the TS0049 Irrigation Valve

  1. Navigate to your Home Assistant configuration folder. Inside this folder, create a subfolder named custom_zha_quirks.

  2. Inside the custom_zha_quirks folder, create a new file. The name of the file doesn’t matter as long as it has a .py extension. For this example, we’ll call it ts0049.py.

  3. Add the following content to the ts0049.py file:

from typing import Any, Dict, Optional, Union

import zigpy.types as t
from zhaquirks import DoublingPowerConfigurationCluster
from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import (
    TUYA_SEND_DATA, TuyaLocalCluster,
)
from zhaquirks.tuya.mcu import (
    DPToAttributeMapping,
    EnchantedDevice,
    TuyaMCUCluster,
    TuyaOnOff,
)
from zigpy.profiles import zha
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import Basic, Ota, Time, PowerConfiguration


class TuyaValveFamilyBattery(TuyaLocalCluster, DoublingPowerConfigurationCluster):
    _values = [10, 50, 90]
    _CONSTANT_ATTRIBUTES = {
        PowerConfiguration.attributes_by_name["battery_quantity"].id: 4,
        PowerConfiguration.attributes_by_name["battery_size"].id: PowerConfiguration.BatterySize.AAA
    }

    def _update_attribute(self, attrid, value):
        if attrid == self.BATTERY_PERCENTAGE_REMAINING:
            value = self._values[value]
        super()._update_attribute(attrid, value)


class TuyaValveFamilyCluster(TuyaMCUCluster):
    """On/Off Tuya family cluster with extra device attributes"""

    attributes = TuyaMCUCluster.attributes.copy()
    attributes.update(
        {
            0xEF01: ("irrigation_time", t.uint32_t, True),
            0xEF02: ("dp_110", t.uint32_t, True),
            0xEF03: ("error_status", t.uint32_t, True),
        }
    )

    async def command(
            self,
            command_id: Union[foundation.GeneralCommand, int, t.uint8_t],
            *args,
            manufacturer: Optional[Union[int, t.uint16_t]] = None,
            expect_reply: bool = True,
            tsn: Optional[Union[int, t.uint8_t]] = None,
            **kwargs: Any,
    ):
        """Override the default Cluster command."""
        self.debug("Setting the NO manufacturer id in command: %s", command_id)
        return await super().command(
            TUYA_SEND_DATA,
            *args,
            manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID,
            expect_reply=expect_reply,
            tsn=tsn,
            **kwargs,
        )

    dp_to_attribute: Dict[int, DPToAttributeMapping] = {
        26: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "error_status",
        ),
        101: DPToAttributeMapping(
            TuyaOnOff.ep_attribute,
            "on_off",
        ),
        110: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "dp_110",
        ),
        111: DPToAttributeMapping(
            TuyaMCUCluster.ep_attribute,
            "irrigation_time",
        ),
        115: DPToAttributeMapping(
            TuyaValveFamilyBattery.ep_attribute,
            "battery_percentage_remaining",
        ),
    }

    data_point_handlers = {
        26: "_dp_2_attr_update",
        101: "_dp_2_attr_update",
        110: "_dp_2_attr_update",
        111: "_dp_2_attr_update",
        115: "_dp_2_attr_update",
    }


class TuyaIrrigationValve(EnchantedDevice):
    """Tuya green irrigation valve device."""
    signature = {
        MODELS_INFO: [("_TZ3210_0jxeoadc", "TS0049")],
        ENDPOINTS: {
            # 
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    TuyaValveFamilyCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    TuyaOnOff,
                    TuyaValveFamilyBattery,
                    TuyaValveFamilyCluster
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
    }

In your configuration.yaml file, add the following lines:

zha:
  custom_quirks_path: /config/custom_zha_quirks/
  enable_quirks: true

Restart Home Assistant. After the reboot, the TS0049 irrigation valve will be recognized in Home Assistant, and you can fully control it through the ZHA integration.

Conclusion

By following these steps, you can easily integrate the TS0049 irrigation valve into your Home Assistant setup, allowing for automated control of your irrigation system. Happy automating!

Don’t have it yet? Here’s a link:

1
Smart Zigbee Irrigation Valve
9.6

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply