Compare commits

...

41 Commits
main ... v1.6.7

Author SHA1 Message Date
Lukas Svoboda 1d8928bf12
Merge pull request #76 from schizza/74-additional-sensors
Release 1.6.7
2025-10-26 21:03:23 +01:00
schizza 397005bd3f
Updates component version to 1.6.7
Bump version

This reflects changes introduced in the '74-additional-sensors'
branch.
2025-10-26 21:02:13 +01:00
schizza 80909e88c0
Adds indoor and channel 2 battery sensors
Adds support for displaying indoor console and channel 2 battery levels as sensors.

Updates sensor logic to use a common list to determine icon representation

Fixes #74
2025-10-26 20:59:57 +01:00
Lukas Svoboda 5022cb7767
Merge pull request #65 from convicte/patch-1
Implement SensorDeviceClass.WIND_DIRECTION
2025-08-28 21:58:28 +02:00
Lukas Svoboda f7cea43722
Merge branch 'stable' into patch-1 2025-08-28 21:58:15 +02:00
Lukas Svoboda 7ff8bb7f92
Merge branch 'main' into patch-1 2025-08-28 21:57:38 +02:00
Lukas Svoboda dbebc501e3
Bump version from 1.6.5 to 1.6.6 2025-08-28 21:55:01 +02:00
Lukas Svoboda 8247f2b854
Merge pull request #72 from FerronN/ft-add-wslink-battery-level
Add outside battery sensor and related translations
2025-08-28 21:53:27 +02:00
Ferron Nijland d48f0fda6e Merge branch 'ft-add-wslink-battery-level' of https://github.com/FerronN/SWS-12500-custom-component into ft-add-wslink-battery-level 2025-08-28 10:42:03 +02:00
schizza 99fd6d266c Adds outside battery sensor
Adds an outside battery sensor to the integration, providing information about the battery level of the outdoor sensor.

This includes:
- Mapping the `t1bat` WSLink item to the `OUTSIDE_BATTERY` sensor.
- Implementing logic to convert the battery level to a human-readable text representation and a corresponding icon.
- Updates precipitation to intensity and fixes data type of battery level
2025-08-28 10:41:44 +02:00
schizza 64dd47a3e9 Option flow configuration
Removes the "migration" step from the option flow menu.
This step will be used in next release.
2025-08-28 10:41:44 +02:00
schizza 720c2148e6 Removes unused import from config_flow
Removes the unused import of `utils` to improve code cleanliness and avoid potential namespace conflicts.
Removed 'migration' from menu as it is intended to use in later version.
2025-08-28 10:41:44 +02:00
schizza b858f648b9 config_flow migrated to stable version.
Config flow was migrated to stable version.

Removes the unit migration flow, which is intended to introduce later.
2025-08-28 10:41:44 +02:00
schizza 07ca4a6833 Reorders constants for better readability
Reorders the import of constants to improve readability and maintain consistency within the module.

Final touches.
2025-08-28 10:41:44 +02:00
schizza de013891c0 Adds missing constant and improves readability
Adds OUTSIDE_BATTERY to the DISABLED_BY_DEFAULT list.
Improves readability by formatting long strings with parenthesis.
2025-08-28 10:41:44 +02:00
schizza 0d0922a494 Improves battery sensor display
Updates the outside battery sensor to display an icon
reflecting the battery level, enhancing the user experience
by providing a visual indication of the battery status.
2025-08-28 10:41:44 +02:00
schizza af19358ac7 Adds battery state translations
Adds translations for the battery state of the outside sensor to both the English and Czech language files.

This change provides more descriptive and user-friendly information about the battery status.
2025-08-28 10:41:44 +02:00
schizza 3dbf8b8a7a Improves battery level representation
Refactors battery level representation by using enum instead of string.

Improves battery level display by adding an icon representation.

