commit
6edaec73d8
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp.web
|
||||||
from aiohttp.web_exceptions import HTTPUnauthorized
|
from aiohttp.web_exceptions import HTTPUnauthorized
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
|
@ -140,11 +140,11 @@ def register_path(
|
||||||
|
|
||||||
hass_data = hass.data.setdefault(DOMAIN, {})
|
hass_data = hass.data.setdefault(DOMAIN, {})
|
||||||
debug = config.options.get(DEV_DBG)
|
debug = config.options.get(DEV_DBG)
|
||||||
_wslink = config.options.get(WSLINK)
|
_wslink = config.options.get(WSLINK, False)
|
||||||
|
|
||||||
routes: Routes = hass_data.get("routes") if "routes" in hass_data else None
|
routes: Routes = hass_data.get("routes", Routes())
|
||||||
|
|
||||||
if routes is None:
|
if not routes.routes:
|
||||||
routes = Routes()
|
routes = Routes()
|
||||||
_LOGGER.info("Routes not found, creating new routes")
|
_LOGGER.info("Routes not found, creating new routes")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Store routes info."""
|
"""Store routes info."""
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
|
|
@ -14,7 +15,7 @@ class Route:
|
||||||
|
|
||||||
url_path: str
|
url_path: str
|
||||||
route: AbstractRoute
|
route: AbstractRoute
|
||||||
handler: callable
|
handler: Callable
|
||||||
enabled: bool = False
|
enabled: bool = False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
@ -29,7 +30,7 @@ class Routes:
|
||||||
"""Initialize routes."""
|
"""Initialize routes."""
|
||||||
self.routes = {}
|
self.routes = {}
|
||||||
|
|
||||||
def switch_route(self, coordinator: callable, url_path: str):
|
def switch_route(self, coordinator: Callable, url_path: str):
|
||||||
"""Switch route."""
|
"""Switch route."""
|
||||||
|
|
||||||
for url, route in self.routes.items():
|
for url, route in self.routes.items():
|
||||||
|
|
@ -47,7 +48,7 @@ class Routes:
|
||||||
self,
|
self,
|
||||||
url_path: str,
|
url_path: str,
|
||||||
route: AbstractRoute,
|
route: AbstractRoute,
|
||||||
handler: callable,
|
handler: Callable,
|
||||||
enabled: bool = False,
|
enabled: bool = False,
|
||||||
):
|
):
|
||||||
"""Add route."""
|
"""Add route."""
|
||||||
|
|
@ -55,7 +56,7 @@ class Routes:
|
||||||
|
|
||||||
def get_route(self, url_path: str) -> Route:
|
def get_route(self, url_path: str) -> Route:
|
||||||
"""Get route."""
|
"""Get route."""
|
||||||
return self.routes.get(url_path)
|
return self.routes.get(url_path, Route)
|
||||||
|
|
||||||
def get_enabled(self) -> str:
|
def get_enabled(self) -> str:
|
||||||
"""Get enabled routes."""
|
"""Get enabled routes."""
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.sensor import RestoreSensor, SensorEntity
|
from homeassistant.components.sensor import SensorEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||||
|
|
@ -12,10 +12,10 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from . import WeatherDataUpdateCoordinator
|
from . import WeatherDataUpdateCoordinator
|
||||||
from .const import (
|
from .const import (
|
||||||
|
BATTERY_LIST,
|
||||||
CHILL_INDEX,
|
CHILL_INDEX,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
HEAT_INDEX,
|
HEAT_INDEX,
|
||||||
OUTSIDE_BATTERY,
|
|
||||||
OUTSIDE_HUMIDITY,
|
OUTSIDE_HUMIDITY,
|
||||||
OUTSIDE_TEMP,
|
OUTSIDE_TEMP,
|
||||||
SENSORS_TO_LOAD,
|
SENSORS_TO_LOAD,
|
||||||
|
|
@ -23,12 +23,12 @@ from .const import (
|
||||||
WIND_DIR,
|
WIND_DIR,
|
||||||
WIND_SPEED,
|
WIND_SPEED,
|
||||||
WSLINK,
|
WSLINK,
|
||||||
BATTERY_LIST,
|
UnitOfBat,
|
||||||
)
|
)
|
||||||
from .sensors_common import WeatherSensorEntityDescription
|
from .sensors_common import WeatherSensorEntityDescription
|
||||||
from .sensors_weather import SENSOR_TYPES_WEATHER_API
|
from .sensors_weather import SENSOR_TYPES_WEATHER_API
|
||||||
from .sensors_wslink import SENSOR_TYPES_WSLINK
|
from .sensors_wslink import SENSOR_TYPES_WSLINK
|
||||||
from .utils import chill_index, heat_index, battery_level_to_icon, battery_level_to_text
|
from .utils import battery_level_to_icon, battery_level_to_text, chill_index, heat_index
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -44,12 +44,12 @@ async def async_setup_entry(
|
||||||
|
|
||||||
sensors_to_load: list = []
|
sensors_to_load: list = []
|
||||||
sensors: list = []
|
sensors: list = []
|
||||||
_wslink = config_entry.data.get(WSLINK)
|
_wslink = config_entry.options.get(WSLINK)
|
||||||
|
|
||||||
SENSOR_TYPES = SENSOR_TYPES_WSLINK if _wslink else SENSOR_TYPES_WEATHER_API
|
SENSOR_TYPES = SENSOR_TYPES_WSLINK if _wslink else SENSOR_TYPES_WEATHER_API
|
||||||
|
|
||||||
# Check if we have some sensors to load.
|
# Check if we have some sensors to load.
|
||||||
if sensors_to_load := config_entry.options.get(SENSORS_TO_LOAD):
|
if sensors_to_load := config_entry.options.get(SENSORS_TO_LOAD, []):
|
||||||
if WIND_DIR in sensors_to_load:
|
if WIND_DIR in sensors_to_load:
|
||||||
sensors_to_load.append(WIND_AZIMUT)
|
sensors_to_load.append(WIND_AZIMUT)
|
||||||
if (OUTSIDE_HUMIDITY in sensors_to_load) and (OUTSIDE_TEMP in sensors_to_load):
|
if (OUTSIDE_HUMIDITY in sensors_to_load) and (OUTSIDE_TEMP in sensors_to_load):
|
||||||
|
|
@ -65,9 +65,9 @@ async def async_setup_entry(
|
||||||
async_add_entities(sensors)
|
async_add_entities(sensors)
|
||||||
|
|
||||||
|
|
||||||
class WeatherSensor(
|
class WeatherSensor( # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
CoordinatorEntity[WeatherDataUpdateCoordinator], RestoreSensor, SensorEntity
|
CoordinatorEntity[WeatherDataUpdateCoordinator], SensorEntity
|
||||||
):
|
): # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
"""Implementation of Weather Sensor entity."""
|
"""Implementation of Weather Sensor entity."""
|
||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
|
@ -94,12 +94,6 @@ class WeatherSensor(
|
||||||
|
|
||||||
self.coordinator.async_add_listener(self._handle_coordinator_update)
|
self.coordinator.async_add_listener(self._handle_coordinator_update)
|
||||||
|
|
||||||
# prev_state_data = await self.async_get_last_sensor_data()
|
|
||||||
# prev_state = await self.async_get_last_state()
|
|
||||||
# if not prev_state:
|
|
||||||
# return
|
|
||||||
# self._data = prev_state_data.native_value
|
|
||||||
|
|
||||||
@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."""
|
||||||
|
|
@ -110,30 +104,30 @@ class WeatherSensor(
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> str | int | float | None:
|
def native_value(self): # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
"""Return value of entity."""
|
"""Return value of entity."""
|
||||||
|
|
||||||
_wslink = self.coordinator.config.options.get(WSLINK)
|
_wslink = self.coordinator.config.options.get(WSLINK)
|
||||||
|
|
||||||
if self.coordinator.data and (WIND_AZIMUT in self.entity_description.key):
|
if self.coordinator.data and (WIND_AZIMUT in self.entity_description.key):
|
||||||
return self.entity_description.value_fn(self.coordinator.data.get(WIND_DIR))
|
return self.entity_description.value_fn(self.coordinator.data.get(WIND_DIR)) # pyright: ignore[ reportAttributeAccessIssue]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.coordinator.data
|
self.coordinator.data
|
||||||
and (HEAT_INDEX in self.entity_description.key)
|
and (HEAT_INDEX in self.entity_description.key)
|
||||||
and not _wslink
|
and not _wslink
|
||||||
):
|
):
|
||||||
return self.entity_description.value_fn(heat_index(self.coordinator.data))
|
return self.entity_description.value_fn(heat_index(self.coordinator.data)) # pyright: ignore[ reportAttributeAccessIssue]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.coordinator.data
|
self.coordinator.data
|
||||||
and (CHILL_INDEX in self.entity_description.key)
|
and (CHILL_INDEX in self.entity_description.key)
|
||||||
and not _wslink
|
and not _wslink
|
||||||
):
|
):
|
||||||
return self.entity_description.value_fn(chill_index(self.coordinator.data))
|
return self.entity_description.value_fn(chill_index(self.coordinator.data)) # pyright: ignore[ reportAttributeAccessIssue]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
None if self._data == "" else self.entity_description.value_fn(self._data)
|
None if self._data == "" else self.entity_description.value_fn(self._data) # pyright: ignore[ reportAttributeAccessIssue]
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -142,19 +136,20 @@ class WeatherSensor(
|
||||||
return generate_entity_id("sensor.{}", self.entity_description.key)
|
return generate_entity_id("sensor.{}", self.entity_description.key)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self) -> str | None:
|
def icon(self) -> str | None: # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
"""Return the dynamic icon for battery representation."""
|
"""Return the dynamic icon for battery representation."""
|
||||||
|
|
||||||
if self.entity_description.key in BATTERY_LIST:
|
if self.entity_description.key in BATTERY_LIST:
|
||||||
try:
|
if self.native_value:
|
||||||
return battery_level_to_icon(self.native_value)
|
battery_level = battery_level_to_text(self.native_value)
|
||||||
except Exception:
|
return battery_level_to_icon(battery_level)
|
||||||
return "mdi:battery-unknown"
|
|
||||||
|
return battery_level_to_icon(UnitOfBat.UNKNOWN)
|
||||||
|
|
||||||
return self.entity_description.icon
|
return self.entity_description.icon
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self) -> DeviceInfo:
|
def device_info(self) -> DeviceInfo: # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
"""Device info."""
|
"""Device info."""
|
||||||
return DeviceInfo(
|
return DeviceInfo(
|
||||||
connections=set(),
|
connections=set(),
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,11 @@ from homeassistant.const import (
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
BARO_PRESSURE,
|
BARO_PRESSURE,
|
||||||
|
CH2_BATTERY,
|
||||||
CH2_HUMIDITY,
|
CH2_HUMIDITY,
|
||||||
CH2_TEMP,
|
CH2_TEMP,
|
||||||
CH2_BATTERY,
|
|
||||||
INDOOR_BATTERY,
|
|
||||||
CH3_HUMIDITY,
|
CH3_HUMIDITY,
|
||||||
CH3_TEMP,
|
CH3_TEMP,
|
||||||
CH4_HUMIDITY,
|
|
||||||
CH4_TEMP,
|
|
||||||
CHILL_INDEX,
|
CHILL_INDEX,
|
||||||
DAILY_RAIN,
|
DAILY_RAIN,
|
||||||
DEW_POINT,
|
DEW_POINT,
|
||||||
|
|
@ -33,7 +30,6 @@ from .const import (
|
||||||
INDOOR_BATTERY,
|
INDOOR_BATTERY,
|
||||||
INDOOR_HUMIDITY,
|
INDOOR_HUMIDITY,
|
||||||
INDOOR_TEMP,
|
INDOOR_TEMP,
|
||||||
INDOOR_BATTERY,
|
|
||||||
MONTHLY_RAIN,
|
MONTHLY_RAIN,
|
||||||
OUTSIDE_BATTERY,
|
OUTSIDE_BATTERY,
|
||||||
OUTSIDE_HUMIDITY,
|
OUTSIDE_HUMIDITY,
|
||||||
|
|
@ -41,6 +37,7 @@ from .const import (
|
||||||
RAIN,
|
RAIN,
|
||||||
SOLAR_RADIATION,
|
SOLAR_RADIATION,
|
||||||
UV,
|
UV,
|
||||||
|
WBGT_TEMP,
|
||||||
WEEKLY_RAIN,
|
WEEKLY_RAIN,
|
||||||
WIND_AZIMUT,
|
WIND_AZIMUT,
|
||||||
WIND_DIR,
|
WIND_DIR,
|
||||||
|
|
@ -48,10 +45,9 @@ from .const import (
|
||||||
WIND_SPEED,
|
WIND_SPEED,
|
||||||
YEARLY_RAIN,
|
YEARLY_RAIN,
|
||||||
UnitOfDir,
|
UnitOfDir,
|
||||||
WBGT_TEMP,
|
|
||||||
)
|
)
|
||||||
from .sensors_common import WeatherSensorEntityDescription
|
from .sensors_common import WeatherSensorEntityDescription
|
||||||
from .utils import battery_level_to_icon, battery_level_to_text, wind_dir_to_text
|
from .utils import wind_dir_to_text
|
||||||
|
|
||||||
SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
||||||
WeatherSensorEntityDescription(
|
WeatherSensorEntityDescription(
|
||||||
|
|
@ -258,7 +254,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
||||||
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
icon="mdi:weather-sunny",
|
icon="mdi:weather-sunny",
|
||||||
translation_key=CH3_TEMP,
|
translation_key=CH3_TEMP,
|
||||||
value_fn=lambda data: cast(float, data),
|
value_fn=lambda data: cast("float", data),
|
||||||
),
|
),
|
||||||
WeatherSensorEntityDescription(
|
WeatherSensorEntityDescription(
|
||||||
key=CH3_HUMIDITY,
|
key=CH3_HUMIDITY,
|
||||||
|
|
@ -267,7 +263,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
||||||
device_class=SensorDeviceClass.HUMIDITY,
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
icon="mdi:weather-sunny",
|
icon="mdi:weather-sunny",
|
||||||
translation_key=CH3_HUMIDITY,
|
translation_key=CH3_HUMIDITY,
|
||||||
value_fn=lambda data: cast(int, data),
|
value_fn=lambda data: cast("int", data),
|
||||||
),
|
),
|
||||||
# WeatherSensorEntityDescription(
|
# WeatherSensorEntityDescription(
|
||||||
# key=CH4_TEMP,
|
# key=CH4_TEMP,
|
||||||
|
|
@ -315,21 +311,21 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
|
||||||
translation_key=OUTSIDE_BATTERY,
|
translation_key=OUTSIDE_BATTERY,
|
||||||
icon="mdi:battery-unknown",
|
icon="mdi:battery-unknown",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
value_fn=lambda data: battery_level_to_text(data),
|
value_fn=lambda data: (data),
|
||||||
),
|
),
|
||||||
WeatherSensorEntityDescription(
|
WeatherSensorEntityDescription(
|
||||||
key=CH2_BATTERY,
|
key=CH2_BATTERY,
|
||||||
translation_key=CH2_BATTERY,
|
translation_key=CH2_BATTERY,
|
||||||
icon="mdi:battery-unknown",
|
icon="mdi:battery-unknown",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
value_fn=lambda data: battery_level_to_text(data),
|
value_fn=lambda data: (data),
|
||||||
),
|
),
|
||||||
WeatherSensorEntityDescription(
|
WeatherSensorEntityDescription(
|
||||||
key=INDOOR_BATTERY,
|
key=INDOOR_BATTERY,
|
||||||
translation_key=INDOOR_BATTERY,
|
translation_key=INDOOR_BATTERY,
|
||||||
icon="mdi:battery-unknown",
|
icon="mdi:battery-unknown",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
value_fn=lambda data: battery_level_to_text(data),
|
value_fn=lambda data: (data),
|
||||||
),
|
),
|
||||||
WeatherSensorEntityDescription(
|
WeatherSensorEntityDescription(
|
||||||
key=WBGT_TEMP,
|
key=WBGT_TEMP,
|
||||||
|
|
|
||||||
|
|
@ -73,16 +73,16 @@
|
||||||
"description": "Resend data to Pocasi Meteo CZ",
|
"description": "Resend data to Pocasi Meteo CZ",
|
||||||
"title": "Configure Pocasi Meteo CZ",
|
"title": "Configure Pocasi Meteo CZ",
|
||||||
"data": {
|
"data": {
|
||||||
"POCASI_API_ID": "ID from your Pocasi Meteo APP",
|
"POCASI_CZ_API_ID": "ID from your Pocasi Meteo APP",
|
||||||
"POCASI_API_KEY": "Key from your Pocasi Meteo APP",
|
"POCASI_CZ_API_KEY": "Key from your Pocasi Meteo APP",
|
||||||
"POCASI_SEND_INTERVAL": "Resend interval in seconds",
|
"POCASI_CZ_SEND_INTERVAL": "Resend interval in seconds",
|
||||||
"pocasi_enabled_checkbox": "Enable resending data to Pocasi Meteo",
|
"pocasi_enabled_checkbox": "Enable resending data to Pocasi Meteo",
|
||||||
"pocasi_logger_checkbox": "Log data and responses"
|
"pocasi_logger_checkbox": "Log data and responses"
|
||||||
},
|
},
|
||||||
"data_description": {
|
"data_description": {
|
||||||
"POCASI_API_ID": "You can obtain your ID in Pocasi Meteo App",
|
"POCASI_CZ_API_ID": "You can obtain your ID in Pocasi Meteo App",
|
||||||
"POCASI_API_KEY": "You can obtain your KEY in Pocasi Meteo App",
|
"POCASI_CZ_API_KEY": "You can obtain your KEY in Pocasi Meteo App",
|
||||||
"POCASI_SEND_INTERVAL": "Resend interval in seconds (minimum 12s, default 30s)",
|
"POCASI_CZ_SEND_INTERVAL": "Resend interval in seconds (minimum 12s, default 30s)",
|
||||||
"pocasi_enabled_checkbox": "Enables resending data to Pocasi Meteo",
|
"pocasi_enabled_checkbox": "Enables resending data to Pocasi Meteo",
|
||||||
"pocasi_logger_checkbox": "Enable only if you want to send debbug data to the developer"
|
"pocasi_logger_checkbox": "Enable only if you want to send debbug data to the developer"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,16 +73,16 @@
|
||||||
"description": "Resend data to Pocasi Meteo CZ",
|
"description": "Resend data to Pocasi Meteo CZ",
|
||||||
"title": "Configure Pocasi Meteo CZ",
|
"title": "Configure Pocasi Meteo CZ",
|
||||||
"data": {
|
"data": {
|
||||||
"POCASI_API_ID": "ID from your Pocasi Meteo APP",
|
"POCASI_CZ_API_ID": "ID from your Pocasi Meteo APP",
|
||||||
"POCASI_API_KEY": "Key from your Pocasi Meteo APP",
|
"POCASI_CZ_API_KEY": "Key from your Pocasi Meteo APP",
|
||||||
"POCASI_SEND_INTERVAL": "Resend interval in seconds",
|
"POCASI_CZ_SEND_INTERVAL": "Resend interval in seconds",
|
||||||
"pocasi_enabled_checkbox": "Enable resending data to Pocasi Meteo",
|
"pocasi_enabled_checkbox": "Enable resending data to Pocasi Meteo",
|
||||||
"pocasi_logger_checkbox": "Log data and responses"
|
"pocasi_logger_checkbox": "Log data and responses"
|
||||||
},
|
},
|
||||||
"data_description": {
|
"data_description": {
|
||||||
"POCASI_API_ID": "You can obtain your ID in Pocasi Meteo App",
|
"POCASI_CZ_API_ID": "You can obtain your ID in Pocasi Meteo App",
|
||||||
"POCASI_API_KEY": "You can obtain your KEY in Pocasi Meteo App",
|
"POCASI_CZ_API_KEY": "You can obtain your KEY in Pocasi Meteo App",
|
||||||
"POCASI_SEND_INTERVAL": "Resend interval in seconds (minimum 12s, default 30s)",
|
"POCASI_CZ_SEND_INTERVAL": "Resend interval in seconds (minimum 12s, default 30s)",
|
||||||
"pocasi_enabled_checkbox": "Enables resending data to Pocasi Meteo",
|
"pocasi_enabled_checkbox": "Enables resending data to Pocasi Meteo",
|
||||||
"pocasi_logger_checkbox": "Enable only if you want to send debbug data to the developer"
|
"pocasi_logger_checkbox": "Enable only if you want to send debbug data to the developer"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,11 @@ import numpy as np
|
||||||
|
|
||||||
from homeassistant.components import persistent_notification
|
from homeassistant.components import persistent_notification
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
|
||||||
UnitOfPrecipitationDepth,
|
|
||||||
UnitOfTemperature,
|
|
||||||
UnitOfVolumetricFlux,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.translation import async_get_translations
|
from homeassistant.helpers.translation import async_get_translations
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
AZIMUT,
|
AZIMUT,
|
||||||
BATTERY_LEVEL,
|
|
||||||
DATABASE_PATH,
|
DATABASE_PATH,
|
||||||
DEV_DBG,
|
DEV_DBG,
|
||||||
OUTSIDE_HUMIDITY,
|
OUTSIDE_HUMIDITY,
|
||||||
|
|
@ -29,8 +23,8 @@ from .const import (
|
||||||
REMAP_WSLINK_ITEMS,
|
REMAP_WSLINK_ITEMS,
|
||||||
SENSORS_TO_LOAD,
|
SENSORS_TO_LOAD,
|
||||||
WIND_SPEED,
|
WIND_SPEED,
|
||||||
UnitOfDir,
|
|
||||||
UnitOfBat,
|
UnitOfBat,
|
||||||
|
UnitOfDir,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
@ -55,7 +49,7 @@ async def translations(
|
||||||
)
|
)
|
||||||
if localize_key in _translations:
|
if localize_key in _translations:
|
||||||
return _translations[localize_key]
|
return _translations[localize_key]
|
||||||
return None
|
return ""
|
||||||
|
|
||||||
|
|
||||||
async def translated_notification(
|
async def translated_notification(
|
||||||
|
|
@ -67,7 +61,7 @@ async def translated_notification(
|
||||||
*,
|
*,
|
||||||
key: str = "message",
|
key: str = "message",
|
||||||
category: str = "notify",
|
category: str = "notify",
|
||||||
) -> str:
|
):
|
||||||
"""Translate notification."""
|
"""Translate notification."""
|
||||||
|
|
||||||
localize_key = f"component.{translation_domain}.{category}.{translation_key}.{key}"
|
localize_key = f"component.{translation_domain}.{category}.{translation_key}.{key}"
|
||||||
|
|
@ -98,7 +92,7 @@ async def translated_notification(
|
||||||
|
|
||||||
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:
|
) -> bool:
|
||||||
"""Update config.options entry."""
|
"""Update config.options entry."""
|
||||||
conf = {**entry.options}
|
conf = {**entry.options}
|
||||||
conf[update_key] = update_value
|
conf[update_key] = update_value
|
||||||
|
|
@ -153,7 +147,7 @@ def check_disabled(
|
||||||
Returns list of found sensors or None
|
Returns list of found sensors or None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
log: bool = config_entry.options.get(DEV_DBG)
|
log: bool = config_entry.options.get(DEV_DBG, False)
|
||||||
entityFound: bool = False
|
entityFound: bool = False
|
||||||
_loaded_sensors = loaded_sensors(config_entry)
|
_loaded_sensors = loaded_sensors(config_entry)
|
||||||
missing_sensors: list = []
|
missing_sensors: list = []
|
||||||
|
|
@ -189,10 +183,15 @@ def battery_level_to_text(battery: int) -> UnitOfBat:
|
||||||
Returns UnitOfBat
|
Returns UnitOfBat
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return {
|
level_map: dict[int, UnitOfBat] = {
|
||||||
0: UnitOfBat.LOW,
|
0: UnitOfBat.LOW,
|
||||||
1: UnitOfBat.NORMAL,
|
1: UnitOfBat.NORMAL,
|
||||||
}.get(int(battery) if battery is not None else None, UnitOfBat.UNKNOWN)
|
}
|
||||||
|
|
||||||
|
if battery is None:
|
||||||
|
return UnitOfBat.UNKNOWN
|
||||||
|
|
||||||
|
return level_map.get(int(battery), UnitOfBat.UNKNOWN)
|
||||||
|
|
||||||
|
|
||||||
def battery_level_to_icon(battery: UnitOfBat) -> str:
|
def battery_level_to_icon(battery: UnitOfBat) -> str:
|
||||||
|
|
@ -219,7 +218,7 @@ def celsius_to_fahrenheit(celsius: float) -> float:
|
||||||
return celsius * 9.0 / 5.0 + 32
|
return celsius * 9.0 / 5.0 + 32
|
||||||
|
|
||||||
|
|
||||||
def heat_index(data: Any, convert: bool = False) -> UnitOfTemperature:
|
def heat_index(data: Any, convert: bool = False) -> float:
|
||||||
"""Calculate heat index from temperature.
|
"""Calculate heat index from temperature.
|
||||||
|
|
||||||
data: dict with temperature and humidity
|
data: dict with temperature and humidity
|
||||||
|
|
@ -257,7 +256,7 @@ def heat_index(data: Any, convert: bool = False) -> UnitOfTemperature:
|
||||||
return simple
|
return simple
|
||||||
|
|
||||||
|
|
||||||
def chill_index(data: Any, convert: bool = False) -> UnitOfTemperature:
|
def chill_index(data: Any, convert: bool = False) -> float:
|
||||||
"""Calculate wind chill index from temperature and wind speed.
|
"""Calculate wind chill index from temperature and wind speed.
|
||||||
|
|
||||||
data: dict with temperature and wind speed
|
data: dict with temperature and wind speed
|
||||||
|
|
@ -286,7 +285,7 @@ def chill_index(data: Any, convert: bool = False) -> UnitOfTemperature:
|
||||||
|
|
||||||
def long_term_units_in_statistics_meta():
|
def long_term_units_in_statistics_meta():
|
||||||
"""Get units in long term statitstics."""
|
"""Get units in long term statitstics."""
|
||||||
|
sensor_units = []
|
||||||
if not Path(DATABASE_PATH).exists():
|
if not Path(DATABASE_PATH).exists():
|
||||||
_LOGGER.error("Database file not found: %s", DATABASE_PATH)
|
_LOGGER.error("Database file not found: %s", DATABASE_PATH)
|
||||||
return False
|
return False
|
||||||
|
|
@ -314,7 +313,7 @@ def long_term_units_in_statistics_meta():
|
||||||
return sensor_units
|
return sensor_units
|
||||||
|
|
||||||
|
|
||||||
async def migrate_data(hass: HomeAssistant, sensor_id: str | None = None) -> bool:
|
async def migrate_data(hass: HomeAssistant, sensor_id: str | None = None) -> int | bool:
|
||||||
"""Migrate data from mm/d to mm."""
|
"""Migrate data from mm/d to mm."""
|
||||||
|
|
||||||
_LOGGER.debug("Sensor %s is required for data migration", sensor_id)
|
_LOGGER.debug("Sensor %s is required for data migration", sensor_id)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from aiohttp.client_exceptions import ClientError
|
||||||
|
|
||||||
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.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
@ -138,20 +140,20 @@ class WindyPush:
|
||||||
_LOGGER.critical(WINDY_INVALID_KEY)
|
_LOGGER.critical(WINDY_INVALID_KEY)
|
||||||
text_for_test = WINDY_INVALID_KEY
|
text_for_test = WINDY_INVALID_KEY
|
||||||
|
|
||||||
update_options(self.hass, self.config, WINDY_ENABLED, False)
|
await update_options(self.hass, self.config, WINDY_ENABLED, False)
|
||||||
|
|
||||||
except WindySuccess:
|
except WindySuccess:
|
||||||
if self.log:
|
if self.log:
|
||||||
_LOGGER.info(WINDY_SUCCESS)
|
_LOGGER.info(WINDY_SUCCESS)
|
||||||
text_for_test = WINDY_SUCCESS
|
text_for_test = WINDY_SUCCESS
|
||||||
|
|
||||||
except session.ClientError as ex:
|
except ClientError as ex:
|
||||||
_LOGGER.critical("Invalid response from Windy: %s", str(ex))
|
_LOGGER.critical("Invalid response from Windy: %s", str(ex))
|
||||||
self.invalid_response_count += 1
|
self.invalid_response_count += 1
|
||||||
if self.invalid_response_count > 3:
|
if self.invalid_response_count > 3:
|
||||||
_LOGGER.critical(WINDY_UNEXPECTED)
|
_LOGGER.critical(WINDY_UNEXPECTED)
|
||||||
text_for_test = WINDY_UNEXPECTED
|
text_for_test = WINDY_UNEXPECTED
|
||||||
update_options(self.hass, self.config, WINDY_ENABLED, False)
|
await update_options(self.hass, self.config, WINDY_ENABLED, False)
|
||||||
|
|
||||||
self.last_update = datetime.now()
|
self.last_update = datetime.now()
|
||||||
self.next_update = self.last_update + timed(minutes=5)
|
self.next_update = self.last_update + timed(minutes=5)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue