diff --git a/.coveragerc b/.coveragerc index 3a7f33f6050b91e8b846be9f0acab7c331e409cf..47d9c84ba0ec1dd63bf81a7f120a7e11b1c0d772 100644 --- a/.coveragerc +++ b/.coveragerc @@ -521,6 +521,7 @@ omit = homeassistant/components/lyric/__init__.py homeassistant/components/lyric/api.py homeassistant/components/lyric/climate.py + homeassistant/components/lyric/sensor.py homeassistant/components/magicseaweed/sensor.py homeassistant/components/mailgun/notify.py homeassistant/components/map/* diff --git a/homeassistant/components/lyric/__init__.py b/homeassistant/components/lyric/__init__.py index 0697dfbfd35da8bde6ca60eb5cdd1c8eb710d815..12990d66ba93c2391f3ff42b2125672c75624117 100644 --- a/homeassistant/components/lyric/__init__.py +++ b/homeassistant/components/lyric/__init__.py @@ -44,7 +44,7 @@ CONFIG_SCHEMA = vol.Schema( _LOGGER = logging.getLogger(__name__) -PLATFORMS = ["climate"] +PLATFORMS = ["climate", "sensor"] async def async_setup(hass: HomeAssistant, config: dict): diff --git a/homeassistant/components/lyric/sensor.py b/homeassistant/components/lyric/sensor.py new file mode 100644 index 0000000000000000000000000000000000000000..c4950f119d9068ebea8179658271270b296ad65f --- /dev/null +++ b/homeassistant/components/lyric/sensor.py @@ -0,0 +1,251 @@ +"""Support for Honeywell Lyric sensor platform.""" +from datetime import datetime, timedelta + +from aiolyric.objects.device import LyricDevice +from aiolyric.objects.location import LyricLocation + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ( + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_TIMESTAMP, +) +from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator +from homeassistant.util import dt as dt_util + +from . import LyricDeviceEntity +from .const import ( + DOMAIN, + PRESET_HOLD_UNTIL, + PRESET_NO_HOLD, + PRESET_PERMANENT_HOLD, + PRESET_TEMPORARY_HOLD, + PRESET_VACATION_HOLD, +) + +LYRIC_SETPOINT_STATUS_NAMES = { + PRESET_NO_HOLD: "Following Schedule", + PRESET_PERMANENT_HOLD: "Held Permanently", + PRESET_TEMPORARY_HOLD: "Held Temporarily", + PRESET_VACATION_HOLD: "Holiday", +} + + +async def async_setup_entry( + hass: HomeAssistantType, entry: ConfigEntry, async_add_entities +) -> None: + """Set up the Honeywell Lyric sensor platform based on a config entry.""" + coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id] + + entities = [] + + for location in coordinator.data.locations: + for device in location.devices: + cls_list = [] + if device.indoorTemperature: + cls_list.append(LyricIndoorTemperatureSensor) + if device.outdoorTemperature: + cls_list.append(LyricOutdoorTemperatureSensor) + if device.displayedOutdoorHumidity: + cls_list.append(LyricOutdoorHumiditySensor) + if device.changeableValues: + if device.changeableValues.nextPeriodTime: + cls_list.append(LyricNextPeriodSensor) + if device.changeableValues.thermostatSetpointStatus: + cls_list.append(LyricSetpointStatusSensor) + for cls in cls_list: + entities.append( + cls( + coordinator, + location, + device, + hass.config.units.temperature_unit, + ) + ) + + async_add_entities(entities, True) + + +class LyricSensor(LyricDeviceEntity): + """Defines a Honeywell Lyric sensor.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + location: LyricLocation, + device: LyricDevice, + key: str, + name: str, + icon: str, + device_class: str = None, + unit_of_measurement: str = None, + ) -> None: + """Initialize Honeywell Lyric sensor.""" + self._device_class = device_class + self._unit_of_measurement = unit_of_measurement + + super().__init__(coordinator, location, device, key, name, icon) + + @property + def device_class(self) -> str: + """Return the device class of the sensor.""" + return self._device_class + + @property + def unit_of_measurement(self) -> str: + """Return the unit this state is expressed in.""" + return self._unit_of_measurement + + +class LyricIndoorTemperatureSensor(LyricSensor): + """Defines a Honeywell Lyric sensor.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + location: LyricLocation, + device: LyricDevice, + unit_of_measurement: str = None, + ) -> None: + """Initialize Honeywell Lyric sensor.""" + + super().__init__( + coordinator, + location, + device, + f"{device.macID}_indoor_temperature", + "Indoor Temperature", + None, + DEVICE_CLASS_TEMPERATURE, + unit_of_measurement, + ) + + @property + def state(self) -> str: + """Return the state of the sensor.""" + return self.device.indoorTemperature + + +class LyricOutdoorTemperatureSensor(LyricSensor): + """Defines a Honeywell Lyric sensor.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + location: LyricLocation, + device: LyricDevice, + unit_of_measurement: str = None, + ) -> None: + """Initialize Honeywell Lyric sensor.""" + + super().__init__( + coordinator, + location, + device, + f"{device.macID}_outdoor_temperature", + "Outdoor Temperature", + None, + DEVICE_CLASS_TEMPERATURE, + unit_of_measurement, + ) + + @property + def state(self) -> str: + """Return the state of the sensor.""" + return self.device.outdoorTemperature + + +class LyricOutdoorHumiditySensor(LyricSensor): + """Defines a Honeywell Lyric sensor.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + location: LyricLocation, + device: LyricDevice, + unit_of_measurement: str = None, + ) -> None: + """Initialize Honeywell Lyric sensor.""" + + super().__init__( + coordinator, + location, + device, + f"{device.macID}_outdoor_humidity", + "Outdoor Humidity", + None, + DEVICE_CLASS_HUMIDITY, + "%", + ) + + @property + def state(self) -> str: + """Return the state of the sensor.""" + return self.device.displayedOutdoorHumidity + + +class LyricNextPeriodSensor(LyricSensor): + """Defines a Honeywell Lyric sensor.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + location: LyricLocation, + device: LyricDevice, + unit_of_measurement: str = None, + ) -> None: + """Initialize Honeywell Lyric sensor.""" + + super().__init__( + coordinator, + location, + device, + f"{device.macID}_next_period_time", + "Next Period Time", + None, + DEVICE_CLASS_TIMESTAMP, + ) + + @property + def state(self) -> datetime: + """Return the state of the sensor.""" + device = self.device + time = dt_util.parse_time(device.changeableValues.nextPeriodTime) + now = dt_util.utcnow() + if time <= now.time(): + now = now + timedelta(days=1) + return dt_util.as_utc(datetime.combine(now.date(), time)) + + +class LyricSetpointStatusSensor(LyricSensor): + """Defines a Honeywell Lyric sensor.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + location: LyricLocation, + device: LyricDevice, + unit_of_measurement: str = None, + ) -> None: + """Initialize Honeywell Lyric sensor.""" + + super().__init__( + coordinator, + location, + device, + f"{device.macID}_setpoint_status", + "Setpoint Status", + "mdi:thermostat", + None, + ) + + @property + def state(self) -> str: + """Return the state of the sensor.""" + device = self.device + if device.changeableValues.thermostatSetpointStatus == PRESET_HOLD_UNTIL: + return f"Held until {device.changeableValues.nextPeriodTime}" + return LYRIC_SETPOINT_STATUS_NAMES.get( + device.changeableValues.thermostatSetpointStatus, "Unknown" + )