From 2412d5a26b1b23dab50f7f66f34078241918d7e6 Mon Sep 17 00:00:00 2001 From: czm <80165078@qq.com> Date: Fri, 10 Oct 2025 10:28:16 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Addsonoff=20mini-zb2gs=E3=80=81mini-zb2gs-l?= =?UTF-8?q?=E3=80=81snzb02dr2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zhaquirks/sonoff/mini-zb2gs-l.py | 58 ++++++++++++ zhaquirks/sonoff/mini-zb2gs.py | 105 ++++++++++++++++++++++ zhaquirks/sonoff/snzb02dr2.py | 147 +++++++++++++++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 zhaquirks/sonoff/mini-zb2gs-l.py create mode 100644 zhaquirks/sonoff/mini-zb2gs.py create mode 100644 zhaquirks/sonoff/snzb02dr2.py diff --git a/zhaquirks/sonoff/mini-zb2gs-l.py b/zhaquirks/sonoff/mini-zb2gs-l.py new file mode 100644 index 0000000000..c3328eb3a0 --- /dev/null +++ b/zhaquirks/sonoff/mini-zb2gs-l.py @@ -0,0 +1,58 @@ +"""Sonoff MINI-ZB2GS-L - Zigbee Switch.""" + +from zigpy import types +from zigpy.quirks import CustomCluster +from zigpy.quirks.v2 import QuirkBuilder +import zigpy.types as t +from zigpy.zcl import foundation +from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef + + +class SonoffCluster(CustomCluster): + """Custom Sonoff cluster.""" + + cluster_id = 0xFC11 + + manufacturer_id_override = foundation.ZCLHeader.NO_MANUFACTURER_ID + + class AttributeDefs(BaseAttributeDefs): + """Attribute definitions.""" + + external_trigger_mode = ZCLAttributeDef( + id=0x0016, + type=t.uint8_t, + ) + detach_relay = ZCLAttributeDef( + id=0x0019, + type=t.bitmap8, + ) + + +class SonoffExternalSwitchTriggerType(types.enum8): + """extern switch trigger type.""" + + Edge_trigger = 0x00 + Pulse_trigger = 0x01 + Normally_off_follow_trigger = 0x02 + Normally_on_follow_trigger = 0x82 + +( + QuirkBuilder("SONOFF", "MINI-ZB2GS-L") + .replaces(SonoffCluster) + .enum( + SonoffCluster.AttributeDefs.external_trigger_mode.name, + SonoffExternalSwitchTriggerType, + SonoffCluster.cluster_id, + translation_key="external_trigger_mode", + fallback_name="External trigger mode", + ) + .switch( + SonoffCluster.AttributeDefs.detach_relay.name, + SonoffCluster.cluster_id, + off_value=0, + on_value=1, + translation_key="detach_relay", + fallback_name="Detach relay", + ) + .add_to_registry() +) diff --git a/zhaquirks/sonoff/mini-zb2gs.py b/zhaquirks/sonoff/mini-zb2gs.py new file mode 100644 index 0000000000..cb8513d593 --- /dev/null +++ b/zhaquirks/sonoff/mini-zb2gs.py @@ -0,0 +1,105 @@ +"""Sonoff MINI-ZB2GS - Zigbee Switch.""" + +from zigpy import types +from zigpy.quirks import CustomCluster +from zigpy.quirks.v2 import QuirkBuilder +import zigpy.types as t +from zigpy.zcl import foundation +from zigpy.typing import AddressingMode, EndpointType +from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef + + +class SonoffCluster(CustomCluster): + """Custom Sonoff cluster.""" + + cluster_id = 0xFC11 + manufacturer_id_override = foundation.ZCLHeader.NO_MANUFACTURER_ID + + class AttributeDefs(BaseAttributeDefs): + """Attribute definitions.""" + external_trigger_mode = ZCLAttributeDef( + id=0x0016, + type=t.uint8_t, + ) + detach_relay = ZCLAttributeDef( + id=0x0019, + type=t.bitmap8, + ) + # 添加turbo模式属性 + turbo_mode = ZCLAttributeDef( + id=0x0012, + type=t.int16s, + ) + # 添加network_led属性 + network_led = ZCLAttributeDef( + id=0x0001, + type=t.Bool, + ) + +class SonoffExternalSwitchTriggerType(types.enum8): + """extern switch trigger type.""" + Edge_trigger = 0x00 + Pulse_trigger = 0x01 + Normally_off_follow_trigger = 0x02 + Normally_on_follow_trigger = 0x82 + +class SonoffDetachRelayType(types.enum8): + """detach relay type.""" + ALL_CH_DETACH_RELAY_CLOSE = 0x00 + JUST_CH1_ENABLE_DETACH_RELAY = 0x01 + JUST_CH2_ENABLE_DETACH_RELAY = 0x02 + CH1_AND_CH2_ENABLE_DETACH_RELAY = 0x03 + +# 定义turbo模式的枚举类型 +class SonoffTurboModeType(types.enum16): + """turbo mode type.""" + NORMAL_MODE = 0x0009 # 9 + TURBO_MODE = 0x0014 # 20 + +( + QuirkBuilder("SONOFF", "MINI-ZB2GS") + .replaces(SonoffCluster, endpoint_id = 1) + .replaces(SonoffCluster, endpoint_id = 2) + .enum( + SonoffCluster.AttributeDefs.external_trigger_mode.name, + SonoffExternalSwitchTriggerType, + SonoffCluster.cluster_id, + translation_key="external_trigger_mode", + fallback_name="External trigger mode", + endpoint_id=1, + ) + .enum( + SonoffCluster.AttributeDefs.detach_relay.name, + SonoffDetachRelayType, + SonoffCluster.cluster_id, + translation_key="detach_relay", + fallback_name="Detach relay", + endpoint_id=1, + ) + .enum( + SonoffCluster.AttributeDefs.external_trigger_mode.name, + SonoffExternalSwitchTriggerType, + SonoffCluster.cluster_id, + translation_key="external_trigger_mode", + fallback_name="External trigger mode", + endpoint_id=2, + ) + # 添加turbo模式实体 + .enum( + SonoffCluster.AttributeDefs.turbo_mode.name, + SonoffTurboModeType, + SonoffCluster.cluster_id, + translation_key="turbo_mode", + fallback_name="Turbo mode", + endpoint_id=1, + ) + # 添加network_led实体 + .switch( + SonoffCluster.AttributeDefs.network_led.name, + SonoffCluster.cluster_id, + translation_key="network_led", + fallback_name="Network LED", + endpoint_id=1, + ) + .add_to_registry() +) \ No newline at end of file diff --git a/zhaquirks/sonoff/snzb02dr2.py b/zhaquirks/sonoff/snzb02dr2.py new file mode 100644 index 0000000000..102cfc71fe --- /dev/null +++ b/zhaquirks/sonoff/snzb02dr2.py @@ -0,0 +1,147 @@ +"""Sonoff SNZB-02WD - Zigbee IP65 LCD smart temperature humidity sensor.""" + +from zigpy.quirks import CustomCluster +from zigpy.quirks.v2 import NumberDeviceClass, QuirkBuilder +from zigpy.quirks.v2.homeassistant import PERCENTAGE, UnitOfTemperature +import zigpy.types as t +from zigpy.zcl import foundation +from zigpy.zcl.foundation import BaseAttributeDefs, DataTypeId, ZCLAttributeDef + + +class TemperatureUnit(t.enum16): + """Temperature unit.""" + + Celsius = 0 + Fahrenheit = 1 + + +class CustomSonoffCluster(CustomCluster): + """Sonoff custom cluster.""" + + cluster_id = 0xFC11 + manufacturer_id_override: t.uint16_t = foundation.ZCLHeader.NO_MANUFACTURER_ID + + class AttributeDefs(BaseAttributeDefs): + """Attribute definitions.""" + + comfort_temperature_max = ZCLAttributeDef( + id=0x0003, + type=t.int16s, + ) + + comfort_temperature_min = ZCLAttributeDef( + id=0x0004, + type=t.int16s, + ) + + comfort_humidity_min = ZCLAttributeDef( + id=0x0005, + type=t.uint16_t, + ) + + comfort_humidity_max = ZCLAttributeDef( + id=0x0006, + type=t.uint16_t, + ) + + temperature_unit = ZCLAttributeDef( + id=0x0007, + type=TemperatureUnit, + zcl_type=DataTypeId.uint16, + ) + + temperature_offset = ZCLAttributeDef( + id=0x2003, + type=t.int16s, + ) + + humidity_offset = ZCLAttributeDef( + id=0x2004, + type=t.int16s, + ) + + +( + QuirkBuilder("SONOFF", "SNZB-02DR2") + .replaces(CustomSonoffCluster) + .number( + CustomSonoffCluster.AttributeDefs.comfort_temperature_min.name, + CustomSonoffCluster.cluster_id, + min_value=-10, + max_value=60, + step=0.1, + device_class=NumberDeviceClass.TEMPERATURE, + unit=UnitOfTemperature.CELSIUS, + multiplier=0.01, + translation_key="comfort_temperature_min", + fallback_name="Comfort temperature min", + ) + .number( + CustomSonoffCluster.AttributeDefs.comfort_temperature_max.name, + CustomSonoffCluster.cluster_id, + min_value=-10, + max_value=60, + step=0.1, + device_class=NumberDeviceClass.TEMPERATURE, + unit=UnitOfTemperature.CELSIUS, + multiplier=0.01, + translation_key="comfort_temperature_max", + fallback_name="Comfort temperature max", + ) + .number( + CustomSonoffCluster.AttributeDefs.comfort_humidity_min.name, + CustomSonoffCluster.cluster_id, + min_value=5, + max_value=95, + step=0.1, + device_class=NumberDeviceClass.HUMIDITY, + unit=PERCENTAGE, + multiplier=0.01, + translation_key="comfort_humidity_min", + fallback_name="Comfort humidity min", + ) + .number( + CustomSonoffCluster.AttributeDefs.comfort_humidity_max.name, + CustomSonoffCluster.cluster_id, + min_value=5, + max_value=95, + step=0.1, + device_class=NumberDeviceClass.HUMIDITY, + unit=PERCENTAGE, + multiplier=0.01, + translation_key="comfort_humidity_max", + fallback_name="Comfort humidity max", + ) + .enum( + CustomSonoffCluster.AttributeDefs.temperature_unit.name, + TemperatureUnit, + CustomSonoffCluster.cluster_id, + translation_key="display_unit", + fallback_name="Display unit", + ) + .number( + CustomSonoffCluster.AttributeDefs.temperature_offset.name, + CustomSonoffCluster.cluster_id, + min_value=-50, + max_value=50, + step=0.1, + device_class=NumberDeviceClass.TEMPERATURE, + unit=UnitOfTemperature.CELSIUS, + multiplier=0.01, + translation_key="temperature_offset", + fallback_name="Temperature offset", + ) + .number( + CustomSonoffCluster.AttributeDefs.humidity_offset.name, + CustomSonoffCluster.cluster_id, + min_value=-50, + max_value=50, + step=0.1, + device_class=NumberDeviceClass.HUMIDITY, + unit=PERCENTAGE, + multiplier=0.01, + translation_key="humidity_offset", + fallback_name="Humidity offset", + ) + .add_to_registry() +) From d5a457c91ef4d9ea0b6dcfa17efcebb5805e28f1 Mon Sep 17 00:00:00 2001 From: czm <80165078@qq.com> Date: Fri, 10 Oct 2025 11:04:57 +0800 Subject: [PATCH 2/2] Add sonoff SNZB-02DR2 --- zhaquirks/sonoff/mini-zb2gs-l.py | 58 ----------------- zhaquirks/sonoff/mini-zb2gs.py | 105 ------------------------------- 2 files changed, 163 deletions(-) delete mode 100644 zhaquirks/sonoff/mini-zb2gs-l.py delete mode 100644 zhaquirks/sonoff/mini-zb2gs.py diff --git a/zhaquirks/sonoff/mini-zb2gs-l.py b/zhaquirks/sonoff/mini-zb2gs-l.py deleted file mode 100644 index c3328eb3a0..0000000000 --- a/zhaquirks/sonoff/mini-zb2gs-l.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Sonoff MINI-ZB2GS-L - Zigbee Switch.""" - -from zigpy import types -from zigpy.quirks import CustomCluster -from zigpy.quirks.v2 import QuirkBuilder -import zigpy.types as t -from zigpy.zcl import foundation -from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef - - -class SonoffCluster(CustomCluster): - """Custom Sonoff cluster.""" - - cluster_id = 0xFC11 - - manufacturer_id_override = foundation.ZCLHeader.NO_MANUFACTURER_ID - - class AttributeDefs(BaseAttributeDefs): - """Attribute definitions.""" - - external_trigger_mode = ZCLAttributeDef( - id=0x0016, - type=t.uint8_t, - ) - detach_relay = ZCLAttributeDef( - id=0x0019, - type=t.bitmap8, - ) - - -class SonoffExternalSwitchTriggerType(types.enum8): - """extern switch trigger type.""" - - Edge_trigger = 0x00 - Pulse_trigger = 0x01 - Normally_off_follow_trigger = 0x02 - Normally_on_follow_trigger = 0x82 - -( - QuirkBuilder("SONOFF", "MINI-ZB2GS-L") - .replaces(SonoffCluster) - .enum( - SonoffCluster.AttributeDefs.external_trigger_mode.name, - SonoffExternalSwitchTriggerType, - SonoffCluster.cluster_id, - translation_key="external_trigger_mode", - fallback_name="External trigger mode", - ) - .switch( - SonoffCluster.AttributeDefs.detach_relay.name, - SonoffCluster.cluster_id, - off_value=0, - on_value=1, - translation_key="detach_relay", - fallback_name="Detach relay", - ) - .add_to_registry() -) diff --git a/zhaquirks/sonoff/mini-zb2gs.py b/zhaquirks/sonoff/mini-zb2gs.py deleted file mode 100644 index cb8513d593..0000000000 --- a/zhaquirks/sonoff/mini-zb2gs.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Sonoff MINI-ZB2GS - Zigbee Switch.""" - -from zigpy import types -from zigpy.quirks import CustomCluster -from zigpy.quirks.v2 import QuirkBuilder -import zigpy.types as t -from zigpy.zcl import foundation -from zigpy.typing import AddressingMode, EndpointType -from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef - - -class SonoffCluster(CustomCluster): - """Custom Sonoff cluster.""" - - cluster_id = 0xFC11 - manufacturer_id_override = foundation.ZCLHeader.NO_MANUFACTURER_ID - - class AttributeDefs(BaseAttributeDefs): - """Attribute definitions.""" - external_trigger_mode = ZCLAttributeDef( - id=0x0016, - type=t.uint8_t, - ) - detach_relay = ZCLAttributeDef( - id=0x0019, - type=t.bitmap8, - ) - # 添加turbo模式属性 - turbo_mode = ZCLAttributeDef( - id=0x0012, - type=t.int16s, - ) - # 添加network_led属性 - network_led = ZCLAttributeDef( - id=0x0001, - type=t.Bool, - ) - -class SonoffExternalSwitchTriggerType(types.enum8): - """extern switch trigger type.""" - Edge_trigger = 0x00 - Pulse_trigger = 0x01 - Normally_off_follow_trigger = 0x02 - Normally_on_follow_trigger = 0x82 - -class SonoffDetachRelayType(types.enum8): - """detach relay type.""" - ALL_CH_DETACH_RELAY_CLOSE = 0x00 - JUST_CH1_ENABLE_DETACH_RELAY = 0x01 - JUST_CH2_ENABLE_DETACH_RELAY = 0x02 - CH1_AND_CH2_ENABLE_DETACH_RELAY = 0x03 - -# 定义turbo模式的枚举类型 -class SonoffTurboModeType(types.enum16): - """turbo mode type.""" - NORMAL_MODE = 0x0009 # 9 - TURBO_MODE = 0x0014 # 20 - -( - QuirkBuilder("SONOFF", "MINI-ZB2GS") - .replaces(SonoffCluster, endpoint_id = 1) - .replaces(SonoffCluster, endpoint_id = 2) - .enum( - SonoffCluster.AttributeDefs.external_trigger_mode.name, - SonoffExternalSwitchTriggerType, - SonoffCluster.cluster_id, - translation_key="external_trigger_mode", - fallback_name="External trigger mode", - endpoint_id=1, - ) - .enum( - SonoffCluster.AttributeDefs.detach_relay.name, - SonoffDetachRelayType, - SonoffCluster.cluster_id, - translation_key="detach_relay", - fallback_name="Detach relay", - endpoint_id=1, - ) - .enum( - SonoffCluster.AttributeDefs.external_trigger_mode.name, - SonoffExternalSwitchTriggerType, - SonoffCluster.cluster_id, - translation_key="external_trigger_mode", - fallback_name="External trigger mode", - endpoint_id=2, - ) - # 添加turbo模式实体 - .enum( - SonoffCluster.AttributeDefs.turbo_mode.name, - SonoffTurboModeType, - SonoffCluster.cluster_id, - translation_key="turbo_mode", - fallback_name="Turbo mode", - endpoint_id=1, - ) - # 添加network_led实体 - .switch( - SonoffCluster.AttributeDefs.network_led.name, - SonoffCluster.cluster_id, - translation_key="network_led", - fallback_name="Network LED", - endpoint_id=1, - ) - .add_to_registry() -) \ No newline at end of file