Changes const BATLEVEL to BATTERY_LEVEL.
2025-08-28 10:41:44 +02:00
schizza a68a4c929a Update const.py 2025-08-28 10:41:44 +02:00
FerronN af286648e9 fix data parsing in sensors_wslink.py 2025-08-28 10:41:44 +02:00
FerronN b6080fe9fd Fix structure en.json 2025-08-28 10:41:44 +02:00
Ferron Nijland a07af5a4fd Add outside battery sensor and related translations 2025-08-28 10:41:44 +02:00
schizza f14e6500d4 Adds unit migration functionality to options flow
Implements a user interface to migrate units for rain sensors including migration of historic data via statistics.
This provides the user with the ability to correct rain units, if they have been set incorrectly.
Includes UI to select sensor and units, as well as trigger migration.
2025-08-28 10:40:03 +02:00
Lukas Svoboda a1f2bf10ea
Merge branch 'stable' into ft-add-wslink-battery-level 2025-08-22 18:15:11 +02:00
schizza e10ea9901c
Adds outside battery sensor
Adds an outside battery sensor to the integration, providing information about the battery level of the outdoor sensor.

This includes:
- Mapping the `t1bat` WSLink item to the `OUTSIDE_BATTERY` sensor.
- Implementing logic to convert the battery level to a human-readable text representation and a corresponding icon.
- Updates precipitation to intensity and fixes data type of battery level
2025-08-22 18:06:35 +02:00
schizza fc8349c06e
Option flow configuration
Removes the "migration" step from the option flow menu.
This step will be used in next release.
2025-08-21 16:46:13 +02:00
schizza d4d2440ae8
Removes unused import from config_flow
Removes the unused import of `utils` to improve code cleanliness and avoid potential namespace conflicts.
Removed 'migration' from menu as it is intended to use in later version.
2025-08-21 16:45:29 +02:00
schizza 827fb71e25
sensors_wslink updated to stable version
Updating to stable version, retaining CH3 sensors.
Left outside battery unchanged. Will work on bug in next commit.
2025-08-21 16:39:05 +02:00
schizza 2d758835dc
config_flow migrated to stable version.
Config flow was migrated to stable version.

Removes the unit migration flow, which is intended to introduce later.
2025-08-21 16:30:10 +02:00
schizza 0027a80968
Update const to stable version
Update constants to stable version.
2025-08-21 16:08:08 +02:00
schizza e11e068c0f Reorders constants for better readability
Reorders the import of constants to improve readability and maintain consistency within the module.

Final touches.
2025-08-18 13:29:00 +02:00
schizza 1ecd88269d Adds missing constant and improves readability
Adds OUTSIDE_BATTERY to the DISABLED_BY_DEFAULT list.
Improves readability by formatting long strings with parenthesis.
2025-08-18 12:53:40 +02:00
schizza 09d79e2032 Improves battery sensor display
Updates the outside battery sensor to display an icon
reflecting the battery level, enhancing the user experience
by providing a visual indication of the battery status.
2025-08-18 12:50:31 +02:00
schizza bbe31da4c5 Adds battery state translations
Adds translations for the battery state of the outside sensor to both the English and Czech language files.

This change provides more descriptive and user-friendly information about the battery status.
2025-08-18 10:55:37 +02:00
schizza 68da7aad98 Improves battery level representation
Refactors battery level representation by using enum instead of string.

Improves battery level display by adding an icon representation.

Changes const BATLEVEL to BATTERY_LEVEL.
2025-08-17 18:34:14 +02:00
schizza de8d2a7b0c
Update const.py 2025-08-16 17:29:22 +02:00
FerronN cf0938a6fd
fix data parsing in sensors_wslink.py 2025-07-11 10:16:59 +02:00
FerronN 4d2dedbb11
Fix structure en.json 2025-07-11 10:15:44 +02:00
Ferron Nijland feed730818 Add outside battery sensor and related translations 2025-07-09 16:26:18 +02:00
schizza b1cec2f38f
Adds CH3 temperature and humidity sensors
Enables CH3 temperature and humidity sensors for WSLink devices.
2025-07-04 19:27:45 +02:00
convicte 6eceee1f4e
Implement SensorDeviceClass.WIND_DIRECTION
This commit adds the latest SensorDeviceClass.WIND_DIRECTION to facilitate correct long term statistics collection for the wind direction sensor.
2025-03-15 23:13:21 +01:00
9 changed files with 202 additions and 231 deletions

