Compare commits

..

No commits in common. "e737fb16d3802b4d004fee7334417c5628f094cd" and "63660006ead91b6c258bd6b1f1b1e7086e087b71" have entirely different histories.

10 changed files with 215 additions and 259 deletions

View File

@ -36,7 +36,11 @@ 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 (
@ -211,7 +215,9 @@ 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.
@ -268,7 +274,9 @@ 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 add_new_sensors # noqa: PLC0415 (local import is intentional)
from .sensor import ( # noqa: PLC0415 (local import is intentional)
add_new_sensors,
)
add_new_sensors(self.hass, self.config, newly_discovered)
@ -286,7 +294,9 @@ 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)
@ -332,22 +342,38 @@ 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,
@ -423,7 +449,9 @@ 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())
@ -459,8 +487,14 @@ 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 = {
@ -473,7 +507,9 @@ 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.

View File

@ -1,53 +0,0 @@
"""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

View File

@ -1,24 +0,0 @@
"""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,
),
)

View File

@ -6,7 +6,12 @@ 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
@ -18,6 +23,7 @@ from .const import (
DOMAIN,
ECOWITT_ENABLED,
ECOWITT_WEBHOOK_ID,
# HEALTH_BEARER_TOKEN,
INVALID_CREDENTIALS,
POCASI_CZ_API_ID,
POCASI_CZ_API_KEY,
@ -31,7 +37,6 @@ from .const import (
WINDY_STATION_ID,
WINDY_STATION_PW,
WSLINK,
WSLINK_ADDON_PORT,
)
@ -60,8 +65,6 @@ 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."""
@ -91,17 +94,22 @@ 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],
@ -112,18 +120,28 @@ 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),
@ -135,13 +153,11 @@ 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", "wslink_port_setup", "ecowitt", "windy", "pocasi"]
step_id="init", menu_options=["basic", "ecowitt", "windy", "pocasi"]
)
async def async_step_basic(self, user_input: Any = None):
@ -278,28 +294,6 @@ 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."""
@ -309,7 +303,6 @@ class ConfigOptionsFlowHandler(OptionsFlow):
**self.pocasi_cz,
**self.sensors,
**self.ecowitt,
**self.wslink_addon_port,
**dict(data),
}
@ -346,7 +339,9 @@ 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",

View File

@ -143,7 +143,6 @@ 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",
@ -236,20 +235,28 @@ 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_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_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 = [

View File

@ -40,7 +40,6 @@ from .const import (
POCASI_CZ_ENABLED,
WINDY_ENABLED,
WSLINK,
WSLINK_ADDON_PORT,
WSLINK_URL,
)
from .data import ENTRY_HEALTH_DATA
@ -79,7 +78,9 @@ 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,
@ -116,8 +117,12 @@ 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)
),
},
}
@ -185,7 +190,9 @@ 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]:
@ -194,10 +201,8 @@ class HealthCoordinator(DataUpdateCoordinator):
url = get_url(self.hass)
ip = await async_get_source_ip(self.hass)
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"
health_url = f"https://{ip}/healthz"
info_url = f"https://{ip}/status/internal"
data = deepcopy(self.data)
addon = data["addon"]
@ -240,7 +245,9 @@ 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),
@ -251,7 +258,9 @@ 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:

View File

