2121 BinarySensorEntityDescription ,
2222 BinarySensorDeviceClass ,
2323)
24-
24+ from homeassistant .helpers .update_coordinator import (
25+ CoordinatorEntity ,
26+ )
2527from homeassistant .helpers .entity import DeviceInfo , EntityCategory
2628from homeassistant .helpers .event import (
27- EventStateChangedData ,
28- async_track_state_change_event ,
2929 async_track_entity_registry_updated_event ,
3030)
31- from homeassistant .helpers .typing import EventType
3231from homeassistant .helpers .reload import async_setup_reload_service
3332
3433from homeassistant .const import (
4241
4342from .const import (
4443 DOMAIN ,
45- DOMAIN_CONFIG ,
4644 DATA ,
47- CONF_ENABLE_REPLACED ,
48- CONF_ROUND_BATTERY ,
49- CONF_BATTERY_INCREASE_THRESHOLD ,
50- EVENT_BATTERY_THRESHOLD ,
51- EVENT_BATTERY_INCREASED ,
52- DEFAULT_BATTERY_INCREASE_THRESHOLD ,
53- ATTR_DEVICE_ID ,
54- ATTR_BATTERY_QUANTITY ,
55- ATTR_BATTERY_TYPE ,
56- ATTR_BATTERY_TYPE_AND_QUANTITY ,
57- ATTR_BATTERY_LOW ,
5845 ATTR_BATTERY_LOW_THRESHOLD ,
59- ATTR_DEVICE_NAME ,
60- ATTR_BATTERY_LEVEL ,
61- ATTR_PREVIOUS_BATTERY_LEVEL ,
6246)
6347
6448from .common import isfloat
65- from . device import BatteryNotesDevice
49+
6650from .coordinator import BatteryNotesCoordinator
6751
6852from .entity import (
@@ -147,21 +131,12 @@ async def async_registry_updated(event: Event) -> None:
147131
148132 device_id = async_add_to_device (hass , config_entry )
149133
150- enable_replaced = True
151- round_battery = False
152-
153- if DOMAIN_CONFIG in hass .data [DOMAIN ]:
154- domain_config : dict = hass .data [DOMAIN ][DOMAIN_CONFIG ]
155- enable_replaced = domain_config .get (CONF_ENABLE_REPLACED , True )
156- round_battery = domain_config .get (CONF_ROUND_BATTERY , False )
157-
158134 description = BatteryNotesBinarySensorEntityDescription (
159135 unique_id_suffix = "_battery_low" ,
160- key = "battery_low " ,
136+ key = "_battery_plus_low " ,
161137 translation_key = "battery_low" ,
162138 icon = "mdi:battery-alert" ,
163139 entity_category = EntityCategory .DIAGNOSTIC ,
164- entity_registry_enabled_default = enable_replaced ,
165140 device_class = BinarySensorDeviceClass .BATTERY ,
166141 )
167142
@@ -175,8 +150,6 @@ async def async_registry_updated(event: Event) -> None:
175150 coordinator ,
176151 description ,
177152 f"{ config_entry .entry_id } { description .unique_id_suffix } " ,
178- device ,
179- round_battery ,
180153 )
181154 ]
182155 )
@@ -190,35 +163,28 @@ async def async_setup_platform(
190163 await async_setup_reload_service (hass , DOMAIN , PLATFORMS )
191164
192165
193- class BatteryNotesBatteryLowSensor (BinarySensorEntity ):
166+ class BatteryNotesBatteryLowSensor (BinarySensorEntity , CoordinatorEntity [ BatteryNotesCoordinator ] ):
194167 """Represents a low battery threshold binary sensor."""
195168
196169 _attr_should_poll = False
197- _battery_entity_id = None
198- device_name = None
199- _previous_battery_low = None
200- _previous_battery_level = None
201- _previous_state_last_changed = None
202-
203- entity_description : BatteryNotesBinarySensorEntityDescription
204170
205171 def __init__ (
206172 self ,
207173 hass : HomeAssistant ,
208174 coordinator : BatteryNotesCoordinator ,
209175 description : BatteryNotesBinarySensorEntityDescription ,
210176 unique_id : str ,
211- device : BatteryNotesDevice ,
212- round_battery : bool ,
213177 ) -> None :
214178 """Create a low battery binary sensor."""
179+
215180 device_registry = dr .async_get (hass )
216181
217182 self .coordinator = coordinator
218183 self .entity_description = description
219184 self ._attr_unique_id = unique_id
220185 self ._attr_has_entity_name = True
221- self .round_battery = round_battery
186+
187+ super ().__init__ (coordinator = coordinator )
222188
223189 if coordinator .device_id and (
224190 device_entry := device_registry .async_get (coordinator .device_id )
@@ -228,141 +194,53 @@ def __init__(
228194 identifiers = device_entry .identifiers ,
229195 )
230196
231- self .entity_id = f"binary_sensor.{ device .name .lower ()} _{ description .key } "
232- self .device_name = device .name
233-
234- self ._battery_entity_id = (
235- device .wrapped_battery .entity_id if device .wrapped_battery else None
236- )
237-
238- @callback
239- async def async_state_changed_listener (
240- self , event : EventType [EventStateChangedData ] | None = None
241- ) -> None :
242- # pylint: disable=unused-argument
243- """Handle child updates."""
244-
245- if not self ._battery_entity_id :
246- return
247-
248- if (
249- wrapped_battery_state := self .hass .states .get (self ._battery_entity_id )
250- ) is None or wrapped_battery_state .state in [STATE_UNAVAILABLE , STATE_UNKNOWN ]:
251- self ._attr_is_on = False
252- self ._attr_available = True
253- return
254-
255- battery_low = bool (
256- float (wrapped_battery_state .state ) < self .coordinator .battery_low_threshold
257- )
258-
259- self .coordinator .set_battery_low (battery_low )
260-
261- self ._attr_is_on = self .coordinator .battery_low
262-
263- self ._attr_available = True
264-
265- self .async_write_ha_state ()
266-
267- _LOGGER .debug (
268- "%s battery_low changed: %s" , self ._battery_entity_id , battery_low
269- )
270-
271- await self .coordinator .async_request_refresh ()
272-
273- if isfloat (wrapped_battery_state .state ):
274- if self .round_battery :
275- battery_level = round (float (wrapped_battery_state .state ), 0 )
276- else :
277- battery_level = round (float (wrapped_battery_state .state ), 1 )
278- else :
279- battery_level = wrapped_battery_state .state
280-
281- if self ._previous_state_last_changed :
282- # Battery low event
283- if battery_low != self ._previous_battery_low :
284- self .hass .bus .fire (
285- EVENT_BATTERY_THRESHOLD ,
286- {
287- ATTR_DEVICE_ID : self .coordinator .device_id ,
288- ATTR_DEVICE_NAME : self .device_name ,
289- ATTR_BATTERY_LOW : battery_low ,
290- ATTR_BATTERY_TYPE_AND_QUANTITY : self .coordinator .battery_type_and_quantity ,
291- ATTR_BATTERY_TYPE : self .coordinator .battery_type ,
292- ATTR_BATTERY_QUANTITY : self .coordinator .battery_quantity ,
293- ATTR_BATTERY_LEVEL : battery_level ,
294- ATTR_PREVIOUS_BATTERY_LEVEL : self ._previous_battery_level ,
295- },
296- )
297-
298- _LOGGER .debug ("battery_threshold event fired Low: %s" , battery_low )
299-
300- # Battery increased event
301- increase_threshold = DEFAULT_BATTERY_INCREASE_THRESHOLD
302- if DOMAIN_CONFIG in self .hass .data [DOMAIN ]:
303- domain_config : dict = self .hass .data [DOMAIN ][DOMAIN_CONFIG ]
304- increase_threshold = domain_config .get (
305- CONF_BATTERY_INCREASE_THRESHOLD , DEFAULT_BATTERY_INCREASE_THRESHOLD
306- )
307-
308- if wrapped_battery_state .state not in [STATE_UNAVAILABLE , STATE_UNKNOWN ]:
309- if (
310- wrapped_battery_state .state
311- and self ._previous_battery_level
312- and float (wrapped_battery_state .state )
313- >= (self ._previous_battery_level + increase_threshold )
314- ):
315- self .hass .bus .fire (
316- EVENT_BATTERY_INCREASED ,
317- {
318- ATTR_DEVICE_ID : self .coordinator .device_id ,
319- ATTR_DEVICE_NAME : self .device_name ,
320- ATTR_BATTERY_LOW : battery_low ,
321- ATTR_BATTERY_TYPE_AND_QUANTITY : self .coordinator .battery_type_and_quantity ,
322- ATTR_BATTERY_TYPE : self .coordinator .battery_type ,
323- ATTR_BATTERY_QUANTITY : self .coordinator .battery_quantity ,
324- ATTR_BATTERY_LEVEL : battery_level ,
325- ATTR_PREVIOUS_BATTERY_LEVEL : self ._previous_battery_level ,
326- },
327- )
328-
329- _LOGGER .debug ("battery_increased event fired" )
330-
331- self ._previous_battery_level = battery_level
332- self ._previous_state_last_changed = wrapped_battery_state .last_changed
333- self ._previous_battery_low = battery_low
197+ self .entity_id = f"binary_sensor.{ coordinator .device_name .lower ()} _{ description .key } "
334198
335199 async def async_added_to_hass (self ) -> None :
336200 """Handle added to Hass."""
337201
338- @callback
339- async def _async_state_changed_listener (
340- event : EventType [EventStateChangedData ] | None = None ,
341- ) -> None :
342- """Handle child updates."""
343- await self .async_state_changed_listener (event )
344-
345- if self ._battery_entity_id :
346- self .async_on_remove (
347- async_track_state_change_event (
348- self .hass , [self ._battery_entity_id ], _async_state_changed_listener
349- )
350- )
351-
352- # Call once on adding
353- await _async_state_changed_listener ()
202+ await super ().async_added_to_hass ()
354203
355204 # Update entity options
356205 registry = er .async_get (self .hass )
357- if registry .async_get (self .entity_id ) is not None and self ._battery_entity_id :
206+ if registry .async_get (self .entity_id ) is not None and self .coordinator . wrapped_battery . entity_id :
358207 registry .async_update_entity_options (
359208 self .entity_id ,
360209 DOMAIN ,
361- {"entity_id" : self ._battery_entity_id },
210+ {"entity_id" : self .coordinator . wrapped_battery . entity_id },
362211 )
363212
364213 await self .coordinator .async_config_entry_first_refresh ()
365214
215+ @callback
216+ def _handle_coordinator_update (self ) -> None :
217+ """Handle updated data from the coordinator."""
218+
219+ if (
220+ (
221+ wrapped_battery_state := self .hass .states .get (
222+ self .coordinator .wrapped_battery .entity_id
223+ )
224+ )
225+ is None
226+ or wrapped_battery_state .state
227+ in [
228+ STATE_UNAVAILABLE ,
229+ STATE_UNKNOWN ,
230+ ]
231+ or not isfloat (wrapped_battery_state .state )
232+ ):
233+ self ._attr_is_on = None
234+ self ._attr_available = False
235+ self .async_write_ha_state ()
236+ return
237+
238+ self ._attr_is_on = self .coordinator .battery_low
239+
240+ self .async_write_ha_state ()
241+
242+ _LOGGER .debug ("%s binary sensor battery_low set to: %s" , self .coordinator .wrapped_battery .entity_id , self .coordinator .battery_low )
243+
366244 @property
367245 def extra_state_attributes (self ) -> dict [str , str ] | None :
368246 """Return the state attributes of battery low."""
0 commit comments