parent
b58ff1b2e5
commit
8b0cc2d25e
|
|
@ -69,6 +69,7 @@ INDOOR_HUMIDITY: Final = "indoor_humidity"
|
||||||
UV: Final = "uv"
|
UV: Final = "uv"
|
||||||
CH2_TEMP: Final = "ch2_temp"
|
CH2_TEMP: Final = "ch2_temp"
|
||||||
CH2_HUMIDITY: Final = "ch2_humidity"
|
CH2_HUMIDITY: Final = "ch2_humidity"
|
||||||
|
HEAT_INDEX: Final = "heat_index"
|
||||||
|
|
||||||
|
|
||||||
REMAP_ITEMS: dict = {
|
REMAP_ITEMS: dict = {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ from .const import (
|
||||||
DAILY_RAIN,
|
DAILY_RAIN,
|
||||||
DEW_POINT,
|
DEW_POINT,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
HEAT_INDEX,
|
||||||
INDOOR_HUMIDITY,
|
INDOOR_HUMIDITY,
|
||||||
INDOOR_TEMP,
|
INDOOR_TEMP,
|
||||||
OUTSIDE_HUMIDITY,
|
OUTSIDE_HUMIDITY,
|
||||||
|
|
@ -51,7 +52,7 @@ from .const import (
|
||||||
WIND_SPEED,
|
WIND_SPEED,
|
||||||
UnitOfDir,
|
UnitOfDir,
|
||||||
)
|
)
|
||||||
from .utils import wind_dir_to_text
|
from .utils import wind_dir_to_text, heat_index
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -215,6 +216,16 @@ SENSOR_TYPES: tuple[WeatherSensorEntityDescription, ...] = (
|
||||||
translation_key=CH2_HUMIDITY,
|
translation_key=CH2_HUMIDITY,
|
||||||
value_fn=lambda data: cast(int, data),
|
value_fn=lambda data: cast(int, data),
|
||||||
),
|
),
|
||||||
|
WeatherSensorEntityDescription(
|
||||||
|
key=HEAT_INDEX,
|
||||||
|
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
|
suggested_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
|
icon="mdi:weather-sunny",
|
||||||
|
translation_key=HEAT_INDEX,
|
||||||
|
value_fn=lambda data: cast(int, data),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -234,6 +245,8 @@ async def async_setup_entry(
|
||||||
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 (WIND_SPEED in sensors_to_load) and (OUTSIDE_TEMP in sensors_to_load):
|
||||||
|
sensors_to_load.append(HEAT_INDEX)
|
||||||
sensors = [
|
sensors = [
|
||||||
WeatherSensor(hass, description, coordinator)
|
WeatherSensor(hass, description, coordinator)
|
||||||
for description in SENSOR_TYPES
|
for description in SENSOR_TYPES
|
||||||
|
|
@ -293,6 +306,9 @@ class WeatherSensor(
|
||||||
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))
|
||||||
|
|
||||||
|
if self.coordinator.data and (HEAT_INDEX in self.entity_description.key):
|
||||||
|
return self.entity_description.value_fn(heat_index(self.coordinator.data))
|
||||||
|
|
||||||
return self.entity_description.value_fn(self._data)
|
return self.entity_description.value_fn(self._data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@
|
||||||
"solar_radiation": { "name": "Sluneční osvit" },
|
"solar_radiation": { "name": "Sluneční osvit" },
|
||||||
"ch2_temp": { "name": "Teplota senzoru 2" },
|
"ch2_temp": { "name": "Teplota senzoru 2" },
|
||||||
"ch2_humidity": { "name": "Vlhkost sensoru 2" },
|
"ch2_humidity": { "name": "Vlhkost sensoru 2" },
|
||||||
|
"heat_index": { "name": "Tepelný index" },
|
||||||
"wind_azimut": {
|
"wind_azimut": {
|
||||||
"name": "Azimut",
|
"name": "Azimut",
|
||||||
"state": {
|
"state": {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@
|
||||||
"solar_radiation": { "name": "Solar irradiance" },
|
"solar_radiation": { "name": "Solar irradiance" },
|
||||||
"ch2_temp": { "name": "Channel 2 temperature" },
|
"ch2_temp": { "name": "Channel 2 temperature" },
|
||||||
"ch2_humidity": { "name": "Channel 2 humidity" },
|
"ch2_humidity": { "name": "Channel 2 humidity" },
|
||||||
|
"heat_index": { "name": "Apparent temperature" },
|
||||||
"wind_azimut": {
|
"wind_azimut": {
|
||||||
"name": "Bearing",
|
"name": "Bearing",
|
||||||
"state": {
|
"state": {
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,31 @@ from homeassistant.components import persistent_notification
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.translation import async_get_translations
|
from homeassistant.helpers.translation import async_get_translations
|
||||||
|
from homeassistant.const import UnitOfTemperature
|
||||||
|
from typing import Any
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from .const import AZIMUT, DEV_DBG, REMAP_ITEMS, SENSORS_TO_LOAD, UnitOfDir
|
from .const import (
|
||||||
|
AZIMUT,
|
||||||
|
DEV_DBG,
|
||||||
|
REMAP_ITEMS,
|
||||||
|
SENSORS_TO_LOAD,
|
||||||
|
UnitOfDir,
|
||||||
|
OUTSIDE_TEMP,
|
||||||
|
OUTSIDE_HUMIDITY,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def translations(
|
async def translations(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
translation_domain: str,
|
translation_domain: str,
|
||||||
translation_key: str,
|
translation_key: str,
|
||||||
*,
|
*,
|
||||||
key: str = "message",
|
key: str = "message",
|
||||||
category: str = "notify"
|
category: str = "notify",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Get translated keys for domain."""
|
"""Get translated keys for domain."""
|
||||||
|
|
||||||
|
|
@ -31,6 +44,7 @@ async def translations(
|
||||||
if localize_key in _translations:
|
if localize_key in _translations:
|
||||||
return _translations[localize_key]
|
return _translations[localize_key]
|
||||||
|
|
||||||
|
|
||||||
async def translated_notification(
|
async def translated_notification(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
translation_domain: str,
|
translation_domain: str,
|
||||||
|
|
@ -39,13 +53,15 @@ async def translated_notification(
|
||||||
notification_id: str | None = None,
|
notification_id: str | None = None,
|
||||||
*,
|
*,
|
||||||
key: str = "message",
|
key: str = "message",
|
||||||
category: str = "notify"
|
category: str = "notify",
|
||||||
) -> str:
|
) -> 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}"
|
||||||
|
|
||||||
localize_title = f"component.{translation_domain}.{category}.{translation_key}.title"
|
localize_title = (
|
||||||
|
f"component.{translation_domain}.{category}.{translation_key}.title"
|
||||||
|
)
|
||||||
|
|
||||||
language = hass.config.language
|
language = hass.config.language
|
||||||
|
|
||||||
|
|
@ -97,10 +113,16 @@ def remap_items(entities):
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def loaded_sensors(config_entry: ConfigEntry) -> list | None:
|
def loaded_sensors(config_entry: ConfigEntry) -> list | None:
|
||||||
"""Get loaded sensors."""
|
"""Get loaded sensors."""
|
||||||
|
|
||||||
return config_entry.options.get(SENSORS_TO_LOAD) if config_entry.options.get(SENSORS_TO_LOAD) else []
|
return (
|
||||||
|
config_entry.options.get(SENSORS_TO_LOAD)
|
||||||
|
if config_entry.options.get(SENSORS_TO_LOAD)
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_disabled(
|
def check_disabled(
|
||||||
hass: HomeAssistant, items, config_entry: ConfigEntry
|
hass: HomeAssistant, items, config_entry: ConfigEntry
|
||||||
|
|
@ -129,6 +151,7 @@ def check_disabled(
|
||||||
|
|
||||||
return missing_sensors if entityFound else None
|
return missing_sensors if entityFound else None
|
||||||
|
|
||||||
|
|
||||||
def wind_dir_to_text(deg: float) -> UnitOfDir | None:
|
def wind_dir_to_text(deg: float) -> UnitOfDir | None:
|
||||||
"""Return wind direction in text representation.
|
"""Return wind direction in text representation.
|
||||||
|
|
||||||
|
|
@ -141,3 +164,32 @@ def wind_dir_to_text(deg: float) -> UnitOfDir | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def heat_index(data: Any) -> UnitOfTemperature:
|
||||||
|
"""Calculate heat index from temperature."""
|
||||||
|
|
||||||
|
temp = float(data[OUTSIDE_TEMP])
|
||||||
|
rh = float(data[OUTSIDE_HUMIDITY])
|
||||||
|
adjustment = None
|
||||||
|
|
||||||
|
simple = 0.5 * (temp + 61.0 + ((temp - 68.0) * 1.2) + (rh * 0.094))
|
||||||
|
if ((simple + temp) / 2) > 80:
|
||||||
|
full_index = (
|
||||||
|
-42.379
|
||||||
|
+ 2.04901523 * temp
|
||||||
|
+ 10.14333127 * rh
|
||||||
|
- 0.22475541 * temp * rh
|
||||||
|
- 0.00683783 * temp * temp
|
||||||
|
- 0.05481717 * rh * rh
|
||||||
|
+ 0.00122874 * temp * temp * rh
|
||||||
|
+ 0.00085282 * temp * rh * rh
|
||||||
|
- 0.00000199 * temp * temp * rh * rh
|
||||||
|
)
|
||||||
|
if rh < 13 and (temp in np.arange(80, 112, 0.1)):
|
||||||
|
adjustment = ((13 - rh) / 4) * math.sqrt((17 - abs(temp - 95)) / 17)
|
||||||
|
|
||||||
|
if rh > 80 and (temp in np.arange(80, 87, 0.1)):
|
||||||
|
adjustment = ((rh - 85) / 10) * ((87 - temp) / 5)
|
||||||
|
|
||||||
|
return full_index + adjustment if adjustment else full_index
|
||||||
|
|
||||||
|
return simple
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue