Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d25a53f
Fix thermostat fan modes to respect fanModeSequence and expose FAN_ON…
vmvarga Mar 12, 2026
2886d25
Apply pre-commit auto fixes
pre-commit-ci[bot] Mar 12, 2026
2304728
Update constants
vmvarga Mar 12, 2026
75510aa
Merge branch 'dev' of https://github.com/vmvarga/zha into dev
vmvarga Mar 12, 2026
dad0f4d
Merge branch 'dev' of https://github.com/zigpy/zha into dev
vmvarga Mar 13, 2026
edfb246
add test
vmvarga Mar 13, 2026
cb6aa3b
Merge branch 'dev' of https://github.com/zigpy/zha into dev
vmvarga Apr 20, 2026
4e3737c
Opt-in fan only via quirks
vmvarga Apr 20, 2026
4f3b43b
Merge remote-tracking branch 'origin/dev' into dev
vmvarga Jun 11, 2026
08c3a7a
Merge branch 'dev' into dev
vmvarga Jun 12, 2026
2dcb767
move fan_only_hvac to zhaquirks
vmvarga Jun 15, 2026
29b4b0d
Merge branch 'dev' of https://github.com/zigpy/zha into dev
vmvarga Jun 15, 2026
4b4a111
Merge branch 'dev' of https://github.com/vmvarga/zha into dev
vmvarga Jun 15, 2026
dcee206
Merge remote-tracking branch 'origin/dev' into dev
vmvarga Jun 25, 2026
a83fa04
Merge remote-tracking branch 'origin/dev' into dev
vmvarga Jul 8, 2026
b3752d5
Merge branch 'dev' into dev
vmvarga Jul 11, 2026
f4ca46c
Merge branch 'dev' into dev
vmvarga Jul 16, 2026
02195a6
Merge branch 'dev' into dev
vmvarga Jul 17, 2026
e636bb3
Merge branch 'dev' into vmvarga-dev
puddly Jul 29, 2026
cb51c85
pre-commit
puddly Jul 29, 2026
4db4310
Fix thermostat fan mode event wiring and ZCL mapping edge cases
vmvarga Jul 29, 2026
666c011
Merge branch 'dev' into dev
vmvarga Jul 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions zha/application/platforms/climate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

from zigpy.profiles import zha
from zigpy.zcl.clusters.hvac import (
FanMode,
RunningState,
SystemMode,
Thermostat as ThermostatCluster,
Expand All @@ -35,12 +34,15 @@
ATTR_UNOCCP_COOL_SETPT,
ATTR_UNOCCP_HEAT_SETPT,
FAN_AUTO,
FAN_MODE_TO_ZCL,
FAN_ON,
HVAC_MODE_2_SYSTEM,
PRECISION_TENTHS,
SEQ_FAN_MODES,
SEQ_OF_OPERATION,
SYSTEM_MODE_2_HVAC,
ZCL_TEMP,
ZCL_TO_FAN_MODE,
ClimateEntityFeature,
HVACAction,
HVACMode,
Expand Down Expand Up @@ -332,9 +334,12 @@ def outdoor_temperature(self):
@property
def fan_mode(self) -> str | None:
"""Return current FAN mode."""
if self._fan_cluster_handler is not None:
current = self._fan_cluster_handler.fan_mode
if current is not None:
return ZCL_TO_FAN_MODE.get(current, FAN_AUTO)
Comment thread
vmvarga marked this conversation as resolved.
Outdated
if self._thermostat_cluster_handler.running_state is None:
return FAN_AUTO

if self._thermostat_cluster_handler.running_state & (
RunningState.Fan_State_On
| RunningState.Fan_2nd_Stage_On
Expand All @@ -348,7 +353,8 @@ def fan_modes(self) -> list[str] | None:
"""Return supported FAN modes."""
if not self._fan_cluster_handler:
return None
return [FAN_AUTO, FAN_ON]
seq = self._fan_cluster_handler.fan_mode_sequence
return SEQ_FAN_MODES.get(seq, [FAN_ON, FAN_AUTO])
Comment thread
vmvarga marked this conversation as resolved.
Outdated

@property
def hvac_action(self) -> HVACAction | None:
Expand Down Expand Up @@ -409,9 +415,12 @@ def hvac_mode(self) -> HVACMode | None:
@property
def hvac_modes(self) -> list[HVACMode]:
"""Return the list of available HVAC operation modes."""
return SEQ_OF_OPERATION.get(
modes = SEQ_OF_OPERATION.get(
self._thermostat_cluster_handler.ctrl_sequence_of_oper, [HVACMode.OFF]
)
if self._fan_cluster_handler is not None and HVACMode.FAN_ONLY not in modes:
modes = [*modes, HVACMode.FAN_ONLY]
return modes

@property
def preset_mode(self) -> str:
Expand Down Expand Up @@ -538,9 +547,12 @@ async def async_set_fan_mode(self, fan_mode: str) -> None:
self.warning("Unsupported '%s' fan mode", fan_mode)
return

mode = FanMode.On if fan_mode == FAN_ON else FanMode.Auto
zcl_mode = FAN_MODE_TO_ZCL.get(fan_mode)
if zcl_mode is None:
self.warning("No ZCL mapping for fan mode '%s'", fan_mode)
return

await self._fan_cluster_handler.async_set_speed(mode)
await self._fan_cluster_handler.async_set_speed(zcl_mode)

async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target operation mode."""
Expand Down
25 changes: 24 additions & 1 deletion zha/application/platforms/climate/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
from enum import IntFlag, StrEnum
from typing import Final

from zigpy.zcl.clusters.hvac import ControlSequenceOfOperation, RunningMode, SystemMode
from zigpy.zcl.clusters.hvac import (
ControlSequenceOfOperation,
FanMode,
RunningMode,
SystemMode,
)

ATTR_SYS_MODE: Final[str] = "system_mode"
ATTR_FAN_MODE: Final[str] = "fan_mode"
Expand Down Expand Up @@ -141,6 +146,24 @@ class HVACAction(StrEnum):
PREHEATING = "preheating"


SEQ_FAN_MODES: dict[int, list[str]] = {
0x00: [FAN_LOW, FAN_MEDIUM, FAN_HIGH],
Comment thread
puddly marked this conversation as resolved.
Outdated
0x01: [FAN_LOW, FAN_HIGH],
0x02: [FAN_LOW, FAN_MEDIUM, FAN_HIGH, FAN_AUTO],
0x03: [FAN_LOW, FAN_HIGH, FAN_AUTO],
0x04: [FAN_ON, FAN_AUTO],
}

FAN_MODE_TO_ZCL: dict[str, FanMode] = {
FAN_LOW: FanMode.Low,
FAN_MEDIUM: FanMode.Medium,
FAN_HIGH: FanMode.High,
FAN_ON: FanMode.On,
FAN_AUTO: FanMode.Auto,
}

ZCL_TO_FAN_MODE: dict[int, str] = {v: k for k, v in FAN_MODE_TO_ZCL.items()}
Comment thread
vmvarga marked this conversation as resolved.
Outdated

RUNNING_MODE = {
RunningMode.Off: HVACMode.OFF,
RunningMode.Cool: HVACMode.COOL,
Expand Down
Loading