11"""Interfaces with Multimatic climate."""
22from __future__ import annotations
33
4- import abc
4+ from abc import ABC , abstractmethod
55from collections .abc import Mapping
66import logging
77from typing import Any
4949 PRESET_QUICK_VETO ,
5050 PRESET_SYSTEM_OFF ,
5151 ROOMS ,
52+ SENSO ,
5253 VENTILATION ,
5354 ZONES ,
55+ CONF_APPLICATION ,
5456)
5557from .coordinator import MultimaticCoordinator
5658from .entities import MultimaticEntity
@@ -74,11 +76,12 @@ async def async_setup_entry(
7476 zones_coo = get_coordinator (hass , ZONES , entry .entry_id )
7577 rooms_coo = get_coordinator (hass , ROOMS , entry .entry_id )
7678 ventilation_coo = get_coordinator (hass , VENTILATION , entry .entry_id )
79+ system_application = SENSO if entry .data [CONF_APPLICATION ] == SENSO else MULTIMATIC
7780
7881 if zones_coo .data :
7982 for zone in zones_coo .data :
8083 if not zone .rbr and zone .enabled :
81- climates .append (ZoneClimate (zones_coo , zone , ventilation_coo .data ))
84+ climates .append (build_zone_climate (zones_coo , zone , ventilation_coo .data , system_application ))
8285
8386 if rooms_coo .data :
8487 rbr_zone = next ((zone for zone in zones_coo .data if zone .rbr ), None )
@@ -103,7 +106,7 @@ async def async_setup_entry(
103106 )
104107
105108
106- class MultimaticClimate (MultimaticEntity , ClimateEntity , abc . ABC ):
109+ class MultimaticClimate (MultimaticEntity , ClimateEntity , ABC ):
107110 """Base class for climate."""
108111
109112 def __init__ (
@@ -131,7 +134,7 @@ def active_mode(self) -> ActiveMode:
131134 return self .coordinator .api .get_active_mode (self .component )
132135
133136 @property
134- @abc . abstractmethod
137+ @abstractmethod
135138 def component (self ) -> Component :
136139 """Return the room or the zone."""
137140
@@ -362,52 +365,22 @@ def current_humidity(self) -> int | None:
362365 return int (humidity ) if humidity is not None else None
363366
364367
365- class ZoneClimate (MultimaticClimate ):
366- """Climate for a zone."""
368+ def build_zone_climate (coordinator : MultimaticCoordinator , zone : Zone , ventilation , application ) -> AbstractZoneClimate :
369+ if application == MULTIMATIC :
370+ return ZoneClimate (coordinator , zone , ventilation )
371+ return ZoneClimateSenso (coordinator , zone , ventilation )
367372
368- _MULTIMATIC_TO_HA : dict [Mode , list ] = {
369- OperatingModes .AUTO : [HVACMode .AUTO , PRESET_COMFORT ],
370- OperatingModes .DAY : [None , PRESET_DAY ],
371- OperatingModes .NIGHT : [None , PRESET_SLEEP ],
372- OperatingModes .OFF : [HVACMode .OFF , PRESET_NONE ],
373- OperatingModes .ON : [None , PRESET_COOLING_ON ],
374- OperatingModes .QUICK_VETO : [None , PRESET_QUICK_VETO ],
375- QuickModes .ONE_DAY_AT_HOME : [HVACMode .AUTO , PRESET_HOME ],
376- QuickModes .PARTY : [None , PRESET_PARTY ],
377- QuickModes .VENTILATION_BOOST : [HVACMode .FAN_ONLY , PRESET_NONE ],
378- QuickModes .ONE_DAY_AWAY : [HVACMode .OFF , PRESET_AWAY ],
379- QuickModes .SYSTEM_OFF : [HVACMode .OFF , PRESET_SYSTEM_OFF ],
380- QuickModes .HOLIDAY : [HVACMode .OFF , PRESET_HOLIDAY ],
381- QuickModes .COOLING_FOR_X_DAYS : [None , PRESET_COOLING_FOR_X_DAYS ],
382- }
383-
384- _HA_MODE_TO_MULTIMATIC = {
385- HVACMode .AUTO : OperatingModes .AUTO ,
386- HVACMode .OFF : OperatingModes .OFF ,
387- HVACMode .FAN_ONLY : QuickModes .VENTILATION_BOOST ,
388- HVACMode .COOL : QuickModes .COOLING_FOR_X_DAYS ,
389- }
390-
391- _HA_PRESET_TO_MULTIMATIC = {
392- PRESET_COMFORT : OperatingModes .AUTO ,
393- PRESET_DAY : OperatingModes .DAY ,
394- PRESET_SLEEP : OperatingModes .NIGHT ,
395- PRESET_COOLING_ON : OperatingModes .ON ,
396- PRESET_HOME : QuickModes .ONE_DAY_AT_HOME ,
397- PRESET_PARTY : QuickModes .PARTY ,
398- PRESET_AWAY : QuickModes .ONE_DAY_AWAY ,
399- PRESET_SYSTEM_OFF : QuickModes .SYSTEM_OFF ,
400- PRESET_COOLING_FOR_X_DAYS : QuickModes .COOLING_FOR_X_DAYS ,
401- }
402373
374+ class AbstractZoneClimate (MultimaticClimate , ABC ):
375+ """Abstract class for a climate for a zone."""
403376 def __init__ (
404377 self , coordinator : MultimaticCoordinator , zone : Zone , ventilation
405378 ) -> None :
406379 """Initialize entity."""
407380 super ().__init__ (coordinator , zone .id )
408381
409- self ._supported_hvac = list (ZoneClimate . _HA_MODE_TO_MULTIMATIC .keys ())
410- self ._supported_presets = list (ZoneClimate . _HA_PRESET_TO_MULTIMATIC .keys ())
382+ self ._supported_hvac = list (self . _ha_mode () .keys ())
383+ self ._supported_presets = list (self . _ha_preset () .keys ())
411384
412385 if not zone .cooling :
413386 self ._supported_presets .remove (PRESET_COOLING_ON )
@@ -419,6 +392,18 @@ def __init__(
419392
420393 self ._zone_id = zone .id
421394
395+ @abstractmethod
396+ def _ha_mode (self ):
397+ pass
398+
399+ @abstractmethod
400+ def _multimatic_mode (self ):
401+ pass
402+
403+ @abstractmethod
404+ def _ha_preset (self ):
405+ pass
406+
422407 @property
423408 def extra_state_attributes (self ) -> Mapping [str , Any ] | None :
424409 """Return entity specific state attributes."""
@@ -438,7 +423,7 @@ def component(self) -> Zone:
438423 def hvac_mode (self ) -> HVACMode :
439424 """Get the hvac mode based on multimatic mode."""
440425 current_mode = self .active_mode .current
441- hvac_mode = ZoneClimate . _MULTIMATIC_TO_HA [current_mode ][0 ]
426+ hvac_mode = self . _multimatic_mode () [current_mode ][0 ]
442427 if not hvac_mode :
443428 if (
444429 current_mode
@@ -497,7 +482,7 @@ async def async_set_temperature(self, **kwargs: Any) -> None:
497482
498483 async def async_set_hvac_mode (self , hvac_mode : HVACMode ) -> None :
499484 """Set new target hvac mode."""
500- mode = ZoneClimate . _HA_MODE_TO_MULTIMATIC [hvac_mode ]
485+ mode = self . _ha_mode () [hvac_mode ]
501486 await self .coordinator .api .set_zone_operating_mode (self , mode )
502487
503488 @property
@@ -511,7 +496,7 @@ def hvac_action(self) -> str | None:
511496 @property
512497 def preset_mode (self ) -> str | None :
513498 """Return the current preset mode, e.g., home, away, temp."""
514- return ZoneClimate . _MULTIMATIC_TO_HA [self .active_mode .current ][1 ]
499+ return self . _multimatic_mode () [self .active_mode .current ][1 ]
515500
516501 @property
517502 def preset_modes (self ) -> list [str ] | None :
@@ -522,5 +507,99 @@ def preset_modes(self) -> list[str] | None:
522507
523508 async def async_set_preset_mode (self , preset_mode : str ) -> None :
524509 """Set new target preset mode."""
525- mode = ZoneClimate . _HA_PRESET_TO_MULTIMATIC [preset_mode ]
510+ mode = self . _ha_preset () [preset_mode ]
526511 await self .coordinator .api .set_zone_operating_mode (self , mode )
512+
513+ class ZoneClimate (AbstractZoneClimate ):
514+ """Climate for a MULTIMATIC zone."""
515+
516+ _MULTIMATIC_TO_HA : dict [Mode , list ] = {
517+ OperatingModes .AUTO : [HVACMode .AUTO , PRESET_COMFORT ],
518+ OperatingModes .DAY : [None , PRESET_DAY ],
519+ OperatingModes .NIGHT : [None , PRESET_SLEEP ],
520+ OperatingModes .OFF : [HVACMode .OFF , PRESET_NONE ],
521+ OperatingModes .ON : [None , PRESET_COOLING_ON ],
522+ OperatingModes .QUICK_VETO : [None , PRESET_QUICK_VETO ],
523+ QuickModes .ONE_DAY_AT_HOME : [HVACMode .AUTO , PRESET_HOME ],
524+ QuickModes .PARTY : [None , PRESET_PARTY ],
525+ QuickModes .VENTILATION_BOOST : [HVACMode .FAN_ONLY , PRESET_NONE ],
526+ QuickModes .ONE_DAY_AWAY : [HVACMode .OFF , PRESET_AWAY ],
527+ QuickModes .SYSTEM_OFF : [HVACMode .OFF , PRESET_SYSTEM_OFF ],
528+ QuickModes .HOLIDAY : [HVACMode .OFF , PRESET_HOLIDAY ],
529+ QuickModes .COOLING_FOR_X_DAYS : [None , PRESET_COOLING_FOR_X_DAYS ],
530+ }
531+
532+ _HA_MODE_TO_MULTIMATIC = {
533+ HVACMode .AUTO : OperatingModes .AUTO ,
534+ HVACMode .OFF : OperatingModes .OFF ,
535+ HVACMode .FAN_ONLY : QuickModes .VENTILATION_BOOST ,
536+ HVACMode .COOL : QuickModes .COOLING_FOR_X_DAYS ,
537+ }
538+
539+ _HA_PRESET_TO_MULTIMATIC = {
540+ PRESET_COMFORT : OperatingModes .AUTO ,
541+ PRESET_DAY : OperatingModes .DAY ,
542+ PRESET_SLEEP : OperatingModes .NIGHT ,
543+ PRESET_COOLING_ON : OperatingModes .ON ,
544+ PRESET_HOME : QuickModes .ONE_DAY_AT_HOME ,
545+ PRESET_PARTY : QuickModes .PARTY ,
546+ PRESET_AWAY : QuickModes .ONE_DAY_AWAY ,
547+ PRESET_SYSTEM_OFF : QuickModes .SYSTEM_OFF ,
548+ PRESET_COOLING_FOR_X_DAYS : QuickModes .COOLING_FOR_X_DAYS ,
549+ }
550+
551+ def _ha_mode (self ):
552+ return ZoneClimate ._HA_MODE_TO_MULTIMATIC
553+
554+ def _multimatic_mode (self ):
555+ return ZoneClimate ._MULTIMATIC_TO_HA
556+
557+ def _ha_preset (self ):
558+ return ZoneClimate ._HA_PRESET_TO_MULTIMATIC
559+
560+
561+ class ZoneClimateSenso (AbstractZoneClimate ):
562+ """Climate for a SENSO zone."""
563+
564+ _SENSO_TO_HA : dict [Mode , list ] = {
565+ OperatingModes .TIME_CONTROLLED : [HVACMode .AUTO , PRESET_COMFORT ],
566+ OperatingModes .DAY : [None , PRESET_DAY ],
567+ OperatingModes .NIGHT : [None , PRESET_SLEEP ],
568+ OperatingModes .OFF : [HVACMode .OFF , PRESET_NONE ],
569+ OperatingModes .MANUAL : [None , PRESET_COOLING_ON ],
570+ OperatingModes .QUICK_VETO : [None , PRESET_QUICK_VETO ],
571+ QuickModes .ONE_DAY_AT_HOME : [HVACMode .AUTO , PRESET_HOME ],
572+ QuickModes .PARTY : [None , PRESET_PARTY ],
573+ QuickModes .VENTILATION_BOOST : [HVACMode .FAN_ONLY , PRESET_NONE ],
574+ QuickModes .ONE_DAY_AWAY : [HVACMode .OFF , PRESET_AWAY ],
575+ QuickModes .SYSTEM_OFF : [HVACMode .OFF , PRESET_SYSTEM_OFF ],
576+ QuickModes .HOLIDAY : [HVACMode .OFF , PRESET_HOLIDAY ],
577+ QuickModes .COOLING_FOR_X_DAYS : [None , PRESET_COOLING_FOR_X_DAYS ],
578+ }
579+ _HA_MODE_TO_SENSO = {
580+ HVACMode .AUTO : OperatingModes .TIME_CONTROLLED ,
581+ HVACMode .OFF : OperatingModes .OFF ,
582+ HVACMode .FAN_ONLY : QuickModes .VENTILATION_BOOST ,
583+ HVACMode .COOL : QuickModes .COOLING_FOR_X_DAYS ,
584+ }
585+
586+ _HA_PRESET_TO_SENSO = {
587+ PRESET_COMFORT : OperatingModes .TIME_CONTROLLED ,
588+ PRESET_DAY : OperatingModes .DAY ,
589+ PRESET_SLEEP : OperatingModes .NIGHT ,
590+ PRESET_COOLING_ON : OperatingModes .MANUAL ,
591+ PRESET_HOME : QuickModes .ONE_DAY_AT_HOME ,
592+ PRESET_PARTY : QuickModes .PARTY ,
593+ PRESET_AWAY : QuickModes .ONE_DAY_AWAY ,
594+ PRESET_SYSTEM_OFF : QuickModes .SYSTEM_OFF ,
595+ PRESET_COOLING_FOR_X_DAYS : QuickModes .COOLING_FOR_X_DAYS ,
596+ }
597+
598+ def _ha_mode (self ):
599+ return ZoneClimateSenso ._HA_MODE_TO_SENSO
600+
601+ def _multimatic_mode (self ):
602+ return ZoneClimateSenso ._SENSO_TO_HA
603+
604+ def _ha_preset (self ):
605+ return ZoneClimateSenso ._HA_PRESET_TO_SENSO
0 commit comments