From 0ed697dafe2828ebc785c137bd6768b9873e427a Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 19 Oct 2024 15:01:34 -0400 Subject: [PATCH 1/2] Add a global device --- custom_components/bermuda/entity.py | 30 +++++++++++ custom_components/bermuda/sensor.py | 78 +++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/custom_components/bermuda/entity.py b/custom_components/bermuda/entity.py index 99f3b99..d086d23 100644 --- a/custom_components/bermuda/entity.py +++ b/custom_components/bermuda/entity.py @@ -153,3 +153,33 @@ def device_state_attributes(self): "id": str(self.coordinator.data.get("id")), "integration": DOMAIN, } + + +class BermudaGlobalEntity(CoordinatorEntity): + """Holds all Bermuda global data under one entity type/device.""" + + def __init__( + self, + coordinator: BermudaDataUpdateCoordinator, + config_entry: ConfigEntry, + ) -> None: + super().__init__(coordinator) + self.coordinator = coordinator + self.config_entry = config_entry + + @callback + def _handle_coordinator_update(self) -> None: + """ + Handle updated data from the co-ordinator. + + (we don't need to implement this, but if we want to do anything special we can) + """ + self.async_write_ha_state() + + @property + def device_info(self): + """Implementing this creates an entry in the device registry.""" + return { + "identifiers": {(DOMAIN, "BERMUDA_GLOBAL")}, + "name": "Bermuda Global", + } diff --git a/custom_components/bermuda/sensor.py b/custom_components/bermuda/sensor.py index 2a6c536..4b8ca37 100644 --- a/custom_components/bermuda/sensor.py +++ b/custom_components/bermuda/sensor.py @@ -6,12 +6,22 @@ from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor.const import SensorDeviceClass, SensorStateClass -from homeassistant.const import SIGNAL_STRENGTH_DECIBELS_MILLIWATT, STATE_UNAVAILABLE, UnitOfLength +from homeassistant.const import ( + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + STATE_UNAVAILABLE, + UnitOfLength, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import _LOGGER, ADDR_TYPE_IBEACON, ADDR_TYPE_PRIVATE_BLE_DEVICE, DOMAIN, SIGNAL_DEVICE_NEW -from .entity import BermudaEntity +from .const import ( + _LOGGER, + ADDR_TYPE_IBEACON, + ADDR_TYPE_PRIVATE_BLE_DEVICE, + DOMAIN, + SIGNAL_DEVICE_NEW, +) +from .entity import BermudaEntity, BermudaGlobalEntity if TYPE_CHECKING: from collections.abc import Mapping @@ -67,7 +77,7 @@ def device_new(address: str, scanners: list[str]) -> None: # Connect device_new to a signal so the coordinator can call it _LOGGER.debug("Registering device_new callback.") entry.async_on_unload(async_dispatcher_connect(hass, SIGNAL_DEVICE_NEW, device_new)) - + async_add_devices([BermudaProxyCount(coordinator, entry), BermudaDeviceCount(coordinator, entry)]) # Now we must tell the co-ord to do initial refresh, so that it will call our callback. # This runs inside the event loop so should be fine as-is. # Disabling as it seems to work ok without, and it might be cause of async race. @@ -300,3 +310,63 @@ def native_value(self): if distance is not None: return round(distance, 3) return None + + +class BermudaGlobalSensor(BermudaGlobalEntity, SensorEntity): + """bermuda Global Sensor class.""" + + _attr_has_entity_name = True + + @property + def name(self): + """Return the name of the sensor.""" + return "Area" + + @property + def device_class(self): + """Return de device class of the sensor.""" + return "bermuda__custom_device_class" + + +class BermudaProxyCount(BermudaGlobalSensor): + """Counts the number of proxies we have access to.""" + + @property + def unique_id(self): + """ + "Uniquely identify this sensor so that it gets stored in the entity_registry, + and can be maintained / renamed etc by the user. + """ + return "BERMUDA_GLOBAL_PROXY_COUNT" + + @property + def native_value(self) -> int: + """Gets the number of proxies we have access to.""" + return len(self.coordinator.scanner_list) + + @property + def name(self): + """Gets the name of the sensor.""" + return "Proxy count" + + +class BermudaDeviceCount(BermudaGlobalSensor): + """Counts the number of devices we can see.""" + + @property + def unique_id(self): + """ + "Uniquely identify this sensor so that it gets stored in the entity_registry, + and can be maintained / renamed etc by the user. + """ + return "BERMUDA_GLOBAL_DEVICE_COUNT" + + @property + def native_value(self) -> int: + """Gets the amount of devices we can see.""" + return len(self.coordinator.devices) + + @property + def name(self): + """Gets the name of the sensor.""" + return "Device count" From 295f37ddfef72580cddade2a1703805cc4a6259b Mon Sep 17 00:00:00 2001 From: Luke Date: Sun, 20 Oct 2024 10:48:48 -0400 Subject: [PATCH 2/2] Address comments --- custom_components/bermuda/sensor.py | 76 ++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/custom_components/bermuda/sensor.py b/custom_components/bermuda/sensor.py index 4b8ca37..a8968d0 100644 --- a/custom_components/bermuda/sensor.py +++ b/custom_components/bermuda/sensor.py @@ -9,6 +9,7 @@ from homeassistant.const import ( SIGNAL_STRENGTH_DECIBELS_MILLIWATT, STATE_UNAVAILABLE, + EntityCategory, UnitOfLength, ) from homeassistant.core import HomeAssistant, callback @@ -77,7 +78,14 @@ def device_new(address: str, scanners: list[str]) -> None: # Connect device_new to a signal so the coordinator can call it _LOGGER.debug("Registering device_new callback.") entry.async_on_unload(async_dispatcher_connect(hass, SIGNAL_DEVICE_NEW, device_new)) - async_add_devices([BermudaProxyCount(coordinator, entry), BermudaDeviceCount(coordinator, entry)]) + async_add_devices( + ( + BermudaTotalProxyCount(coordinator, entry), + BermudaActiveProxyCount(coordinator, entry), + BermudaTotalDeviceCount(coordinator, entry), + BermudaVisibleDeviceCount(coordinator, entry), + ) + ) # Now we must tell the co-ord to do initial refresh, so that it will call our callback. # This runs inside the event loop so should be fine as-is. # Disabling as it seems to work ok without, and it might be cause of async race. @@ -328,8 +336,10 @@ def device_class(self): return "bermuda__custom_device_class" -class BermudaProxyCount(BermudaGlobalSensor): - """Counts the number of proxies we have access to.""" +class BermudaTotalProxyCount(BermudaGlobalSensor): + """Counts the total number of proxies we have access to.""" + + _attr_entity_category = EntityCategory.DIAGNOSTIC @property def unique_id(self): @@ -347,11 +357,37 @@ def native_value(self) -> int: @property def name(self): """Gets the name of the sensor.""" - return "Proxy count" + return "Total proxy count" + +class BermudaActiveProxyCount(BermudaGlobalSensor): + """Counts the number of proxies that are active.""" -class BermudaDeviceCount(BermudaGlobalSensor): - """Counts the number of devices we can see.""" + _attr_entity_category = EntityCategory.DIAGNOSTIC + + @property + def unique_id(self): + """ + "Uniquely identify this sensor so that it gets stored in the entity_registry, + and can be maintained / renamed etc by the user. + """ + return "BERMUDA_GLOBAL_ACTIVE_PROXY_COUNT" + + @property + def native_value(self) -> int: + """Gets the number of proxies we have access to.""" + return self.coordinator.count_active_scanners() + + @property + def name(self): + """Gets the name of the sensor.""" + return "Active proxy count" + + +class BermudaTotalDeviceCount(BermudaGlobalSensor): + """Counts the total number of devices we can see.""" + + _attr_entity_category = EntityCategory.DIAGNOSTIC @property def unique_id(self): @@ -363,10 +399,34 @@ def unique_id(self): @property def native_value(self) -> int: - """Gets the amount of devices we can see.""" + """Gets the amount of devices we have seen.""" return len(self.coordinator.devices) @property def name(self): """Gets the name of the sensor.""" - return "Device count" + return "Total device count" + + +class BermudaVisibleDeviceCount(BermudaGlobalSensor): + """Counts the number of devices that are active.""" + + _attr_entity_category = EntityCategory.DIAGNOSTIC + + @property + def unique_id(self): + """ + "Uniquely identify this sensor so that it gets stored in the entity_registry, + and can be maintained / renamed etc by the user. + """ + return "BERMUDA_GLOBAL_VISIBLE_DEVICE_COUNT" + + @property + def native_value(self) -> int: + """Gets the amount of devices that are active.""" + return self.coordinator.count_active_devices() + + @property + def name(self): + """Gets the name of the sensor.""" + return "Visible device count"