From 9607864c295f260989cc052427a144f2e567ad60 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Tue, 27 Jul 2021 19:10:38 +0200 Subject: [PATCH] Bump `gios` library to version 2.0 (#53557) * Bump gios library * Fix pylint error --- homeassistant/components/gios/config_flow.py | 1 + homeassistant/components/gios/const.py | 2 +- homeassistant/components/gios/manifest.json | 2 +- homeassistant/components/gios/sensor.py | 56 ++++++++++++++------ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/gios/test_sensor.py | 36 +++++++++++-- 7 files changed, 77 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/gios/config_flow.py b/homeassistant/components/gios/config_flow.py index d2bd3968d10..ff3f33408a5 100644 --- a/homeassistant/components/gios/config_flow.py +++ b/homeassistant/components/gios/config_flow.py @@ -41,6 +41,7 @@ class GiosFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): gios = Gios(user_input[CONF_STATION_ID], websession) await gios.async_update() + assert gios.station_name is not None return self.async_create_entry( title=gios.station_name, data=user_input, diff --git a/homeassistant/components/gios/const.py b/homeassistant/components/gios/const.py index f78e876a0e7..834735c6189 100644 --- a/homeassistant/components/gios/const.py +++ b/homeassistant/components/gios/const.py @@ -31,7 +31,7 @@ ATTR_CO: Final = "co" ATTR_NO2: Final = "no2" ATTR_O3: Final = "o3" ATTR_PM10: Final = "pm10" -ATTR_PM25: Final = "pm2.5" +ATTR_PM25: Final = "pm25" ATTR_SO2: Final = "so2" ATTR_AQI: Final = "aqi" diff --git a/homeassistant/components/gios/manifest.json b/homeassistant/components/gios/manifest.json index f13da0e3f33..3e7bf9aceca 100644 --- a/homeassistant/components/gios/manifest.json +++ b/homeassistant/components/gios/manifest.json @@ -3,7 +3,7 @@ "name": "GIO\u015a", "documentation": "https://www.home-assistant.io/integrations/gios", "codeowners": ["@bieniu"], - "requirements": ["gios==1.0.2"], + "requirements": ["gios==2.0.0"], "config_flow": true, "quality_scale": "platinum", "iot_class": "cloud_polling" diff --git a/homeassistant/components/gios/sensor.py b/homeassistant/components/gios/sensor.py index b9c1290dc00..4ab7facec9f 100644 --- a/homeassistant/components/gios/sensor.py +++ b/homeassistant/components/gios/sensor.py @@ -1,13 +1,19 @@ """Support for the GIOS service.""" from __future__ import annotations +import logging from typing import Any, cast -from homeassistant.components.sensor import ATTR_STATE_CLASS, SensorEntity +from homeassistant.components.sensor import ( + ATTR_STATE_CLASS, + DOMAIN as PLATFORM, + SensorEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_ATTRIBUTION, ATTR_NAME, CONF_NAME from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.entity_registry import async_get_registry from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -15,6 +21,7 @@ from . import GiosDataUpdateCoordinator from .const import ( ATTR_AQI, ATTR_INDEX, + ATTR_PM25, ATTR_STATION, ATTR_UNIT, ATTR_VALUE, @@ -25,6 +32,8 @@ from .const import ( SENSOR_TYPES, ) +_LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback @@ -34,10 +43,26 @@ async def async_setup_entry( coordinator = hass.data[DOMAIN][entry.entry_id] + # Due to the change of the attribute name of one sensor, it is necessary to migrate + # the unique_id to the new name. + entity_registry = await async_get_registry(hass) + old_unique_id = f"{coordinator.gios.station_id}-pm2.5" + if entity_id := entity_registry.async_get_entity_id( + PLATFORM, DOMAIN, old_unique_id + ): + new_unique_id = f"{coordinator.gios.station_id}-{ATTR_PM25}" + _LOGGER.debug( + "Migrating entity %s from old unique ID '%s' to new unique ID '%s'", + entity_id, + old_unique_id, + new_unique_id, + ) + entity_registry.async_update_entity(entity_id, new_unique_id=new_unique_id) + sensors: list[GiosSensor | GiosAqiSensor] = [] - for sensor, sensor_data in coordinator.data.items(): - if sensor not in SENSOR_TYPES or not sensor_data.get(ATTR_VALUE): + for sensor in SENSOR_TYPES: + if getattr(coordinator.data, sensor) is None: continue if sensor == ATTR_AQI: sensors.append(GiosAqiSensor(name, sensor, coordinator)) @@ -64,12 +89,14 @@ class GiosSensor(CoordinatorEntity, SensorEntity): "entry_type": "service", } self._attr_icon = "mdi:blur" - self._attr_name = f"{name} {sensor_type.upper()}" + if sensor_type == ATTR_PM25: + self._attr_name = f"{name} PM2.5" + else: + self._attr_name = f"{name} {sensor_type.upper()}" self._attr_state_class = self._description.get(ATTR_STATE_CLASS) self._attr_unique_id = f"{coordinator.gios.station_id}-{sensor_type}" self._attr_unit_of_measurement = self._description.get(ATTR_UNIT) self._sensor_type = sensor_type - self._state = None self._attrs: dict[str, Any] = { ATTR_ATTRIBUTION: ATTRIBUTION, ATTR_STATION: self.coordinator.gios.station_name, @@ -78,18 +105,17 @@ class GiosSensor(CoordinatorEntity, SensorEntity): @property def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" - if self.coordinator.data[self._sensor_type].get(ATTR_INDEX): - self._attrs[ATTR_NAME] = self.coordinator.data[self._sensor_type][ATTR_NAME] - self._attrs[ATTR_INDEX] = self.coordinator.data[self._sensor_type][ - ATTR_INDEX - ] + self._attrs[ATTR_NAME] = getattr(self.coordinator.data, self._sensor_type).name + self._attrs[ATTR_INDEX] = getattr( + self.coordinator.data, self._sensor_type + ).index return self._attrs @property def state(self) -> StateType: """Return the state.""" - self._state = self.coordinator.data[self._sensor_type][ATTR_VALUE] - return cast(StateType, self._description[ATTR_VALUE](self._state)) + state = getattr(self.coordinator.data, self._sensor_type).value + return cast(StateType, self._description[ATTR_VALUE](state)) class GiosAqiSensor(GiosSensor): @@ -98,12 +124,10 @@ class GiosAqiSensor(GiosSensor): @property def state(self) -> StateType: """Return the state.""" - return cast(StateType, self.coordinator.data[self._sensor_type][ATTR_VALUE]) + return cast(StateType, getattr(self.coordinator.data, self._sensor_type).value) @property def available(self) -> bool: """Return if entity is available.""" available = super().available - return available and bool( - self.coordinator.data[self._sensor_type].get(ATTR_VALUE) - ) + return available and bool(getattr(self.coordinator.data, self._sensor_type)) diff --git a/requirements_all.txt b/requirements_all.txt index 97cb5be27e4..38d7bd57c7c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -683,7 +683,7 @@ georss_qld_bushfire_alert_client==0.5 getmac==0.8.2 # homeassistant.components.gios -gios==1.0.2 +gios==2.0.0 # homeassistant.components.gitter gitterpy==0.1.7 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 26123a6a672..36de2c46daf 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -392,7 +392,7 @@ georss_qld_bushfire_alert_client==0.5 getmac==0.8.2 # homeassistant.components.gios -gios==1.0.2 +gios==2.0.0 # homeassistant.components.glances glances_api==0.2.0 diff --git a/tests/components/gios/test_sensor.py b/tests/components/gios/test_sensor.py index 8ce192b7e9c..2da3d8e1e8c 100644 --- a/tests/components/gios/test_sensor.py +++ b/tests/components/gios/test_sensor.py @@ -5,8 +5,17 @@ from unittest.mock import patch from gios import ApiError -from homeassistant.components.gios.const import ATTR_INDEX, ATTR_STATION, ATTRIBUTION -from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT +from homeassistant.components.gios.const import ( + ATTR_INDEX, + ATTR_STATION, + ATTRIBUTION, + DOMAIN, +) +from homeassistant.components.sensor import ( + ATTR_STATE_CLASS, + DOMAIN as PLATFORM, + STATE_CLASS_MEASUREMENT, +) from homeassistant.const import ( ATTR_ATTRIBUTION, ATTR_ICON, @@ -126,7 +135,7 @@ async def test_sensor(hass): entry = registry.async_get("sensor.home_pm2_5") assert entry - assert entry.unique_id == "123-pm2.5" + assert entry.unique_id == "123-pm25" state = hass.states.get("sensor.home_so2") assert state @@ -306,7 +315,7 @@ async def test_invalid_indexes(hass): entry = registry.async_get("sensor.home_pm2_5") assert entry - assert entry.unique_id == "123-pm2.5" + assert entry.unique_id == "123-pm25" state = hass.states.get("sensor.home_so2") assert state @@ -352,3 +361,22 @@ async def test_aqi_sensor_availability(hass): state = hass.states.get("sensor.home_aqi") assert state assert state.state == STATE_UNAVAILABLE + + +async def test_unique_id_migration(hass): + """Test states of the unique_id migration.""" + registry = er.async_get(hass) + + registry.async_get_or_create( + PLATFORM, + DOMAIN, + "123-pm2.5", + suggested_object_id="home_pm2_5", + disabled_by=None, + ) + + await init_integration(hass) + + entry = registry.async_get("sensor.home_pm2_5") + assert entry + assert entry.unique_id == "123-pm25"