From ac7284770a96b8cd0f7ddd7c64695c9e2b01a9c7 Mon Sep 17 00:00:00 2001 From: schizza Date: Thu, 18 Apr 2024 20:54:57 +0200 Subject: [PATCH] New sensor fo Azimut now supported. - A new constant `WIND_AZIMUT` is added to allow creating a wind direction sensor that returns a text value from `UnitOfDir` instead of just a numeric degree value. - The wind direction sensor entity now optionally creates both a numeric wind direction sensor using `WIND_DIR` and a text-based azimuth sensor using `WIND_AZIMUT`. If the numeric one is enabled, the text one will also be added. So in summary, these changes improve the usability of wind data by adding a more human-readable text version alongside the existing numeric version. --- custom_components/sws12500/const.py | 40 +++++++++++++++++++ custom_components/sws12500/sensor.py | 17 ++++++++ custom_components/sws12500/strings.json | 23 ++++++++++- .../sws12500/translations/cs.json | 23 ++++++++++- .../sws12500/translations/en.json | 23 ++++++++++- custom_components/sws12500/utils.py | 15 ++++++- 6 files changed, 137 insertions(+), 4 deletions(-) diff --git a/custom_components/sws12500/const.py b/custom_components/sws12500/const.py index e8b0c55..c8a6439 100644 --- a/custom_components/sws12500/const.py +++ b/custom_components/sws12500/const.py @@ -1,5 +1,6 @@ """Constants.""" +from enum import StrEnum from typing import Final DOMAIN = "sws12500" @@ -59,6 +60,7 @@ OUTSIDE_HUMIDITY: Final = "outside_humidity" WIND_SPEED: Final = "wind_speed" WIND_GUST: Final = "wind_gust" WIND_DIR: Final = "wind_dir" +WIND_AZIMUT: Final = "wind_azimut" RAIN: Final = "rain" DAILY_RAIN: Final = "daily_rain" SOLAR_RADIATION: Final = "solar_radiation" @@ -89,3 +91,41 @@ REMAP_ITEMS: dict = { DISABLED_BY_DEFAULT: Final = [CH2_TEMP, CH2_HUMIDITY] +class UnitOfDir(StrEnum): + """Wind direrction azimut.""" + + NNE = "NNE" + NE = "NE" + ENE = "ENE" + E = "E" + ESE = "ESE" + SE = "SE" + SSE = "SSE" + S = "S" + SSW = "SSW" + SW = "SW" + WSW = "WSW" + W = "W" + WNW = "WNW" + NW = "NW" + NNW = "NNW" + N = "N" + +AZIMUT: list[UnitOfDir] = [ + UnitOfDir.NNE, + UnitOfDir.NE, + UnitOfDir.ENE, + UnitOfDir.E, + UnitOfDir.ESE, + UnitOfDir.SE, + UnitOfDir.SSE, + UnitOfDir.S, + UnitOfDir.SSW, + UnitOfDir.SW, + UnitOfDir.WSW, + UnitOfDir.W, + UnitOfDir.WNW, + UnitOfDir.NW, + UnitOfDir.NNW, + UnitOfDir.N, +] diff --git a/custom_components/sws12500/sensor.py b/custom_components/sws12500/sensor.py index a8d1c24..72fc409 100644 --- a/custom_components/sws12500/sensor.py +++ b/custom_components/sws12500/sensor.py @@ -45,10 +45,13 @@ from .const import ( SENSORS_TO_LOAD, SOLAR_RADIATION, UV, + WIND_AZIMUT, WIND_DIR, WIND_GUST, WIND_SPEED, + UnitOfDir, ) +from .utils import wind_dir_to_text _LOGGER = logging.getLogger(__name__) @@ -145,6 +148,14 @@ SENSOR_TYPES: tuple[WeatherSensorEntityDescription, ...] = ( translation_key=WIND_DIR, value_fn=lambda data: cast(int, data), ), + WeatherSensorEntityDescription( + key=WIND_AZIMUT, + icon="mdi:sign-direction", + value_fn=lambda data: cast(str, wind_dir_to_text(data)), + device_class=SensorDeviceClass.ENUM, + options=list(UnitOfDir), + translation_key=WIND_AZIMUT, + ), WeatherSensorEntityDescription( key=RAIN, native_unit_of_measurement=UnitOfPrecipitationDepth.INCHES, @@ -221,6 +232,8 @@ async def async_setup_entry( # Check if we have some sensors to load. if sensors_to_load := config_entry.options.get(SENSORS_TO_LOAD): + if WIND_DIR in sensors_to_load: + sensors_to_load.append(WIND_AZIMUT) sensors = [ WeatherSensor(hass, description, coordinator) for description in SENSOR_TYPES @@ -276,6 +289,10 @@ class WeatherSensor( @property def native_value(self) -> str | int | float | None: """Return value of entity.""" + + 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._data) @property diff --git a/custom_components/sws12500/strings.json b/custom_components/sws12500/strings.json index 501fe5f..07adcf3 100644 --- a/custom_components/sws12500/strings.json +++ b/custom_components/sws12500/strings.json @@ -76,7 +76,28 @@ "daily_rain": { "name": "Daily precipitation" }, "solar_radiation": { "name": "Solar irradiance" }, "ch2_temp": { "name": "Channel 2 temperature" }, - "ch2_humidity": { "name": "Channel 2 humidity" } + "ch2_humidity": { "name": "Channel 2 humidity" }, + "wind_azimut": { + "name": "Bearing", + "state": { + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW" + } + } } }, "notify": { diff --git a/custom_components/sws12500/translations/cs.json b/custom_components/sws12500/translations/cs.json index 45579cc..7bf1298 100644 --- a/custom_components/sws12500/translations/cs.json +++ b/custom_components/sws12500/translations/cs.json @@ -75,7 +75,28 @@ "daily_rain": { "name": "Denní úhrn srážek" }, "solar_radiation": { "name": "Sluneční osvit" }, "ch2_temp": { "name": "Teplota senzoru 2" }, - "ch2_humidity": { "name": "Vlhkost sensoru 2" } + "ch2_humidity": { "name": "Vlhkost sensoru 2" }, + "wind_azimut": { + "name": "Azimut", + "state": { + "N": "S", + "NNE": "SSV", + "NE": "SV", + "ENE": "VVS", + "E": "V", + "ESE": "VVJ", + "SE": "JV", + "SSE": "JJV", + "S": "J", + "SSW": "JJZ", + "SW": "JZ", + "WSW": "JZZ", + "W": "Z", + "WNW": "ZZS", + "NW": "SZ", + "NNW": "SSZ" + } + } } }, "notify": { diff --git a/custom_components/sws12500/translations/en.json b/custom_components/sws12500/translations/en.json index 501fe5f..07adcf3 100644 --- a/custom_components/sws12500/translations/en.json +++ b/custom_components/sws12500/translations/en.json @@ -76,7 +76,28 @@ "daily_rain": { "name": "Daily precipitation" }, "solar_radiation": { "name": "Solar irradiance" }, "ch2_temp": { "name": "Channel 2 temperature" }, - "ch2_humidity": { "name": "Channel 2 humidity" } + "ch2_humidity": { "name": "Channel 2 humidity" }, + "wind_azimut": { + "name": "Bearing", + "state": { + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW" + } + } } }, "notify": { diff --git a/custom_components/sws12500/utils.py b/custom_components/sws12500/utils.py index e560723..568400c 100644 --- a/custom_components/sws12500/utils.py +++ b/custom_components/sws12500/utils.py @@ -7,7 +7,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.translation import async_get_translations -from .const import DEV_DBG, REMAP_ITEMS, SENSORS_TO_LOAD +from .const import AZIMUT, DEV_DBG, REMAP_ITEMS, SENSORS_TO_LOAD, UnitOfDir _LOGGER = logging.getLogger(__name__) @@ -128,3 +128,16 @@ def check_disabled( _LOGGER.info("Add sensor (%s) to loading queue", item) return missing_sensors if entityFound else None + +def wind_dir_to_text(deg: float) -> UnitOfDir | None: + """Return wind direction in text representation. + + Returns UnitOfDir or None + """ + + if deg: + return AZIMUT[int(abs((float(deg) - 11.25) % 360) / 22.5)] + + return None + +