Skip to content

Commit

Permalink
Merge branch 'release/0.0.78'
Browse files Browse the repository at this point in the history
  • Loading branch information
dmulcahey committed Jul 26, 2022
2 parents 53d432b + a2a1804 commit 170cc1f
Show file tree
Hide file tree
Showing 10 changed files with 716 additions and 81 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from setuptools import find_packages, setup

VERSION = "0.0.77"
VERSION = "0.0.78"


setup(
Expand Down
50 changes: 19 additions & 31 deletions zhaquirks/elko/smart_super_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,25 @@ class Sensor(t.enum8):
attributes = ElkoThermostatCluster.attributes.copy()
attributes.update(
{
UNKNOWN_1: ("unknown_1", t.uint16_t, True),
DISPLAY_TEXT: ("display_text", t.CharacterString, True),
ACTIVE_SENSOR: ("active_sensor", Sensor, True),
UNKNOWN_2: ("unknown_2", t.uint8_t, True),
REGULATOR_MODE: ("regulator_mode", t.Bool, True),
DEVICE_ON: ("device_on", t.Bool, True),
UNKNOWN_3: ("unknown_3", t.LongOctetString, True),
POWER_CONSUMPTION: ("power_consumtion", t.uint16_t, True),
FLOOR_SENSOR_TEMPERATURE: ("floor_sensor_temperature", t.int16s, True),
UNKNOWN_4: ("unknown_4", t.uint16_t, True),
NIGHT_LOWERING: ("night_lowering", t.Bool, True),
UNKNOWN_5: ("unknown_5", t.Bool, True),
CHILD_LOCK: ("child_lock", t.Bool, True),
PROTECTION_MAX_TEMP: ("protection_max_temp", t.uint8_t, True),
HEATING_ACTIVE: ("heating_active", t.Bool, True),
UNKNOWN_6: ("unknown_6", t.LongOctetString, True),
UNKNOWN_7: ("unknown_7", t.int8s, True),
UNKNOWN_8: ("unknown_8", t.uint8_t, True),
UNKNOWN_9: ("unknown_9", t.uint8_t, True),
UNKNOWN_1: ("unknown_1", t.uint16_t),
DISPLAY_TEXT: ("display_text", t.CharacterString),
ACTIVE_SENSOR: ("active_sensor", Sensor),
UNKNOWN_2: ("unknown_2", t.uint8_t),
REGULATOR_MODE: ("regulator_mode", t.Bool),
DEVICE_ON: ("device_on", t.Bool),
UNKNOWN_3: ("unknown_3", t.LongOctetString),
POWER_CONSUMPTION: ("power_consumtion", t.uint16_t),
FLOOR_SENSOR_TEMPERATURE: ("floor_sensor_temperature", t.int16s),
UNKNOWN_4: ("unknown_4", t.uint16_t),
NIGHT_LOWERING: ("night_lowering", t.Bool),
UNKNOWN_5: ("unknown_5", t.Bool),
CHILD_LOCK: ("child_lock", t.Bool),
PROTECTION_MAX_TEMP: ("protection_max_temp", t.uint8_t),
HEATING_ACTIVE: ("heating_active", t.Bool),
UNKNOWN_6: ("unknown_6", t.LongOctetString),
UNKNOWN_7: ("unknown_7", t.int8s),
UNKNOWN_8: ("unknown_8", t.uint8_t),
UNKNOWN_9: ("unknown_9", t.uint8_t),
}
)

Expand All @@ -82,18 +82,6 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.active_sensor = None

def _read_attributes(self, args, manufacturer=None):
"""Read attributes ZCL foundation command."""
if manufacturer is None and self._has_manuf_attr(args):
manufacturer = 0
return super()._read_attributes(args, manufacturer=manufacturer)

def _write_attributes(self, args, manufacturer=None):
"""Write attribute ZCL foundation command."""
if manufacturer is None and self._has_manuf_attr([a.attrid for a in args]):
manufacturer = 0
return super()._write_attributes(args, manufacturer=manufacturer)

async def write_attributes(self, attributes, manufacturer=None):
"""Override writes to thermostat attributes."""
if "system_mode" in attributes:
Expand Down
5 changes: 4 additions & 1 deletion zhaquirks/ikea/starkvind.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ def __init__(self, *args, **kwargs):
# <SimpleDescriptor endpoint=1 profile=260 device_type=7 (0x0007)
# device_version=0
# input_clusters=[0, 3, 4, 5, 514, 64599, 64637] output_clusters=[25, 1024, 1066]>
MODELS_INFO: [(IKEA, "STARKVIND Air purifier")],
MODELS_INFO: [
(IKEA, "STARKVIND Air purifier"),
(IKEA, "STARKVIND Air purifier table"),
],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
Expand Down
89 changes: 89 additions & 0 deletions zhaquirks/inovelli/VZM31SN.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,95 @@
WWAH_CLUSTER_ID = 64599


class InovelliVZM31SNv11(CustomDevice):
"""VZM31-SN 2 in 1 Switch/Dimmer Module."""

signature = {
MODELS_INFO: [("Inovelli", "VZM31-SN")],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
Identify.cluster_id, # 3
Groups.cluster_id, # 4
Scenes.cluster_id, # 5
OnOff.cluster_id, # 6
LevelControl.cluster_id, # 8
Metering.cluster_id, # 1794
ElectricalMeasurement.cluster_id, # 2820
Diagnostic.cluster_id, # 2821
INOVELLI_VZM31SN_CLUSTER_ID, # 64561
WWAH_CLUSTER_ID, # 64599
],
OUTPUT_CLUSTERS: [Ota.cluster_id], # 19
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id], # 0 # 3
OUTPUT_CLUSTERS: [
Identify.cluster_id, # 3
OnOff.cluster_id, # 6
LevelControl.cluster_id, # 8
INOVELLI_VZM31SN_CLUSTER_ID, # 64561
],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 0x0061,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [0x0021],
},
},
}

replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic, # 0
Identify, # 3
Groups, # 4
Scenes, # 5
OnOff, # 6
LevelControl, # 8
Metering, # 1794
ElectricalMeasurement, # 2820
Diagnostic, # 2821
Inovelli_VZM31SN_Cluster, # 64561
WWAH_CLUSTER_ID, # 64599
],
OUTPUT_CLUSTERS: [
Ota, # 19
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic, Identify], # 0 # 3
OUTPUT_CLUSTERS: [
Identify, # 3
OnOff, # 6
LevelControl, # 8
Inovelli_VZM31SN_Cluster, # 64561
],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 0x0061,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [0x0021],
},
},
}

device_automation_triggers = INOVELLI_AUTOMATION_TRIGGERS


class InovelliVZM31SNv10(CustomDevice):
"""VZM31-SN 2 in 1 Switch/Dimmer Module."""

Expand Down
1 change: 1 addition & 0 deletions zhaquirks/inovelli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class Inovelli_VZM31SN_Cluster(CustomCluster):
0x0102: ("output_mode", t.Bool, True),
0x0103: ("on_off_led_mode", t.Bool, True),
0x0104: ("firmware_progress_led", t.Bool, True),
0x0105: ("relay_click_in_on_off_mode", t.Bool, True),
}
)

