Add sensor platform to Modern Forms integration (#52249)

* Add sensor platform to Modern Forms integration

* Changes to sensors to timestamp class

* lint cleanup
This commit is contained in:
Brian Towles 2021-06-29 03:05:39 -05:00 committed by GitHub
parent 6a528acafe
commit 3ab42c50c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 206 additions and 0 deletions

View File

@ -13,6 +13,7 @@ from aiomodernforms.models import Device as ModernFormsDeviceState
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_MODEL, ATTR_NAME, ATTR_SW_VERSION, CONF_HOST
@ -31,6 +32,7 @@ SCAN_INTERVAL = timedelta(seconds=5)
PLATFORMS = [
LIGHT_DOMAIN,
FAN_DOMAIN,
SENSOR_DOMAIN,
SWITCH_DOMAIN,
]
_LOGGER = logging.getLogger(__name__)

View File

@ -0,0 +1,118 @@
"""Support for Modern Forms switches."""
from __future__ import annotations
from datetime import datetime
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import DEVICE_CLASS_TIMESTAMP
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util import dt as dt_util
from . import ModernFormsDataUpdateCoordinator, ModernFormsDeviceEntity
from .const import CLEAR_TIMER, DOMAIN
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Modern Forms sensor based on a config entry."""
coordinator: ModernFormsDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
sensors: list[ModernFormsSensor] = [
ModernFormsFanTimerRemainingTimeSensor(entry.entry_id, coordinator),
]
# Only setup light sleep timer sensor if light unit installed
if coordinator.data.info.light_type:
sensors.append(
ModernFormsLightTimerRemainingTimeSensor(entry.entry_id, coordinator)
)
async_add_entities(sensors)
class ModernFormsSensor(ModernFormsDeviceEntity, SensorEntity):
"""Defines a Modern Forms binary sensor."""
def __init__(
self,
*,
entry_id: str,
coordinator: ModernFormsDataUpdateCoordinator,
name: str,
icon: str,
key: str,
) -> None:
"""Initialize Modern Forms switch."""
self._key = key
super().__init__(
entry_id=entry_id, coordinator=coordinator, name=name, icon=icon
)
self._attr_unique_id = f"{self.coordinator.data.info.mac_address}_{self._key}"
class ModernFormsLightTimerRemainingTimeSensor(ModernFormsSensor):
"""Defines the Modern Forms Light Timer remaining time sensor."""
def __init__(
self, entry_id: str, coordinator: ModernFormsDataUpdateCoordinator
) -> None:
"""Initialize Modern Forms Away mode switch."""
super().__init__(
coordinator=coordinator,
entry_id=entry_id,
icon="mdi:timer-outline",
key="light_timer_remaining_time",
name=f"{coordinator.data.info.device_name} Light Sleep Time",
)
self._attr_device_class = DEVICE_CLASS_TIMESTAMP
@property
def state(self) -> StateType:
"""Return the state of the sensor."""
sleep_time: datetime = dt_util.utc_from_timestamp(
self.coordinator.data.state.light_sleep_timer
)
if (
self.coordinator.data.state.light_sleep_timer == CLEAR_TIMER
or (sleep_time - dt_util.utcnow()).total_seconds() < 0
):
return None
return sleep_time.isoformat()
class ModernFormsFanTimerRemainingTimeSensor(ModernFormsSensor):
"""Defines the Modern Forms Light Timer remaining time sensor."""
def __init__(
self, entry_id: str, coordinator: ModernFormsDataUpdateCoordinator
) -> None:
"""Initialize Modern Forms Away mode switch."""
super().__init__(
coordinator=coordinator,
entry_id=entry_id,
icon="mdi:timer-outline",
key="fan_timer_remaining_time",
name=f"{coordinator.data.info.device_name} Fan Sleep Time",
)
self._attr_device_class = DEVICE_CLASS_TIMESTAMP
@property
def state(self) -> StateType:
"""Return the state of the sensor."""
sleep_time: datetime = dt_util.utc_from_timestamp(
self.coordinator.data.state.fan_sleep_timer
)
if (
self.coordinator.data.state.fan_sleep_timer == CLEAR_TIMER
or (sleep_time - dt_util.utcnow()).total_seconds() < 0
):
return None
return sleep_time.isoformat()

View File

@ -37,6 +37,18 @@ async def modern_forms_no_light_call_mock(method, url, data):
return response
async def modern_forms_timers_set_mock(method, url, data):
"""Set up the basic returns based on info or status request."""
if COMMAND_QUERY_STATIC_DATA in data:
fixture = "modern_forms/device_info.json"
else:
fixture = "modern_forms/device_status_timers_active.json"
response = AiohttpClientMockResponse(
method=method, url=url, json=json.loads(load_fixture(fixture))
)
return response
async def init_integration(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,

View File

@ -0,0 +1,57 @@
"""Tests for the Modern Forms sensor platform."""
from datetime import datetime
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_ICON, DEVICE_CLASS_TIMESTAMP
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.components.modern_forms import init_integration, modern_forms_timers_set_mock
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_sensors(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the creation and values of the Modern Forms sensors."""
# await init_integration(hass, aioclient_mock)
await init_integration(hass, aioclient_mock)
er.async_get(hass)
# Light timer remaining time
state = hass.states.get("sensor.modernformsfan_light_sleep_time")
assert state
assert state.attributes.get(ATTR_ICON) == "mdi:timer-outline"
assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP
assert state.state == "unknown"
# Fan timer remaining time
state = hass.states.get("sensor.modernformsfan_fan_sleep_time")
assert state
assert state.attributes.get(ATTR_ICON) == "mdi:timer-outline"
assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP
assert state.state == "unknown"
async def test_active_sensors(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the creation and values of the Modern Forms sensors."""
# await init_integration(hass, aioclient_mock)
await init_integration(hass, aioclient_mock, mock_type=modern_forms_timers_set_mock)
er.async_get(hass)
# Light timer remaining time
state = hass.states.get("sensor.modernformsfan_light_sleep_time")
assert state
assert state.attributes.get(ATTR_ICON) == "mdi:timer-outline"
assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP
datetime.fromisoformat(state.state)
# Fan timer remaining time
state = hass.states.get("sensor.modernformsfan_fan_sleep_time")
assert state
assert state.attributes.get(ATTR_ICON) == "mdi:timer-outline"
assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TIMESTAMP
datetime.fromisoformat(state.state)

View File

@ -0,0 +1,17 @@
{
"adaptiveLearning": false,
"awayModeEnabled": false,
"clientId": "MF_000000000000",
"decommission": false,
"factoryReset": false,
"fanDirection": "forward",
"fanOn": true,
"fanSleepTimer": 9999999999,
"fanSpeed": 3,
"lightBrightness": 50,
"lightOn": true,
"lightSleepTimer": 9999999999,
"resetRfPairList": false,
"rfPairModeActive": false,
"schedule": ""
}