Move ReCollect Waste "next pickup" info to its own sensor (#62558)

This commit is contained in:
Aaron Bach 2022-01-06 08:05:48 -07:00 committed by GitHub
parent 1baa3d87d1
commit c341adb0d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 28 deletions

View File

@ -2,14 +2,15 @@
from __future__ import annotations from __future__ import annotations
from datetime import date, timedelta from datetime import date, timedelta
from typing import Any
from aiorecollect.client import Client, PickupEvent from aiorecollect.client import Client, PickupEvent
from aiorecollect.errors import RecollectError from aiorecollect.errors import RecollectError
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import aiohttp_client from homeassistant.helpers import aiohttp_client, entity_registry as er
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import CONF_PLACE_ID, CONF_SERVICE_ID, DOMAIN, LOGGER from .const import CONF_PLACE_ID, CONF_SERVICE_ID, DOMAIN, LOGGER
@ -69,3 +70,32 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN].pop(entry.entry_id) hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok return unload_ok
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Migrate an old config entry."""
version = entry.version
LOGGER.debug("Migrating from version %s", version)
# 1 -> 2: Update unique ID of existing, single sensor entity to be consistent with
# common format for platforms going forward:
if version == 1:
version = entry.version = 2
@callback
def migrate_unique_id(entity_entry: er.RegistryEntry) -> dict[str, Any]:
"""Migrate the unique ID to a new format."""
return {
"new_unique_id": (
f"{entry.data[CONF_PLACE_ID]}_"
f"{entry.data[CONF_SERVICE_ID]}_"
"current_pickup"
)
}
await er.async_migrate_entries(hass, entry.entry_id, migrate_unique_id)
LOGGER.info("Migration to version %s successful", version)
return True

View File

@ -23,7 +23,7 @@ DATA_SCHEMA = vol.Schema(
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for ReCollect Waste.""" """Handle a config flow for ReCollect Waste."""
VERSION = 1 VERSION = 2
@staticmethod @staticmethod
@callback @callback

View File

@ -3,7 +3,11 @@ from __future__ import annotations
from aiorecollect.client import PickupType from aiorecollect.client import PickupType
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_FRIENDLY_NAME from homeassistant.const import CONF_FRIENDLY_NAME
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
@ -13,14 +17,24 @@ from homeassistant.helpers.update_coordinator import (
DataUpdateCoordinator, DataUpdateCoordinator,
) )
from .const import CONF_PLACE_ID, CONF_SERVICE_ID, DOMAIN from .const import CONF_PLACE_ID, CONF_SERVICE_ID, DOMAIN, LOGGER
ATTR_PICKUP_TYPES = "pickup_types" ATTR_PICKUP_TYPES = "pickup_types"
ATTR_AREA_NAME = "area_name" ATTR_AREA_NAME = "area_name"
ATTR_NEXT_PICKUP_TYPES = "next_pickup_types"
ATTR_NEXT_PICKUP_DATE = "next_pickup_date"
DEFAULT_NAME = "Waste Pickup" SENSOR_TYPE_CURRENT_PICKUP = "current_pickup"
SENSOR_TYPE_NEXT_PICKUP = "next_pickup"
SENSOR_DESCRIPTIONS = (
SensorEntityDescription(
key=SENSOR_TYPE_CURRENT_PICKUP,
name="Current Pickup",
),
SensorEntityDescription(
key=SENSOR_TYPE_NEXT_PICKUP,
name="Next Pickup",
),
)
@callback @callback
@ -41,7 +55,13 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up ReCollect Waste sensors based on a config entry.""" """Set up ReCollect Waste sensors based on a config entry."""
coordinator = hass.data[DOMAIN][entry.entry_id] coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([ReCollectWasteSensor(coordinator, entry)])
async_add_entities(
[
ReCollectWasteSensor(coordinator, entry, description)
for description in SENSOR_DESCRIPTIONS
]
)
class ReCollectWasteSensor(CoordinatorEntity, SensorEntity): class ReCollectWasteSensor(CoordinatorEntity, SensorEntity):
@ -49,16 +69,19 @@ class ReCollectWasteSensor(CoordinatorEntity, SensorEntity):
_attr_device_class = SensorDeviceClass.DATE _attr_device_class = SensorDeviceClass.DATE
def __init__(self, coordinator: DataUpdateCoordinator, entry: ConfigEntry) -> None: def __init__(
self,
coordinator: DataUpdateCoordinator,
entry: ConfigEntry,
description: SensorEntityDescription,
) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__(coordinator) super().__init__(coordinator)
self._attr_extra_state_attributes = {} self._attr_extra_state_attributes = {}
self._attr_name = DEFAULT_NAME self._attr_unique_id = f"{entry.data[CONF_PLACE_ID]}_{entry.data[CONF_SERVICE_ID]}_{description.key}"
self._attr_unique_id = (
f"{entry.data[CONF_PLACE_ID]}{entry.data[CONF_SERVICE_ID]}"
)
self._entry = entry self._entry = entry
self.entity_description = description
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None:
@ -74,24 +97,25 @@ class ReCollectWasteSensor(CoordinatorEntity, SensorEntity):
@callback @callback
def update_from_latest_data(self) -> None: def update_from_latest_data(self) -> None:
"""Update the state.""" """Update the state."""
if self.entity_description.key == SENSOR_TYPE_CURRENT_PICKUP:
try: try:
pickup_event = self.coordinator.data[0] event = self.coordinator.data[0]
next_pickup_event = self.coordinator.data[1]
except IndexError: except IndexError:
self._attr_native_value = None LOGGER.error("No current pickup found")
self._attr_extra_state_attributes = {} return
else:
try:
event = self.coordinator.data[1]
except IndexError:
LOGGER.info("No next pickup found")
return return
self._attr_extra_state_attributes.update( self._attr_extra_state_attributes.update(
{ {
ATTR_PICKUP_TYPES: async_get_pickup_type_names( ATTR_PICKUP_TYPES: async_get_pickup_type_names(
self._entry, pickup_event.pickup_types self._entry, event.pickup_types
), ),
ATTR_AREA_NAME: pickup_event.area_name, ATTR_AREA_NAME: event.area_name,
ATTR_NEXT_PICKUP_TYPES: async_get_pickup_type_names(
self._entry, next_pickup_event.pickup_types
),
ATTR_NEXT_PICKUP_DATE: next_pickup_event.date.isoformat(),
} }
) )
self._attr_native_value = pickup_event.date self._attr_native_value = event.date