@@ -41,35 +41,50 @@ def __init__(
4141 self ._manufacturer : str = "Rinnai"
4242 self ._device_information : Optional [Dict [str , Any ]] = None
4343 self .options = options
44- self ._listeners = []
4544 super ().__init__ (
4645 hass ,
4746 LOGGER ,
4847 name = f"{ RINNAI_DOMAIN } -{ device_id } " ,
4948 update_interval = timedelta (seconds = 60 ),
5049 )
5150
52- async def _async_update_data (self ) -> None :
53- """Update data via library """
51+ async def _async_update_data (self ) -> dict [ str , Any ] :
52+ """Fetch data from device via API and return the fetched device information as a dict[str, Any]. """
5453 try :
5554 async with timeout (10 ):
56- await asyncio .gather (
57- self ._update_device ()
58- )
55+ device_info = await self .api_client .device .get_info (self ._rinnai_device_id )
5956 except Unauthenticated as error :
6057 LOGGER .error ("Authentication error: %s" , error )
6158 raise ConfigEntryAuthFailed from error
6259 except RequestError as error :
6360 raise UpdateFailed (error ) from error
6461
62+ # Optionally perform maintenance retrieval if enabled (outside try block)
63+ if self .options .get (CONF_MAINT_INTERVAL_ENABLED , False ):
64+ try :
65+ await self .async_do_maintenance_retrieval ()
66+ except Unauthenticated as error :
67+ LOGGER .error ("Authentication error during maintenance retrieval: %s" , error )
68+ raise ConfigEntryAuthFailed from error
69+ except RequestError as error :
70+ LOGGER .warning ("Maintenance retrieval failed due to request error: %s" , error )
71+ else :
72+ LOGGER .debug ("Skipping Maintenance retrieval since disabled inside of configuration" )
73+
74+ LOGGER .debug ("Rinnai device data: %s" , device_info )
75+ self ._device_information = device_info
76+ return device_info
77+
6578 @property
6679 def id (self ) -> str :
6780 """Return Rinnai thing name"""
6881 return self ._rinnai_device_id
6982
7083 @property
71- def device_name (self ) -> str :
84+ def device_name (self ) -> Optional [ str ] :
7285 """Return device name."""
86+ if not self ._device_information :
87+ return None
7388 return self ._device_information ["data" ]["getDevice" ]["device_name" ]
7489
7590 @property
@@ -78,126 +93,171 @@ def manufacturer(self) -> str:
7893 return self ._manufacturer
7994
8095 @property
81- def model (self ) -> str :
96+ def model (self ) -> Optional [ str ] :
8297 """Return model for device"""
98+ if not self ._device_information :
99+ return None
83100 return self ._device_information ["data" ]["getDevice" ]["model" ]
84101
85102 @property
86- def firmware_version (self ) -> str :
103+ def firmware_version (self ) -> Optional [ str ] :
87104 """Return the serial number for the device"""
105+ if not self ._device_information :
106+ return None
88107 return self ._device_information ["data" ]["getDevice" ]["firmware" ]
89108
90109 @property
91- def thing_name (self ) -> str :
110+ def thing_name (self ) -> Optional [ str ] :
92111 """Return model for device"""
112+ if not self ._device_information :
113+ return None
93114 return self ._device_information ["data" ]["getDevice" ]["thing_name" ]
94115
95116 @property
96- def user_uuid (self ) -> str :
117+ def user_uuid (self ) -> Optional [ str ] :
97118 """Return model for device"""
119+ if not self ._device_information :
120+ return None
98121 return self ._device_information ["data" ]["getDevice" ]["user_uuid" ]
99122
100123 @property
101- def current_temperature (self ) -> float :
124+ def current_temperature (self ) -> Optional [ float ] :
102125 """Return the current temperature in degrees F"""
126+ if not self ._device_information :
127+ return None
103128 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["domestic_temperature" ])
104129
105130 @property
106131 def target_temperature (self ) -> Optional [float ]:
107132 """Return the current temperature in degrees F"""
133+ if not self ._device_information :
134+ return None
108135 if self ._device_information ["data" ]["getDevice" ]["shadow" ]["set_domestic_temperature" ] is None :
109136 return None
110137 return float (self ._device_information ["data" ]["getDevice" ]["shadow" ]["set_domestic_temperature" ])
111138
112139 @property
113- def serial_number (self ) -> str :
140+ def serial_number (self ) -> Optional [ str ] :
114141 """Return the serial number for the device"""
142+ if not self ._device_information :
143+ return None
115144 return self ._device_information ["data" ]["getDevice" ]["info" ]["serial_id" ]
116145
117146 @property
118- def last_known_state (self ) -> str :
147+ def last_known_state (self ) -> Optional [str ]:
148+ if not self ._device_information :
149+ return None
119150 return self ._device_information ["data" ]["getDevice" ]["activity" ]["eventType" ]
120151
121152 @property
122- def is_heating (self ) -> bool :
153+ def is_heating (self ) -> Optional [bool ]:
154+ if not self ._device_information :
155+ return None
123156 value = self ._device_information ["data" ]["getDevice" ]["info" ]["domestic_combustion" ]
124157 return _convert_to_bool (value )
125158
126159 @property
127- def is_on (self ) -> bool :
160+ def is_on (self ) -> Optional [bool ]:
161+ if not self ._device_information :
162+ return None
128163 value = self ._device_information ["data" ]["getDevice" ]["shadow" ]["set_operation_enabled" ]
129164 return _convert_to_bool (value )
130165
131166 @property
132- def is_recirculating (self ) -> bool :
167+ def is_recirculating (self ) -> Optional [bool ]:
168+ if not self ._device_information :
169+ return None
133170 value = self ._device_information ["data" ]["getDevice" ]["shadow" ]["recirculation_enabled" ]
134171 return _convert_to_bool (value )
135172
136173 @property
137174 def vacation_mode_on (self ) -> Optional [bool ]:
175+ if not self ._device_information :
176+ return None
138177 value = self ._device_information ["data" ]["getDevice" ]["shadow" ]["schedule_holiday" ]
139178 if value is None :
140179 return None
141180 return _convert_to_bool (value )
142181
143182 @property
144- def outlet_temperature (self ) -> float :
183+ def outlet_temperature (self ) -> Optional [float ]:
184+ if not self ._device_information :
185+ return None
145186 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m02_outlet_temperature" ])
146187
147188 @property
148- def inlet_temperature (self ) -> float :
189+ def inlet_temperature (self ) -> Optional [float ]:
190+ if not self ._device_information :
191+ return None
149192 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m08_inlet_temperature" ])
150193
151194 @property
152195 def water_flow_rate (self ) -> Optional [float ]:
153196 """Return the current temperature in degrees F"""
197+ if not self ._device_information :
198+ return None
154199 if self ._device_information ["data" ]["getDevice" ]["info" ]["m01_water_flow_rate_raw" ] is None :
155200 return None
156201 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m01_water_flow_rate_raw" ])
157202
158203 @property
159204 def combustion_cycles (self ) -> Optional [float ]:
160205 """Return the current temperature in degrees F"""
206+ if not self ._device_information :
207+ return None
161208 if self ._device_information ["data" ]["getDevice" ]["info" ]["m04_combustion_cycles" ] is None :
162209 return None
163210 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m04_combustion_cycles" ])
164211
165212 @property
166213 def operation_hours (self ) -> Optional [float ]:
167214 """Return the operation hours."""
215+ if not self ._device_information :
216+ return None
168217 if self ._device_information ["data" ]["getDevice" ]["info" ]["operation_hours" ] is None :
169218 return None
170219 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["operation_hours" ])
171220
172221 @property
173222 def pump_hours (self ) -> Optional [float ]:
174223 """Return the pump hours."""
224+ if not self ._device_information :
225+ return None
175226 if self ._device_information ["data" ]["getDevice" ]["info" ]["m19_pump_hours" ] is None :
176227 return None
177228 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m19_pump_hours" ])
178229
179230 @property
180231 def fan_current (self ) -> Optional [float ]:
181232 """Return the fan current."""
233+ if not self ._device_information :
234+ return None
182235 if self ._device_information ["data" ]["getDevice" ]["info" ]["m09_fan_current" ] is None :
183236 return None
184237 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m09_fan_current" ])
185238
186239 @property
187240 def fan_frequency (self ) -> Optional [float ]:
188241 """Return the fan frequency."""
242+ if not self ._device_information :
243+ return None
189244 if self ._device_information ["data" ]["getDevice" ]["info" ]["m05_fan_frequency" ] is None :
190245 return None
191246 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m05_fan_frequency" ])
192247
193248 @property
194249 def pump_cycles (self ) -> Optional [float ]:
195250 """Return the pump cycles."""
251+ if not self ._device_information :
252+ return None
196253 if self ._device_information ["data" ]["getDevice" ]["info" ]["m20_pump_cycles" ] is None :
197254 return None
198255 return float (self ._device_information ["data" ]["getDevice" ]["info" ]["m20_pump_cycles" ])
199256
200257 async def async_set_temperature (self , temperature : int ) -> None :
258+ if not self ._device_information :
259+ LOGGER .debug ("Cannot set temperature: device information not yet loaded" )
260+ return
201261 try :
202262 await self .api_client .device .set_temperature (self ._device_information ["data" ]["getDevice" ], temperature )
203263 except Unauthenticated as error :
@@ -207,6 +267,9 @@ async def async_set_temperature(self, temperature: int) -> None:
207267 raise UpdateFailed (error ) from error
208268
209269 async def async_start_recirculation (self , duration : int ) -> None :
270+ if not self ._device_information :
271+ LOGGER .debug ("Cannot start recirculation: device information not yet loaded" )
272+ return
210273 try :
211274 await self .api_client .device .start_recirculation (self ._device_information ["data" ]["getDevice" ], duration )
212275 except Unauthenticated as error :
@@ -216,6 +279,9 @@ async def async_start_recirculation(self, duration: int) -> None:
216279 raise UpdateFailed (error ) from error
217280
218281 async def async_stop_recirculation (self ) -> None :
282+ if not self ._device_information :
283+ LOGGER .debug ("Cannot stop recirculation: device information not yet loaded" )
284+ return
219285 try :
220286 await self .api_client .device .stop_recirculation (self ._device_information ["data" ]["getDevice" ])
221287 except Unauthenticated as error :
@@ -225,6 +291,9 @@ async def async_stop_recirculation(self) -> None:
225291 raise UpdateFailed (error ) from error
226292
227293 async def async_enable_vacation_mode (self ) -> None :
294+ if not self ._device_information :
295+ LOGGER .debug ("Cannot enable vacation mode: device information not yet loaded" )
296+ return
228297 try :
229298 await self .api_client .device .enable_vacation_mode (self ._device_information ["data" ]["getDevice" ])
230299 except Unauthenticated as error :
@@ -234,6 +303,9 @@ async def async_enable_vacation_mode(self) -> None:
234303 raise UpdateFailed (error ) from error
235304
236305 async def async_disable_vacation_mode (self ) -> None :
306+ if not self ._device_information :
307+ LOGGER .debug ("Cannot disable vacation mode: device information not yet loaded" )
308+ return
237309 try :
238310 await self .api_client .device .disable_vacation_mode (self ._device_information ["data" ]["getDevice" ])
239311 except Unauthenticated as error :
@@ -243,6 +315,9 @@ async def async_disable_vacation_mode(self) -> None:
243315 raise UpdateFailed (error ) from error
244316
245317 async def async_turn_off (self ) -> None :
318+ if not self ._device_information :
319+ LOGGER .debug ("Cannot turn off device: device information not yet loaded" )
320+ return
246321 try :
247322 await self .api_client .device .turn_off (self ._device_information ["data" ]["getDevice" ])
248323 except Unauthenticated as error :
@@ -252,6 +327,9 @@ async def async_turn_off(self) -> None:
252327 raise UpdateFailed (error ) from error
253328
254329 async def async_turn_on (self ) -> None :
330+ if not self ._device_information :
331+ LOGGER .debug ("Cannot turn on device: device information not yet loaded" )
332+ return
255333 try :
256334 await self .api_client .device .turn_on (self ._device_information ["data" ]["getDevice" ])
257335 except Unauthenticated as error :
@@ -262,6 +340,9 @@ async def async_turn_on(self) -> None:
262340
263341 @Throttle (MIN_TIME_BETWEEN_UPDATES )
264342 async def async_do_maintenance_retrieval (self ) -> None :
343+ if not self ._device_information :
344+ LOGGER .debug ("Cannot perform maintenance retrieval: device information not yet loaded" )
345+ return
265346 try :
266347 await self .api_client .device .do_maintenance_retrieval (self ._device_information ["data" ]["getDevice" ])
267348 LOGGER .debug ("Rinnai Maintenance Retrieval Started" )
@@ -270,16 +351,3 @@ async def async_do_maintenance_retrieval(self) -> None:
270351 raise ConfigEntryAuthFailed from error
271352 except RequestError as error :
272353 raise UpdateFailed (error ) from error
273-
274- async def _update_device (self , * _ ) -> None :
275- """Update the device information from the API"""
276- self ._device_information = await self .api_client .device .get_info (
277- self ._rinnai_device_id
278- )
279-
280- if self .options [CONF_MAINT_INTERVAL_ENABLED ]:
281- await self .async_do_maintenance_retrieval ()
282- else :
283- LOGGER .debug ("Skipping Maintenance retrieval since disabled inside of configuration" )
284-
285- LOGGER .debug ("Rinnai device data: %s" , self ._device_information )
0 commit comments