View File

@ -1,15 +1,12 @@
"""Config flow for Sencor SWS 12500 Weather Station integration."""
import logging
from typing import Any
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, OptionsFlow
from homeassistant.const import UnitOfPrecipitationDepth, UnitOfVolumetricFlux
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.entity_registry as er
from .const import (
API_ID,
@ -17,18 +14,12 @@ from .const import (
DEV_DBG,
DOMAIN,
INVALID_CREDENTIALS,
MIG_FROM,
MIG_TO,
SENSOR_TO_MIGRATE,
SENSORS_TO_LOAD,
WINDY_API_KEY,
WINDY_ENABLED,
WINDY_LOGGER_ENABLED,
WSLINK,
)
from .utils import long_term_units_in_statistics_meta, migrate_data
_LOGGER = logging.getLogger(__name__)
class CannotConnect(HomeAssistantError):
@ -52,13 +43,6 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.user_data_schema = {}
self.sensors: dict[str, Any] = {}
self.migrate_schema = {}
self.migrate_sensor_select = {}
self.migrate_unit_selection = {}
self.count = 0
self.selected_sensor = ""
self.unit_values = [unit.value for unit in UnitOfVolumetricFlux]
self.unit_values.extend([unit.value for unit in UnitOfPrecipitationDepth])
@property
def config_entry(self):
@ -82,9 +66,11 @@ class ConfigOptionsFlowHandler(OptionsFlow):
}
self.sensors: dict[str, Any] = {
SENSORS_TO_LOAD: self.config_entry.options.get(SENSORS_TO_LOAD)
if isinstance(self.config_entry.options.get(SENSORS_TO_LOAD), list)
else []
SENSORS_TO_LOAD: (
self.config_entry.options.get(SENSORS_TO_LOAD)
if isinstance(self.config_entry.options.get(SENSORS_TO_LOAD), list)
else []
)
}
self.windy_data: dict[str, Any] = {
@ -104,43 +90,13 @@ class ConfigOptionsFlowHandler(OptionsFlow):
vol.Optional(
WINDY_LOGGER_ENABLED,
default=self.windy_data[WINDY_LOGGER_ENABLED],
): bool or False,
}
self.migrate_sensor_select = {
vol.Required(SENSOR_TO_MIGRATE): vol.In(
await self.load_sensors_to_migrate() or {}
),
}
self.migrate_unit_selection = {
vol.Required(MIG_FROM): vol.In(self.unit_values),
vol.Required(MIG_TO): vol.In(self.unit_values),
vol.Optional("trigger_action", default=False): bool,
}
# "mm/d", "mm/h", "mm", "in/d", "in/h", "in"
async def load_sensors_to_migrate(self) -> dict[str, Any]:
"""Load sensors to migrate."""
sensor_statistics = await long_term_units_in_statistics_meta(self.hass)
entity_registry = er.async_get(self.hass)
sensors = entity_registry.entities.get_entries_for_config_entry_id(
self.config_entry.entry_id
)
return {
sensor.entity_id: f"{sensor.name or sensor.original_name} (current settings: {sensor.unit_of_measurement}, longterm stats unit: {sensor_statistics.get(sensor.entity_id)})"
for sensor in sensors
if sensor.unique_id in {"rain", "daily_rain"}
): bool
or False,
}
async def async_step_init(self, user_input=None):
"""Manage the options - show menu first."""
return self.async_show_menu(
step_id="init", menu_options=["basic", "windy", "migration"]
)
return self.async_show_menu(step_id="init", menu_options=["basic", "windy"])
async def async_step_basic(self, user_input=None):
"""Manage basic options - credentials."""
@ -208,151 +164,6 @@ class ConfigOptionsFlowHandler(OptionsFlow):
return self.async_create_entry(title=DOMAIN, data=user_input)
async def async_step_migration(self, user_input=None):
"""Migrate sensors."""
errors = {}
data_schema = vol.Schema(self.migrate_sensor_select)
data_schema.schema.update()
await self._get_entry_data()
if user_input is None:
return self.async_show_form(
step_id="migration",
data_schema=vol.Schema(self.migrate_sensor_select),
errors=errors,
description_placeholders={
"migration_status": "-",
"migration_count": "-",
},
)
self.selected_sensor = user_input.get(SENSOR_TO_MIGRATE)
return await self.async_step_migration_units()
async def async_step_migration_units(self, user_input=None):
"""Migrate unit step."""
registry = er.async_get(self.hass)
sensor_entry = registry.async_get(self.selected_sensor)
sensor_stats = await long_term_units_in_statistics_meta(self.hass)
default_unit = sensor_entry.unit_of_measurement if sensor_entry else None
if default_unit not in self.unit_values:
default_unit = self.unit_values[0]
data_schema = vol.Schema({
vol.Required(MIG_FROM, default=default_unit): vol.In(self.unit_values),
vol.Required(MIG_TO): vol.In(self.unit_values),
vol.Optional("trigger_action", default=False): bool,
})
if user_input is None:
return self.async_show_form(
step_id="migration_units",
data_schema=data_schema,
errors={},
description_placeholders={
"migration_sensor": sensor_entry.original_name,
"migration_stats": sensor_stats.get(self.selected_sensor),
},
)
if user_input.get("trigger_action"):
self.count = await migrate_data(
self.hass,
self.selected_sensor,
user_input.get(MIG_FROM),
user_input.get(MIG_TO),
)
registry.async_update_entity(self.selected_sensor,
unit_of_measurement=user_input.get(MIG_TO),
)
state = self.hass.states.get(self.selected_sensor)
if state:
_LOGGER.info("State attributes before update: %s", state.attributes)
attributes = dict(state.attributes)
attributes["unit_of_measurement"] = user_input.get(MIG_TO)
self.hass.states.async_set(self.selected_sensor, state.state, attributes)
_LOGGER.info("State attributes after update: %s", attributes)
options = {**self.config_entry.options, "reload_sensor": self.selected_sensor}
self.hass.config_entries.async_update_entry(self.config_entry, options=options)
await self.hass.config_entries.async_reload(self.config_entry.entry_id)
await self.hass.async_block_till_done()
_LOGGER.info("Migration complete for sensor %s: %s row updated, new measurement unit: %s, ",
self.selected_sensor,
self.count,
user_input.get(MIG_TO),
)
await self._get_entry_data()
sensor_entry = er.async_get(self.hass).async_get(self.selected_sensor)
sensor_stat = await self.load_sensors_to_migrate()
return self.async_show_form(
step_id="migration_complete",
data_schema=vol.Schema({}),
errors={},
description_placeholders={
"migration_sensor": sensor_entry.unit_of_measurement,
"migration_stats": sensor_stat.get(self.selected_sensor),
"migration_count": self.count,
},
)
# retain windy data
user_input.update(self.windy_data)
# retain user_data
user_input.update(self.user_data)
# retain senors
user_input.update(self.sensors)
return self.async_create_entry(title=DOMAIN, data=user_input)
async def async_step_migration_complete(self, user_input=None):
"""Migration complete."""
errors = {}
await self._get_entry_data()
sensor_entry = er.async_get(self.hass).async_get(self.selected_sensor)
sensor_stat = await self.load_sensors_to_migrate()
if user_input is None:
return self.async_show_form(
step_id="migration_complete",
data_schema=vol.Schema({}),
errors=errors,
description_placeholders={
"migration_sensor": sensor_entry.unit_of_measurement,
"migration_stats": sensor_stat.get(self.selected_sensor),
"migration_count": self.count,
},
)
# retain windy data
user_input.update(self.windy_data)
# retain user_data
user_input.update(self.user_data)
# retain senors
user_input.update(self.sensors)
return self.async_create_entry(title=DOMAIN, data=user_input)
class ConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Sencor SWS 12500 Weather Station."""

View File

@ -63,6 +63,7 @@ OUTSIDE_TEMP: Final = "outside_temp"
DEW_POINT: Final = "dew_point"
OUTSIDE_HUMIDITY: Final = "outside_humidity"
OUTSIDE_CONNECTION: Final = "outside_connection"
OUTSIDE_BATTERY: Final = "outside_battery"
WIND_SPEED: Final = "wind_speed"
WIND_GUST: Final = "wind_gust"
WIND_DIR: Final = "wind_dir"
@ -76,10 +77,12 @@ DAILY_RAIN: Final = "daily_rain"
SOLAR_RADIATION: Final = "solar_radiation"
INDOOR_TEMP: Final = "indoor_temp"
INDOOR_HUMIDITY: Final = "indoor_humidity"
INDOOR_BATTERY: Final = "indoor_battery"
UV: Final = "uv"
CH2_TEMP: Final = "ch2_temp"
CH2_HUMIDITY: Final = "ch2_humidity"
CH2_CONNECTION: Final = "ch2_connection"
CH2_BATTERY: Final = "ch2_battery"
CH3_TEMP: Final = "ch3_temp"
CH3_HUMIDITY: Final = "ch3_humidity"
CH3_CONNECTION: Final = "ch3_connection"
@ -90,7 +93,7 @@ HEAT_INDEX: Final = "heat_index"
CHILL_INDEX: Final = "chill_index"
REMAP_ITEMS: dict = {
REMAP_ITEMS: dict[str, str] = {
"baromin": BARO_PRESSURE,
"tempf": OUTSIDE_TEMP,
"dewptf": DEW_POINT,
@ -112,7 +115,7 @@ REMAP_ITEMS: dict = {
"soilmoisture3": CH4_HUMIDITY,
}
REMAP_WSLINK_ITEMS: dict = {
REMAP_WSLINK_ITEMS: dict[str, str] = {
"intem": INDOOR_TEMP,
"inhum": INDOOR_HUMIDITY,
"t1tem": OUTSIDE_TEMP,
@ -137,6 +140,11 @@ REMAP_WSLINK_ITEMS: dict = {
"t1rainwy": WEEKLY_RAIN,
"t1rainmth": MONTHLY_RAIN,
"t1rainyr": YEARLY_RAIN,
"t234c2tem": CH3_TEMP,
"t234c2hum": CH3_HUMIDITY,
"t1bat": OUTSIDE_BATTERY,
"inbat": INDOOR_BATTERY,
"t234c1bat": CH2_BATTERY,
}
# TODO: Add more sensors
@ -149,10 +157,18 @@ REMAP_WSLINK_ITEMS: dict = {
DISABLED_BY_DEFAULT: Final = [
CH2_TEMP,
CH2_HUMIDITY,
CH2_BATTERY,
CH3_TEMP,
CH3_HUMIDITY,
CH4_TEMP,
CH4_HUMIDITY,
OUTSIDE_BATTERY,
]
BATTERY_LIST = [
OUTSIDE_BATTERY,
INDOOR_BATTERY,
CH2_BATTERY,
]
@ -195,3 +211,18 @@ AZIMUT: list[UnitOfDir] = [
UnitOfDir.NNW,
UnitOfDir.N,
]
class UnitOfBat(StrEnum):
"""Battery level unit of measure."""
LOW = "low"
NORMAL = "normal"
UNKNOWN = "unknown"
BATTERY_LEVEL: list[UnitOfBat] = [
UnitOfBat.LOW,
UnitOfBat.NORMAL,
UnitOfBat.UNKNOWN,
]

View File

@ -10,6 +10,6 @@
"issue_tracker": "https://github.com/schizza/SWS-12500-custom-component/issues",
"requirements": [],
"ssdp": [],
"version": "1.6.2",
"version": "1.6.7",
"zeroconf": []
}

View File

@ -15,6 +15,7 @@ from .const import (
CHILL_INDEX,
DOMAIN,
HEAT_INDEX,
OUTSIDE_BATTERY,
OUTSIDE_HUMIDITY,
OUTSIDE_TEMP,
SENSORS_TO_LOAD,
@ -22,11 +23,12 @@ from .const import (
WIND_DIR,
WIND_SPEED,
WSLINK,
BATTERY_LIST,
)
from .sensors_common import WeatherSensorEntityDescription
from .sensors_weather import SENSOR_TYPES_WEATHER_API
from .sensors_wslink import SENSOR_TYPES_WSLINK
from .utils import chill_index, heat_index
from .utils import chill_index, heat_index, battery_level_to_icon, battery_level_to_text
_LOGGER = logging.getLogger(__name__)
@ -130,13 +132,27 @@ class WeatherSensor(
):
return self.entity_description.value_fn(chill_index(self.coordinator.data))
return None if self._data == "" else 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:
"""Return name."""
return generate_entity_id("sensor.{}", self.entity_description.key)
@property
def icon(self) -> str | None:
"""Return the dynamic icon for battery representation."""
if self.entity_description.key in BATTERY_LIST:
try:
return battery_level_to_icon(self.native_value)
except Exception:
return "mdi:battery-unknown"
return self.entity_description.icon
@property
def device_info(self) -> DeviceInfo:
"""Device info."""

View File

@ -19,6 +19,8 @@ from .const import (
BARO_PRESSURE,
CH2_HUMIDITY,
CH2_TEMP,
CH2_BATTERY,
INDOOR_BATTERY,
CH3_HUMIDITY,
CH3_TEMP,
CH4_HUMIDITY,
@ -27,25 +29,28 @@ from .const import (
DAILY_RAIN,
DEW_POINT,
HEAT_INDEX,
HOURLY_RAIN,
INDOOR_BATTERY,
INDOOR_HUMIDITY,
INDOOR_TEMP,
INDOOR_BATTERY,
MONTHLY_RAIN,
OUTSIDE_BATTERY,
OUTSIDE_HUMIDITY,
OUTSIDE_TEMP,
RAIN,
SOLAR_RADIATION,
UV,
WEEKLY_RAIN,
WIND_AZIMUT,
WIND_DIR,
WIND_GUST,
WIND_SPEED,
UnitOfDir,
MONTHLY_RAIN,
YEARLY_RAIN,
HOURLY_RAIN,
WEEKLY_RAIN,
UnitOfDir,
)
from .sensors_common import WeatherSensorEntityDescription
from .utils import wind_dir_to_text
from .utils import battery_level_to_icon, battery_level_to_text, wind_dir_to_text
SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
@ -127,6 +132,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
key=WIND_DIR,
native_unit_of_measurement=DEGREE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.WIND_DIRECTION,
suggested_display_precision=None,
icon="mdi:sign-direction",
translation_key=WIND_DIR,
@ -143,7 +149,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
key=RAIN,
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
device_class=SensorDeviceClass.PRECIPITATION,
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.TOTAL,
suggested_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=2,
@ -243,25 +249,25 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
translation_key=CH2_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
# WeatherSensorEntityDescription(
# key=CH3_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=CH3_TEMP,
# value_fn=lambda data: cast(float, data),
# ),
# WeatherSensorEntityDescription(
# key=CH3_HUMIDITY,
# native_unit_of_measurement=PERCENTAGE,
# state_class=SensorStateClass.MEASUREMENT,
# device_class=SensorDeviceClass.HUMIDITY,
# icon="mdi:weather-sunny",
# translation_key=CH3_HUMIDITY,
# value_fn=lambda data: cast(int, data),
# ),
WeatherSensorEntityDescription(
key=CH3_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=CH3_TEMP,
value_fn=lambda data: cast(float, data),
),
WeatherSensorEntityDescription(
key=CH3_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH3_HUMIDITY,
value_fn=lambda data: cast(int, data),
),
# WeatherSensorEntityDescription(
# key=CH4_TEMP,
# native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
@ -303,4 +309,25 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
translation_key=CHILL_INDEX,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=OUTSIDE_BATTERY,
translation_key=OUTSIDE_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: battery_level_to_text(data),
),
WeatherSensorEntityDescription(
key=CH2_BATTERY,
translation_key=CH2_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: battery_level_to_text(data),
),
WeatherSensorEntityDescription(
key=INDOOR_BATTERY,
translation_key=INDOOR_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: battery_level_to_text(data),
),
)

View File

@ -131,6 +131,14 @@
"wnw": "WNW",
"nw": "NW",
"nnw": "NNW"
},
"outside_battery": {
"name": "Outside battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
}
}
}

View File

@ -136,6 +136,30 @@
"nw": "SZ",
"nnw": "SSZ"
}
},
"outside_battery": {
"name": "Stav nabití venkovní baterie",
"state": {
"low": "Nízká",
"normal": "Normální",
"unknown": "Neznámá / zcela vybitá"
}
},
"indoor_battery": {
"name": "Stav nabití baterie kozole",
"state": {
"low": "Nízká",
"normal": "Normální",
"unknown": "Neznámá / zcela vybitá"
}
},
"ch2_battery": {
"name": "Stav nabití baterie kanálu 2",
"state": {
"low": "Nízká",
"normal": "Normální",
"unknown": "Neznámá / zcela vybitá"
}
}
}
},

View File

@ -136,6 +136,30 @@
"nw": "NW",
"nnw": "NNW"
}
},
"outside_battery": {
"name": "Outside battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch2_battery": {
"name": "Channel 2 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"indoor_battery": {
"name": "Console battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
}
}
},

View File

@ -20,6 +20,7 @@ from homeassistant.helpers.translation import async_get_translations
from .const import (
AZIMUT,
BATTERY_LEVEL,
DATABASE_PATH,
DEV_DBG,
OUTSIDE_HUMIDITY,
@ -29,6 +30,7 @@ from .const import (
SENSORS_TO_LOAD,
WIND_SPEED,
UnitOfDir,
UnitOfBat,
)
_LOGGER = logging.getLogger(__name__)
@ -181,6 +183,32 @@ def wind_dir_to_text(deg: float) -> UnitOfDir | None:
return None
def battery_level_to_text(battery: int) -> UnitOfBat:
"""Return battery level in text representation.
Returns UnitOfBat
"""
return {
0: UnitOfBat.LOW,
1: UnitOfBat.NORMAL,
}.get(int(battery) if battery is not None else None, UnitOfBat.UNKNOWN)
def battery_level_to_icon(battery: UnitOfBat) -> str:
"""Return battery level in icon representation.
Returns str
"""
icons = {
UnitOfBat.LOW: "mdi:battery-low",
UnitOfBat.NORMAL: "mdi:battery",
}
return icons.get(battery, "mdi:battery-unknown")
def fahrenheit_to_celsius(fahrenheit: float) -> float:
"""Convert Fahrenheit to Celsius."""
return (fahrenheit - 32) * 5.0 / 9.0
@ -267,10 +295,12 @@ def long_term_units_in_statistics_meta():
db = conn.cursor()
try:
db.execute("""
db.execute(
"""
SELECT statistic_id, unit_of_measurement from statistics_meta
WHERE statistic_id LIKE 'sensor.weather_station_sws%'
""")
"""
)
rows = db.fetchall()
sensor_units = {
statistic_id: f"{statistic_id} ({unit})" for statistic_id, unit in rows