Skip to content

Commit b544e35

Browse files
Responses (#4325)
1 parent 1cb7cb5 commit b544e35

6 files changed

Lines changed: 180 additions & 51 deletions

File tree

custom_components/battery_notes/const.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
SERVICE_DATA_DAYS_LAST_REPLACED = "days_last_replaced"
7575

7676
SERVICE_CHECK_BATTERY_LOW = "check_battery_low"
77+
SERVICE_DATA_RAISE_EVENTS = "raise_events"
7778

7879
EVENT_BATTERY_THRESHOLD = "battery_notes_battery_threshold"
7980
EVENT_BATTERY_INCREASED = "battery_notes_battery_increased"
@@ -115,12 +116,20 @@
115116
SERVICE_CHECK_BATTERY_LAST_REPLACED_SCHEMA = vol.Schema(
116117
{
117118
vol.Required(SERVICE_DATA_DAYS_LAST_REPLACED): cv.positive_int,
119+
vol.Optional(SERVICE_DATA_RAISE_EVENTS, default=True): cv.boolean,
118120
}
119121
)
120122

121123
SERVICE_CHECK_BATTERY_LAST_REPORTED_SCHEMA = vol.Schema(
122124
{
123125
vol.Required(SERVICE_DATA_DAYS_LAST_REPORTED): cv.positive_int,
126+
vol.Optional(SERVICE_DATA_RAISE_EVENTS, default=True): cv.boolean,
127+
}
128+
)
129+
130+
SERVICE_CHECK_BATTERY_LOW_SCHEMA = vol.Schema(
131+
{
132+
vol.Optional(SERVICE_DATA_RAISE_EVENTS, default=True): cv.boolean,
124133
}
125134
)
126135

custom_components/battery_notes/services.py

Lines changed: 108 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import logging
44
from datetime import datetime
5-
from typing import cast
5+
from typing import Any, cast
66

77
from homeassistant.core import (
88
HomeAssistant,
99
ServiceCall,
1010
ServiceResponse,
11+
SupportsResponse,
1112
callback,
1213
)
1314
from homeassistant.exceptions import HomeAssistantError
@@ -44,9 +45,11 @@
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
)
5154
from .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
222229
async 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

284315
async 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

327381
async 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

custom_components/battery_notes/services.yaml

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ set_battery_replaced:
2222
datetime:
2323
check_battery_last_replaced:
2424
name: Check battery replaced
25-
description: "Raise events for devices that haven't had their battery replaced."
25+
description: Get or raise events for devices that haven't had their battery replaced."
2626
fields:
2727
days_last_replaced:
2828
name: Days
@@ -33,9 +33,16 @@ check_battery_last_replaced:
3333
min: 1
3434
max: 720
3535
mode: box
36+
raise_events:
37+
name: Raise events
38+
description: Raise events for use in automation triggers.
39+
required: false
40+
default: true
41+
selector:
42+
boolean:
3643
check_battery_last_reported:
3744
name: Check battery reported
38-
description: "Raise events for devices that haven't reported their battery level."
45+
description: "Get or raise events for devices that haven't reported their battery level."
3946
fields:
4047
days_last_reported:
4148
name: Days
@@ -46,7 +53,22 @@ check_battery_last_reported:
4653
min: 1
4754
max: 100
4855
mode: box
56+
raise_events:
57+
name: Raise events
58+
description: Raise events for use in automation triggers.
59+
required: false
60+
default: true
61+
selector:
62+
boolean:
4963

5064
check_battery_low:
5165
name: Check battery low
52-
description: "Raise events for devices that have a low battery."
66+
description: "Get or raise events for devices that have a low battery."
67+
fields:
68+
raise_events:
69+
name: Raise events
70+
description: Raise events for use in automation triggers.
71+
required: false
72+
default: true
73+
selector:
74+
boolean:

custom_components/battery_notes/translations/en.json

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,27 +276,42 @@
276276
"name": "Set battery replaced"
277277
},
278278
"check_battery_last_replaced": {
279-
"description": "Raise events for devices that haven't had their battery replaced.",
279+
"description": "Get or raise events for devices that haven't had their battery replaced.",
280280
"fields": {
281281
"days_last_reported": {
282282
"description": "Number of days since a device last had its battery replaced.",
283283
"name": "Days"
284+
},
285+
"raise_events": {
286+
"description": "Raise events for use in automation triggers.",
287+
"name": "Raise events"
284288
}
289+
285290
},
286291
"name": "Check battery last replaced"
287292
},
288293
"check_battery_last_reported": {
289-
"description": "Raise events for devices that haven't reported their battery level.",
294+
"description": "Get or raise events for devices that haven't reported their battery level.",
290295
"fields": {
291296
"days_last_reported": {
292297
"description": "Number of days since a device last reported its battery level.",
293298
"name": "Days"
299+
},
300+
"raise_events": {
301+
"description": "Raise events for use in automation triggers.",
302+
"name": "Raise events"
294303
}
295304
},
296305
"name": "Check battery last reported"
297306
},
298307
"check_battery_low": {
299-
"description": "Raise events for devices that have a low battery.",
308+
"description": "Get or raise events for devices that have a low battery.",
309+
"fields": {
310+
"raise_events": {
311+
"description": "Raise events for use in automation triggers.",
312+
"name": "Raise events"
313+
}
314+
},
300315
"name": "Check battery low"
301316
}
302317
},

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dev = [
3030
"colorlog",
3131
"homeassistant==2025.9.0",
3232
"mypy",
33+
"pycares<5.0.0",
3334
"ruff",
3435
]
3536

0 commit comments

Comments
 (0)