22
33import logging
44from datetime import datetime
5- from typing import cast
5+ from typing import Any , cast
66
77from homeassistant .core import (
88 HomeAssistant ,
99 ServiceCall ,
1010 ServiceResponse ,
11+ SupportsResponse ,
1112 callback ,
1213)
1314from homeassistant .exceptions import HomeAssistantError
4445 SERVICE_CHECK_BATTERY_LAST_REPORTED ,
4546 SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA ,
4647 SERVICE_CHECK_BATTERY_LOW ,
48+ SERVICE_CHECK_BATTERY_LOW_SCHEMA ,
4749 SERVICE_DATA_DATE_TIME_REPLACED ,
4850 SERVICE_DATA_DAYS_LAST_REPLACED ,
4951 SERVICE_DATA_DAYS_LAST_REPORTED ,
52+ SERVICE_DATA_RAISE_EVENTS ,
5053)
5154from .coordinator import BatteryNotesConfigEntry
5255
@@ -69,19 +72,23 @@ def async_setup_services(hass: HomeAssistant) -> None:
6972 SERVICE_CHECK_BATTERY_LAST_REPORTED ,
7073 _async_battery_last_reported ,
7174 schema = SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA ,
75+ supports_response = SupportsResponse .OPTIONAL ,
7276 )
7377
7478 hass .services .async_register (
7579 DOMAIN ,
7680 SERVICE_CHECK_BATTERY_LAST_REPLACED ,
7781 _async_battery_last_replaced ,
7882 schema = SERVICE_CHECK_BATTERY_LAST_REPLACED_SCHEMA ,
83+ supports_response = SupportsResponse .OPTIONAL ,
7984 )
8085
8186 hass .services .async_register (
8287 DOMAIN ,
8388 SERVICE_CHECK_BATTERY_LOW ,
8489 _async_battery_low ,
90+ schema = SERVICE_CHECK_BATTERY_LOW_SCHEMA ,
91+ supports_response = SupportsResponse .OPTIONAL ,
8592 )
8693
8794
@@ -222,9 +229,12 @@ async def _async_battery_replaced(call: ServiceCall) -> ServiceResponse: # noqa
222229async def _async_battery_last_replaced (call : ServiceCall ) -> ServiceResponse :
223230 """Handle the service call."""
224231 days_last_replaced = cast (int , call .data .get (SERVICE_DATA_DAYS_LAST_REPLACED ))
232+ raise_events = call .data .get (SERVICE_DATA_RAISE_EVENTS , True )
225233
226234 entity_registry = er .async_get (call .hass )
227235
236+ return_items : list [dict [str , Any ]] = []
237+
228238 for config_entry in call .hass .config_entries .async_loaded_entries (DOMAIN ):
229239 battery_notes_config_entry = cast (BatteryNotesConfigEntry , config_entry )
230240 if not battery_notes_config_entry .runtime_data .subentry_coordinators :
@@ -257,33 +267,57 @@ async def _async_battery_last_replaced(call: ServiceCall) -> ServiceResponse:
257267 )
258268
259269 if time_since_last_replaced .days > days_last_replaced :
260- call .hass .bus .async_fire (
261- EVENT_BATTERY_NOT_REPLACED ,
270+ if raise_events :
271+ call .hass .bus .async_fire (
272+ EVENT_BATTERY_NOT_REPLACED ,
273+ {
274+ ATTR_DEVICE_ID : coordinator .device_id or "" ,
275+ ATTR_SOURCE_ENTITY_ID : coordinator .source_entity_id
276+ or "" ,
277+ ATTR_DEVICE_NAME : coordinator .device_name ,
278+ ATTR_BATTERY_TYPE_AND_QUANTITY : coordinator .battery_type_and_quantity ,
279+ ATTR_BATTERY_TYPE : coordinator .battery_type ,
280+ ATTR_BATTERY_QUANTITY : coordinator .battery_quantity ,
281+ ATTR_BATTERY_LAST_REPORTED : coordinator .last_reported ,
282+ ATTR_BATTERY_LAST_REPORTED_LEVEL : coordinator .last_reported_level ,
283+ ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced ,
284+ ATTR_BATTERY_LAST_REPLACED_DAYS : time_since_last_replaced .days ,
285+ },
286+ )
287+ _LOGGER .debug (
288+ "Raised event device %s battery not replaced since %s" ,
289+ coordinator .device_id ,
290+ str (coordinator .last_replaced ),
291+ )
292+
293+ return_items .append (
262294 {
263295 ATTR_DEVICE_ID : coordinator .device_id or "" ,
264296 ATTR_SOURCE_ENTITY_ID : coordinator .source_entity_id or "" ,
265297 ATTR_DEVICE_NAME : coordinator .device_name ,
266298 ATTR_BATTERY_TYPE_AND_QUANTITY : coordinator .battery_type_and_quantity ,
267299 ATTR_BATTERY_TYPE : coordinator .battery_type ,
268300 ATTR_BATTERY_QUANTITY : coordinator .battery_quantity ,
269- ATTR_BATTERY_LAST_REPORTED : coordinator .last_reported ,
301+ ATTR_BATTERY_LAST_REPORTED : coordinator .last_reported .isoformat ()
302+ if coordinator .last_reported
303+ else None ,
270304 ATTR_BATTERY_LAST_REPORTED_LEVEL : coordinator .last_reported_level ,
271- ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced ,
305+ ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced . isoformat () ,
272306 ATTR_BATTERY_LAST_REPLACED_DAYS : time_since_last_replaced .days ,
273- },
307+ }
274308 )
275309
276- _LOGGER .debug (
277- "Raised event device %s battery not replaced since %s" ,
278- coordinator .device_id ,
279- str (coordinator .last_replaced ),
280- )
310+ if call .return_response :
311+ return {"check_battery_last_replaced" : cast (Any , return_items )}
281312 return None
282313
283314
284315async def _async_battery_last_reported (call : ServiceCall ) -> ServiceResponse :
285316 """Handle the service call."""
286317 days_last_reported = cast (int , call .data .get (SERVICE_DATA_DAYS_LAST_REPORTED ))
318+ raise_events = call .data .get (SERVICE_DATA_RAISE_EVENTS , True )
319+
320+ return_items : list [dict [str , Any ]] = []
287321
288322 for config_entry in call .hass .config_entries .async_loaded_entries (DOMAIN ):
289323 battery_notes_config_entry = cast (BatteryNotesConfigEntry , config_entry )
@@ -298,34 +332,57 @@ async def _async_battery_last_reported(call: ServiceCall) -> ServiceResponse:
298332 datetime .fromisoformat (str (utcnow_no_timezone ()) + "+00:00" )
299333 - coordinator .last_reported
300334 )
301-
302335 if time_since_last_reported .days > days_last_reported :
303- call .hass .bus .async_fire (
304- EVENT_BATTERY_NOT_REPORTED ,
336+ if raise_events :
337+ call .hass .bus .async_fire (
338+ EVENT_BATTERY_NOT_REPORTED ,
339+ {
340+ ATTR_DEVICE_ID : coordinator .device_id or "" ,
341+ ATTR_SOURCE_ENTITY_ID : coordinator .source_entity_id
342+ or "" ,
343+ ATTR_DEVICE_NAME : coordinator .device_name ,
344+ ATTR_BATTERY_TYPE_AND_QUANTITY : coordinator .battery_type_and_quantity ,
345+ ATTR_BATTERY_TYPE : coordinator .battery_type ,
346+ ATTR_BATTERY_QUANTITY : coordinator .battery_quantity ,
347+ ATTR_BATTERY_LAST_REPORTED : coordinator .last_reported ,
348+ ATTR_BATTERY_LAST_REPORTED_DAYS : time_since_last_reported .days ,
349+ ATTR_BATTERY_LAST_REPORTED_LEVEL : coordinator .last_reported_level ,
350+ ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced ,
351+ },
352+ )
353+ _LOGGER .debug (
354+ "Raised event device %s not reported since %s" ,
355+ coordinator .device_id ,
356+ str (coordinator .last_reported ),
357+ )
358+
359+ return_items .append (
305360 {
306361 ATTR_DEVICE_ID : coordinator .device_id or "" ,
307362 ATTR_SOURCE_ENTITY_ID : coordinator .source_entity_id or "" ,
308363 ATTR_DEVICE_NAME : coordinator .device_name ,
309364 ATTR_BATTERY_TYPE_AND_QUANTITY : coordinator .battery_type_and_quantity ,
310365 ATTR_BATTERY_TYPE : coordinator .battery_type ,
311366 ATTR_BATTERY_QUANTITY : coordinator .battery_quantity ,
312- ATTR_BATTERY_LAST_REPORTED : coordinator .last_reported ,
367+ ATTR_BATTERY_LAST_REPORTED : coordinator .last_reported . isoformat () ,
313368 ATTR_BATTERY_LAST_REPORTED_DAYS : time_since_last_reported .days ,
314369 ATTR_BATTERY_LAST_REPORTED_LEVEL : coordinator .last_reported_level ,
315- ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced ,
316- },
370+ ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced .isoformat ()
371+ if coordinator .last_replaced
372+ else None ,
373+ }
317374 )
318375
319- _LOGGER .debug (
320- "Raised event device %s not reported since %s" ,
321- coordinator .device_id ,
322- str (coordinator .last_reported ),
323- )
376+ if call .return_response :
377+ return {"check_battery_last_reported" : cast (Any , return_items )}
324378 return None
325379
326380
327381async def _async_battery_low (call : ServiceCall ) -> ServiceResponse :
328382 """Handle the service call."""
383+ raise_events = call .data .get (SERVICE_DATA_RAISE_EVENTS , True )
384+
385+ return_items : list [dict [str , Any ]] = []
329386
330387 for config_entry in call .hass .config_entries .async_loaded_entries (DOMAIN ):
331388 battery_notes_config_entry = cast (BatteryNotesConfigEntry , config_entry )
@@ -336,8 +393,29 @@ async def _async_battery_low(call: ServiceCall) -> ServiceResponse:
336393 coordinator
337394 ) in battery_notes_config_entry .runtime_data .subentry_coordinators .values ():
338395 if coordinator .battery_low is True :
339- call .hass .bus .async_fire (
340- EVENT_BATTERY_THRESHOLD ,
396+ if raise_events :
397+ call .hass .bus .async_fire (
398+ EVENT_BATTERY_THRESHOLD ,
399+ {
400+ ATTR_DEVICE_ID : coordinator .device_id or "" ,
401+ ATTR_DEVICE_NAME : coordinator .device_name ,
402+ ATTR_SOURCE_ENTITY_ID : coordinator .source_entity_id or "" ,
403+ ATTR_BATTERY_LOW : coordinator .battery_low ,
404+ ATTR_BATTERY_LOW_THRESHOLD : coordinator .battery_low_threshold ,
405+ ATTR_BATTERY_TYPE_AND_QUANTITY : coordinator .battery_type_and_quantity ,
406+ ATTR_BATTERY_TYPE : coordinator .battery_type ,
407+ ATTR_BATTERY_QUANTITY : coordinator .battery_quantity ,
408+ ATTR_BATTERY_LEVEL : coordinator .rounded_battery_level ,
409+ ATTR_PREVIOUS_BATTERY_LEVEL : coordinator .rounded_previous_battery_level ,
410+ ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced ,
411+ ATTR_BATTERY_THRESHOLD_REMINDER : True ,
412+ },
413+ )
414+ _LOGGER .debug (
415+ "Raised event device %s battery low" ,
416+ coordinator .device_id ,
417+ )
418+ return_items .append (
341419 {
342420 ATTR_DEVICE_ID : coordinator .device_id or "" ,
343421 ATTR_DEVICE_NAME : coordinator .device_name ,
@@ -349,13 +427,13 @@ async def _async_battery_low(call: ServiceCall) -> ServiceResponse:
349427 ATTR_BATTERY_QUANTITY : coordinator .battery_quantity ,
350428 ATTR_BATTERY_LEVEL : coordinator .rounded_battery_level ,
351429 ATTR_PREVIOUS_BATTERY_LEVEL : coordinator .rounded_previous_battery_level ,
352- ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced ,
430+ ATTR_BATTERY_LAST_REPLACED : coordinator .last_replaced .isoformat ()
431+ if coordinator .last_replaced
432+ else None ,
353433 ATTR_BATTERY_THRESHOLD_REMINDER : True ,
354- },
434+ }
355435 )
356436
357- _LOGGER .debug (
358- "Raised event device %s battery low" ,
359- coordinator .device_id ,
360- )
437+ if call .return_response :
438+ return {"check_battery_battery_low" : cast (Any , return_items )}
361439 return None
0 commit comments