feat(sensor): add disabled-by-default connection-mode diagnostic sensor
Exposes whether a device is currently in observe (push) or poll mode, for troubleshooting the observe-mode feature without digging through logs. Disabled by default since it's not everyday-use information.
This commit is contained in:
@@ -3,9 +3,13 @@ from __future__ import annotations
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity, SensorDeviceClass, SensorStateClass
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .observe import MODE_OBSERVE, MODE_POLL
|
||||
from .registry.entities import SensorDesc
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -19,11 +23,13 @@ async def async_setup_entry(
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
coordinator: LocalThingsCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
async_add_entities(
|
||||
entities = [
|
||||
LocalThingsSensor(coordinator, b)
|
||||
for b in coordinator.bound
|
||||
if isinstance(b.desc, SensorDesc) and _is_included(b, coordinator)
|
||||
)
|
||||
]
|
||||
entities.append(LocalThingsConnectionModeSensor(coordinator))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class LocalThingsSensor(LocalThingsEntity, SensorEntity):
|
||||
@@ -40,3 +46,29 @@ class LocalThingsSensor(LocalThingsEntity, SensorEntity):
|
||||
@property
|
||||
def native_value(self):
|
||||
return (self.coordinator.data or {}).get(self._state_key)
|
||||
|
||||
|
||||
class LocalThingsConnectionModeSensor(CoordinatorEntity[LocalThingsCoordinator], SensorEntity):
|
||||
"""Diagnostic sensor exposing whether this device is currently
|
||||
receiving push notifications (observe mode) or being polled only.
|
||||
Disabled by default — it's for troubleshooting, not everyday use."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = 'Connection mode'
|
||||
_attr_translation_key = 'connection_mode'
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
_attr_entity_registry_enabled_default = False
|
||||
_attr_device_class = SensorDeviceClass.ENUM
|
||||
_attr_options = [MODE_OBSERVE, MODE_POLL]
|
||||
|
||||
def __init__(self, coordinator: LocalThingsCoordinator) -> None:
|
||||
super().__init__(coordinator)
|
||||
self._attr_unique_id = f"{DOMAIN}_{coordinator.device_serial}_connection_mode"
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
return self.coordinator.device_info
|
||||
|
||||
@property
|
||||
def native_value(self) -> str:
|
||||
return self.coordinator.observe_mode
|
||||
|
||||
@@ -45,6 +45,12 @@
|
||||
"icestatus_stop": "Idle",
|
||||
"icestatus_run": "Making ice"
|
||||
}
|
||||
},
|
||||
"connection_mode": {
|
||||
"state": {
|
||||
"observe": "Push (observe)",
|
||||
"poll": "Polling"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -45,6 +45,12 @@
|
||||
"icestatus_stop": "Idle",
|
||||
"icestatus_run": "Making ice"
|
||||
}
|
||||
},
|
||||
"connection_mode": {
|
||||
"state": {
|
||||
"observe": "Push (observe)",
|
||||
"poll": "Polling"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from custom_components.localthings.const import DOMAIN
|
||||
from custom_components.localthings.observe import MODE_POLL
|
||||
|
||||
|
||||
async def test_sensors_registered(
|
||||
@@ -45,3 +46,37 @@ async def test_sensor_state_from_coordinator(
|
||||
assert state.state not in ('unknown', 'unavailable'), (
|
||||
f"Sensor state is {state.state}"
|
||||
)
|
||||
|
||||
|
||||
async def test_connection_mode_sensor_registered_disabled_by_default(
|
||||
hass: HomeAssistant, mock_entry, mock_coordinator_session
|
||||
) -> None:
|
||||
"""The connection-mode diagnostic sensor is registered but disabled by
|
||||
default — it's for troubleshooting, not everyday use."""
|
||||
await hass.config_entries.async_setup(mock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
entries = er.async_entries_for_config_entry(ent_reg, mock_entry.entry_id)
|
||||
mode_entries = [e for e in entries if e.unique_id.endswith('_connection_mode')]
|
||||
assert len(mode_entries) == 1
|
||||
entry = mode_entries[0]
|
||||
assert entry.disabled_by is not None
|
||||
assert entry.entity_category == 'diagnostic'
|
||||
|
||||
|
||||
async def test_connection_mode_sensor_reflects_coordinator_mode(
|
||||
hass: HomeAssistant, mock_entry, mock_coordinator_session
|
||||
) -> None:
|
||||
"""native_value reads coordinator.observe_mode directly, live."""
|
||||
from custom_components.localthings.sensor import LocalThingsConnectionModeSensor
|
||||
|
||||
await hass.config_entries.async_setup(mock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
coordinator = hass.data[DOMAIN][mock_entry.entry_id]
|
||||
sensor = LocalThingsConnectionModeSensor(coordinator)
|
||||
assert sensor.native_value == MODE_POLL
|
||||
|
||||
coordinator._observe._set_mode('observe')
|
||||
assert sensor.native_value == 'observe'
|
||||
|
||||
Reference in New Issue
Block a user