EPTTECH TS0601 TZE200 water level sensor ZHA

I got zigbee ultrasonic water level sensor made by EPTTECH, it works fine in Tuya application, however neithe ZHA supports it nor Local Tuya shows level in Home Assistant.
Unfortunatelly my custom quirk did not work either, or I may missed something in it…

"""Custom quirk for EPTTECH TLC2206-ZB Tank Level Sensor."""

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, Groups, Scenes, Ota, Time
from zigpy.zcl.clusters.measurement import FlowMeasurement
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, TuyaMCUCluster
import zigpy.types as t

# Define the data points (DPs) for the sensor
TUYA_TANK_LEVEL_PERCENT_DP = 22
TUYA_TANK_DEPTH_DP = 2
TUYA_TANK_STATE_DP = 1
TUYA_INSTALLATION_HEIGHT_DP = 19
TUYA_MAX_SET_DP = 7
TUYA_MIN_SET_DP = 8
TUYA_DEPTH_MAX_DP = 21

class LiquidLevelStatus(t.enum8):
    """Enum for liquid level status."""
    NORMAL = 0x00
    LOW = 0x01
    HIGH = 0x02

class TuyaTankLevelMeasurement(TuyaLocalCluster):
    """Custom cluster for tank level measurement."""

    cluster_id = FlowMeasurement.cluster_id
    name = "Tank Level Measurement"
    ep_attribute = "liquid_level_measurement"

    attributes = {
        0x0000: ("measured_value", t.uint16_t, True),
        0x0001: ("min_measured_value", t.uint16_t, True),
        0x0002: ("max_measured_value", t.uint16_t, True),
        0xFF00: ("liquid_level_percent", t.uint8_t, True),
        0xFF01: ("liquid_depth", t.uint16_t, True),  # Assuming depth is in mm
        0xFF02: ("liquid_state", LiquidLevelStatus, True),
        0xFF03: ("installation_height", t.uint16_t, True),  # mm
        0xFF04: ("max_set", t.uint8_t, True),  # Percentage
        0xFF05: ("mini_set", t.uint8_t, True),  # Percentage
        0xFF06: ("liquid_depth_max", t.uint16_t, True),  # mm
    }

class TuyaTankLevelCluster(TuyaMCUCluster):
    """Custom cluster for handling EPTTECH TLC2206-ZB tank level sensor data points."""

    dp_to_attribute: dict[int, DPToAttributeMapping] = {
        TUYA_TANK_LEVEL_PERCENT_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "liquid_level_percent",
        ),
        TUYA_TANK_DEPTH_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "liquid_depth",
            converter=lambda x: x / 100,  # Convert mm to meters
        ),
        TUYA_TANK_STATE_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "liquid_state",
            converter=lambda x: LiquidLevelStatus(x),
        ),
        TUYA_INSTALLATION_HEIGHT_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "installation_height",
        ),
        TUYA_MAX_SET_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "max_set",
        ),
        TUYA_MIN_SET_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "mini_set",
        ),
        TUYA_DEPTH_MAX_DP: DPToAttributeMapping(
            TuyaTankLevelMeasurement.ep_attribute,
            "liquid_depth_max",
        ),
    }

    data_point_handlers = {
        TUYA_TANK_LEVEL_PERCENT_DP: "_dp_2_attr_update",
        TUYA_TANK_DEPTH_DP: "_dp_2_attr_update",
        TUYA_TANK_STATE_DP: "_dp_2_attr_update",
        TUYA_INSTALLATION_HEIGHT_DP: "_dp_2_attr_update",
        TUYA_MAX_SET_DP: "_dp_2_attr_update",
        TUYA_MIN_SET_DP: "_dp_2_attr_update",
        TUYA_DEPTH_MAX_DP: "_dp_2_attr_update",
    }

class EPTTECH_TLC2206ZB(CustomDevice):
    """Custom quirk for EPTTECH TLC2206-ZB Tank Level Sensor."""

    signature = {
        MODELS_INFO: [("TS0601", "_TZE200_lvkk0hdg")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,  # Device type commonly used for sensors
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    TuyaTankLevelCluster.cluster_id,  # Custom cluster for tank level
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,
                    Time.cluster_id,
                ],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    TuyaTankLevelCluster,  # Custom cluster for tank level
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,
                    Time.cluster_id,
                ],
            },
        },
    }

Help is much appreciated!

Could someone address it to ZHA developers?

1 Like

I’m looking at this sensor as well - it would be great if it is made to work, as I don’t think there is an alternative?

Are those the correct Tuya data points? If you are copying from a z2m converter, do you have a link?

Did you get this working? I’m trying to set it up as well, and this is my first experience with ZHA Quirks, so I’m not entirely certain I know what I’m doing. Is there any kind of repository for custom quirks, or do we just find them in forums like this?

There is a similar device and quirk here [Device Support Request] Tuya ultrasonic level sensor (TS0601 by _TZE284_kyyu8rbj) · Issue #3356 · zigpy/zha-device-handlers · GitHub

Usually these have similar Datapoints, so it may work with just modifying the manufacturer, otherwise we need the Datapoints to do anything.