Expand Down
1 change: 1 addition & 0 deletions zhaquirks/sourcingandcreation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Module for Sourcing & Creation devices."""
119 changes: 119 additions & 0 deletions zhaquirks/sourcingandcreation/smart_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"""Device handler for Sourcing & Creation EB-SB-1B (Boulanger Essentielb 8009289) smart button."""

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
Basic,
Groups,
Identify,
LevelControl,
OnOff,
Ota,
PowerConfiguration,
)
from zigpy.zcl.clusters.homeautomation import Diagnostic
from zigpy.zcl.clusters.lighting import Color
from zigpy.zcl.clusters.lightlink import LightLink

from zhaquirks.const import (
CLUSTER_ID,
COMMAND,
COMMAND_STEP,
COMMAND_STEP_COLOR_TEMP,
COMMAND_STOP,
DEVICE_TYPE,
DOUBLE_PRESS,
ENDPOINT_ID,
ENDPOINTS,
INPUT_CLUSTERS,
LONG_PRESS,
LONG_RELEASE,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
SHORT_PRESS,
TURN_ON,
)


class SourcingAndCreationSmartButton(CustomDevice):
"""Custom device representing Sourcing & Creation smart button."""

signature = {
# <SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=2048,
# device_version=1,
# input_clusters=[0, 1, 3, 2821, 4096, 64769],
# output_clusters=[3, 4, 6, 8, 25, 768, 4096])>
MODELS_INFO: [("Sourcing & Creation", "EB-SB-1B")],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID, # 260
DEVICE_TYPE: zha.DeviceType.COLOR_CONTROLLER, # 2048
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
PowerConfiguration.cluster_id, # 1
Identify.cluster_id, # 3
Diagnostic.cluster_id, # 2821
LightLink.cluster_id, # 4096
0xFD01, # 64769
],
OUTPUT_CLUSTERS: [
Identify.cluster_id, # 3
Groups.cluster_id, # 4
OnOff.cluster_id, # 6
LevelControl.cluster_id, # 8
Ota.cluster_id, # 25
Color.cluster_id, # 768
LightLink.cluster_id, # 4096
],
}
},
}

replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.COLOR_CONTROLLER,
INPUT_CLUSTERS: [
Basic.cluster_id, # 0
PowerConfiguration.cluster_id, # 1
Identify.cluster_id, # 3
Diagnostic.cluster_id, # 2821
LightLink.cluster_id, # 4096
0xFD01, # 64769
],
OUTPUT_CLUSTERS: [
Identify.cluster_id, # 3
Groups.cluster_id, # 4
OnOff.cluster_id, # 6
LevelControl.cluster_id, # 8
Ota.cluster_id, # 25
Color.cluster_id, # 768
LightLink.cluster_id, # 4096
],
}
},
}

device_automation_triggers = {
(SHORT_PRESS, TURN_ON): {
CLUSTER_ID: 6, # OnOff.cluster_id
ENDPOINT_ID: 1,
},
(LONG_PRESS, TURN_ON): {
COMMAND: COMMAND_STEP,
CLUSTER_ID: 8, # LevelControl.cluster_id
ENDPOINT_ID: 1,
},
(LONG_RELEASE, TURN_ON): {
COMMAND: COMMAND_STOP,
CLUSTER_ID: 8, # LevelControl.cluster_id
ENDPOINT_ID: 1,
},
(DOUBLE_PRESS, TURN_ON): {
COMMAND: COMMAND_STEP_COLOR_TEMP,
CLUSTER_ID: 768, # Color.cluster_id
ENDPOINT_ID: 1,
},
}
53 changes: 12 additions & 41 deletions zhaquirks/tuya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,43 +100,6 @@
ATTR_COVER_POSITION = 0x0008
ATTR_COVER_DIRECTION = 0x8001
ATTR_COVER_INVERTED = 0x8002
# For most tuya devices 0 = Up/Open, 1 = Stop, 2 = Down/Close
TUYA_COVER_COMMAND = {
"_TZE200_zah67ekd": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_fzo2pocs": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_xuzcvlku": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_rddyvrci": {0x0000: 0x0002, 0x0001: 0x0001, 0x0002: 0x0000},
"_TZE200_3i3exuay": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_nueqqe6k": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_gubdgai2": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_zpzndjez": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_cowvfni3": {0x0000: 0x0002, 0x0001: 0x0000, 0x0002: 0x0001},
"_TYST11_wmcdj3aq": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_yenbr4om": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_5sbebbzs": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_xaabybja": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_hsgrhjpf": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_iossyxra": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_68nvbio9": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_zuz7f94z": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_ergbiejo": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_nhyj64w2": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
"_TZE200_pw7mji0l": {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001},
}
# Taken from zigbee-herdsman-converters
# Contains all covers which need their position inverted by default
# Default is 100 = open, 0 = closed; Devices listed here will use 0 = open, 100 = closed instead
# Use manufacturerName to identify device!
# Don't invert _TZE200_cowvfni3: https://github.com/Koenkk/zigbee2mqtt/issues/6043
TUYA_COVER_INVERTED_BY_DEFAULT = [
"_TZE200_wmcdj3aq",
"_TZE200_nogaemzt",
"_TZE200_xuzcvlku",
"_TZE200_xaabybja",
"_TZE200_yenbr4om",
"_TZE200_zpzndjez",
"_TZE200_zuz7f94z",
]

# ---------------------------------------------------------
# TUYA Switch Custom Values
Expand Down Expand Up @@ -1123,7 +1086,7 @@ def cover_event(self, attribute, value):
invert_attr = self._attr_cache.get(ATTR_COVER_INVERTED) == 1
invert = (
not invert_attr
if self.endpoint.device.manufacturer in TUYA_COVER_INVERTED_BY_DEFAULT
if self.endpoint.device.tuya_cover_inverted_by_default
else invert_attr
)
value = value if invert else 100 - value
Expand Down Expand Up @@ -1166,7 +1129,7 @@ def command(
tuya_payload.data = [
1,
# need to implement direction change
TUYA_COVER_COMMAND[manufacturer][command_id],
self.endpoint.device.tuya_cover_command[command_id],
] # remap the command to the Tuya command
# Set Position Command
elif command_id == WINDOW_COVER_COMMAND_LIFTPERCENT:
Expand All @@ -1178,7 +1141,7 @@ def command(
invert_attr = self._attr_cache.get(ATTR_COVER_INVERTED) == 1
invert = (
not invert_attr
if self.endpoint.device.manufacturer in TUYA_COVER_INVERTED_BY_DEFAULT
if self.endpoint.device.tuya_cover_inverted_by_default
else invert_attr
)
position = args[0] if invert else 100 - args[0]
Expand Down Expand Up @@ -1221,7 +1184,15 @@ def command(


class TuyaWindowCover(CustomDevice):
"""Tuya switch device."""
"""Tuya Window cover device."""

# For most tuya devices 0 = Up/Open, 1 = Stop, 2 = Down/Close
tuya_cover_command = {0x0000: 0x0000, 0x0001: 0x0002, 0x0002: 0x0001}

# For all covers which need their position inverted by default
# Default (False) is 100 = open, 0 = closed; When True use 0 = open, 100 = closed instead
# Don't invert _TZE200_cowvfni3: https://github.com/Koenkk/zigbee2mqtt/issues/6043
tuya_cover_inverted_by_default = False

def __init__(self, *args, **kwargs):
"""Init device."""
Expand Down
Loading

0 comments on commit 170cc1f

Please sign in to comment.