Use SensorEntityDescription for arlo (#54223)

* Use SensorEntityDescription.
This commit is contained in:
jan iversen 2021-08-09 12:16:35 +02:00 committed by GitHub
parent e7f0768ae6
commit 6ea50823c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 57 deletions

View File

@ -1,13 +1,19 @@
"""Sensor support for Netgear Arlo IP cameras.""" """Sensor support for Netgear Arlo IP cameras."""
from dataclasses import replace
import logging import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
CONCENTRATION_PARTS_PER_MILLION, CONCENTRATION_PARTS_PER_MILLION,
CONF_MONITORED_CONDITIONS, CONF_MONITORED_CONDITIONS,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TEMPERATURE,
PERCENTAGE, PERCENTAGE,
@ -22,17 +28,43 @@ from . import ATTRIBUTION, DATA_ARLO, DEFAULT_BRAND, SIGNAL_UPDATE_ARLO
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
# sensor_type [ description, unit, icon ] SENSOR_TYPES = (
SENSOR_TYPES = { SensorEntityDescription(key="last_capture", name="Last", icon="mdi:run-fast"),
"last_capture": ["Last", None, "run-fast"], SensorEntityDescription(key="total_cameras", name="Arlo Cameras", icon="mdi:video"),
"total_cameras": ["Arlo Cameras", None, "video"], SensorEntityDescription(
"captured_today": ["Captured Today", None, "file-video"], key="captured_today", name="Captured Today", icon="mdi:file-video"
"battery_level": ["Battery Level", PERCENTAGE, "battery-50"], ),
"signal_strength": ["Signal Strength", None, "signal"], SensorEntityDescription(
"temperature": ["Temperature", TEMP_CELSIUS, "thermometer"], key="battery_level",
"humidity": ["Humidity", PERCENTAGE, "water-percent"], name="Battery Level",
"air_quality": ["Air Quality", CONCENTRATION_PARTS_PER_MILLION, "biohazard"], unit_of_measurement=PERCENTAGE,
} icon="mdi:battery-50",
device_class=DEVICE_CLASS_BATTERY,
),
SensorEntityDescription(
key="signal_strength", name="Signal Strength", icon="mdi:signal"
),
SensorEntityDescription(
key="temperature",
name="Temperature",
unit_of_measurement=TEMP_CELSIUS,
icon="mdi:thermometer",
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key="humidity",
name="Humidity",
unit_of_measurement=PERCENTAGE,
icon="mdi:water-percent",
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key="air_quality",
name="Air Quality",
unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
icon="mdi:biohazard",
),
)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{ {
@ -50,24 +82,27 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
return return
sensors = [] sensors = []
for sensor_type in config[CONF_MONITORED_CONDITIONS]: for sensor_original in SENSOR_TYPES:
if sensor_type == "total_cameras": if sensor_original.key not in config[CONF_MONITORED_CONDITIONS]:
sensors.append(ArloSensor(SENSOR_TYPES[sensor_type][0], arlo, sensor_type)) continue
sensor_entry = replace(sensor_original)
if sensor_entry.key == "total_cameras":
sensors.append(ArloSensor(arlo, sensor_entry))
else: else:
for camera in arlo.cameras: for camera in arlo.cameras:
if sensor_type in ("temperature", "humidity", "air_quality"): if sensor_entry.key in ("temperature", "humidity", "air_quality"):
continue continue
name = f"{SENSOR_TYPES[sensor_type][0]} {camera.name}" sensor_entry.name = f"{sensor_entry.name} {camera.name}"
sensors.append(ArloSensor(name, camera, sensor_type)) sensors.append(ArloSensor(camera, sensor_entry))
for base_station in arlo.base_stations: for base_station in arlo.base_stations:
if ( if (
sensor_type in ("temperature", "humidity", "air_quality") sensor_entry.key in ("temperature", "humidity", "air_quality")
and base_station.model_id == "ABC1000" and base_station.model_id == "ABC1000"
): ):
name = f"{SENSOR_TYPES[sensor_type][0]} {base_station.name}" sensor_entry.name = f"{sensor_entry.name} {base_station.name}"
sensors.append(ArloSensor(name, base_station, sensor_type)) sensors.append(ArloSensor(base_station, sensor_entry))
add_entities(sensors, True) add_entities(sensors, True)
@ -75,19 +110,11 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class ArloSensor(SensorEntity): class ArloSensor(SensorEntity):
"""An implementation of a Netgear Arlo IP sensor.""" """An implementation of a Netgear Arlo IP sensor."""
def __init__(self, name, device, sensor_type): def __init__(self, device, sensor_entry):
"""Initialize an Arlo sensor.""" """Initialize an Arlo sensor."""
_LOGGER.debug("ArloSensor created for %s", name) self.entity_description = sensor_entry
self._name = name
self._data = device self._data = device
self._sensor_type = sensor_type
self._state = None self._state = None
self._icon = f"mdi:{SENSOR_TYPES.get(self._sensor_type)[2]}"
@property
def name(self):
"""Return the name of this camera."""
return self._name
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
@ -110,36 +137,22 @@ class ArloSensor(SensorEntity):
@property @property
def icon(self): def icon(self):
"""Icon to use in the frontend, if any.""" """Icon to use in the frontend, if any."""
if self._sensor_type == "battery_level" and self._state is not None: if self.entity_description.key == "battery_level" and self._state is not None:
return icon_for_battery_level( return icon_for_battery_level(
battery_level=int(self._state), charging=False battery_level=int(self._state), charging=False
) )
return self._icon return self.entity_description.icon
@property
def unit_of_measurement(self):
"""Return the units of measurement."""
return SENSOR_TYPES.get(self._sensor_type)[1]
@property
def device_class(self):
"""Return the device class of the sensor."""
if self._sensor_type == "temperature":
return DEVICE_CLASS_TEMPERATURE
if self._sensor_type == "humidity":
return DEVICE_CLASS_HUMIDITY
return None
def update(self): def update(self):
"""Get the latest data and updates the state.""" """Get the latest data and updates the state."""
_LOGGER.debug("Updating Arlo sensor %s", self.name) _LOGGER.debug("Updating Arlo sensor %s", self.name)
if self._sensor_type == "total_cameras": if self.entity_description.key == "total_cameras":
self._state = len(self._data.cameras) self._state = len(self._data.cameras)
elif self._sensor_type == "captured_today": elif self.entity_description.key == "captured_today":
self._state = len(self._data.captured_today) self._state = len(self._data.captured_today)
elif self._sensor_type == "last_capture": elif self.entity_description.key == "last_capture":
try: try:
video = self._data.last_video video = self._data.last_video
self._state = video.created_at_pretty("%m-%d-%Y %H:%M:%S") self._state = video.created_at_pretty("%m-%d-%Y %H:%M:%S")
@ -151,31 +164,31 @@ class ArloSensor(SensorEntity):
_LOGGER.debug(error_msg) _LOGGER.debug(error_msg)
self._state = None self._state = None
elif self._sensor_type == "battery_level": elif self.entity_description.key == "battery_level":
try: try:
self._state = self._data.battery_level self._state = self._data.battery_level
except TypeError: except TypeError:
self._state = None self._state = None
elif self._sensor_type == "signal_strength": elif self.entity_description.key == "signal_strength":
try: try:
self._state = self._data.signal_strength self._state = self._data.signal_strength
except TypeError: except TypeError:
self._state = None self._state = None
elif self._sensor_type == "temperature": elif self.entity_description.key == "temperature":
try: try:
self._state = self._data.ambient_temperature self._state = self._data.ambient_temperature
except TypeError: except TypeError:
self._state = None self._state = None
elif self._sensor_type == "humidity": elif self.entity_description.key == "humidity":
try: try:
self._state = self._data.ambient_humidity self._state = self._data.ambient_humidity
except TypeError: except TypeError:
self._state = None self._state = None
elif self._sensor_type == "air_quality": elif self.entity_description.key == "air_quality":
try: try:
self._state = self._data.ambient_air_quality self._state = self._data.ambient_air_quality
except TypeError: except TypeError:
@ -189,7 +202,7 @@ class ArloSensor(SensorEntity):
attrs[ATTR_ATTRIBUTION] = ATTRIBUTION attrs[ATTR_ATTRIBUTION] = ATTRIBUTION
attrs["brand"] = DEFAULT_BRAND attrs["brand"] = DEFAULT_BRAND
if self._sensor_type != "total_cameras": if self.entity_description.key != "total_cameras":
attrs["model"] = self._data.model_id attrs["model"] = self._data.model_id
return attrs return attrs

View File

@ -5,6 +5,7 @@ from unittest.mock import patch
import pytest import pytest
from homeassistant.components.arlo import DATA_ARLO, sensor as arlo from homeassistant.components.arlo import DATA_ARLO, sensor as arlo
from homeassistant.components.arlo.sensor import SENSOR_TYPES
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
@ -20,7 +21,11 @@ def _get_named_tuple(input_dict):
def _get_sensor(name="Last", sensor_type="last_capture", data=None): def _get_sensor(name="Last", sensor_type="last_capture", data=None):
if data is None: if data is None:
data = {} data = {}
return arlo.ArloSensor(name, data, sensor_type) sensor_entry = next(
sensor_entry for sensor_entry in SENSOR_TYPES if sensor_entry.key == sensor_type
)
sensor_entry.name = name
return arlo.ArloSensor(data, sensor_entry)
@pytest.fixture() @pytest.fixture()