Coverage for custom_components/supernotify/sensor.py: 98%

40 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-11-08 17:42 +0000

1"""Sensor platform: the notification/failure counters as real, restorable entities. 

2 

3The two SupernotifyCounterSensor entities are created by SupernotifyEngine itself (so they exist, 

4and count, even before this platform loads, or without a config entry at all) and just handed to 

5Home Assistant here. They are the single home of the counts - the engine has no separate copy - 

6and being RestoreSensors, the counts survive a Home Assistant restart. 

7""" 

8 

9from __future__ import annotations 

10 

11from typing import TYPE_CHECKING 

12 

13from homeassistant.components.sensor import RestoreSensor, SensorStateClass 

14from homeassistant.const import EntityCategory 

15 

16from . import DOMAIN 

17from .hass_api import ha_device_info 

18 

19if TYPE_CHECKING: 

20 from homeassistant.core import HomeAssistant 

21 from homeassistant.helpers.device_registry import DeviceInfo 

22 from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback 

23 

24 from . import SupernotifyConfigEntry 

25 

26# Entities are pushed, never polled, and their actions only change local state 

27PARALLEL_UPDATES = 0 

28 

29 

30async def async_setup_entry( 

31 hass: HomeAssistant, 

32 entry: SupernotifyConfigEntry, 

33 async_add_entities: AddConfigEntryEntitiesCallback, 

34) -> None: 

35 """Add the engine's sent/failure counters as restorable sensor entities.""" 

36 _ = hass 

37 async_add_entities(entry.runtime_data.counter_sensors) 

38 

39 

40class SupernotifyCounterSensor(RestoreSensor): 

41 """A monotonically increasing counter, restored across restarts.""" 

42 

43 _attr_has_entity_name = True 

44 _attr_entity_category = EntityCategory.DIAGNOSTIC 

45 _attr_state_class = SensorStateClass.TOTAL_INCREASING 

46 _attr_native_value = 0 

47 _attr_should_poll = False 

48 

49 def __init__(self, unique_id: str, translation_key: str) -> None: 

50 self._attr_unique_id = unique_id 

51 self._attr_translation_key = translation_key 

52 # Kept as the entity_id the counters have always had, rather than the one HA would derive 

53 # from the device and entity name - see SupernotifyScenarioSwitch for why this is 

54 # tolerated 

55 self.entity_id = f"sensor.{DOMAIN}_{unique_id}" 

56 

57 @property 

58 def device_info(self) -> DeviceInfo | None: 

59 """The single SuperNotify device - the platform, and so the config entry, is only known 

60 once the entity has been handed to Home Assistant""" 

61 if self.platform is None or self.platform.config_entry is None: 

62 return None 

63 return ha_device_info(self.platform.config_entry.entry_id) 

64 

65 @property 

66 def count(self) -> int: 

67 return self._attr_native_value if isinstance(self._attr_native_value, int) else 0 

68 

69 async def async_added_to_hass(self) -> None: 

70 await super().async_added_to_hass() 

71 last_data = await self.async_get_last_sensor_data() 

72 if last_data is not None and isinstance(last_data.native_value, (int, float)): 

73 self._attr_native_value = int(last_data.native_value) 

74 self.async_write_ha_state() 

75 

76 def increment(self) -> None: 

77 self._attr_native_value = self.count + 1 

78 self.refresh() 

79 

80 def refresh(self) -> None: 

81 """Publish the current count, if the entity has been added to Home Assistant yet""" 

82 if self.hass is not None: 

83 self.async_write_ha_state()