Skip to content

Commit

Permalink
initial swv support
Browse files Browse the repository at this point in the history
  • Loading branch information
benbancroft committed Aug 31, 2024
1 parent 5c4e08d commit 79bfbfe
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
43 changes: 43 additions & 0 deletions tests/test_sonoff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Tests for Sonoff quirks."""

from unittest import mock

import pytest

import zhaquirks
import zhaquirks.sonoff.swv

zhaquirks.setup()


def test_sonoff_swv(assert_signature_matches_quirk):
"""Test new 'Sonoff SWV' signature is matched to its quirk."""

signature = {
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4742, maximum_buffer_size=82, maximum_incoming_transfer_size=255, server_mask=11264, maximum_outgoing_transfer_size=255, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=True, *is_mains_powered=False, *is_receiver_on_when_idle=True, *is_router=False, *is_security_capable=False)",
"endpoints": {
"1": {
"profile_id": 0x0104,
"device_type": "0x0002",
"in_clusters": [
"0x0000",
"0x0001",
"0x0003",
"0x0006",
"0x0020",
"0x0404",
"0x0b05",
"0xfc11",
"0xfc57",
],
"out_clusters": ["0x000a", "0x0019"],
}
},
"manufacturer": "SONOFF",
"model": "SWV",
"class": "sonoff.swv.SonoffSmartWaterValveSWV",
}

assert_signature_matches_quirk(
zhaquirks.sonoff.swv.SonoffSmartWaterValveSWV, signature
)
112 changes: 112 additions & 0 deletions zhaquirks/sonoff/swv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""Sonoff SWV - Zigbee smart water valve."""

from zigpy.profiles import zha
from zigpy.quirks import CustomCluster, CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import (
Basic,
PowerConfiguration,
Identify,
OnOff,
PollControl,
Ota,
Time,
)
from zigpy.zcl.clusters.homeautomation import Diagnostic
from zigpy.zcl.clusters.measurement import FlowMeasurement

from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)

SONOFF_CLUSTER_FC11_ID = 0xFC11
SONOFF_CLUSTER_FC57_ID = 0xFC57
ATTR_SONOFF_VALVE_STATUS = 0x500C


class ValveStatusBitmap(t.bitmap8):
"""Valve status value enum."""

Water_Shortage = 0x1
Water_Leakage = 0x2


class SonoffFC11Cluster(CustomCluster):
"""Sonoff manufacture specific cluster that provides valve status."""

@property
def _is_manuf_specific(self) -> bool:
"""Override manufacturer specific property.
valve_status return UNSUPPORTED_ATTRIBUTE if manufacturer_specific is set on report command.
We therefore need to treat cluster as if it doesn't have ID within manufacturer specific range
and explicitly set if each attribute is manufacturer_specific or not instead in attribute list.
"""
return False

cluster_id = SONOFF_CLUSTER_FC11_ID
ep_attribute = "sonoff_manufacturer"
attributes = {ATTR_SONOFF_VALVE_STATUS: ("valve_status", ValveStatusBitmap, False)}


class SonoffSmartWaterValveSWV(CustomDevice):
"""Sonoff smart water valve - model SWV."""

signature = {
# <SimpleDescriptor endpoint=1, profile=260, device_type=2
# device_version=1
# input_clusters=[0x0000, 0x0001, 0x0003, 0x0006, 0x0020, 0x0404, 0x0b05, 0xfc11, 0xfc57]
# output_clusters=[0x000a, 0x0019]>
MODELS_INFO: [
("SONOFF", "SWV"),
],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_OUTPUT,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfiguration.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
PollControl.cluster_id,
FlowMeasurement.cluster_id,
Diagnostic.cluster_id,
SONOFF_CLUSTER_FC11_ID,
SONOFF_CLUSTER_FC57_ID,
],
OUTPUT_CLUSTERS: [
Time.cluster_id,
Ota.cluster_id,
],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_OUTPUT,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfiguration.cluster_id,
Identify.cluster_id,
OnOff.cluster_id,
PollControl.cluster_id,
FlowMeasurement.cluster_id,
Diagnostic.cluster_id,
SonoffFC11Cluster,
SONOFF_CLUSTER_FC57_ID,
],
OUTPUT_CLUSTERS: [
Time.cluster_id,
Ota.cluster_id,
],
},
},
}

0 comments on commit 79bfbfe

Please sign in to comment.