diff --git a/custom_components/sws12500/__init__.py b/custom_components/sws12500/__init__.py index 558d134..f7f1f45 100644 --- a/custom_components/sws12500/__init__.py +++ b/custom_components/sws12500/__init__.py @@ -97,6 +97,10 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator): self.hass, DOMAIN, f"sensor.{t_key}", key="name", category="entity" ) for t_key in sensors + if await translations( + self.hass, DOMAIN, f"sensor.{t_key}", key="name", category="entity" + ) + is not None ] human_readable = "\n".join(translate_sensors) diff --git a/custom_components/sws12500/const.py b/custom_components/sws12500/const.py index 9a60f76..19e06d6 100644 --- a/custom_components/sws12500/const.py +++ b/custom_components/sws12500/const.py @@ -60,6 +60,7 @@ BARO_PRESSURE: Final = "baro_pressure" OUTSIDE_TEMP: Final = "outside_temp" DEW_POINT: Final = "dew_point" OUTSIDE_HUMIDITY: Final = "outside_humidity" +OUTSIDE_CONNECTION: Final = "outside_connection" WIND_SPEED: Final = "wind_speed" WIND_GUST: Final = "wind_gust" WIND_DIR: Final = "wind_dir" @@ -72,10 +73,13 @@ INDOOR_HUMIDITY: Final = "indoor_humidity" UV: Final = "uv" CH2_TEMP: Final = "ch2_temp" CH2_HUMIDITY: Final = "ch2_humidity" +CH2_CONNECTION: Final = "ch2_connection" CH3_TEMP: Final = "ch3_temp" CH3_HUMIDITY: Final = "ch3_humidity" +CH3_CONNECTION: Final = "ch3_connection" CH4_TEMP: Final = "ch4_temp" CH4_HUMIDITY: Final = "ch4_humidity" +CH4_CONNECTION: Final = "ch4_connection" HEAT_INDEX: Final = "heat_index" CHILL_INDEX: Final = "chill_index" @@ -105,19 +109,37 @@ REMAP_ITEMS: dict = { REMAP_WSLINK_ITEMS: dict = { "intem": INDOOR_TEMP, "inhum": INDOOR_HUMIDITY, - "t1temp": OUTSIDE_TEMP, + "t1tem": OUTSIDE_TEMP, "t1hum": OUTSIDE_HUMIDITY, "t1dew": DEW_POINT, "t1wdir": WIND_DIR, "t1ws": WIND_SPEED, - "t1wg": WIND_GUST, + "t1wgust": WIND_GUST, "t1rainra": RAIN, "t1raindy": DAILY_RAIN, "t1solrad": SOLAR_RADIATION, "rbar": BARO_PRESSURE, - "uvi": UV + "t1uvi": UV, + "t234c1tem": CH2_TEMP, + "t234c1hum": CH2_HUMIDITY, + "t1cn": OUTSIDE_CONNECTION, + "t234c1cn": CH2_CONNECTION, + "t234c2cn": CH3_CONNECTION, + "t1chill": CHILL_INDEX, + "t1heat": HEAT_INDEX, } +# TODO: Add more sensors +# +# 'inbat' indoor battery level (1 normal, 0 low) +# 't1rainhr' hourly rain rate in mm +# 't1rainwy' weekly rain rate in mm +# 't1rainmth': monthly rain rate in mm +# 't1rainyr': yearly rain rate in mm +# 't1bat': outdoor battery level (1 normal, 0 low) +# 't234c1bat': CH2 battery level (1 normal, 0 low) CH2 in integration is CH1 in WSLink + + DISABLED_BY_DEFAULT: Final = [ CH2_TEMP, CH2_HUMIDITY, @@ -167,4 +189,3 @@ AZIMUT: list[UnitOfDir] = [ UnitOfDir.NNW, UnitOfDir.N, ] - diff --git a/custom_components/sws12500/sensor.py b/custom_components/sws12500/sensor.py index fc6888d..a0275a2 100644 --- a/custom_components/sws12500/sensor.py +++ b/custom_components/sws12500/sensor.py @@ -111,16 +111,26 @@ class WeatherSensor( def native_value(self) -> str | int | float | None: """Return value of entity.""" + _wslink = self.coordinator.config.options.get(WSLINK) + if self.coordinator.data and (WIND_AZIMUT in self.entity_description.key): return self.entity_description.value_fn(self.coordinator.data.get(WIND_DIR)) - if self.coordinator.data and (HEAT_INDEX in self.entity_description.key): + if ( + self.coordinator.data + and (HEAT_INDEX in self.entity_description.key) + and not _wslink + ): return self.entity_description.value_fn(heat_index(self.coordinator.data)) - if self.coordinator.data and (CHILL_INDEX in self.entity_description.key): + if ( + self.coordinator.data + and (CHILL_INDEX in self.entity_description.key) + and not _wslink + ): return self.entity_description.value_fn(chill_index(self.coordinator.data)) - return self.entity_description.value_fn(self._data) + return None if self._data == "" else self.entity_description.value_fn(self._data) @property def suggested_entity_id(self) -> str: diff --git a/custom_components/sws12500/sensors_weather.py b/custom_components/sws12500/sensors_weather.py index 9912633..a61750f 100644 --- a/custom_components/sws12500/sensors_weather.py +++ b/custom_components/sws12500/sensors_weather.py @@ -51,7 +51,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=INDOOR_HUMIDITY, @@ -64,12 +64,12 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = ( ), WeatherSensorEntityDescription( key=OUTSIDE_TEMP, - native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, icon="mdi:thermometer", device_class=SensorDeviceClass.TEMPERATURE, translation_key=OUTSIDE_TEMP, - value_fn=lambda data: cast(float, data), + value_fn=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=OUTSIDE_HUMIDITY, @@ -78,7 +78,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=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=DEW_POINT, @@ -87,7 +87,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=BARO_PRESSURE, @@ -97,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=lambda data: cast(float, data), + value_fn=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=WIND_SPEED, @@ -107,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=lambda data: cast(int, data), + value_fn=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=WIND_GUST, @@ -117,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=lambda data: cast(float, data), + value_fn=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=WIND_DIR, @@ -126,12 +126,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=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=WIND_AZIMUT, icon="mdi:sign-direction", - value_fn=lambda data: cast(str, wind_dir_to_text(data)), + value_fn=lambda data: cast("str", wind_dir_to_text(data)), device_class=SensorDeviceClass.ENUM, options=list(UnitOfDir), translation_key=WIND_AZIMUT, @@ -145,7 +145,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=DAILY_RAIN, @@ -156,7 +156,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=SOLAR_RADIATION, @@ -165,7 +165,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=UV, @@ -174,7 +174,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=CH2_TEMP, @@ -184,7 +184,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=CH2_HUMIDITY, @@ -193,7 +193,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=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=CH3_TEMP, @@ -203,7 +203,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=CH3_HUMIDITY, @@ -212,7 +212,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=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=CH4_TEMP, @@ -222,7 +222,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=lambda data: cast("float", data), ), WeatherSensorEntityDescription( key=CH4_HUMIDITY, @@ -231,7 +231,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=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=HEAT_INDEX, @@ -239,9 +239,10 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = ( state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.TEMPERATURE, suggested_unit_of_measurement=UnitOfTemperature.CELSIUS, + suggested_display_precision=2, icon="mdi:weather-sunny", translation_key=HEAT_INDEX, - value_fn=lambda data: cast(int, data), + value_fn=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=CHILL_INDEX, @@ -252,6 +253,6 @@ 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=lambda data: cast("int", data), ), ) diff --git a/custom_components/sws12500/sensors_wslink.py b/custom_components/sws12500/sensors_wslink.py index 880ec53..f006e05 100644 --- a/custom_components/sws12500/sensors_wslink.py +++ b/custom_components/sws12500/sensors_wslink.py @@ -176,25 +176,25 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = ( translation_key=UV, value_fn=lambda data: cast("float", data), ), - # WeatherSensorEntityDescription( - # key=CH2_TEMP, - # 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=CH2_TEMP, - # value_fn=lambda data: cast(float, data), - # ), - # WeatherSensorEntityDescription( - # key=CH2_HUMIDITY, - # native_unit_of_measurement=PERCENTAGE, - # state_class=SensorStateClass.MEASUREMENT, - # device_class=SensorDeviceClass.HUMIDITY, - # icon="mdi:weather-sunny", - # translation_key=CH2_HUMIDITY, - # value_fn=lambda data: cast(int, data), - # ), + WeatherSensorEntityDescription( + key=CH2_TEMP, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.TEMPERATURE, + suggested_unit_of_measurement=UnitOfTemperature.CELSIUS, + icon="mdi:weather-sunny", + translation_key=CH2_TEMP, + value_fn=lambda data: cast("float", data), + ), + WeatherSensorEntityDescription( + key=CH2_HUMIDITY, + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.HUMIDITY, + icon="mdi:weather-sunny", + translation_key=CH2_HUMIDITY, + value_fn=lambda data: cast("int", data), + ), # WeatherSensorEntityDescription( # key=CH3_TEMP, # native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, @@ -235,17 +235,18 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = ( # ), WeatherSensorEntityDescription( key=HEAT_INDEX, - native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.TEMPERATURE, suggested_unit_of_measurement=UnitOfTemperature.CELSIUS, + suggested_display_precision=2, icon="mdi:weather-sunny", translation_key=HEAT_INDEX, value_fn=lambda data: cast("int", data), ), WeatherSensorEntityDescription( key=CHILL_INDEX, - native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.TEMPERATURE, suggested_unit_of_measurement=UnitOfTemperature.CELSIUS, diff --git a/custom_components/sws12500/utils.py b/custom_components/sws12500/utils.py index cbf4d41..d92671c 100644 --- a/custom_components/sws12500/utils.py +++ b/custom_components/sws12500/utils.py @@ -131,9 +131,7 @@ def remap_wslink_items(entities): def loaded_sensors(config_entry: ConfigEntry) -> list | None: """Get loaded sensors.""" - return ( - config_entry.options.get(SENSORS_TO_LOAD) or [] - ) + return config_entry.options.get(SENSORS_TO_LOAD) or [] def check_disabled( @@ -176,13 +174,30 @@ def wind_dir_to_text(deg: float) -> UnitOfDir | None: return None -def heat_index(data: Any) -> UnitOfTemperature: - """Calculate heat index from temperature.""" +def fahrenheit_to_celsius(fahrenheit: float) -> float: + """Convert Fahrenheit to Celsius.""" + return (fahrenheit - 32) * 5.0 / 9.0 + + +def celsius_to_fahrenheit(celsius: float) -> float: + """Convert Celsius to Fahrenheit.""" + return celsius * 9.0 / 5.0 + 32 + + +def heat_index(data: Any, convert: bool = False) -> UnitOfTemperature: + """Calculate heat index from temperature. + + data: dict with temperature and humidity + convert: bool, convert recieved data from Celsius to Fahrenheit + """ temp = float(data[OUTSIDE_TEMP]) rh = float(data[OUTSIDE_HUMIDITY]) adjustment = None + if convert: + temp = celsius_to_fahrenheit(temp) + simple = 0.5 * (temp + 61.0 + ((temp - 68.0) * 1.2) + (rh * 0.094)) if ((simple + temp) / 2) > 80: full_index = ( @@ -207,12 +222,19 @@ def heat_index(data: Any) -> UnitOfTemperature: return simple -def chill_index(data: Any) -> UnitOfTemperature: - """Calculate wind chill index.""" +def chill_index(data: Any, convert: bool = False) -> UnitOfTemperature: + """Calculate wind chill index from temperature and wind speed. + + data: dict with temperature and wind speed + convert: bool, convert recieved data from Celsius to Fahrenheit + """ temp = float(data[OUTSIDE_TEMP]) wind = float(data[WIND_SPEED]) + if convert: + temp = celsius_to_fahrenheit(temp) + return ( round( (