Wow, very interesting- this is what I was looking for. Thank you!
If either of you are willing to test and are familiar with setting up a custom quirk, I believe this update will fix the issue -
(just add these 2 files your custom quirk folder named zhacustomquirks, or if you already have a folder, just change the import in VZM31SN.py “from zhacustomquirks import INOVELLI_AUTOMATION_TRIGGERS, Inovelli_VZM31SN_Cluster
” to reflect your folder name)
__init__.py
"""Module for Inovelli quirks implementations."""
import logging
from typing import Any, List, Optional, Union
from zigpy.quirks import CustomCluster
import zigpy.types as t
from zigpy.zcl import foundation
from zhaquirks.const import (
BUTTON,
BUTTON_1,
BUTTON_2,
BUTTON_3,
BUTTON_4,
BUTTON_5,
BUTTON_6,
COMMAND,
COMMAND_DOUBLE,
COMMAND_HOLD,
COMMAND_ID,
COMMAND_PRESS,
COMMAND_QUAD,
COMMAND_RELEASE,
COMMAND_TRIPLE,
DOUBLE_PRESS,
PRESS_TYPE,
QUADRUPLE_PRESS,
QUINTUPLE_PRESS,
TRIPLE_PRESS,
ZHA_SEND_EVENT,
)
_LOGGER = logging.getLogger(__name__)
INOVELLI_VZM31SN_CLUSTER_ID = 64561
# Press Types
# 0 - pressed
# 1 - released
# 2 - held
# 3 - 2x
# 4 - 3x
# 5 - 4x
# 6 - 5x
COMMAND_QUINTUPLE = "quintuple"
PRESS_TYPES = {
0: COMMAND_PRESS,
1: COMMAND_RELEASE,
2: COMMAND_HOLD,
3: COMMAND_DOUBLE,
4: COMMAND_TRIPLE,
5: COMMAND_QUAD,
6: COMMAND_QUINTUPLE,
}
LED_NOTIFICATION_TYPES = {
0: "LED_1",
1: "LED_2",
2: "LED_3",
3: "LED_4",
4: "LED_5",
5: "LED_6",
6: "LED_7",
16: "ALL_LEDS",
255: "CONFIG_BUTTON_DOUBLE_PRESS",
}
# Buttons
# 1 - down button
# 2 - up button
# 3 - config button
# 4 - aux down button
# 5 - aux up button
# 6 - aux config button
BUTTONS = {1: BUTTON_1, 2: BUTTON_2, 3: BUTTON_3, 4: BUTTON_4, 5: BUTTON_5, 6: BUTTON_6}
ON = "Up"
OFF = "Down"
CONFIG = "Config"
AUX_ON = "Aux Up"
AUX_OFF = "Aux Down"
AUX_CONFIG = "Aux Config"
NOTIFICATION_TYPE = "notification_type"
class Inovelli_Cluster(CustomCluster):
"""Inovelli base cluster."""
attributes = {
0x0001: ("dimming_speed_up_remote", t.uint8_t, True),
0x0003: ("ramp_rate_off_to_on_remote", t.uint8_t, True),
0x0005: ("dimming_speed_down_remote", t.uint8_t, True),
0x0007: ("ramp_rate_on_to_off_remote", t.uint8_t, True),
0x0009: ("minimum_level", t.uint8_t, True),
0x000A: ("maximum_level", t.uint8_t, True),
0x000C: ("auto_off_timer", t.uint16_t, True),
0x000E: ("default_level_remote", t.uint8_t, True),
0x000F: ("state_after_power_restored", t.uint8_t, True),
0x0015: ("power_type", t.uint8_t, True),
0x0020: ("internal_temp_monitor", t.uint8_t, True),
0x0021: ("overheated", t.Bool, True),
0x0034: ("smart_bulb_mode", t.Bool, True),
0x005F: ("led_color_when_on", t.uint8_t, True),
0x0061: ("led_intensity_when_on", t.uint8_t, True),
0x0101: ("remote_protection", t.Bool, True),
0x0102: ("output_mode", t.Bool, True),
}
server_commands = {
0x00: foundation.ZCLCommandDef(
"button_event",
{"button_pressed": t.uint8_t, "press_type": t.uint8_t},
direction=foundation.Direction.Server_to_Client,
is_manufacturer_specific=True,
),
0x01: foundation.ZCLCommandDef(
"led_effect",
{
"led_effect": t.uint8_t,
"led_color": t.uint8_t,
"led_level": t.uint8_t,
"led_duration": t.uint8_t,
},
direction=foundation.Direction.Server_to_Client,
is_manufacturer_specific=True,
),
0x02: foundation.ZCLCommandDef(
"reset_energy_meter",
{},
direction=foundation.Direction.Server_to_Client,
is_manufacturer_specific=True,
),
0x03: foundation.ZCLCommandDef(
"individual_led_effect",
{
"led_number": t.uint8_t,
"led_effect": t.uint8_t,
"led_color": t.uint8_t,
"led_level": t.uint8_t,
"led_duration": t.uint8_t,
},
direction=foundation.Direction.Server_to_Client,
is_manufacturer_specific=True,
),
0x24: foundation.ZCLCommandDef(
"led_effect_complete",
{
"notification_type": t.uint8_t,
},
direction=foundation.Direction.Server_to_Client,
is_manufacturer_specific=True,
),
}
def handle_cluster_request(
self,
hdr: foundation.ZCLHeader,
args: List[Any],
*,
dst_addressing: Optional[
Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
] = None,
):
"""Handle a cluster request."""
_LOGGER.debug(
"%s: handle_cluster_request - Command: %s Data: %s",
self.name,
hdr.command_id,
args,
)
if hdr.command_id == self.commands_by_name["button_event"].id:
button = BUTTONS[args.button_pressed]
press_type = PRESS_TYPES[args.press_type]
action = f"{button}_{press_type}"
event_args = {
BUTTON: button,
PRESS_TYPE: press_type,
COMMAND_ID: hdr.command_id,
}
self.listener_event(ZHA_SEND_EVENT, action, event_args)
return
if hdr.command_id == self.commands_by_name["led_effect_complete"].id:
notification_type = LED_NOTIFICATION_TYPES.get(
args.notification_type, "unknown"
)
action = f"led_effect_complete_{notification_type}"
event_args = {
NOTIFICATION_TYPE: notification_type,
COMMAND_ID: hdr.command_id,
}
self.listener_event(ZHA_SEND_EVENT, action, event_args)
return
class Inovelli_VZM31SN_Cluster(Inovelli_Cluster):
"""Inovelli VZM31-SN custom cluster."""
cluster_id = 0xFC31
name = "InovelliVZM31SNCluster"
ep_attribute = "inovelli_vzm31sn_cluster"
attributes = {
key: Inovelli_Cluster.attributes[key] for key in Inovelli_Cluster.attributes
}
attributes.update(
{
0x0002: ("dimming_speed_up_local", t.uint8_t, True),
0x0004: ("ramp_rate_off_to_on_local", t.uint8_t, True),
0x0006: ("dimming_speed_down_local", t.uint8_t, True),
0x0008: ("ramp_rate_on_to_off_local", t.uint8_t, True),
0x000B: ("invert_switch", t.Bool, True),
0x000D: ("default_level_local", t.uint8_t, True),
0x0011: ("load_level_indicator_timeout", t.uint8_t, True),
0x0012: ("active_power_reports", t.uint8_t, True),
0x0013: ("periodic_power_and_energy_reports", t.uint8_t, True),
0x0014: ("active_energy_reports", t.uint16_t, True),
0x0016: ("switch_type", t.uint8_t, True),
0x0019: ("increased_non_neutral_output", t.Bool, True),
0x001A: ("leading_or_trailing_edge", t.Bool, True),
0x0032: ("button_delay", t.uint8_t, True),
0x0033: ("device_bind_number", t.uint8_t, True),
0x0035: ("double_tap_up_enabled", t.Bool, True),
0x0036: ("double_tap_down_enabled", t.Bool, True),
0x0037: ("double_tap_up_level", t.uint8_t, True),
0x0038: ("double_tap_down_level", t.uint8_t, True),
0x003C: ("default_led1_strip_color_when_on", t.uint8_t, True),
0x003D: ("default_led1_strip_color_when_off", t.uint8_t, True),
0x003E: ("default_led1_strip_intensity_when_on", t.uint8_t, True),
0x003F: ("default_led1_strip_intensity_when_off", t.uint8_t, True),
0x0041: ("default_led2_strip_color_when_on", t.uint8_t, True),
0x0042: ("default_led2_strip_color_when_off", t.uint8_t, True),
0x0043: ("default_led2_strip_intensity_when_on", t.uint8_t, True),
0x0044: ("default_led2_strip_intensity_when_off", t.uint8_t, True),
0x0046: ("default_led3_strip_color_when_on", t.uint8_t, True),
0x0047: ("default_led3_strip_color_when_off", t.uint8_t, True),
0x0048: ("default_led3_strip_intensity_when_on", t.uint8_t, True),
0x0049: ("default_led3_strip_intensity_when_off", t.uint8_t, True),
0x004B: ("default_led4_strip_color_when_on", t.uint8_t, True),
0x004C: ("default_led4_strip_color_when_off", t.uint8_t, True),
0x004D: ("default_led4_strip_intensity_when_on", t.uint8_t, True),
0x004E: ("default_led4_strip_intensity_when_off", t.uint8_t, True),
0x0050: ("default_led5_strip_color_when_on", t.uint8_t, True),
0x0051: ("default_led5_strip_color_when_off", t.uint8_t, True),
0x0052: ("default_led5_strip_intensity_when_on", t.uint8_t, True),
0x0053: ("default_led5_strip_intensity_when_off", t.uint8_t, True),
0x0055: ("default_led6_strip_color_when_on", t.uint8_t, True),
0x0056: ("default_led6_strip_color_when_off", t.uint8_t, True),
0x0057: ("default_led6_strip_intensity_when_on", t.uint8_t, True),
0x0058: ("default_led6_strip_intensity_when_off", t.uint8_t, True),
0x005A: ("default_led7_strip_color_when_on", t.uint8_t, True),
0x005B: ("default_led7_strip_color_when_off", t.uint8_t, True),
0x005C: ("default_led7_strip_intensity_when_on", t.uint8_t, True),
0x005D: ("default_led7_strip_intensity_when_off", t.uint8_t, True),
0x0060: ("led_color_when_off", t.uint8_t, True),
0x0062: ("led_intensity_when_off", t.uint8_t, True),
0x0064: ("led_scaling_mode", t.Bool, True),
0x007B: ("aux_switch_scenes", t.Bool, True),
0x007D: ("binding_off_to_on_sync_level", t.Bool, True),
0x0100: ("local_protection", 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),
0x0106: ("disable_clear_notifications_double_tap", t.Bool, True),
}
)
class Inovelli_VZM35SN_Cluster(Inovelli_Cluster):
"""Inovelli VZM35-SN custom cluster."""
cluster_id = 0xFC31
name = "InovelliVZM35SNCluster"
ep_attribute = "inovelli_vzm31sn_cluster"
attributes = {
key: Inovelli_Cluster.attributes[key] for key in Inovelli_Cluster.attributes
}
attributes.update(
{
0x0002: ("dimming_speed_up_local", t.uint8_t, True),
0x0004: ("ramp_rate_off_to_on_local", t.uint8_t, True),
0x0006: ("dimming_speed_down_local", t.uint8_t, True),
0x0008: ("ramp_rate_on_to_off_local", t.uint8_t, True),
0x000B: ("invert_switch", t.Bool, True),
0x000D: ("default_level_local", t.uint8_t, True),
0x0011: ("load_level_indicator_timeout", t.uint8_t, True),
0x0016: ("switch_type", t.uint8_t, True),
0x0017: ("quick_start_time", t.uint8_t, True),
0x001E: ("non_neutral_aux_med_gear_learn_value", t.uint8_t, True),
0x001F: ("non_neutral_aux_low_gear_learn_value", t.uint8_t, True),
0x0032: ("button_delay", t.uint8_t, True),
0x0033: ("device_bind_number", t.uint8_t, True),
0x0034: ("smart_fan_mode", t.Bool, True),
0x0035: ("double_tap_up_enabled", t.Bool, True),
0x0036: ("double_tap_down_enabled", t.Bool, True),
0x0037: ("double_tap_up_level", t.uint8_t, True),
0x0038: ("double_tap_down_level", t.uint8_t, True),
0x003C: ("default_led1_strip_color_when_on", t.uint8_t, True),
0x003D: ("default_led1_strip_color_when_off", t.uint8_t, True),
0x003E: ("default_led1_strip_intensity_when_on", t.uint8_t, True),
0x003F: ("default_led1_strip_intensity_when_off", t.uint8_t, True),
0x0041: ("default_led2_strip_color_when_on", t.uint8_t, True),
0x0042: ("default_led2_strip_color_when_off", t.uint8_t, True),
0x0043: ("default_led2_strip_intensity_when_on", t.uint8_t, True),
0x0044: ("default_led2_strip_intensity_when_off", t.uint8_t, True),
0x0046: ("default_led3_strip_color_when_on", t.uint8_t, True),
0x0047: ("default_led3_strip_color_when_off", t.uint8_t, True),
0x0048: ("default_led3_strip_intensity_when_on", t.uint8_t, True),
0x0049: ("default_led3_strip_intensity_when_off", t.uint8_t, True),
0x004B: ("default_led4_strip_color_when_on", t.uint8_t, True),
0x004C: ("default_led4_strip_color_when_off", t.uint8_t, True),
0x004D: ("default_led4_strip_intensity_when_on", t.uint8_t, True),
0x004E: ("default_led4_strip_intensity_when_off", t.uint8_t, True),
0x0050: ("default_led5_strip_color_when_on", t.uint8_t, True),
0x0051: ("default_led5_strip_color_when_off", t.uint8_t, True),
0x0052: ("default_led5_strip_intensity_when_on", t.uint8_t, True),
0x0053: ("default_led5_strip_intensity_when_off", t.uint8_t, True),
0x0055: ("default_led6_strip_color_when_on", t.uint8_t, True),
0x0056: ("default_led6_strip_color_when_off", t.uint8_t, True),
0x0057: ("default_led6_strip_intensity_when_on", t.uint8_t, True),
0x0058: ("default_led6_strip_intensity_when_off", t.uint8_t, True),
0x005A: ("default_led7_strip_color_when_on", t.uint8_t, True),
0x005B: ("default_led7_strip_color_when_off", t.uint8_t, True),
0x005C: ("default_led7_strip_intensity_when_on", t.uint8_t, True),
0x005D: ("default_led7_strip_intensity_when_off", t.uint8_t, True),
0x0060: ("led_color_when_off", t.uint8_t, True),
0x0062: ("led_intensity_when_off", t.uint8_t, True),
0x0078: ("fan_single_tap_behavior", t.uint8_t, True),
0x0079: ("fan_timer_display", t.Bool, True),
0x007B: ("aux_switch_scenes", t.Bool, True),
0x0081: ("fan_breeze_mode", t.uint32_t, True),
0x0082: ("fan_module_binding_control", t.uint8_t, True),
0x0083: ("low_for_bound_control", t.uint8_t, True),
0x0084: ("medium_for_bound_control", t.uint8_t, True),
0x0085: ("high_for_bound_control", t.uint8_t, True),
0x0086: ("led_color_for_bound_control", t.uint8_t, True),
0x0100: ("local_protection", t.Bool, True),
0x0103: ("on_off_led_mode", t.Bool, True),
0x0104: ("firmware_progress_led", t.Bool, True),
0x0106: ("disable_clear_notifications_double_tap", t.Bool, True),
0x0107: ("smart_fan_led_display_levels", t.uint8_t, True),
}
)
class Inovelli_VZM36_Light_Cluster(Inovelli_Cluster):
"""Inovelli VZM36 Light custom cluster."""
cluster_id = 0xFC31
name = "InovelliVZM36LightCluster"
ep_attribute = "inovelli_vzm31sn_cluster"
attributes = {
key: Inovelli_Cluster.attributes[key] for key in Inovelli_Cluster.attributes
}
attributes.update(
{
0x0017: ("quick_start_time", t.uint8_t, True),
0x0018: ("quick_start_level", t.uint8_t, True),
0x0019: ("increased_non_neutral_output", t.Bool, True),
}
)
class Inovelli_VZM36_Fan_Cluster(Inovelli_Cluster):
"""Inovelli VZM36 Fan custom cluster."""
cluster_id = 0xFC31
name = "InovelliVZM36FanCluster"
ep_attribute = "inovelli_vzm31sn_cluster"
attributes = {
key: Inovelli_Cluster.attributes[key] for key in Inovelli_Cluster.attributes
}
attributes.update(
{
0x0017: ("quick_start_time", t.uint8_t, True),
0x0034: ("smart_fan_mode", t.Bool, True),
0x0081: ("breeze_mode", t.uint32_t, True),
}
)
INOVELLI_AUTOMATION_TRIGGERS = {
(COMMAND_PRESS, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_PRESS}"},
(COMMAND_PRESS, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_PRESS}"},
(COMMAND_PRESS, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_PRESS}"},
(COMMAND_PRESS, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_PRESS}"},
(COMMAND_PRESS, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_PRESS}"},
(COMMAND_PRESS, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_PRESS}"},
(COMMAND_HOLD, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_HOLD}"},
(COMMAND_HOLD, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_HOLD}"},
(COMMAND_HOLD, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_HOLD}"},
(COMMAND_HOLD, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_HOLD}"},
(COMMAND_HOLD, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_HOLD}"},
(COMMAND_HOLD, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_HOLD}"},
(DOUBLE_PRESS, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_DOUBLE}"},
(DOUBLE_PRESS, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_DOUBLE}"},
(DOUBLE_PRESS, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_DOUBLE}"},
(DOUBLE_PRESS, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_DOUBLE}"},
(DOUBLE_PRESS, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_DOUBLE}"},
(DOUBLE_PRESS, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_DOUBLE}"},
(TRIPLE_PRESS, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_TRIPLE}"},
(TRIPLE_PRESS, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_TRIPLE}"},
(TRIPLE_PRESS, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_TRIPLE}"},
(TRIPLE_PRESS, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_TRIPLE}"},
(TRIPLE_PRESS, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_TRIPLE}"},
(TRIPLE_PRESS, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_TRIPLE}"},
(QUADRUPLE_PRESS, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_QUAD}"},
(QUADRUPLE_PRESS, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_QUAD}"},
(QUADRUPLE_PRESS, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_QUAD}"},
(QUADRUPLE_PRESS, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_QUAD}"},
(QUADRUPLE_PRESS, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_QUAD}"},
(QUADRUPLE_PRESS, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_QUAD}"},
(QUINTUPLE_PRESS, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_QUINTUPLE}"},
(QUINTUPLE_PRESS, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_QUINTUPLE}"},
(QUINTUPLE_PRESS, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_QUINTUPLE}"},
(QUINTUPLE_PRESS, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_QUINTUPLE}"},
(QUINTUPLE_PRESS, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_QUINTUPLE}"},
(QUINTUPLE_PRESS, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_QUINTUPLE}"},
(COMMAND_RELEASE, ON): {COMMAND: f"{BUTTON_2}_{COMMAND_RELEASE}"},
(COMMAND_RELEASE, OFF): {COMMAND: f"{BUTTON_1}_{COMMAND_RELEASE}"},
(COMMAND_RELEASE, CONFIG): {COMMAND: f"{BUTTON_3}_{COMMAND_RELEASE}"},
(COMMAND_RELEASE, AUX_ON): {COMMAND: f"{BUTTON_5}_{COMMAND_RELEASE}"},
(COMMAND_RELEASE, AUX_OFF): {COMMAND: f"{BUTTON_4}_{COMMAND_RELEASE}"},
(COMMAND_RELEASE, AUX_CONFIG): {COMMAND: f"{BUTTON_6}_{COMMAND_RELEASE}"},
}
VZM31SN.py
"""VZM31-SN Two in One Switch/Dimmer Module."""
from zigpy.profiles import zgp, zha
from zigpy.profiles.zha import DeviceType
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
Basic,
GreenPowerProxy,
Groups,
Identify,
LevelControl,
OnOff,
Ota,
Scenes,
)
from zigpy.zcl.clusters.homeautomation import Diagnostic, ElectricalMeasurement
from zigpy.zcl.clusters.smartenergy import Metering
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
#from zhaquirks.inovelli import INOVELLI_AUTOMATION_TRIGGERS, Inovelli_VZM31SN_Cluster
from zhacustomquirks import INOVELLI_AUTOMATION_TRIGGERS, Inovelli_VZM31SN_Cluster
INOVELLI_VZM31SN_CLUSTER_ID = 64561
WWAH_CLUSTER_ID = 64599
class InovelliVZM31SNv12(CustomDevice):
"""VZM31-SN 2 in 1 Switch/Dimmer Module Firmware version 2.08 and above."""
signature = {
MODELS_INFO: [("Inovelli", "VZM31-SN")],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
Inovelli_VZM31SN_Cluster,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [
Ota.cluster_id,
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
device_automation_triggers = INOVELLI_AUTOMATION_TRIGGERS
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,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
Inovelli_VZM31SN_Cluster,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Ota.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
device_automation_triggers = INOVELLI_AUTOMATION_TRIGGERS
class InovelliVZM31SNv10(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,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
Inovelli_VZM31SN_Cluster,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Ota.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Basic.cluster_id, Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
},
}
device_automation_triggers = INOVELLI_AUTOMATION_TRIGGERS
class InovelliVZM31SNv9(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.DIMMER_SWITCH,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
Inovelli_VZM31SN_Cluster,
WWAH_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Ota.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
},
}
device_automation_triggers = INOVELLI_AUTOMATION_TRIGGERS
class InovelliVZM31SN(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.DIMMER_SWITCH,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
],
OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
INOVELLI_VZM31SN_CLUSTER_ID,
],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
Diagnostic.cluster_id,
Inovelli_VZM31SN_Cluster,
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Ota.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: DeviceType.DIMMER_SWITCH,
INPUT_CLUSTERS: [Identify.cluster_id],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Inovelli_VZM31SN_Cluster,
],
},
},
}
device_automation_triggers = INOVELLI_AUTOMATION_TRIGGERS
Assuming that works as expected, I’ll get a PR in to update the quirk properly and you won’t need the custom one once it’s live.
1 Like
Awesome, I’ll get a PR in for it tonight, thanks!
2 Likes
Y’all are amazing - thanks very much.
Just following up on this, I don’t have an aux switch setup to test but I do believe that @chack put in a PR to get this functionality sorted out.