Compare commits
3 Commits
63660006ea
...
e737fb16d3
| Author | SHA1 | Date |
|---|---|---|
|
|
e737fb16d3 | |
|
|
159d465db5 | |
|
|
9d5fafa8d0 |
|
|
@ -36,11 +36,7 @@ from py_typecheck import checked, checked_or
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import (
|
||||
ConfigEntryNotReady,
|
||||
InvalidStateError,
|
||||
PlatformNotReady,
|
||||
)
|
||||
from homeassistant.exceptions import ConfigEntryNotReady, InvalidStateError, PlatformNotReady
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .const import (
|
||||
|
|
@ -215,9 +211,7 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
raise HTTPUnauthorized
|
||||
|
||||
# Convert raw payload keys to our internal sensor keys (stable identifiers).
|
||||
remaped_items: dict[str, str] = (
|
||||
remap_wslink_items(data) if _wslink else remap_items(data)
|
||||
)
|
||||
remaped_items: dict[str, str] = remap_wslink_items(data) if _wslink else remap_items(data)
|
||||
|
||||
# Auto-discovery: if payload contains keys that are not enabled/loaded yet,
|
||||
# add them to the option list and create entities dynamically.
|
||||
|
|
@ -274,9 +268,7 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
# NOTE: Some linters prefer top-level imports. In this case the local import is
|
||||
# intentional and prevents "partially initialized module" errors.
|
||||
|
||||
from .sensor import ( # noqa: PLC0415 (local import is intentional)
|
||||
add_new_sensors,
|
||||
)
|
||||
from .sensor import add_new_sensors # noqa: PLC0415 (local import is intentional)
|
||||
|
||||
add_new_sensors(self.hass, self.config, newly_discovered)
|
||||
|
||||
|
|
@ -294,9 +286,7 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
# to avoid additional background polling tasks.
|
||||
|
||||
_windy_enabled = checked_or(self.config.options.get(WINDY_ENABLED), bool, False)
|
||||
_pocasi_enabled = checked_or(
|
||||
self.config.options.get(POCASI_CZ_ENABLED), bool, False
|
||||
)
|
||||
_pocasi_enabled = checked_or(self.config.options.get(POCASI_CZ_ENABLED), bool, False)
|
||||
|
||||
if _windy_enabled:
|
||||
await self.windy.push_data_to_windy(data, _wslink)
|
||||
|
|
@ -342,38 +332,22 @@ def register_path(
|
|||
|
||||
# Register webhooks in HomeAssistant with dispatcher
|
||||
try:
|
||||
_default_route = hass.http.app.router.add_get(
|
||||
DEFAULT_URL, routes.dispatch, name="_default_route"
|
||||
)
|
||||
_wslink_post_route = hass.http.app.router.add_post(
|
||||
WSLINK_URL, routes.dispatch, name="_wslink_post_route"
|
||||
)
|
||||
_wslink_get_route = hass.http.app.router.add_get(
|
||||
WSLINK_URL, routes.dispatch, name="_wslink_get_route"
|
||||
)
|
||||
_health_route = hass.http.app.router.add_get(
|
||||
HEALTH_URL, routes.dispatch, name="_health_route"
|
||||
)
|
||||
_default_route = hass.http.app.router.add_get(DEFAULT_URL, routes.dispatch, name="_default_route")
|
||||
_wslink_post_route = hass.http.app.router.add_post(WSLINK_URL, routes.dispatch, name="_wslink_post_route")
|
||||
_wslink_get_route = hass.http.app.router.add_get(WSLINK_URL, routes.dispatch, name="_wslink_get_route")
|
||||
_health_route = hass.http.app.router.add_get(HEALTH_URL, routes.dispatch, name="_health_route")
|
||||
|
||||
# Save initialised routes
|
||||
hass_data["routes"] = routes
|
||||
|
||||
except RuntimeError as Ex:
|
||||
_LOGGER.critical(
|
||||
"Routes cannot be added. Integration will not work as expected. %s", Ex
|
||||
)
|
||||
_LOGGER.critical("Routes cannot be added. Integration will not work as expected. %s", Ex)
|
||||
raise ConfigEntryNotReady from Ex
|
||||
|
||||
# Finally create internal route dispatcher with provided urls, while we have webhooks registered.
|
||||
routes.add_route(
|
||||
DEFAULT_URL, _default_route, coordinator.received_data, enabled=not _wslink
|
||||
)
|
||||
routes.add_route(
|
||||
WSLINK_URL, _wslink_post_route, coordinator.received_data, enabled=_wslink
|
||||
)
|
||||
routes.add_route(
|
||||
WSLINK_URL, _wslink_get_route, coordinator.received_data, enabled=_wslink
|
||||
)
|
||||
routes.add_route(DEFAULT_URL, _default_route, coordinator.received_data, enabled=not _wslink)
|
||||
routes.add_route(WSLINK_URL, _wslink_post_route, coordinator.received_data, enabled=_wslink)
|
||||
routes.add_route(WSLINK_URL, _wslink_get_route, coordinator.received_data, enabled=_wslink)
|
||||
# Make health route `sticky` so it will not change upon updating options.
|
||||
routes.add_route(
|
||||
HEALTH_URL,
|
||||
|
|
@ -449,9 +423,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
if routes:
|
||||
_LOGGER.debug("We have routes registered, will try to switch dispatcher.")
|
||||
routes.switch_route(
|
||||
coordinator.received_data, DEFAULT_URL if not _wslink else WSLINK_URL
|
||||
)
|
||||
routes.switch_route(coordinator.received_data, DEFAULT_URL if not _wslink else WSLINK_URL)
|
||||
routes.set_ingress_observer(coordinator_health.record_dispatch)
|
||||
coordinator_health.update_routing(routes)
|
||||
_LOGGER.debug("%s", routes.show_enabled())
|
||||
|
|
@ -487,14 +459,8 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
|
|||
"""
|
||||
|
||||
if (hass_data := checked(hass.data.get(DOMAIN), dict[str, Any])) is not None:
|
||||
if (
|
||||
entry_data := checked(hass_data.get(entry.entry_id), dict[str, Any])
|
||||
) is not None:
|
||||
if (
|
||||
old_options := checked(
|
||||
entry_data.get(ENTRY_LAST_OPTIONS), dict[str, Any]
|
||||
)
|
||||
) is not None:
|
||||
if (entry_data := checked(hass_data.get(entry.entry_id), dict[str, Any])) is not None:
|
||||
if (old_options := checked(entry_data.get(ENTRY_LAST_OPTIONS), dict[str, Any])) is not None:
|
||||
new_options = dict(entry.options)
|
||||
|
||||
changed_keys = {
|
||||
|
|
@ -507,9 +473,7 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
|
|||
entry_data[ENTRY_LAST_OPTIONS] = new_options
|
||||
|
||||
if changed_keys == {SENSORS_TO_LOAD}:
|
||||
_LOGGER.debug(
|
||||
"Options updated (%s); skipping reload.", SENSORS_TO_LOAD
|
||||
)
|
||||
_LOGGER.debug("Options updated (%s); skipping reload.", SENSORS_TO_LOAD)
|
||||
return
|
||||
else:
|
||||
# No/invalid snapshot: store current options for next comparison.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
"""Battery binary sensor entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from py_typecheck import checked_or
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorEntity, BinarySensorEntityDescription
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
|
||||
class BatteryBinarySensor( # pyright: ignore[reportIncompatibleVariableOverride]
|
||||
CoordinatorEntity, BinarySensorEntity
|
||||
):
|
||||
"""Represent a low-battery binary sensor.
|
||||
|
||||
Station payload uses:
|
||||
- ``0`` => low battery (binary sensor is ``on``)
|
||||
- ``1`` => battery OK (binary sensor is ``off``)
|
||||
"""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: Any,
|
||||
description: BinarySensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the battery binary sensor."""
|
||||
super().__init__(coordinator)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{description.key}_battery"
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool | None: # pyright: ignore[reportIncompatibleVariableOverride]
|
||||
"""Return low-battery state.
|
||||
|
||||
``True`` means low battery for ``BinarySensorDeviceClass.BATTERY``.
|
||||
"""
|
||||
data = checked_or(self.coordinator.data, dict[str, Any], {})
|
||||
raw: Any = data.get(self.entity_description.key)
|
||||
|
||||
if raw is None or raw == "":
|
||||
return None
|
||||
|
||||
try:
|
||||
value = int(raw)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
return value == 0
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
"""Battery sensors."""
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
|
||||
BATTERY_BINARY_SENSORS: tuple[BinarySensorEntityDescription, ...] = (
|
||||
BinarySensorEntityDescription(
|
||||
key="outside_battery",
|
||||
translation_key="outside_battery",
|
||||
device_class=BinarySensorDeviceClass.BATTERY,
|
||||
),
|
||||
BinarySensorEntityDescription(
|
||||
key="indoor_battery",
|
||||
translation_key="indoor_battery",
|
||||
device_class=BinarySensorDeviceClass.BATTERY,
|
||||
),
|
||||
BinarySensorEntityDescription(
|
||||
key="ch2_battery",
|
||||
translation_key="ch2_battery",
|
||||
device_class=BinarySensorDeviceClass.BATTERY,
|
||||
),
|
||||
)
|
||||
|
|
@ -6,12 +6,7 @@ from typing import Any
|
|||
import voluptuous as vol
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
ConfigEntry,
|
||||
ConfigFlow,
|
||||
ConfigFlowResult,
|
||||
OptionsFlow,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult, OptionsFlow
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.network import get_url
|
||||
|
|
@ -23,7 +18,6 @@ from .const import (
|
|||
DOMAIN,
|
||||
ECOWITT_ENABLED,
|
||||
ECOWITT_WEBHOOK_ID,
|
||||
# HEALTH_BEARER_TOKEN,
|
||||
INVALID_CREDENTIALS,
|
||||
POCASI_CZ_API_ID,
|
||||
POCASI_CZ_API_KEY,
|
||||
|
|
@ -37,6 +31,7 @@ from .const import (
|
|||
WINDY_STATION_ID,
|
||||
WINDY_STATION_PW,
|
||||
WSLINK,
|
||||
WSLINK_ADDON_PORT,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -65,6 +60,8 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
|||
self.pocasi_cz_schema = {}
|
||||
self.ecowitt: dict[str, Any] = {}
|
||||
self.ecowitt_schema = {}
|
||||
self.wslink_addon_port: dict[str, int] = {}
|
||||
self.wslink_addod_schema = {}
|
||||
|
||||
async def _get_entry_data(self):
|
||||
"""Get entry data."""
|
||||
|
|
@ -94,22 +91,17 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
|||
self.windy_data = {
|
||||
WINDY_STATION_ID: self.config_entry.options.get(WINDY_STATION_ID, ""),
|
||||
WINDY_STATION_PW: self.config_entry.options.get(WINDY_STATION_PW, ""),
|
||||
WINDY_LOGGER_ENABLED: self.config_entry.options.get(
|
||||
WINDY_LOGGER_ENABLED, False
|
||||
),
|
||||
WINDY_LOGGER_ENABLED: self.config_entry.options.get(WINDY_LOGGER_ENABLED, False),
|
||||
WINDY_ENABLED: self.config_entry.options.get(WINDY_ENABLED, False),
|
||||
}
|
||||
|
||||
self.windy_data_schema = {
|
||||
vol.Optional(
|
||||
WINDY_STATION_ID, default=self.windy_data.get(WINDY_STATION_ID, "")
|
||||
): str,
|
||||
vol.Optional(WINDY_STATION_ID, default=self.windy_data.get(WINDY_STATION_ID, "")): str,
|
||||
vol.Optional(
|
||||
WINDY_STATION_PW,
|
||||
default=self.windy_data.get(WINDY_STATION_PW, ""),
|
||||
): str,
|
||||
vol.Optional(WINDY_ENABLED, default=self.windy_data[WINDY_ENABLED]): bool
|
||||
or False,
|
||||
vol.Optional(WINDY_ENABLED, default=self.windy_data[WINDY_ENABLED]): bool or False,
|
||||
vol.Optional(
|
||||
WINDY_LOGGER_ENABLED,
|
||||
default=self.windy_data[WINDY_LOGGER_ENABLED],
|
||||
|
|
@ -120,28 +112,18 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
|||
POCASI_CZ_API_ID: self.config_entry.options.get(POCASI_CZ_API_ID, ""),
|
||||
POCASI_CZ_API_KEY: self.config_entry.options.get(POCASI_CZ_API_KEY, ""),
|
||||
POCASI_CZ_ENABLED: self.config_entry.options.get(POCASI_CZ_ENABLED, False),
|
||||
POCASI_CZ_LOGGER_ENABLED: self.config_entry.options.get(
|
||||
POCASI_CZ_LOGGER_ENABLED, False
|
||||
),
|
||||
POCASI_CZ_SEND_INTERVAL: self.config_entry.options.get(
|
||||
POCASI_CZ_SEND_INTERVAL, 30
|
||||
),
|
||||
POCASI_CZ_LOGGER_ENABLED: self.config_entry.options.get(POCASI_CZ_LOGGER_ENABLED, False),
|
||||
POCASI_CZ_SEND_INTERVAL: self.config_entry.options.get(POCASI_CZ_SEND_INTERVAL, 30),
|
||||
}
|
||||
|
||||
self.pocasi_cz_schema = {
|
||||
vol.Required(
|
||||
POCASI_CZ_API_ID, default=self.pocasi_cz.get(POCASI_CZ_API_ID)
|
||||
): str,
|
||||
vol.Required(
|
||||
POCASI_CZ_API_KEY, default=self.pocasi_cz.get(POCASI_CZ_API_KEY)
|
||||
): str,
|
||||
vol.Required(POCASI_CZ_API_ID, default=self.pocasi_cz.get(POCASI_CZ_API_ID)): str,
|
||||
vol.Required(POCASI_CZ_API_KEY, default=self.pocasi_cz.get(POCASI_CZ_API_KEY)): str,
|
||||
vol.Required(
|
||||
POCASI_CZ_SEND_INTERVAL,
|
||||
default=self.pocasi_cz.get(POCASI_CZ_SEND_INTERVAL),
|
||||
): int,
|
||||
vol.Optional(
|
||||
POCASI_CZ_ENABLED, default=self.pocasi_cz.get(POCASI_CZ_ENABLED)
|
||||
): bool,
|
||||
vol.Optional(POCASI_CZ_ENABLED, default=self.pocasi_cz.get(POCASI_CZ_ENABLED)): bool,
|
||||
vol.Optional(
|
||||
POCASI_CZ_LOGGER_ENABLED,
|
||||
default=self.pocasi_cz.get(POCASI_CZ_LOGGER_ENABLED),
|
||||
|
|
@ -153,11 +135,13 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
|||
ECOWITT_ENABLED: self.config_entry.options.get(ECOWITT_ENABLED, False),
|
||||
}
|
||||
|
||||
self.wslink_addon_port = {WSLINK_ADDON_PORT: self.config_entry.options.get(WSLINK_ADDON_PORT, 443)}
|
||||
|
||||
async def async_step_init(self, user_input: dict[str, Any] = {}):
|
||||
"""Manage the options - show menu first."""
|
||||
_ = user_input
|
||||
return self.async_show_menu(
|
||||
step_id="init", menu_options=["basic", "ecowitt", "windy", "pocasi"]
|
||||
step_id="init", menu_options=["basic", "wslink_port_setup", "ecowitt", "windy", "pocasi"]
|
||||
)
|
||||
|
||||
async def async_step_basic(self, user_input: Any = None):
|
||||
|
|
@ -294,6 +278,28 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
|||
user_input = self.retain_data(user_input)
|
||||
return self.async_create_entry(title=DOMAIN, data=user_input)
|
||||
|
||||
async def async_step_wslink_port_setup(self, user_input: Any = None) -> ConfigFlowResult:
|
||||
"""WSLink Addon port setup."""
|
||||
|
||||
errors: dict[str, str] = {}
|
||||
await self._get_entry_data()
|
||||
|
||||
if not (port := self.wslink_addon_port.get(WSLINK_ADDON_PORT)):
|
||||
port = 433
|
||||
|
||||
wslink_port_schema = {
|
||||
vol.Required(WSLINK_ADDON_PORT, default=port): int,
|
||||
}
|
||||
if user_input is None:
|
||||
return self.async_show_form(
|
||||
step_id="wslink_port_setup",
|
||||
data_schema=vol.Schema(wslink_port_schema),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
user_input = self.retain_data(user_input)
|
||||
return self.async_create_entry(title=DOMAIN, data=user_input)
|
||||
|
||||
def retain_data(self, data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Retain user_data."""
|
||||
|
||||
|
|
@ -303,6 +309,7 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
|||
**self.pocasi_cz,
|
||||
**self.sensors,
|
||||
**self.ecowitt,
|
||||
**self.wslink_addon_port,
|
||||
**dict(data),
|
||||
}
|
||||
|
||||
|
|
@ -339,9 +346,7 @@ class ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
elif user_input[API_KEY] == user_input[API_ID]:
|
||||
errors["base"] = "valid_credentials_match"
|
||||
else:
|
||||
return self.async_create_entry(
|
||||
title=DOMAIN, data=user_input, options=user_input
|
||||
)
|
||||
return self.async_create_entry(title=DOMAIN, data=user_input, options=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ POCASI_CZ_SEND_MINIMUM: Final = 12 # minimal time to resend data
|
|||
WSLINK: Final = "wslink"
|
||||
|
||||
WINDY_MAX_RETRIES: Final = 3
|
||||
WSLINK_ADDON_PORT: Final = "WSLINK_ADDON_PORT"
|
||||
|
||||
__all__ = [
|
||||
"DOMAIN",
|
||||
|
|
@ -235,28 +236,20 @@ POCASI_CZ_API_ID = "POCASI_CZ_API_ID"
|
|||
POCASI_CZ_SEND_INTERVAL = "POCASI_SEND_INTERVAL"
|
||||
POCASI_CZ_ENABLED = "pocasi_enabled_chcekbox"
|
||||
POCASI_CZ_LOGGER_ENABLED = "pocasi_logger_checkbox"
|
||||
POCASI_INVALID_KEY: Final = (
|
||||
"Pocasi Meteo refused to accept data. Invalid ID/Key combination?"
|
||||
)
|
||||
POCASI_INVALID_KEY: Final = "Pocasi Meteo refused to accept data. Invalid ID/Key combination?"
|
||||
POCASI_CZ_SUCCESS: Final = "Successfully sent data to Pocasi Meteo"
|
||||
POCASI_CZ_UNEXPECTED: Final = (
|
||||
"Pocasti Meteo responded unexpectedly 3 times in row. Resendig is now disabled!"
|
||||
)
|
||||
POCASI_CZ_UNEXPECTED: Final = "Pocasti Meteo responded unexpectedly 3 times in row. Resendig is now disabled!"
|
||||
|
||||
WINDY_STATION_ID = "WINDY_STATION_ID"
|
||||
WINDY_STATION_PW = "WINDY_STATION_PWD"
|
||||
WINDY_ENABLED: Final = "windy_enabled_checkbox"
|
||||
WINDY_LOGGER_ENABLED: Final = "windy_logger_checkbox"
|
||||
WINDY_NOT_INSERTED: Final = (
|
||||
"Windy responded with 400 error. Invalid ID/password combination?"
|
||||
)
|
||||
WINDY_INVALID_KEY: Final = "Windy API KEY is invalid. Send data to Windy is now disabled. Check your API KEY and try again."
|
||||
WINDY_SUCCESS: Final = (
|
||||
"Windy successfully sent data and data was successfully inserted by Windy API"
|
||||
)
|
||||
WINDY_UNEXPECTED: Final = (
|
||||
"Windy responded unexpectedly 3 times in a row. Send to Windy is now disabled!"
|
||||
WINDY_NOT_INSERTED: Final = "Windy responded with 400 error. Invalid ID/password combination?"
|
||||
WINDY_INVALID_KEY: Final = (
|
||||
"Windy API KEY is invalid. Send data to Windy is now disabled. Check your API KEY and try again."
|
||||
)
|
||||
WINDY_SUCCESS: Final = "Windy successfully sent data and data was successfully inserted by Windy API"
|
||||
WINDY_UNEXPECTED: Final = "Windy responded unexpectedly 3 times in a row. Send to Windy is now disabled!"
|
||||
|
||||
|
||||
PURGE_DATA_POCAS: Final = [
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ from .const import (
|
|||
POCASI_CZ_ENABLED,
|
||||
WINDY_ENABLED,
|
||||
WSLINK,
|
||||
WSLINK_ADDON_PORT,
|
||||
WSLINK_URL,
|
||||
)
|
||||
from .data import ENTRY_HEALTH_DATA
|
||||
|
|
@ -78,9 +79,7 @@ def _empty_forwarding_state(enabled: bool) -> dict[str, Any]:
|
|||
|
||||
def _default_health_data(config: ConfigEntry) -> dict[str, Any]:
|
||||
"""Build the default health/debug payload for this config entry."""
|
||||
configured_protocol = _protocol_name(
|
||||
checked_or(config.options.get(WSLINK), bool, False)
|
||||
)
|
||||
configured_protocol = _protocol_name(checked_or(config.options.get(WSLINK), bool, False))
|
||||
return {
|
||||
"integration_status": f"online_{configured_protocol}",
|
||||
"configured_protocol": configured_protocol,
|
||||
|
|
@ -117,12 +116,8 @@ def _default_health_data(config: ConfigEntry) -> dict[str, Any]:
|
|||
"reason": "no_data",
|
||||
},
|
||||
"forwarding": {
|
||||
"windy": _empty_forwarding_state(
|
||||
checked_or(config.options.get(WINDY_ENABLED), bool, False)
|
||||
),
|
||||
"pocasi": _empty_forwarding_state(
|
||||
checked_or(config.options.get(POCASI_CZ_ENABLED), bool, False)
|
||||
),
|
||||
"windy": _empty_forwarding_state(checked_or(config.options.get(WINDY_ENABLED), bool, False)),
|
||||
"pocasi": _empty_forwarding_state(checked_or(config.options.get(POCASI_CZ_ENABLED), bool, False)),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -190,9 +185,7 @@ class HealthCoordinator(DataUpdateCoordinator):
|
|||
|
||||
data["integration_status"] = integration_status
|
||||
data["active_protocol"] = (
|
||||
last_protocol
|
||||
if accepted and last_protocol in {"wu", "wslink"}
|
||||
else configured_protocol
|
||||
last_protocol if accepted and last_protocol in {"wu", "wslink"} else configured_protocol
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
|
|
@ -201,8 +194,10 @@ class HealthCoordinator(DataUpdateCoordinator):
|
|||
url = get_url(self.hass)
|
||||
ip = await async_get_source_ip(self.hass)
|
||||
|
||||
health_url = f"https://{ip}/healthz"
|
||||
info_url = f"https://{ip}/status/internal"
|
||||
port = checked_or(self.config_entry.options.get(WSLINK_ADDON_PORT), int, 443)
|
||||
|
||||
health_url = f"https://{ip}:{port}/healthz"
|
||||
info_url = f"https://{ip}:{port}/status/internal"
|
||||
|
||||
data = deepcopy(self.data)
|
||||
addon = data["addon"]
|
||||
|
|
@ -245,9 +240,7 @@ class HealthCoordinator(DataUpdateCoordinator):
|
|||
def update_routing(self, routes: Routes | None) -> None:
|
||||
"""Store the currently enabled routes for diagnostics."""
|
||||
data = deepcopy(self.data)
|
||||
data["configured_protocol"] = _protocol_name(
|
||||
checked_or(self.config.options.get(WSLINK), bool, False)
|
||||
)
|
||||
data["configured_protocol"] = _protocol_name(checked_or(self.config.options.get(WSLINK), bool, False))
|
||||
if routes is not None:
|
||||
data["routes"] = {
|
||||
"wu_enabled": routes.path_enabled(DEFAULT_URL),
|
||||
|
|
@ -258,9 +251,7 @@ class HealthCoordinator(DataUpdateCoordinator):
|
|||
self._refresh_summary(data)
|
||||
self._commit(data)
|
||||
|
||||
def record_dispatch(
|
||||
self, request: aiohttp.web.Request, route_enabled: bool, reason: str | None
|
||||
) -> None:
|
||||
def record_dispatch(self, request: aiohttp.web.Request, route_enabled: bool, reason: str | None) -> None:
|
||||
"""Record every ingress observed by the dispatcher.
|
||||
|
||||
This runs before the actual webhook handler. It lets diagnostics answer:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
"""Sensor entities for the SWS12500 integration for old endpoint."""
|
||||
|
||||
from typing import cast
|
||||
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
|
||||
from homeassistant.const import (
|
||||
DEGREE,
|
||||
|
|
@ -41,7 +39,7 @@ from .const import (
|
|||
UnitOfDir,
|
||||
)
|
||||
from .sensors_common import WeatherSensorEntityDescription
|
||||
from .utils import chill_index, heat_index, wind_dir_to_text
|
||||
from .utils import chill_index, heat_index, to_float, to_int, wind_dir_to_text
|
||||
|
||||
SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
||||
WeatherSensorEntityDescription(
|
||||
|
|
@ -51,7 +49,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
translation_key=INDOOR_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=INDOOR_HUMIDITY,
|
||||
|
|
@ -60,7 +58,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
translation_key=INDOOR_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=OUTSIDE_TEMP,
|
||||
|
|
@ -69,7 +67,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
translation_key=OUTSIDE_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=OUTSIDE_HUMIDITY,
|
||||
|
|
@ -78,7 +76,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
translation_key=OUTSIDE_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=DEW_POINT,
|
||||
|
|
@ -87,7 +85,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer-lines",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
translation_key=DEW_POINT,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=BARO_PRESSURE,
|
||||
|
|
@ -97,7 +95,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
|
||||
suggested_unit_of_measurement=UnitOfPressure.HPA,
|
||||
translation_key=BARO_PRESSURE,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_SPEED,
|
||||
|
|
@ -107,7 +105,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
icon="mdi:weather-windy",
|
||||
translation_key=WIND_SPEED,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_GUST,
|
||||
|
|
@ -117,7 +115,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
icon="mdi:windsock",
|
||||
translation_key=WIND_GUST,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_DIR,
|
||||
|
|
@ -127,15 +125,12 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=None,
|
||||
icon="mdi:sign-direction",
|
||||
translation_key=WIND_DIR,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_AZIMUT,
|
||||
icon="mdi:sign-direction",
|
||||
value_fn=lambda data: cast("str", wind_dir_to_text(data)),
|
||||
value_from_data_fn=lambda data: cast(
|
||||
"str", wind_dir_to_text(cast("float", data.get(WIND_DIR) or 0.0))
|
||||
),
|
||||
value_from_data_fn=lambda dir: wind_dir_to_text(dir.get(WIND_DIR, 0.0)),
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[e.value for e in UnitOfDir],
|
||||
translation_key=WIND_AZIMUT,
|
||||
|
|
@ -149,7 +144,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=DAILY_RAIN,
|
||||
|
|
@ -160,7 +155,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=DAILY_RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=SOLAR_RADIATION,
|
||||
|
|
@ -169,7 +164,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.IRRADIANCE,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=SOLAR_RADIATION,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=UV,
|
||||
|
|
@ -178,7 +173,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UV_INDEX,
|
||||
icon="mdi:sunglasses",
|
||||
translation_key=UV,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH2_TEMP,
|
||||
|
|
@ -188,7 +183,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH2_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH2_HUMIDITY,
|
||||
|
|
@ -197,7 +192,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH2_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH3_TEMP,
|
||||
|
|
@ -207,7 +202,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH3_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH3_HUMIDITY,
|
||||
|
|
@ -216,7 +211,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH3_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH4_TEMP,
|
||||
|
|
@ -226,7 +221,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH4_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH4_HUMIDITY,
|
||||
|
|
@ -235,7 +230,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH4_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=HEAT_INDEX,
|
||||
|
|
@ -246,7 +241,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=HEAT_INDEX,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
value_from_data_fn=heat_index,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
|
|
@ -258,7 +253,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CHILL_INDEX,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
value_from_data_fn=chill_index,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
"""Sensor entities for the SWS12500 integration for old endpoint."""
|
||||
|
||||
from typing import cast
|
||||
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
|
||||
from homeassistant.const import (
|
||||
DEGREE,
|
||||
|
|
@ -64,7 +62,7 @@ from .const import (
|
|||
UnitOfDir,
|
||||
)
|
||||
from .sensors_common import WeatherSensorEntityDescription
|
||||
from .utils import battery_level, wind_dir_to_text
|
||||
from .utils import battery_level, to_float, to_int, wind_dir_to_text
|
||||
|
||||
SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
||||
WeatherSensorEntityDescription(
|
||||
|
|
@ -74,7 +72,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
translation_key=INDOOR_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=INDOOR_HUMIDITY,
|
||||
|
|
@ -83,7 +81,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
translation_key=INDOOR_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=OUTSIDE_TEMP,
|
||||
|
|
@ -92,7 +90,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
translation_key=OUTSIDE_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=OUTSIDE_HUMIDITY,
|
||||
|
|
@ -101,7 +99,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
translation_key=OUTSIDE_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=DEW_POINT,
|
||||
|
|
@ -110,7 +108,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
icon="mdi:thermometer-lines",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
translation_key=DEW_POINT,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=BARO_PRESSURE,
|
||||
|
|
@ -120,7 +118,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
|
||||
suggested_unit_of_measurement=UnitOfPressure.HPA,
|
||||
translation_key=BARO_PRESSURE,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_SPEED,
|
||||
|
|
@ -130,7 +128,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
icon="mdi:weather-windy",
|
||||
translation_key=WIND_SPEED,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_GUST,
|
||||
|
|
@ -140,7 +138,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
|
||||
icon="mdi:windsock",
|
||||
translation_key=WIND_GUST,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_DIR,
|
||||
|
|
@ -150,15 +148,12 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=None,
|
||||
icon="mdi:sign-direction",
|
||||
translation_key=WIND_DIR,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WIND_AZIMUT,
|
||||
icon="mdi:sign-direction",
|
||||
value_fn=lambda data: cast("str", wind_dir_to_text(data)),
|
||||
value_from_data_fn=lambda data: cast(
|
||||
"str", wind_dir_to_text(cast("float", data.get(WIND_DIR) or 0.0))
|
||||
),
|
||||
value_from_data_fn=lambda dir: wind_dir_to_text(dir.get(WIND_DIR, 0.0)),
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[e.value for e in UnitOfDir],
|
||||
translation_key=WIND_AZIMUT,
|
||||
|
|
@ -172,7 +167,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=DAILY_RAIN,
|
||||
|
|
@ -183,7 +178,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=DAILY_RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=HOURLY_RAIN,
|
||||
|
|
@ -194,7 +189,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=HOURLY_RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WEEKLY_RAIN,
|
||||
|
|
@ -205,7 +200,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=WEEKLY_RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=MONTHLY_RAIN,
|
||||
|
|
@ -216,7 +211,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=MONTHLY_RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=YEARLY_RAIN,
|
||||
|
|
@ -227,7 +222,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-pouring",
|
||||
translation_key=YEARLY_RAIN,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=SOLAR_RADIATION,
|
||||
|
|
@ -236,7 +231,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.IRRADIANCE,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=SOLAR_RADIATION,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=UV,
|
||||
|
|
@ -245,7 +240,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UV_INDEX,
|
||||
icon="mdi:sunglasses",
|
||||
translation_key=UV,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH2_TEMP,
|
||||
|
|
@ -255,7 +250,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH2_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH2_HUMIDITY,
|
||||
|
|
@ -264,7 +259,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH2_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH3_TEMP,
|
||||
|
|
@ -274,7 +269,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH3_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH3_HUMIDITY,
|
||||
|
|
@ -283,7 +278,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH3_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH4_TEMP,
|
||||
|
|
@ -293,7 +288,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH4_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH4_HUMIDITY,
|
||||
|
|
@ -302,7 +297,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH4_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH5_TEMP,
|
||||
|
|
@ -312,7 +307,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH5_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH5_HUMIDITY,
|
||||
|
|
@ -321,7 +316,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH5_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH6_TEMP,
|
||||
|
|
@ -331,7 +326,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH6_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH6_HUMIDITY,
|
||||
|
|
@ -340,7 +335,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH6_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH7_TEMP,
|
||||
|
|
@ -350,7 +345,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH7_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH7_HUMIDITY,
|
||||
|
|
@ -359,7 +354,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH7_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH8_TEMP,
|
||||
|
|
@ -369,7 +364,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH8_TEMP,
|
||||
value_fn=lambda data: cast("float", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH8_HUMIDITY,
|
||||
|
|
@ -378,34 +373,28 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CH8_HUMIDITY,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=HEAT_INDEX,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
value_fn=lambda data: data,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH3_BATTERY,
|
||||
translation_key=CH3_BATTERY,
|
||||
icon="mdi:battery-unknown",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
value_fn=lambda data: data,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH4_BATTERY,
|
||||
translation_key=CH4_BATTERY,
|
||||
icon="mdi:battery-unknown",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
value_fn=lambda data: data,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH5_BATTERY,
|
||||
translation_key=CH5_BATTERY,
|
||||
icon="mdi:battery-unknown",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
value_fn=lambda data: data,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH6_BATTERY,
|
||||
|
|
@ -419,14 +408,14 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
translation_key=CH7_BATTERY,
|
||||
icon="mdi:battery-unknown",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
value_fn=lambda data: data,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CH8_BATTERY,
|
||||
translation_key=CH8_BATTERY,
|
||||
icon="mdi:battery-unknown",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
value_fn=lambda data: data,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=HEAT_INDEX,
|
||||
|
|
@ -437,7 +426,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=HEAT_INDEX,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=CHILL_INDEX,
|
||||
|
|
@ -448,7 +437,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
suggested_display_precision=2,
|
||||
icon="mdi:weather-sunny",
|
||||
translation_key=CHILL_INDEX,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=OUTSIDE_BATTERY,
|
||||
|
|
@ -473,12 +462,8 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
WeatherSensorEntityDescription(
|
||||
key=INDOOR_BATTERY,
|
||||
translation_key=INDOOR_BATTERY,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[e.value for e in UnitOfBat],
|
||||
value_fn=None,
|
||||
value_from_data_fn=lambda data: (
|
||||
battery_level(data.get(INDOOR_BATTERY, None)).value
|
||||
),
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
value_fn=to_int,
|
||||
),
|
||||
WeatherSensorEntityDescription(
|
||||
key=WBGT_TEMP,
|
||||
|
|
@ -488,6 +473,6 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
|||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
suggested_display_precision=2,
|
||||
value_fn=lambda data: cast("int", data),
|
||||
value_fn=to_float,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
"windy": "Nastavení pro přeposílání dat na Windy",
|
||||
"pocasi": "Nastavení pro přeposlání dat na Počasí Meteo CZ",
|
||||
"ecowitt": "Nastavení pro stanice Ecowitt",
|
||||
"wslink_port_setup": "Nastavení portu WSLink Addonu",
|
||||
"migration": "Migrace statistiky senzoru"
|
||||
}
|
||||
},
|
||||
|
|
@ -108,6 +109,16 @@
|
|||
"ecowitt_enabled": "Povolit přijímání dat ze stanic Ecowitt"
|
||||
}
|
||||
},
|
||||
"wslink_port_setup": {
|
||||
"description": "Nastavení portu, kde naslouchá WSLink Addon. Slouží pro příjem diagnostik.",
|
||||
"title": "Port WSLink Addonu",
|
||||
"data": {
|
||||
"WSLINK_ADDON_PORT": "Naslouchající port WSLink Addonu"
|
||||
},
|
||||
"data_description": {
|
||||
"WSLINK_ADDON_PORT": "Zadejte port, tak jak jej máte nastavený ve WSLink Addonu."
|
||||
}
|
||||
},
|
||||
"migration": {
|
||||
"title": "Migrace statistiky senzoru.",
|
||||
"description": "Pro správnou funkci dlouhodobé statistiky je nutné provést migraci jednotky senzoru v dlouhodobé statistice. Původní jednotka dlouhodobé statistiky pro denní úhrn srážek byla v mm/d, nicméně stanice zasílá pouze data v mm bez časového rozlišení.\n\n Senzor, který má být migrován je pro denní úhrn srážek. Pokud je v seznamu již správná hodnota u senzoru pro denní úhrn (mm), pak je již migrace hotová.\n\n Výsledek migrace pro senzor: {migration_status}, přepvedeno celkem {migration_count} řádků.",
|
||||
|
|
|
|||
|
|
@ -204,8 +204,10 @@ def wind_dir_to_text(deg: float) -> UnitOfDir | None:
|
|||
Returns UnitOfDir or None
|
||||
"""
|
||||
|
||||
if deg:
|
||||
return AZIMUT[int(abs((float(deg) - 11.25) % 360) / 22.5)]
|
||||
_deg = to_float(deg)
|
||||
if _deg is not None:
|
||||
_LOGGER.debug("wind_dir: %s", AZIMUT[int(abs((_deg - 11.25) % 360) / 22.5)])
|
||||
return AZIMUT[int(abs((_deg - 11.25) % 360) / 22.5)]
|
||||
|
||||
return None
|
||||
|
||||
|
|
@ -263,11 +265,32 @@ def celsius_to_fahrenheit(celsius: float) -> float:
|
|||
return celsius * 9.0 / 5.0 + 32
|
||||
|
||||
|
||||
def _to_float(val: Any) -> float | None:
|
||||
def to_int(val: Any) -> int | None:
|
||||
"""Convert int or string to int."""
|
||||
|
||||
if val is None:
|
||||
return None
|
||||
|
||||
if isinstance(val, str) and val.strip() == "":
|
||||
return None
|
||||
|
||||
try:
|
||||
v = int(val)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
else:
|
||||
return v
|
||||
|
||||
|
||||
def to_float(val: Any) -> float | None:
|
||||
"""Convert int or string to float."""
|
||||
|
||||
if not val:
|
||||
if val is None:
|
||||
return None
|
||||
|
||||
if isinstance(val, str) and val.strip() == "":
|
||||
return None
|
||||
|
||||
try:
|
||||
v = float(val)
|
||||
except (TypeError, ValueError):
|
||||
|
|
@ -284,14 +307,14 @@ def heat_index(
|
|||
data: dict with temperature and humidity
|
||||
convert: bool, convert recieved data from Celsius to Fahrenheit
|
||||
"""
|
||||
if (temp := _to_float(data.get(OUTSIDE_TEMP))) is None:
|
||||
if (temp := to_float(data.get(OUTSIDE_TEMP))) is None:
|
||||
_LOGGER.error(
|
||||
"We are missing/invalid OUTSIDE TEMP (%s), cannot calculate wind chill index.",
|
||||
temp,
|
||||
)
|
||||
return None
|
||||
|
||||
if (rh := _to_float(data.get(OUTSIDE_HUMIDITY))) is None:
|
||||
if (rh := to_float(data.get(OUTSIDE_HUMIDITY))) is None:
|
||||
_LOGGER.error(
|
||||
"We are missing/invalid OUTSIDE HUMIDITY (%s), cannot calculate wind chill index.",
|
||||
rh,
|
||||
|
|
@ -335,8 +358,8 @@ def chill_index(
|
|||
data: dict with temperature and wind speed
|
||||
convert: bool, convert recieved data from Celsius to Fahrenheit
|
||||
"""
|
||||
temp = _to_float(data.get(OUTSIDE_TEMP))
|
||||
wind = _to_float(data.get(WIND_SPEED))
|
||||
temp = to_float(data.get(OUTSIDE_TEMP))
|
||||
wind = to_float(data.get(WIND_SPEED))
|
||||
|
||||
if temp is None:
|
||||
_LOGGER.error(
|
||||
|
|
|
|||
Loading…
Reference in New Issue