mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
Modernize/Simplify Twente Milieu (#59632)
This commit is contained in:
parent
aa89c670eb
commit
28a0ba4df3
@ -1140,6 +1140,7 @@ omit =
|
|||||||
homeassistant/components/tuya/switch.py
|
homeassistant/components/tuya/switch.py
|
||||||
homeassistant/components/tuya/util.py
|
homeassistant/components/tuya/util.py
|
||||||
homeassistant/components/tuya/vacuum.py
|
homeassistant/components/tuya/vacuum.py
|
||||||
|
homeassistant/components/twentemilieu/__init__.py
|
||||||
homeassistant/components/twentemilieu/const.py
|
homeassistant/components/twentemilieu/const.py
|
||||||
homeassistant/components/twentemilieu/sensor.py
|
homeassistant/components/twentemilieu/sensor.py
|
||||||
homeassistant/components/twilio_call/notify.py
|
homeassistant/components/twilio_call/notify.py
|
||||||
|
@ -133,6 +133,7 @@ homeassistant.components.tplink.*
|
|||||||
homeassistant.components.tractive.*
|
homeassistant.components.tractive.*
|
||||||
homeassistant.components.tradfri.*
|
homeassistant.components.tradfri.*
|
||||||
homeassistant.components.tts.*
|
homeassistant.components.tts.*
|
||||||
|
homeassistant.components.twentemilieu.*
|
||||||
homeassistant.components.upcloud.*
|
homeassistant.components.upcloud.*
|
||||||
homeassistant.components.uptime.*
|
homeassistant.components.uptime.*
|
||||||
homeassistant.components.uptimerobot.*
|
homeassistant.components.uptimerobot.*
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
"""Support for Twente Milieu."""
|
"""Support for Twente Milieu."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
from datetime import date, timedelta
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
from twentemilieu import TwenteMilieu
|
from twentemilieu import TwenteMilieu, WasteType
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -12,17 +11,9 @@ from homeassistant.const import CONF_ID
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
|
||||||
from homeassistant.helpers.typing import ConfigType
|
|
||||||
|
|
||||||
from .const import (
|
from .const import CONF_HOUSE_LETTER, CONF_HOUSE_NUMBER, CONF_POST_CODE, DOMAIN, LOGGER
|
||||||
CONF_HOUSE_LETTER,
|
|
||||||
CONF_HOUSE_NUMBER,
|
|
||||||
CONF_POST_CODE,
|
|
||||||
DATA_UPDATE,
|
|
||||||
DOMAIN,
|
|
||||||
)
|
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(seconds=3600)
|
SCAN_INTERVAL = timedelta(seconds=3600)
|
||||||
|
|
||||||
@ -32,35 +23,6 @@ SERVICE_SCHEMA = vol.Schema({vol.Optional(CONF_ID): cv.string})
|
|||||||
PLATFORMS = ["sensor"]
|
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:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up Twente Milieu from a config entry."""
|
"""Set up Twente Milieu from a config entry."""
|
||||||
session = async_get_clientsession(hass)
|
session = async_get_clientsession(hass)
|
||||||
@ -71,24 +33,30 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
|
|
||||||
unique_id = entry.data[CONF_ID]
|
coordinator: DataUpdateCoordinator[
|
||||||
hass.data.setdefault(DOMAIN, {})[unique_id] = twentemilieu
|
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)
|
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
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Unload Twente Milieu config entry."""
|
"""Unload Twente Milieu config entry."""
|
||||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
if unload_ok:
|
||||||
del hass.data[DOMAIN][entry.data[CONF_ID]]
|
del hass.data[DOMAIN][entry.entry_id]
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
@ -66,7 +66,8 @@ class TwenteMilieuFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
errors["base"] = "invalid_address"
|
errors["base"] = "invalid_address"
|
||||||
return await self._show_setup_form(errors)
|
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(
|
return self.async_create_entry(
|
||||||
title=str(unique_id),
|
title=str(unique_id),
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
"""Constants for the Twente Milieu integration."""
|
"""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_POST_CODE = "post_code"
|
||||||
CONF_HOUSE_NUMBER = "house_number"
|
CONF_HOUSE_NUMBER = "house_number"
|
||||||
|
@ -2,21 +2,23 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
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.components.sensor import SensorEntity, SensorEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_ID, DEVICE_CLASS_DATE
|
from homeassistant.const import CONF_ID, DEVICE_CLASS_DATE
|
||||||
from homeassistant.core import HomeAssistant
|
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 import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
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
|
from .const import DOMAIN
|
||||||
|
|
||||||
PARALLEL_UPDATES = 1
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -71,55 +73,38 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up Twente Milieu sensor based on a config entry."""
|
"""Set up Twente Milieu sensor based on a config entry."""
|
||||||
twentemilieu = hass.data[DOMAIN][entry.data[CONF_ID]]
|
coordinator = hass.data[DOMAIN][entry.data[CONF_ID]]
|
||||||
|
|
||||||
try:
|
|
||||||
await twentemilieu.update()
|
|
||||||
except TwenteMilieuConnectionError as exception:
|
|
||||||
raise PlatformNotReady from exception
|
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
TwenteMilieuSensor(coordinator, description, entry) for description in SENSORS
|
||||||
TwenteMilieuSensor(twentemilieu, entry.data[CONF_ID], description)
|
|
||||||
for description in SENSORS
|
|
||||||
],
|
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TwenteMilieuSensor(SensorEntity):
|
class TwenteMilieuSensor(CoordinatorEntity, SensorEntity):
|
||||||
"""Defines a Twente Milieu sensor."""
|
"""Defines a Twente Milieu sensor."""
|
||||||
|
|
||||||
entity_description: TwenteMilieuSensorDescription
|
entity_description: TwenteMilieuSensorDescription
|
||||||
_attr_should_poll = False
|
coordinator: DataUpdateCoordinator[dict[WasteType, date | None]]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
twentemilieu: TwenteMilieu,
|
coordinator: DataUpdateCoordinator,
|
||||||
unique_id: str,
|
|
||||||
description: TwenteMilieuSensorDescription,
|
description: TwenteMilieuSensorDescription,
|
||||||
|
entry: ConfigEntry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the Twente Milieu entity."""
|
"""Initialize the Twente Milieu entity."""
|
||||||
|
super().__init__(coordinator=coordinator)
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._twentemilieu = twentemilieu
|
self._attr_unique_id = f"{DOMAIN}_{entry.data[CONF_ID]}_{description.key}"
|
||||||
self._attr_unique_id = f"{DOMAIN}_{unique_id}_{description.key}"
|
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
identifiers={(DOMAIN, unique_id)},
|
configuration_url="https://www.twentemilieu.nl",
|
||||||
|
identifiers={(DOMAIN, entry.data[CONF_ID])},
|
||||||
manufacturer="Twente Milieu",
|
manufacturer="Twente Milieu",
|
||||||
name="Twente Milieu",
|
name="Twente Milieu",
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
@property
|
||||||
"""Connect to dispatcher listening for entity data notifications."""
|
def native_value(self) -> StateType:
|
||||||
self.async_on_remove(
|
"""Return the state of the sensor."""
|
||||||
async_dispatcher_connect(
|
if pickup := self.coordinator.data.get(self.entity_description.waste_type):
|
||||||
self.hass, DATA_UPDATE, self.async_schedule_update_ha_state
|
return pickup.isoformat()
|
||||||
)
|
return None
|
||||||
)
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
@ -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_return_any = true
|
||||||
warn_unreachable = 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.*]
|
[mypy-homeassistant.components.upcloud.*]
|
||||||
check_untyped_defs = true
|
check_untyped_defs = true
|
||||||
disallow_incomplete_defs = true
|
disallow_incomplete_defs = true
|
||||||
|
@ -74,7 +74,10 @@ async def test_address_already_set_up(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test we abort if address has already been set up."""
|
"""Test we abort if address has already been set up."""
|
||||||
MockConfigEntry(
|
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)
|
).add_to_hass(hass)
|
||||||
|
|
||||||
aioclient_mock.post(
|
aioclient_mock.post(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user