From 4618faa5a5f187a6e648ea94f2dc71cb40f502ec Mon Sep 17 00:00:00 2001 From: InovelliUSA Date: Thu, 30 Jul 2026 11:29:51 -0600 Subject: [PATCH 1/3] Add an InovelliFan entity implementation --- zha/application/platforms/fan/__init__.py | 33 ++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/zha/application/platforms/fan/__init__.py b/zha/application/platforms/fan/__init__.py index ed37f19dd..df9d928d8 100644 --- a/zha/application/platforms/fan/__init__.py +++ b/zha/application/platforms/fan/__init__.py @@ -15,7 +15,7 @@ AttributeWrittenEvent, ReportingConfig, ) -from zigpy.zcl.clusters import hvac +from zigpy.zcl.clusters import general, hvac from zha.application import Platform from zha.application.helpers import safe_read, write_attributes_safe @@ -585,3 +585,34 @@ def speed_range(self) -> tuple[int, int]: def preset_modes_to_name(self) -> dict[int, str]: """Return a dict from preset mode to name.""" return {6: PRESET_MODE_SMART} + +@register_entity(hvac.Fan.cluster_id) +class InovelliFan(Fan): + """Representation of an Inovelli fan.""" + + _cluster_handler_match = ClusterHandlerMatch( + cluster_handlers=frozenset({CLUSTER_HANDLER_FAN}), + manufacturers=frozenset({"Inovelli"}), + models=frozenset({"VZM35-SN","VZM36",}), + feature_priority=(PlatformFeatureGroup.THERMOSTAT_FAN, 1), + ) + + async def async_turn_on( + self, + speed: str | None = None, + percentage: int | None = None, + preset_mode: str | None = None, + ) -> None: + """Turn the entity on.""" + if speed is None and percentage is None and preset_mode is None: + on_off_cluster = self.endpoint.zigpy_endpoint.in_clusters[ + general.OnOff.cluster_id + ] + await on_off_cluster.on() + return + + await super().async_turn_on( + speed=speed, + percentage=percentage, + preset_mode=preset_mode, + ) \ No newline at end of file From 10570795b68f5d0b4080e95311aa85912a9ebf32 Mon Sep 17 00:00:00 2001 From: InovelliUSA Date: Thu, 30 Jul 2026 13:02:04 -0600 Subject: [PATCH 2/3] Fix correct ClusterMatch --- zha/application/platforms/fan/__init__.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/zha/application/platforms/fan/__init__.py b/zha/application/platforms/fan/__init__.py index df9d928d8..260880e00 100644 --- a/zha/application/platforms/fan/__init__.py +++ b/zha/application/platforms/fan/__init__.py @@ -590,10 +590,15 @@ def preset_modes_to_name(self) -> dict[int, str]: class InovelliFan(Fan): """Representation of an Inovelli fan.""" - _cluster_handler_match = ClusterHandlerMatch( - cluster_handlers=frozenset({CLUSTER_HANDLER_FAN}), + _cluster_match = ClusterMatch( + server_clusters=frozenset({hvac.Fan.cluster_id}), manufacturers=frozenset({"Inovelli"}), - models=frozenset({"VZM35-SN","VZM36",}), + models=frozenset( + { + "VZM35-SN", + "VZM36", + } + ), feature_priority=(PlatformFeatureGroup.THERMOSTAT_FAN, 1), ) From ef187857eb2270f3f4a7fa1d3c7aff45e5d110db Mon Sep 17 00:00:00 2001 From: InovelliUSA Date: Sat, 8 Aug 2026 07:11:08 -0600 Subject: [PATCH 3/3] spacing update and unit test update --- tests/data/devices/inovelli-vzm36.json | 2 +- zha/application/platforms/fan/__init__.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/data/devices/inovelli-vzm36.json b/tests/data/devices/inovelli-vzm36.json index 1795b261f..8a5cfb160 100644 --- a/tests/data/devices/inovelli-vzm36.json +++ b/tests/data/devices/inovelli-vzm36.json @@ -441,7 +441,7 @@ "unique_id": "ab:cd:ef:12:25:9f:47:fc-2-514", "migrate_unique_ids": [], "platform": "fan", - "class_name": "Fan", + "class_name": "InovelliFan", "translation_key": "fan", "translation_placeholders": null, "device_class": null, diff --git a/zha/application/platforms/fan/__init__.py b/zha/application/platforms/fan/__init__.py index 260880e00..27bb22d9d 100644 --- a/zha/application/platforms/fan/__init__.py +++ b/zha/application/platforms/fan/__init__.py @@ -586,6 +586,7 @@ def preset_modes_to_name(self) -> dict[int, str]: """Return a dict from preset mode to name.""" return {6: PRESET_MODE_SMART} + @register_entity(hvac.Fan.cluster_id) class InovelliFan(Fan): """Representation of an Inovelli fan.""" @@ -620,4 +621,4 @@ async def async_turn_on( speed=speed, percentage=percentage, preset_mode=preset_mode, - ) \ No newline at end of file + )