diff --git a/homeassistant/components/lametric/const.py b/homeassistant/components/lametric/const.py index 1ba48e0d992..6a3df3b54f1 100644 --- a/homeassistant/components/lametric/const.py +++ b/homeassistant/components/lametric/const.py @@ -7,7 +7,7 @@ from typing import Final from homeassistant.const import Platform DOMAIN: Final = "lametric" -PLATFORMS = [Platform.BUTTON, Platform.NUMBER, Platform.SWITCH] +PLATFORMS = [Platform.BUTTON, Platform.NUMBER, Platform.SENSOR, Platform.SWITCH] LOGGER = logging.getLogger(__package__) SCAN_INTERVAL = timedelta(seconds=30) diff --git a/homeassistant/components/lametric/sensor.py b/homeassistant/components/lametric/sensor.py new file mode 100644 index 00000000000..b9ff430ab2b --- /dev/null +++ b/homeassistant/components/lametric/sensor.py @@ -0,0 +1,87 @@ +"""Support for LaMetric sensors.""" +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass + +from demetriek import Device + +from homeassistant.components.sensor import ( + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import PERCENTAGE +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .const import DOMAIN +from .coordinator import LaMetricDataUpdateCoordinator +from .entity import LaMetricEntity + + +@dataclass +class LaMetricEntityDescriptionMixin: + """Mixin values for LaMetric entities.""" + + value_fn: Callable[[Device], int | None] + + +@dataclass +class LaMetricSensorEntityDescription( + SensorEntityDescription, LaMetricEntityDescriptionMixin +): + """Class describing LaMetric sensor entities.""" + + +SENSORS = [ + LaMetricSensorEntityDescription( + key="rssi", + name="Wi-Fi signal", + icon="mdi:wifi", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda device: device.wifi.rssi, + ), +] + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up LaMetric sensor based on a config entry.""" + coordinator: LaMetricDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + async_add_entities( + LaMetricSensorEntity( + coordinator=coordinator, + description=description, + ) + for description in SENSORS + ) + + +class LaMetricSensorEntity(LaMetricEntity, SensorEntity): + """Representation of a LaMetric sensor.""" + + entity_description: LaMetricSensorEntityDescription + + def __init__( + self, + coordinator: LaMetricDataUpdateCoordinator, + description: LaMetricSensorEntityDescription, + ) -> None: + """Initiate LaMetric sensor.""" + super().__init__(coordinator) + self.entity_description = description + self._attr_unique_id = f"{coordinator.data.serial_number}-{description.key}" + + @property + def native_value(self) -> int | None: + """Return the sensor value.""" + return self.entity_description.value_fn(self.coordinator.data) diff --git a/tests/components/lametric/test_sensor.py b/tests/components/lametric/test_sensor.py new file mode 100644 index 00000000000..76f584b1cde --- /dev/null +++ b/tests/components/lametric/test_sensor.py @@ -0,0 +1,54 @@ +"""Tests for the LaMetric sensor platform.""" +from unittest.mock import AsyncMock, MagicMock + +from homeassistant.components.lametric.const import DOMAIN +from homeassistant.components.sensor import ATTR_STATE_CLASS, SensorStateClass +from homeassistant.const import ( + ATTR_DEVICE_CLASS, + ATTR_FRIENDLY_NAME, + ATTR_ICON, + ATTR_UNIT_OF_MEASUREMENT, + PERCENTAGE, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr, entity_registry as er +from homeassistant.helpers.entity import EntityCategory + +from tests.common import MockConfigEntry + + +async def test_wifi_signal( + hass: HomeAssistant, + entity_registry_enabled_by_default: AsyncMock, + init_integration: MockConfigEntry, + mock_lametric: MagicMock, +) -> None: + """Test the LaMetric Wi-Fi sensor.""" + device_registry = dr.async_get(hass) + entity_registry = er.async_get(hass) + + state = hass.states.get("sensor.frenck_s_lametric_wi_fi_signal") + assert state + assert state.attributes.get(ATTR_DEVICE_CLASS) is None + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's LaMetric Wi-Fi signal" + assert state.attributes.get(ATTR_ICON) == "mdi:wifi" + assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE + assert state.state == "21" + + entry = entity_registry.async_get(state.entity_id) + assert entry + assert entry.device_id + assert entry.entity_category is EntityCategory.DIAGNOSTIC + assert entry.unique_id == "SA110405124500W00BS9-rssi" + + device = device_registry.async_get(entry.device_id) + assert device + assert device.configuration_url is None + assert device.connections == {(dr.CONNECTION_NETWORK_MAC, "aa:bb:cc:dd:ee:ff")} + assert device.entry_type is None + assert device.hw_version is None + assert device.identifiers == {(DOMAIN, "SA110405124500W00BS9")} + assert device.manufacturer == "LaMetric Inc." + assert device.name == "Frenck's LaMetric" + assert device.sw_version == "2.2.2"