Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Giex GX03 Valve #3411

Merged
merged 10 commits into from
Oct 19, 2024
39 changes: 39 additions & 0 deletions tests/test_tuya_valve.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

from tests.common import ClusterListener, wait_for_zigpy_tasks
import zhaquirks
import zhaquirks.tuya
import zhaquirks.tuya.ts0601_valve

zhaquirks.setup()

Expand Down Expand Up @@ -127,3 +129,40 @@ async def test_report_values_psbzs(zigpy_device_from_quirk, quirk):
assert tuya_listener.attribute_updates[2][1] == 0 # frost lock state is inverted
assert tuya_listener.attribute_updates[3][0] == 0xEF13
assert tuya_listener.attribute_updates[3][1] == 1 # frost lock state is inverted


@pytest.mark.parametrize(
"model,manuf",
[
("_TZE284_8zizsafo", "TS0601"),
],
)
async def test_giex_03_quirk(zigpy_device_from_v2_quirk, model, manuf):
"""Test Giex GX03 Valve Quirk."""

quirked_device = zigpy_device_from_v2_quirk(model, manuf)
tuya_cluster = quirked_device.endpoints[1].tuya_manufacturer

with mock.patch.object(
tuya_cluster.endpoint, "request", return_value=foundation.Status.SUCCESS
) as m1:
(status,) = await tuya_cluster.write_attributes(
{
"valve_one_duration": 10,
}
)
await wait_for_zigpy_tasks()
m1.assert_called_with(
cluster=61184,
sequence=1,
data=b"\x01\x01\x00\x00\x01\x19\x02\x00\x04\x00\x00\x00\x0a",
command_id=0,
timeout=5,
expect_reply=False,
use_ieee=False,
ask_for_ack=None,
priority=t.PacketPriority.NORMAL,
)
assert status == [
foundation.WriteAttributesStatusRecord(foundation.Status.SUCCESS)
]
10 changes: 10 additions & 0 deletions zhaquirks/tuya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,16 @@ class TuyaPowerConfigurationCluster3AA(TuyaPowerConfigurationCluster):
}


class TuyaPowerConfigurationCluster4AA(PowerConfiguration, TuyaLocalCluster):
"""PowerConfiguration cluster for devices with 4 AA."""

_CONSTANT_ATTRIBUTES = {
PowerConfiguration.AttributeDefs.battery_size.id: 3,
PowerConfiguration.AttributeDefs.battery_rated_voltage.id: 15,
PowerConfiguration.AttributeDefs.battery_quantity.id: 4,
}


class TuyaThermostat(CustomDevice):
"""Generic Tuya thermostat device."""

Expand Down
105 changes: 104 additions & 1 deletion zhaquirks/tuya/ts0601_valve.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.quirks.v2 import EntityPlatform, EntityType
from zigpy.quirks.v2.homeassistant import UnitOfTime
from zigpy.quirks.v2.homeassistant.sensor import SensorDeviceClass, SensorStateClass
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import Basic, Groups, Identify, OnOff, Ota, Scenes, Time
Expand All @@ -16,7 +19,13 @@
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import TUYA_CLUSTER_ED00_ID, EnchantedDevice, TuyaLocalCluster
from zhaquirks.tuya import (
TUYA_CLUSTER_ED00_ID,
EnchantedDevice,
TuyaLocalCluster,
TuyaPowerConfigurationCluster4AA,
)
from zhaquirks.tuya.builder import TuyaQuirkBuilder
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaMCUCluster,
Expand Down Expand Up @@ -493,3 +502,97 @@ class GiexValveVar02(CustomDevice):
}
}
}


class GiexIrrigationStatus(t.enum8):
"""Giex Irrigation Status Enum."""

Manual = 0x00
Auto = 0x01
Idle = 0x02


(
TuyaQuirkBuilder("_TZE284_8zizsafo", "TS0601") # Giex GX04
.tuya_battery(dp_id=59, power_cfg=TuyaPowerConfigurationCluster4AA)
.tuya_switch(
dp_id=1,
attribute_name="valve_one_on_off",
entity_type=EntityType.STANDARD,
translation_key="valve_one_on_off",
fallback_name="Valve 1",
)
.tuya_switch(
dp_id=2,
attribute_name="valve_two_on_off",
entity_type=EntityType.STANDARD,
translation_key="valve_two_on_off",
fallback_name="Valve 2",
)
.tuya_number(
dp_id=13,
attribute_name="valve_one_countdown",
type=t.uint16_t,
device_class=SensorDeviceClass.DURATION,
unit=UnitOfTime.MINUTES,
min_value=0,
max_value=1440,
step=1,
translation_key="valve_one_countdown",
fallback_name="Irrigation time 1",
)
.tuya_number(
dp_id=14,
attribute_name="valve_two_countdown",
type=t.uint16_t,
device_class=SensorDeviceClass.DURATION,
unit=UnitOfTime.MINUTES,
min_value=0,
max_value=1440,
step=1,
translation_key="valve_two_countdown",
fallback_name="Irrigation time 2",
)
.tuya_sensor(
dp_id=25,
attribute_name="valve_one_duration",
type=t.uint32_t,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.DURATION,
unit=UnitOfTime.SECONDS,
entity_type=EntityType.STANDARD,
translation_key="irrigation_duration",
TheJulianJES marked this conversation as resolved.
Show resolved Hide resolved
fallback_name="Irrigation duration 1",
)
.tuya_sensor(
dp_id=26,
attribute_name="valve_two_duration",
type=t.uint32_t,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.DURATION,
unit=UnitOfTime.SECONDS,
entity_type=EntityType.STANDARD,
translation_key="irrigation_duration",
TheJulianJES marked this conversation as resolved.
Show resolved Hide resolved
fallback_name="Irrigation duration 2",
)
.tuya_enum(
dp_id=104,
attribute_name="valve_one_status",
enum_class=GiexIrrigationStatus,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.STANDARD,
translation_key="valve_one_status",
fallback_name="Status 1",
)
.tuya_enum(
dp_id=105,
attribute_name="valve_two_status",
enum_class=GiexIrrigationStatus,
entity_platform=EntityPlatform.SENSOR,
entity_type=EntityType.STANDARD,
translation_key="valve_two_status",
fallback_name="Status 2",
)
.skip_configuration()
.add_to_registry()
)