@ -1,5 +1,7 @@
"""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,
@ -39,7 +41,7 @@ from .const import (
UnitOfDir,
)
from .sensors_common import WeatherSensorEntityDescription
from .utils import chill_index, heat_index, to_float, to_int, wind_dir_to_text
from .utils import chill_index, heat_index, wind_dir_to_text
SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
@ -49,7 +51,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.TEMPERATURE,
translation_key=INDOOR_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=INDOOR_HUMIDITY,
@ -58,7 +60,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.HUMIDITY,
translation_key=INDOOR_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=OUTSIDE_TEMP,
@ -67,7 +69,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.TEMPERATURE,
translation_key=OUTSIDE_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=OUTSIDE_HUMIDITY,
@ -76,7 +78,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.HUMIDITY,
translation_key=OUTSIDE_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=DEW_POINT,
@ -85,7 +87,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer-lines",
device_class=SensorDeviceClass.TEMPERATURE,
translation_key=DEW_POINT,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=BARO_PRESSURE,
@ -95,7 +97,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
suggested_unit_of_measurement=UnitOfPressure.HPA,
translation_key=BARO_PRESSURE,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=WIND_SPEED,
@ -105,7 +107,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=to_float,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=WIND_GUST,
@ -115,7 +117,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
icon="mdi:windsock",
translation_key=WIND_GUST,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=WIND_DIR,
@ -125,12 +127,15 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=None,
icon="mdi:sign-direction",
translation_key=WIND_DIR,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=WIND_AZIMUT,
icon="mdi:sign-direction",
value_from_data_fn=lambda dir: wind_dir_to_text(dir.get(WIND_DIR, 0.0)),
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))
),
device_class=SensorDeviceClass.ENUM,
options=[e.value for e in UnitOfDir],
translation_key=WIND_AZIMUT,
@ -144,7 +149,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=DAILY_RAIN,
@ -155,7 +160,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=DAILY_RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=SOLAR_RADIATION,
@ -164,7 +169,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.IRRADIANCE,
icon="mdi:weather-sunny",
translation_key=SOLAR_RADIATION,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=UV,
@ -173,7 +178,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
native_unit_of_measurement=UV_INDEX,
icon="mdi:sunglasses",
translation_key=UV,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH2_TEMP,
@ -183,7 +188,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH2_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH2_HUMIDITY,
@ -192,7 +197,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH2_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH3_TEMP,
@ -202,7 +207,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH3_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH3_HUMIDITY,
@ -211,7 +216,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH3_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH4_TEMP,
@ -221,7 +226,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH4_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH4_HUMIDITY,
@ -230,7 +235,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH4_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=HEAT_INDEX,
@ -241,7 +246,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-sunny",
translation_key=HEAT_INDEX,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
value_from_data_fn=heat_index,
),
WeatherSensorEntityDescription(
@ -253,7 +258,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-sunny",
translation_key=CHILL_INDEX,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
value_from_data_fn=chill_index,
),
)

View File

@ -1,5 +1,7 @@
"""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,
@ -62,7 +64,7 @@ from .const import (
UnitOfDir,
)
from .sensors_common import WeatherSensorEntityDescription
from .utils import battery_level, to_float, to_int, wind_dir_to_text
from .utils import battery_level, wind_dir_to_text
SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
@ -72,7 +74,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.TEMPERATURE,
translation_key=INDOOR_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=INDOOR_HUMIDITY,
@ -81,7 +83,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.HUMIDITY,
translation_key=INDOOR_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=OUTSIDE_TEMP,
@ -90,7 +92,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.TEMPERATURE,
translation_key=OUTSIDE_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=OUTSIDE_HUMIDITY,
@ -99,7 +101,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer",
device_class=SensorDeviceClass.HUMIDITY,
translation_key=OUTSIDE_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=DEW_POINT,
@ -108,7 +110,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
icon="mdi:thermometer-lines",
device_class=SensorDeviceClass.TEMPERATURE,
translation_key=DEW_POINT,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=BARO_PRESSURE,
@ -118,7 +120,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
suggested_unit_of_measurement=UnitOfPressure.HPA,
translation_key=BARO_PRESSURE,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=WIND_SPEED,
@ -128,7 +130,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
icon="mdi:weather-windy",
translation_key=WIND_SPEED,
value_fn=to_float,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=WIND_GUST,
@ -138,7 +140,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
icon="mdi:windsock",
translation_key=WIND_GUST,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=WIND_DIR,
@ -148,12 +150,15 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=None,
icon="mdi:sign-direction",
translation_key=WIND_DIR,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=WIND_AZIMUT,
icon="mdi:sign-direction",
value_from_data_fn=lambda dir: wind_dir_to_text(dir.get(WIND_DIR, 0.0)),
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))
),
device_class=SensorDeviceClass.ENUM,
options=[e.value for e in UnitOfDir],
translation_key=WIND_AZIMUT,
@ -167,7 +172,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=DAILY_RAIN,
@ -178,7 +183,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=DAILY_RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=HOURLY_RAIN,
@ -189,7 +194,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=HOURLY_RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=WEEKLY_RAIN,
@ -200,7 +205,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=WEEKLY_RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=MONTHLY_RAIN,
@ -211,7 +216,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=MONTHLY_RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=YEARLY_RAIN,
@ -222,7 +227,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=YEARLY_RAIN,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=SOLAR_RADIATION,
@ -231,7 +236,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.IRRADIANCE,
icon="mdi:weather-sunny",
translation_key=SOLAR_RADIATION,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=UV,
@ -240,7 +245,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
native_unit_of_measurement=UV_INDEX,
icon="mdi:sunglasses",
translation_key=UV,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH2_TEMP,
@ -250,7 +255,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH2_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH2_HUMIDITY,
@ -259,7 +264,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH2_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH3_TEMP,
@ -269,7 +274,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH3_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH3_HUMIDITY,
@ -278,7 +283,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH3_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH4_TEMP,
@ -288,7 +293,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH4_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH4_HUMIDITY,
@ -297,7 +302,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH4_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH5_TEMP,
@ -307,7 +312,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH5_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH5_HUMIDITY,
@ -316,7 +321,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH5_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH6_TEMP,
@ -326,7 +331,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH6_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH6_HUMIDITY,
@ -335,7 +340,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH6_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH7_TEMP,
@ -345,7 +350,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH7_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH7_HUMIDITY,
@ -354,7 +359,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH7_HUMIDITY,
value_fn=to_int,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH8_TEMP,
@ -364,7 +369,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
icon="mdi:weather-sunny",
translation_key=CH8_TEMP,
value_fn=to_float,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH8_HUMIDITY,
@ -373,28 +378,34 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH8_HUMIDITY,
value_fn=to_int,
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,
),
WeatherSensorEntityDescription(
key=CH3_BATTERY,
translation_key=CH3_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=to_int,
value_fn=lambda data: data,
),
WeatherSensorEntityDescription(
key=CH4_BATTERY,
translation_key=CH4_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=to_int,
value_fn=lambda data: data,
),
WeatherSensorEntityDescription(
key=CH5_BATTERY,
translation_key=CH5_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=to_int,
value_fn=lambda data: data,
),
WeatherSensorEntityDescription(
key=CH6_BATTERY,
@ -408,14 +419,14 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
translation_key=CH7_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=to_int,
value_fn=lambda data: data,
),
WeatherSensorEntityDescription(
key=CH8_BATTERY,
translation_key=CH8_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=to_int,
value_fn=lambda data: data,
),
WeatherSensorEntityDescription(
key=HEAT_INDEX,
@ -426,7 +437,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-sunny",
translation_key=HEAT_INDEX,
value_fn=to_float,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CHILL_INDEX,
@ -437,7 +448,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
suggested_display_precision=2,
icon="mdi:weather-sunny",
translation_key=CHILL_INDEX,
value_fn=to_float,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=OUTSIDE_BATTERY,
@ -462,8 +473,12 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
key=INDOOR_BATTERY,
translation_key=INDOOR_BATTERY,
device_class=SensorDeviceClass.BATTERY,
value_fn=to_int,
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
),
),
WeatherSensorEntityDescription(
key=WBGT_TEMP,
@ -473,6 +488,6 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
value_fn=to_float,
value_fn=lambda data: cast("int", data),
),
)

View File

@ -44,7 +44,6 @@
"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"
}
},
@ -109,16 +108,6 @@
"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ů.",

View File

@ -204,10 +204,8 @@ def wind_dir_to_text(deg: float) -> UnitOfDir | None:
Returns UnitOfDir or None
"""
_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)]
if deg:
return AZIMUT[int(abs((float(deg) - 11.25) % 360) / 22.5)]
return None
@ -265,32 +263,11 @@ def celsius_to_fahrenheit(celsius: float) -> float:
return celsius * 9.0 / 5.0 + 32
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:
def _to_float(val: Any) -> float | None:
"""Convert int or string to float."""
if val is None:
if not val:
return None
if isinstance(val, str) and val.strip() == "":
return None
try:
v = float(val)
except (TypeError, ValueError):
@ -307,14 +284,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,
@ -358,8 +335,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(