Modernize/Simplify Twente Milieu (#59632)

This commit is contained in:
Franck Nijhof 2021-11-13 15:34:09 +01:00 committed by GitHub
parent aa89c670eb
commit 28a0ba4df3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 107 deletions

View File

@ -1140,6 +1140,7 @@ omit =
homeassistant/components/tuya/switch.py
homeassistant/components/tuya/util.py
homeassistant/components/tuya/vacuum.py
homeassistant/components/twentemilieu/__init__.py
homeassistant/components/twentemilieu/const.py
homeassistant/components/twentemilieu/sensor.py
homeassistant/components/twilio_call/notify.py

View File

@ -133,6 +133,7 @@ homeassistant.components.tplink.*
homeassistant.components.tractive.*
homeassistant.components.tradfri.*
homeassistant.components.tts.*
homeassistant.components.twentemilieu.*
homeassistant.components.upcloud.*
homeassistant.components.uptime.*
homeassistant.components.uptimerobot.*

View File

@ -1,10 +1,9 @@
"""Support for Twente Milieu."""
from __future__ import annotations
import asyncio
from datetime import timedelta
from datetime import date, timedelta
from twentemilieu import TwenteMilieu
from twentemilieu import TwenteMilieu, WasteType
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
@ -12,17 +11,9 @@ from homeassistant.const import CONF_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
CONF_HOUSE_LETTER,
CONF_HOUSE_NUMBER,
CONF_POST_CODE,
DATA_UPDATE,
DOMAIN,
)
from .const import CONF_HOUSE_LETTER, CONF_HOUSE_NUMBER, CONF_POST_CODE, DOMAIN, LOGGER
SCAN_INTERVAL = timedelta(seconds=3600)
@ -32,35 +23,6 @@ SERVICE_SCHEMA = vol.Schema({vol.Optional(CONF_ID): cv.string})
PLATFORMS = ["sensor"]
async def _update_twentemilieu(hass: HomeAssistant, unique_id: str | None) -> None:
"""Update Twente Milieu."""
if unique_id is not None:
twentemilieu = hass.data[DOMAIN].get(unique_id)
if twentemilieu is not None:
await twentemilieu.update()
async_dispatcher_send(hass, DATA_UPDATE, unique_id)
else:
await asyncio.wait(
[twentemilieu.update() for twentemilieu in hass.data[DOMAIN].values()]
)
for uid in hass.data[DOMAIN]:
async_dispatcher_send(hass, DATA_UPDATE, uid)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Twente Milieu components."""
async def update(call) -> None:
"""Service call to manually update the data."""
unique_id = call.data.get(CONF_ID)
await _update_twentemilieu(hass, unique_id)
hass.services.async_register(DOMAIN, SERVICE_UPDATE, update, schema=SERVICE_SCHEMA)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Twente Milieu from a config entry."""
session = async_get_clientsession(hass)
@ -71,24 +33,30 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
session=session,
)
unique_id = entry.data[CONF_ID]
hass.data.setdefault(DOMAIN, {})[unique_id] = twentemilieu
coordinator: DataUpdateCoordinator[
dict[WasteType, date | None]
] = DataUpdateCoordinator(
hass,
LOGGER,
name=DOMAIN,
update_interval=SCAN_INTERVAL,
update_method=twentemilieu.update,
)
await coordinator.async_config_entry_first_refresh()
# For backwards compat, set unique ID
if entry.unique_id is None:
hass.config_entries.async_update_entry(entry, unique_id=entry.data[CONF_ID])
hass.data.setdefault(DOMAIN, {})[entry.data[CONF_ID]] = coordinator
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
async def _interval_update(now=None) -> None:
"""Update Twente Milieu data."""
await _update_twentemilieu(hass, unique_id)
async_track_time_interval(hass, _interval_update, SCAN_INTERVAL)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload Twente Milieu config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
del hass.data[DOMAIN][entry.data[CONF_ID]]
if unload_ok:
del hass.data[DOMAIN][entry.entry_id]
return unload_ok

View File

@ -66,7 +66,8 @@ class TwenteMilieuFlowHandler(ConfigFlow, domain=DOMAIN):
errors["base"] = "invalid_address"
return await self._show_setup_form(errors)
self._async_abort_entries_match({CONF_ID: unique_id})
await self.async_set_unique_id(str(unique_id))
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=str(unique_id),

