From 70bfd562689dac72aeb063289a100b5e22113e88 Mon Sep 17 00:00:00 2001 From: schizza Date: Wed, 17 Apr 2024 13:12:47 +0200 Subject: [PATCH] Ability to add newly discovered sensors. * Add discovered sensors to loading queue. * Notify users that we have new sensors and we need to restart Home Assistant --- custom_components/sws12500/__init__.py | 52 +++++++----- custom_components/sws12500/manifest.json | 2 +- custom_components/sws12500/property.py | 46 ----------- custom_components/sws12500/sensor.py | 25 +++--- custom_components/sws12500/strings.json | 6 ++ .../sws12500/translations/cs.json | 6 ++ .../sws12500/translations/en.json | 6 ++ custom_components/sws12500/utils.py | 80 ++++++++++++++++--- 8 files changed, 132 insertions(+), 91 deletions(-) delete mode 100644 custom_components/sws12500/property.py diff --git a/custom_components/sws12500/__init__.py b/custom_components/sws12500/__init__.py index ef89a2b..fa5d886 100644 --- a/custom_components/sws12500/__init__.py +++ b/custom_components/sws12500/__init__.py @@ -19,7 +19,15 @@ from .const import ( SENSORS_TO_LOAD, WINDY_ENABLED, ) -from .utils import anonymize, check_disabled, remap_items, update_options +from .utils import ( + anonymize, + check_disabled, + loaded_sensors, + remap_items, + translated_notification, + translations, + update_options, +) from .windy_func import WindyPush _LOGGER = logging.getLogger(__name__) @@ -65,10 +73,22 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator): remaped_items = remap_items(data) if sensors := check_disabled(self.hass, remaped_items, self.config): - await update_options( - self.hass, self.config_entry, SENSORS_TO_LOAD, sensors + translate_sensors = [ + await translations(self.hass, DOMAIN, f"sensor.{t_key}", key="name", category="entity") + for t_key in sensors + ] + human_readable = "\n".join(translate_sensors) + + await translated_notification( + self.hass, + DOMAIN, + "added", + {"added_sensors": f"{human_readable}\n"}, ) - # await self.hass.config_entries.async_reload(self.config.entry_id) + if _loaded_sensors := loaded_sensors(self.config_entry): + sensors.extend(_loaded_sensors) + await update_options(self.hass, self.config_entry, SENSORS_TO_LOAD, sensors) + await self.hass.config_entries.async_reload(self.config.entry_id) self.async_set_updated_data(remaped_items) @@ -131,11 +151,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return True -async def update_listener(hass: HomeAssistant, entry: ConfigEntry): - """Update setup listener.""" - await hass.config_entries.async_reload(entry.entry_id) - _LOGGER.info("Settings updated") +async def update_listener(hass: HomeAssistant, entry: ConfigEntry): + """Update setup listener.""" + # Disabled as on fire async_reload, integration stops writing data, + # and we don't need to reload config entry for proper work. + + # await hass.config_entries.async_reload(entry.entry_id) + + _LOGGER.info("Settings updated") async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @@ -147,15 +171,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: unregister_path(hass) return _ok - - -# async def async_setup(hass: HomeAssistant, entry: ConfigEntry) -> bool: -# """Set up the component. - -# This component can only be configured through the Integrations UI. -# """ -# hass.data.setdefault(DOMAIN, {}) - -# await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - -# return True diff --git a/custom_components/sws12500/manifest.json b/custom_components/sws12500/manifest.json index 5a21dd4..3cd2411 100644 --- a/custom_components/sws12500/manifest.json +++ b/custom_components/sws12500/manifest.json @@ -10,6 +10,6 @@ "iot_class": "local_push", "requirements": [], "ssdp": [], - "version": "0.1.2", + "version": "0.1.3", "zeroconf": [] } diff --git a/custom_components/sws12500/property.py b/custom_components/sws12500/property.py deleted file mode 100644 index eae6870..0000000 --- a/custom_components/sws12500/property.py +++ /dev/null @@ -1,46 +0,0 @@ - @property - def translation_key(self): - """Return translation key.""" - return self.entity_description.translation_key - - @property - def device_class(self): - """Return device class.""" - return self.entity_description.device_class - - @property - def name(self) -> str: - """Return the name of the switch.""" - return str(self.entity_description.name) - - @property - def unique_id(self) -> str: - """Return a unique, Home Assistant friendly identifier for this entity.""" - return self.entity_description.key - - @property - def native_value(self): - """Return value of entity.""" - return self._state - - @property - def icon(self) -> str: - """Return icon of entity.""" - return str(self.entity_description.icon) - - @property - def native_unit_of_measurement(self) -> str: - """Return unit of measurement.""" - return str(self.entity_description.native_unit_of_measurement) - - @property - def state_class(self) -> str: - """Return stateClass.""" - - return str(self.entity_description.state_class) - - @property - def suggested_unit_of_measurement(self) -> str: - """Return sugestet_unit_of_measurement.""" - return str(self.entity_description.suggested_unit_of_measurement) - \ No newline at end of file diff --git a/custom_components/sws12500/sensor.py b/custom_components/sws12500/sensor.py index 0c439bd..a8d1c24 100644 --- a/custom_components/sws12500/sensor.py +++ b/custom_components/sws12500/sensor.py @@ -251,24 +251,26 @@ class WeatherSensor( self._attr_unique_id = description.key self._data = None - # async def async_added_to_hass(self) -> None: - # """Handle listeners to reloaded sensors.""" + async def async_added_to_hass(self) -> None: + """Handle listeners to reloaded sensors.""" - # await super().async_added_to_hass() + await super().async_added_to_hass() - # self.coordinator.async_add_listener(self._handle_coordinator_update) + self.coordinator.async_add_listener(self._handle_coordinator_update) - # # prev_state_data = await self.async_get_last_sensor_data() - # # prev_state = await self.async_get_last_state() - # # if not prev_state: - # # return - # # self._data = prev_state_data.native_value + # prev_state_data = await self.async_get_last_sensor_data() + # prev_state = await self.async_get_last_state() + # if not prev_state: + # return + # self._data = prev_state_data.native_value @callback def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" self._data = self.coordinator.data.get(self.entity_description.key) + super()._handle_coordinator_update() + self.async_write_ha_state() @property @@ -281,11 +283,6 @@ class WeatherSensor( """Return name.""" return generate_entity_id("sensor.{}", self.entity_description.key) - # @property - # def translation_key(self) -> str: - # """"Returns translation key.""" - # return self.entity_description.translation_key - @property def device_info(self) -> DeviceInfo: """Device info.""" diff --git a/custom_components/sws12500/strings.json b/custom_components/sws12500/strings.json index 3b0be99..501fe5f 100644 --- a/custom_components/sws12500/strings.json +++ b/custom_components/sws12500/strings.json @@ -78,5 +78,11 @@ "ch2_temp": { "name": "Channel 2 temperature" }, "ch2_humidity": { "name": "Channel 2 humidity" } } + }, + "notify": { + "added": { + "title": "New sensors for SWS 12500 found.", + "message": "{added_sensors}\nHomeAssistant needs to be restarted for proper integreation run." + } } } diff --git a/custom_components/sws12500/translations/cs.json b/custom_components/sws12500/translations/cs.json index dbe7ffa..45579cc 100644 --- a/custom_components/sws12500/translations/cs.json +++ b/custom_components/sws12500/translations/cs.json @@ -77,5 +77,11 @@ "ch2_temp": { "name": "Teplota senzoru 2" }, "ch2_humidity": { "name": "Vlhkost sensoru 2" } } + }, + "notify": { + "added": { + "title": "Nalezeny nové senzory pro SWS 12500.", + "message": "{added_sensors}\nJe třeba restartovat Home Assistenta pro správnou funkci komponenty." + } } } diff --git a/custom_components/sws12500/translations/en.json b/custom_components/sws12500/translations/en.json index 3b0be99..501fe5f 100644 --- a/custom_components/sws12500/translations/en.json +++ b/custom_components/sws12500/translations/en.json @@ -78,5 +78,11 @@ "ch2_temp": { "name": "Channel 2 temperature" }, "ch2_humidity": { "name": "Channel 2 humidity" } } + }, + "notify": { + "added": { + "title": "New sensors for SWS 12500 found.", + "message": "{added_sensors}\nHomeAssistant needs to be restarted for proper integreation run." + } } } diff --git a/custom_components/sws12500/utils.py b/custom_components/sws12500/utils.py index aad89c0..e560723 100644 --- a/custom_components/sws12500/utils.py +++ b/custom_components/sws12500/utils.py @@ -2,23 +2,76 @@ import logging +from homeassistant.components import persistent_notification from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.helpers.translation import async_get_translations from .const import DEV_DBG, REMAP_ITEMS, SENSORS_TO_LOAD _LOGGER = logging.getLogger(__name__) +async def translations( + hass: HomeAssistant, + translation_domain: str, + translation_key: str, + *, + key: str = "message", + category: str = "notify" +) -> str: + """Get translated keys for domain.""" + + localize_key = f"component.{translation_domain}.{category}.{translation_key}.{key}" + + language = hass.config.language + + _translations = await async_get_translations( + hass, language, category, [translation_domain] + ) + if localize_key in _translations: + return _translations[localize_key] + +async def translated_notification( + hass: HomeAssistant, + translation_domain: str, + translation_key: str, + translation_placeholders: dict[str, str] | None = None, + notification_id: str | None = None, + *, + key: str = "message", + category: str = "notify" +) -> str: + """Translate notification.""" + + localize_key = f"component.{translation_domain}.{category}.{translation_key}.{key}" + + localize_title = f"component.{translation_domain}.{category}.{translation_key}.title" + + language = hass.config.language + + _translations = await async_get_translations( + hass, language, category, [translation_domain] + ) + if localize_key in _translations: + if not translation_placeholders: + persistent_notification.async_create( + hass, + _translations[localize_key], + _translations[localize_title], + notification_id, + ) + else: + message = _translations[localize_key].format(**translation_placeholders) + persistent_notification.async_create( + hass, message, _translations[localize_title], notification_id + ) + async def update_options( hass: HomeAssistant, entry: ConfigEntry, update_key, update_value ) -> None: """Update config.options entry.""" - conf = {} - - for k in entry.options: - conf[k] = entry.options[k] - + conf = {**entry.options} conf[update_key] = update_value return hass.config_entries.async_update_entry(entry, options=conf) @@ -44,8 +97,14 @@ def remap_items(entities): return items +def loaded_sensors(config_entry: ConfigEntry) -> list | None: + """Get loaded sensors.""" -def check_disabled(hass: HomeAssistant, items, config_entry: ConfigEntry) -> list | None: + return config_entry.options.get(SENSORS_TO_LOAD) if config_entry.options.get(SENSORS_TO_LOAD) else [] + +def check_disabled( + hass: HomeAssistant, items, config_entry: ConfigEntry +) -> list | None: """Check if we have data for unloaded sensors. If so, then add sensor to load queue. @@ -55,16 +114,17 @@ def check_disabled(hass: HomeAssistant, items, config_entry: ConfigEntry) -> lis log: bool = config_entry.options.get(DEV_DBG) entityFound: bool = False - loaded_sensors: list = config_entry.options.get(SENSORS_TO_LOAD) if config_entry.options.get(SENSORS_TO_LOAD) else [] + _loaded_sensors = loaded_sensors(config_entry) + missing_sensors: list = [] for item in items: if log: _LOGGER.info("Checking %s", item) - if item not in loaded_sensors: - loaded_sensors.append(item) + if item not in _loaded_sensors: + missing_sensors.append(item) entityFound = True if log: _LOGGER.info("Add sensor (%s) to loading queue", item) - return loaded_sensors if entityFound else None + return missing_sensors if entityFound else None