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
pull/12/head
schizza 2024-04-17 13:12:47 +02:00
parent b62e6abccf
commit 70bfd56268
8 changed files with 132 additions and 91 deletions

View File

@ -19,7 +19,15 @@ from .const import (
SENSORS_TO_LOAD, SENSORS_TO_LOAD,
WINDY_ENABLED, 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 from .windy_func import WindyPush
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -65,10 +73,22 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
remaped_items = remap_items(data) remaped_items = remap_items(data)
if sensors := check_disabled(self.hass, remaped_items, self.config): if sensors := check_disabled(self.hass, remaped_items, self.config):
await update_options( translate_sensors = [
self.hass, self.config_entry, SENSORS_TO_LOAD, 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) self.async_set_updated_data(remaped_items)
@ -131,11 +151,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True 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: 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) unregister_path(hass)
return _ok 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

View File

@ -10,6 +10,6 @@
"iot_class": "local_push", "iot_class": "local_push",
"requirements": [], "requirements": [],
"ssdp": [], "ssdp": [],
"version": "0.1.2", "version": "0.1.3",
"zeroconf": [] "zeroconf": []
} }

View File

@ -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)

View File

@ -251,24 +251,26 @@ class WeatherSensor(
self._attr_unique_id = description.key self._attr_unique_id = description.key
self._data = None self._data = None
# async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
# """Handle listeners to reloaded sensors.""" """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_data = await self.async_get_last_sensor_data()
# # prev_state = await self.async_get_last_state() # prev_state = await self.async_get_last_state()
# # if not prev_state: # if not prev_state:
# # return # return
# # self._data = prev_state_data.native_value # self._data = prev_state_data.native_value
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator.""" """Handle updated data from the coordinator."""
self._data = self.coordinator.data.get(self.entity_description.key) self._data = self.coordinator.data.get(self.entity_description.key)
super()._handle_coordinator_update()
self.async_write_ha_state() self.async_write_ha_state()
@property @property
@ -281,11 +283,6 @@ class WeatherSensor(
"""Return name.""" """Return name."""
return generate_entity_id("sensor.{}", self.entity_description.key) 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 @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
"""Device info.""" """Device info."""

View File

@ -78,5 +78,11 @@
"ch2_temp": { "name": "Channel 2 temperature" }, "ch2_temp": { "name": "Channel 2 temperature" },
"ch2_humidity": { "name": "Channel 2 humidity" } "ch2_humidity": { "name": "Channel 2 humidity" }
} }
},
"notify": {
"added": {
"title": "New sensors for SWS 12500 found.",
"message": "{added_sensors}\n<b>HomeAssistant needs to be restarted for proper integreation run.</b>"
}
} }
} }

View File

@ -77,5 +77,11 @@
"ch2_temp": { "name": "Teplota senzoru 2" }, "ch2_temp": { "name": "Teplota senzoru 2" },
"ch2_humidity": { "name": "Vlhkost sensoru 2" } "ch2_humidity": { "name": "Vlhkost sensoru 2" }
} }
},
"notify": {
"added": {
"title": "Nalezeny nové senzory pro SWS 12500.",
"message": "{added_sensors}\n<b>Je třeba restartovat Home Assistenta pro správnou funkci komponenty.</b>"
}
} }
} }

View File

@ -78,5 +78,11 @@
"ch2_temp": { "name": "Channel 2 temperature" }, "ch2_temp": { "name": "Channel 2 temperature" },
"ch2_humidity": { "name": "Channel 2 humidity" } "ch2_humidity": { "name": "Channel 2 humidity" }
} }
},
"notify": {
"added": {
"title": "New sensors for SWS 12500 found.",
"message": "{added_sensors}\n<b>HomeAssistant needs to be restarted for proper integreation run.</b>"
}
} }
} }

View File

@ -2,23 +2,76 @@
import logging import logging
from homeassistant.components import persistent_notification
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.translation import async_get_translations
from .const import DEV_DBG, REMAP_ITEMS, SENSORS_TO_LOAD from .const import DEV_DBG, REMAP_ITEMS, SENSORS_TO_LOAD
_LOGGER = logging.getLogger(__name__) _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( async def update_options(
hass: HomeAssistant, entry: ConfigEntry, update_key, update_value hass: HomeAssistant, entry: ConfigEntry, update_key, update_value
) -> None: ) -> None:
"""Update config.options entry.""" """Update config.options entry."""
conf = {} conf = {**entry.options}
for k in entry.options:
conf[k] = entry.options[k]
conf[update_key] = update_value conf[update_key] = update_value
return hass.config_entries.async_update_entry(entry, options=conf) return hass.config_entries.async_update_entry(entry, options=conf)
@ -44,8 +97,14 @@ def remap_items(entities):
return items 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. """Check if we have data for unloaded sensors.
If so, then add sensor to load queue. 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) log: bool = config_entry.options.get(DEV_DBG)
entityFound: bool = False 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: for item in items:
if log: if log:
_LOGGER.info("Checking %s", item) _LOGGER.info("Checking %s", item)
if item not in loaded_sensors: if item not in _loaded_sensors:
loaded_sensors.append(item) missing_sensors.append(item)
entityFound = True entityFound = True
if log: if log:
_LOGGER.info("Add sensor (%s) to loading queue", item) _LOGGER.info("Add sensor (%s) to loading queue", item)
return loaded_sensors if entityFound else None return missing_sensors if entityFound else None