View File

@ -1,8 +1,12 @@
"""Constants for the Twente Milieu integration."""
from datetime import timedelta
import logging
from typing import Final
DOMAIN = "twentemilieu"
DOMAIN: Final = "twentemilieu"
DATA_UPDATE = "twentemilieu_update"
LOGGER = logging.getLogger(__package__)
SCAN_INTERVAL = timedelta(hours=1)
CONF_POST_CODE = "post_code"
CONF_HOUSE_NUMBER = "house_number"

View File

@ -2,21 +2,23 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import date
from twentemilieu import TwenteMilieu, TwenteMilieuConnectionError, WasteType
from twentemilieu import WasteType
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID, DEVICE_CLASS_DATE
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from .const import DATA_UPDATE, DOMAIN
PARALLEL_UPDATES = 1
from .const import DOMAIN
@dataclass
@ -71,55 +73,38 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Twente Milieu sensor based on a config entry."""
twentemilieu = hass.data[DOMAIN][entry.data[CONF_ID]]
try:
await twentemilieu.update()
except TwenteMilieuConnectionError as exception:
raise PlatformNotReady from exception
coordinator = hass.data[DOMAIN][entry.data[CONF_ID]]
async_add_entities(
[
TwenteMilieuSensor(twentemilieu, entry.data[CONF_ID], description)
for description in SENSORS
],
True,
TwenteMilieuSensor(coordinator, description, entry) for description in SENSORS
)
class TwenteMilieuSensor(SensorEntity):
class TwenteMilieuSensor(CoordinatorEntity, SensorEntity):
"""Defines a Twente Milieu sensor."""
entity_description: TwenteMilieuSensorDescription
_attr_should_poll = False
coordinator: DataUpdateCoordinator[dict[WasteType, date | None]]
def __init__(
self,
twentemilieu: TwenteMilieu,
unique_id: str,
coordinator: DataUpdateCoordinator,
description: TwenteMilieuSensorDescription,
entry: ConfigEntry,
) -> None:
"""Initialize the Twente Milieu entity."""
super().__init__(coordinator=coordinator)
self.entity_description = description
self._twentemilieu = twentemilieu
self._attr_unique_id = f"{DOMAIN}_{unique_id}_{description.key}"
self._attr_unique_id = f"{DOMAIN}_{entry.data[CONF_ID]}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, unique_id)},
configuration_url="https://www.twentemilieu.nl",
identifiers={(DOMAIN, entry.data[CONF_ID])},
manufacturer="Twente Milieu",
name="Twente Milieu",
)
async def async_added_to_hass(self) -> None:
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
async_dispatcher_connect(
self.hass, DATA_UPDATE, self.async_schedule_update_ha_state
)
)
async def async_update(self) -> None:
"""Update Twente Milieu entity."""
pickups = await self._twentemilieu.update()
self._attr_native_value = None
if pickup := pickups.get(self.entity_description.waste_type):
self._attr_native_value = pickup.isoformat()
@property
def native_value(self) -> StateType:
"""Return the state of the sensor."""
if pickup := self.coordinator.data.get(self.entity_description.waste_type):
return pickup.isoformat()
return None

View File

@ -1,11 +0,0 @@
update:
name: Update
description: Update all entities with fresh data from Twente Milieu
fields:
id:
name: ID
description: Specific unique address ID to update
advanced: true
example: 1300012345
selector:
text:

View File

@ -1474,6 +1474,17 @@ no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.twentemilieu.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.upcloud.*]
check_untyped_defs = true
disallow_incomplete_defs = true

View File

@ -74,7 +74,10 @@ async def test_address_already_set_up(
) -> None:
"""Test we abort if address has already been set up."""
MockConfigEntry(
domain=DOMAIN, data={**FIXTURE_USER_INPUT, CONF_ID: "12345"}, title="12345"
domain=DOMAIN,
data={**FIXTURE_USER_INPUT, CONF_ID: "12345"},
title="12345",
unique_id="12345",
).add_to_hass(hass)
aioclient_mock.post(