hass-core/homeassistant/components/nest/sensor_sdm.py
PeteRager 504ce8e93a
Set nest entities as unavailable on lost connection (#78773)
* NEST - Issues with lost internet connectivity #70479

Update Climate and Sensor entities to be unavailable when the device connectivity trait indicates the device is offline.

The prior behavior, the last known values would be displayed indefinitely if the device lost internet connectivity.  This was creating the illusion that the device was still connected.  With this change, the Home Assistant entities will become unavailable when the device loses connectivity.

* Update formatting

* Add doc strings, fix indentation

* Fix doc strings

* Update test_climate_sdm.py

* Update test_climate_sdm.py

* Update test_sensor_sdm.py

* Update test_sensor_sdm.py

* more formatting fixes

* Place availability logic in mixin

1. Consolidate repeated code into mixin and apply mixin to Climate and Sensor entities
2. Return true instead of super.available()
3. No unit test changes required to maintain code coverage

* Define self._device is mixin to make linter happier

* Remove logger used for debugging

* restore whitespace

* Fix test due to underlying merge change

* Update availability_mixin.py

* Move availability logic into device_info

* Update sensor_sdm.py
2022-09-28 19:23:11 -07:00

106 lines
3.5 KiB
Python

"""Support for Google Nest SDM sensors."""
from __future__ import annotations
import logging
from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from google_nest_sdm.device_traits import HumidityTrait, TemperatureTrait
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DATA_DEVICE_MANAGER, DOMAIN
from .device_info import NestDeviceInfo
_LOGGER = logging.getLogger(__name__)
DEVICE_TYPE_MAP = {
"sdm.devices.types.CAMERA": "Camera",
"sdm.devices.types.DISPLAY": "Display",
"sdm.devices.types.DOORBELL": "Doorbell",
"sdm.devices.types.THERMOSTAT": "Thermostat",
}
async def async_setup_sdm_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the sensors."""
device_manager: DeviceManager = hass.data[DOMAIN][entry.entry_id][
DATA_DEVICE_MANAGER
]
entities: list[SensorEntity] = []
for device in device_manager.devices.values():
if TemperatureTrait.NAME in device.traits:
entities.append(TemperatureSensor(device))
if HumidityTrait.NAME in device.traits:
entities.append(HumiditySensor(device))
async_add_entities(entities)
class SensorBase(SensorEntity):
"""Representation of a dynamically updated Sensor."""
_attr_should_poll = False
_attr_state_class = SensorStateClass.MEASUREMENT
_attr_has_entity_name = True
def __init__(self, device: Device) -> None:
"""Initialize the sensor."""
self._device = device
self._device_info = NestDeviceInfo(device)
self._attr_unique_id = f"{device.name}-{self.device_class}"
self._attr_device_info = self._device_info.device_info
@property
def available(self) -> bool:
"""Return the device availability."""
return self._device_info.available
async def async_added_to_hass(self) -> None:
"""Run when entity is added to register update signal handler."""
self.async_on_remove(
self._device.add_update_listener(self.async_write_ha_state)
)
class TemperatureSensor(SensorBase):
"""Representation of a Temperature Sensor."""
_attr_device_class = SensorDeviceClass.TEMPERATURE
_attr_native_unit_of_measurement = TEMP_CELSIUS
_attr_name = "Temperature"
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
trait: TemperatureTrait = self._device.traits[TemperatureTrait.NAME]
# Round for display purposes because the API returns 5 decimal places.
# This can be removed if the SDM API issue is fixed, or a frontend
# display fix is added for all integrations.
return float(round(trait.ambient_temperature_celsius, 1))
class HumiditySensor(SensorBase):
"""Representation of a Humidity Sensor."""
_attr_device_class = SensorDeviceClass.HUMIDITY
_attr_native_unit_of_measurement = PERCENTAGE
_attr_name = "Humidity"
@property
def native_value(self) -> int:
"""Return the state of the sensor."""
trait: HumidityTrait = self._device.traits[HumidityTrait.NAME]
# Cast without loss of precision because the API always returns an integer.
return int(trait.ambient_humidity_percent)