Add coordinator and number platform to LaMetric (#76766)

This commit is contained in:
Franck Nijhof 2022-08-20 19:06:35 +02:00 committed by GitHub
parent 9ac01b8c9b
commit 49957c752b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 25 deletions

View File

@ -640,7 +640,10 @@ omit =
homeassistant/components/kwb/sensor.py homeassistant/components/kwb/sensor.py
homeassistant/components/lacrosse/sensor.py homeassistant/components/lacrosse/sensor.py
homeassistant/components/lametric/__init__.py homeassistant/components/lametric/__init__.py
homeassistant/components/lametric/coordinator.py
homeassistant/components/lametric/entity.py
homeassistant/components/lametric/notify.py homeassistant/components/lametric/notify.py
homeassistant/components/lametric/number.py
homeassistant/components/lannouncer/notify.py homeassistant/components/lannouncer/notify.py
homeassistant/components/lastfm/sensor.py homeassistant/components/lastfm/sensor.py
homeassistant/components/launch_library/__init__.py homeassistant/components/launch_library/__init__.py

View File

@ -1,25 +1,17 @@
"""Support for LaMetric time.""" """Support for LaMetric time."""
from demetriek import LaMetricConnectionError, LaMetricDevice
import voluptuous as vol import voluptuous as vol
from homeassistant.components import notify as hass_notify
from homeassistant.components.repairs import IssueSeverity, async_create_issue from homeassistant.components.repairs import IssueSeverity, async_create_issue
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_NAME, Platform
CONF_API_KEY,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
CONF_HOST,
CONF_NAME,
Platform,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN from .const import DOMAIN, PLATFORMS
from .coordinator import LaMetricDataUpdateCoordinator
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
vol.All( vol.All(
@ -56,18 +48,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up LaMetric from a config entry.""" """Set up LaMetric from a config entry."""
lametric = LaMetricDevice( coordinator = LaMetricDataUpdateCoordinator(hass, entry)
host=entry.data[CONF_HOST], await coordinator.async_config_entry_first_refresh()
api_key=entry.data[CONF_API_KEY],
session=async_get_clientsession(hass),
)
try: hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
device = await lametric.device() await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
except LaMetricConnectionError as ex:
raise ConfigEntryNotReady("Cannot connect to LaMetric device") from ex
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = lametric
# Set up notify platform, no entry support for notify component yet, # Set up notify platform, no entry support for notify component yet,
# have to use discovery to load platform. # have to use discovery to load platform.
@ -76,8 +61,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass, hass,
Platform.NOTIFY, Platform.NOTIFY,
DOMAIN, DOMAIN,
{CONF_NAME: device.name, "entry_id": entry.entry_id}, {CONF_NAME: coordinator.data.name, "entry_id": entry.entry_id},
hass.data[DOMAIN]["hass_config"], hass.data[DOMAIN]["hass_config"],
) )
) )
return True return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload LaMetric config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
del hass.data[DOMAIN][entry.entry_id]
await hass_notify.async_reload(hass, DOMAIN)
return unload_ok

View File

@ -1,11 +1,16 @@
"""Constants for the LaMetric integration.""" """Constants for the LaMetric integration."""
from datetime import timedelta
import logging import logging
from typing import Final from typing import Final
from homeassistant.const import Platform
DOMAIN: Final = "lametric" DOMAIN: Final = "lametric"
PLATFORMS = [Platform.NUMBER]
LOGGER = logging.getLogger(__package__) LOGGER = logging.getLogger(__package__)
SCAN_INTERVAL = timedelta(seconds=30)
CONF_CYCLES: Final = "cycles" CONF_CYCLES: Final = "cycles"
CONF_ICON_TYPE: Final = "icon_type" CONF_ICON_TYPE: Final = "icon_type"

View File

@ -0,0 +1,38 @@
"""DataUpdateCoordinator for the LaMatric integration."""
from __future__ import annotations
from demetriek import Device, LaMetricDevice, LaMetricError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_HOST
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, LOGGER, SCAN_INTERVAL
class LaMetricDataUpdateCoordinator(DataUpdateCoordinator[Device]):
"""The LaMetric Data Update Coordinator."""
config_entry: ConfigEntry
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Initialize the LaMatric coordinator."""
self.config_entry = entry
self.lametric = LaMetricDevice(
host=entry.data[CONF_HOST],
api_key=entry.data[CONF_API_KEY],
session=async_get_clientsession(hass),
)
super().__init__(hass, LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
async def _async_update_data(self) -> Device:
"""Fetch device information of the LaMetric device."""
try:
return await self.lametric.device()
except LaMetricError as ex:
raise UpdateFailed(
"Could not fetch device information from LaMetric device"
) from ex

View File

@ -0,0 +1,29 @@
"""Base entity for the LaMetric integration."""
from __future__ import annotations
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, format_mac
from homeassistant.helpers.entity import DeviceInfo, Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import LaMetricDataUpdateCoordinator
class LaMetricEntity(CoordinatorEntity[LaMetricDataUpdateCoordinator], Entity):
"""Defines a LaMetric entity."""
_attr_has_entity_name = True
def __init__(self, coordinator: LaMetricDataUpdateCoordinator) -> None:
"""Initialize the LaMetric entity."""
super().__init__(coordinator=coordinator)
self._attr_device_info = DeviceInfo(
connections={
(CONNECTION_NETWORK_MAC, format_mac(coordinator.data.wifi.mac))
},
identifiers={(DOMAIN, coordinator.data.serial_number)},
manufacturer="LaMetric Inc.",
model=coordinator.data.model,
name=coordinator.data.name,
sw_version=coordinator.data.os_version,
)

View File

@ -4,7 +4,7 @@
"documentation": "https://www.home-assistant.io/integrations/lametric", "documentation": "https://www.home-assistant.io/integrations/lametric",
"requirements": ["demetriek==0.2.2"], "requirements": ["demetriek==0.2.2"],
"codeowners": ["@robbiet480", "@frenck"], "codeowners": ["@robbiet480", "@frenck"],
"iot_class": "local_push", "iot_class": "local_polling",
"dependencies": ["application_credentials", "repairs"], "dependencies": ["application_credentials", "repairs"],
"loggers": ["demetriek"], "loggers": ["demetriek"],
"config_flow": true, "config_flow": true,

View File

@ -0,0 +1,90 @@
"""Support for LaMetric numbers."""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import Any
from demetriek import Device, LaMetricDevice
from homeassistant.components.number import NumberEntity, NumberEntityDescription
from homeassistant.config_entries import ConfigEntry
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]
set_value_fn: Callable[[LaMetricDevice, float], Awaitable[Any]]
@dataclass
class LaMetricNumberEntityDescription(
NumberEntityDescription, LaMetricEntityDescriptionMixin
):
"""Class describing LaMetric number entities."""
NUMBERS = [
LaMetricNumberEntityDescription(
key="volume",
name="Volume",
icon="mdi:volume-high",
entity_category=EntityCategory.CONFIG,
native_step=1,
native_min_value=0,
native_max_value=100,
value_fn=lambda device: device.audio.volume,
set_value_fn=lambda api, volume: api.audio(volume=int(volume)),
),
]
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up LaMetric number based on a config entry."""
coordinator: LaMetricDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
LaMetricNumberEntity(
coordinator=coordinator,
description=description,
)
for description in NUMBERS
)
class LaMetricNumberEntity(LaMetricEntity, NumberEntity):
"""Representation of a LaMetric number."""
entity_description: LaMetricNumberEntityDescription
def __init__(
self,
coordinator: LaMetricDataUpdateCoordinator,
description: LaMetricNumberEntityDescription,
) -> None:
"""Initiate LaMetric Number."""
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 number value."""
return self.entity_description.value_fn(self.coordinator.data)
async def async_set_native_value(self, value: float) -> None:
"""Change to new number value."""
await self.entity_description.set_value_fn(self.coordinator.lametric, value)
await self.coordinator.async_request_refresh()