99 ATTR_TARGET_TEMP_HIGH ,
1010 ATTR_TARGET_TEMP_LOW ,
1111 PRESET_AWAY ,
12+ PRESET_BOOST ,
1213 PRESET_COMFORT ,
1314 PRESET_ECO ,
1415 PRESET_NONE ,
1516 ClimateEntity ,
1617 ClimateEntityFeature ,
17- HVACAction ,
1818 HVACMode ,
1919)
20- from homeassistant .config_entries import ConfigEntry
2120from homeassistant .const import ATTR_TEMPERATURE , PRECISION_HALVES , UnitOfTemperature
2221from homeassistant .core import HomeAssistant
22+ from homeassistant .exceptions import ServiceValidationError
2323from homeassistant .helpers .entity_platform import AddConfigEntryEntitiesCallback
2424
25- from .coordinator import CometBlueDataUpdateCoordinator
25+ from .coordinator import CometBlueConfigEntry , CometBlueDataUpdateCoordinator
2626from .entity import CometBlueBluetoothEntity
2727
2828LOGGER = logging .getLogger (__name__ )
3131MIN_TEMP = 7.5
3232MAX_TEMP = 28.5
3333
34- DEFAULT_PRESETS = {PRESET_COMFORT , PRESET_ECO }
35-
3634
3735async def async_setup_entry (
3836 hass : HomeAssistant ,
39- entry : ConfigEntry ,
37+ entry : CometBlueConfigEntry ,
4038 async_add_entities : AddConfigEntryEntitiesCallback ,
4139) -> None :
4240 """Set up the client entities."""
4341
44- coordinator : CometBlueDataUpdateCoordinator = entry .runtime_data
42+ coordinator = entry .runtime_data
4543 async_add_entities ([CometBlueClimateEntity (coordinator )])
4644
4745
@@ -53,10 +51,11 @@ class CometBlueClimateEntity(CometBlueBluetoothEntity, ClimateEntity):
5351 _attr_name = None
5452 _attr_hvac_modes = [HVACMode .AUTO , HVACMode .HEAT , HVACMode .OFF ]
5553 _attr_preset_modes = [
56- PRESET_NONE ,
54+ PRESET_COMFORT ,
5755 PRESET_ECO ,
56+ PRESET_BOOST ,
5857 PRESET_AWAY ,
59- PRESET_COMFORT ,
58+ PRESET_NONE ,
6059 ]
6160 _attr_supported_features : ClimateEntityFeature = (
6261 ClimateEntityFeature .TARGET_TEMPERATURE
@@ -72,27 +71,27 @@ def __init__(self, coordinator: CometBlueDataUpdateCoordinator) -> None:
7271 """Initialize CometBlueClimateEntity."""
7372
7473 super ().__init__ (coordinator )
75- self ._attr_unique_id = f" { coordinator .address } -climate"
74+ self ._attr_unique_id = coordinator .address
7675
7776 @property
7877 def current_temperature (self ) -> float | None :
7978 """Return the current temperature."""
80- return self .coordinator .data ["currentTemp" ]
79+ return self .coordinator .data . temperatures ["currentTemp" ]
8180
8281 @property
8382 def target_temperature (self ) -> float | None :
8483 """Return the temperature currently set to be reached."""
85- return self .coordinator .data ["manualTemp" ]
84+ return self .coordinator .data . temperatures ["manualTemp" ]
8685
8786 @property
8887 def target_temperature_high (self ) -> float | None :
8988 """Return the upper bound target temperature."""
90- return self .coordinator .data ["targetTempHigh" ]
89+ return self .coordinator .data . temperatures ["targetTempHigh" ]
9190
9291 @property
9392 def target_temperature_low (self ) -> float | None :
9493 """Return the lower bound target temperature."""
95- return self .coordinator .data ["targetTempLow" ]
94+ return self .coordinator .data . temperatures ["targetTempLow" ]
9695
9796 @property
9897 def hvac_mode (self ) -> HVACMode | None :
@@ -103,76 +102,58 @@ def hvac_mode(self) -> HVACMode | None:
103102 return HVACMode .HEAT
104103 return HVACMode .AUTO
105104
106- @property
107- def hvac_action (self ) -> HVACAction | None :
108- """Return the current running hvac action if supported."""
109-
110- if self .target_temperature == MIN_TEMP :
111- return HVACAction .OFF
112- if (self .target_temperature or 0.0 ) > (
113- self .target_temperature_low or 0.0
114- ) or self .target_temperature == MAX_TEMP :
115- return HVACAction .HEATING
116- return HVACAction .IDLE
117-
118105 @property
119106 def preset_mode (self ) -> str | None :
120107 """Return the current preset mode, e.g., home, away, temp."""
121108 # presets have an order in which they are displayed on TRV:
122- # away, comfort, eco, none (manual)
109+ # away, boost, comfort, eco, none (manual)
123110 if (
124- self .coordinator .data [ " holiday" ] .get ("start" ) is None
125- and self .coordinator .data [ " holiday" ] .get ("end" ) is not None
111+ self .coordinator .data . holiday .get ("start" ) is None
112+ and self .coordinator .data . holiday .get ("end" ) is not None
126113 and self .target_temperature
127- == self .coordinator .data [ " holiday" ] .get ("temperature" )
114+ == self .coordinator .data . holiday .get ("temperature" )
128115 ):
129116 return PRESET_AWAY
117+ if self .target_temperature == MAX_TEMP :
118+ return PRESET_BOOST
130119 if self .target_temperature == self .target_temperature_high :
131120 return PRESET_COMFORT
132121 if self .target_temperature == self .target_temperature_low :
133122 return PRESET_ECO
134123 return PRESET_NONE
135124
136- @property
137- def preset_modes (self ) -> list [str ] | None :
138- """Return a list of available preset modes.
139-
140- Will only show presets that are supported by the device.
141- """
142- if self .preset_mode :
143- return list (DEFAULT_PRESETS | {self .preset_mode })
144- return list (DEFAULT_PRESETS )
145-
146125 async def async_set_temperature (self , ** kwargs : Any ) -> None :
147126 """Set new target temperatures."""
148127
149128 if self .preset_mode == PRESET_AWAY :
150- raise ValueError (
129+ raise ServiceValidationError (
151130 "Cannot adjust TRV remotely, manually disable 'holiday' mode on TRV first"
152131 )
153132
154133 await self .coordinator .send_command (
155- " set_temperature_async" ,
134+ self . coordinator . device . set_temperature_async ,
156135 {
157136 "values" : {
158137 # manual temperature always needs to be set, otherwise TRV will turn OFF
159138 "manualTemp" : kwargs .get (ATTR_TEMPERATURE )
160139 or self .target_temperature ,
140+ # other temperatures can be left unchanged by setting them to None
161141 "targetTempLow" : kwargs .get (ATTR_TARGET_TEMP_LOW ),
162142 "targetTempHigh" : kwargs .get (ATTR_TARGET_TEMP_HIGH ),
163143 }
164144 },
165- self .entity_id ,
166145 )
167146 await self .coordinator .async_request_refresh ()
168147
169148 async def async_set_preset_mode (self , preset_mode : str ) -> None :
170149 """Set new target preset mode."""
171150
172151 if self .preset_modes and preset_mode not in self .preset_modes :
173- raise ValueError (f"Unsupported preset_mode '{ preset_mode } '" )
152+ raise ServiceValidationError (f"Unsupported preset_mode '{ preset_mode } '" )
174153 if preset_mode in [PRESET_NONE , PRESET_AWAY ]:
175- raise ValueError (f"Unable to set preset '{ preset_mode } ', display only." )
154+ raise ServiceValidationError (
155+ f"Unable to set preset '{ preset_mode } ', display only."
156+ )
176157 if preset_mode == PRESET_ECO :
177158 return await self .async_set_temperature (
178159 temperature = self .target_temperature_low
@@ -181,6 +162,8 @@ async def async_set_preset_mode(self, preset_mode: str) -> None:
181162 return await self .async_set_temperature (
182163 temperature = self .target_temperature_high
183164 )
165+ if preset_mode == PRESET_BOOST :
166+ return await self .async_set_temperature (temperature = MAX_TEMP )
184167 return None
185168
186169 async def async_set_hvac_mode (self , hvac_mode : HVACMode ) -> None :
@@ -194,7 +177,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
194177 return await self .async_set_temperature (
195178 temperature = self .target_temperature_low
196179 )
197- raise ValueError (f"Unknown HVAC mode '{ hvac_mode } '" )
180+ raise ServiceValidationError (f"Unknown HVAC mode '{ hvac_mode } '" )
198181
199182 async def async_turn_on (self ) -> None :
200183 """Turn the entity on."""
0 commit comments