Modernize/Simplify Twente Milieu (#59632)
parent
aa89c670eb
commit
28a0ba4df3
|
@ -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
|
||||
|
|
|
@ -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.*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
11
mypy.ini
11
mypy.ini
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue