Compare commits

..

49 Commits

Author SHA1 Message Date
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
schizza 99d25bfd56 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-04-24 17:56:47 +02:00
Lukas Svoboda af87fd0719
Merge pull request #69 from schizza/wslink_name_fix1
WSLINK_name_fix
2025-04-13 17:54:53 +02:00
schizza 0ab5321170 Corrects translation keys for rain sensors
Updates the translation keys for hourly, weekly, monthly, and yearly rain sensors to ensure they accurately reflect the corresponding time periods.
2025-04-13 17:52:58 +02:00
schizza fdcd28f96a Fix BUG 68
Fixing Issue #68
2025-04-04 14:18:23 +02:00
Lukas Svoboda 093a7915f0
Merge pull request #67 from schizza/add_sensors_for_wslink
Adds rain sensors for different time periods for WSLink
2025-04-04 13:15:01 +02:00
schizza ea0a5e34e3 Update version number 2025-04-04 13:14:19 +02:00
Lukas Svoboda fdd4cacddf
Merge branch 'main' into add_sensors_for_wslink 2025-04-04 13:11:45 +02:00
schizza 601d1f3984 Adds rain sensors for different time periods for WSLink
Adds hourly, weekly, monthly, and yearly rain sensors to the integration for WSLink connection.

The units of measurement are corrected for the rain sensor, now displaying millimeters per hour as the station is sending data in mm/h for 'rain' sensor. And cumulative precipitation is in millimeters.

Also includes translations for the new sensors.
2025-04-04 13:10:10 +02:00
Lukas Svoboda 287e74673e
Create config.yml 2025-03-29 11:30:34 +01:00
Lukas Svoboda 397e44e5f2
Update issue templates 2025-03-29 11:27:06 +01:00
Lukas Svoboda f9d80d7a00
Update bug_report.md 2025-03-19 18:25:13 +01:00
Lukas Svoboda 2b57eeb4fa
Create FUNDING.yml 2025-03-19 18:23:59 +01:00
Lukas Svoboda dc5c45483e
Update issue templates 2025-03-19 17:54:22 +01:00
14 changed files with 352 additions and 109 deletions

5
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,5 @@
# These are supported funding model platforms
github: schizza
ko_fi: schizza
buy_me_a_coffee: schizza

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
Provide `Developer log` if applicable
**Provide information about your station:**
- Weather station type:
- firmware version:
- [ ] Using PWS protocol
- [ ] Using WSLink API
- [ ] Using WSLink proxy Add-on
**Additional context**
Add any other context about the problem here.

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Is your feature request a new addition**
Describe what you want to achieve. How new feature should work.
**Additional context**
Add any other context or screenshots about the feature request here.

34
.github/ISSUE_TEMPLATE/issue.md vendored Normal file
View File

@ -0,0 +1,34 @@
---
name: Issue
about: A minor issue that does not significantly affect functionality.
title: "[ISSUE]"
labels: issue
assignees: ''
---
**Describe the issue**
A clear and concise description of what the issue is.
**To Reproduce**
Steps to reproduce the behavior if any:
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
Provide `Developer log` if applicable
**Provide information about your station:**
- Weather station type:
- firmware version:
- [ ] Using PWS protocol
- [ ] Using WSLink API
- [ ] Using WSLink proxy Add-on
**Additional context**
Add any other context about the problem here.

View File

@ -7,7 +7,6 @@ import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, OptionsFlow
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from .utils import long_term_units_in_statistics_meta, migrate_data
from .const import (
API_ID,
@ -16,7 +15,6 @@ from .const import (
DOMAIN,
INVALID_CREDENTIALS,
SENSORS_TO_LOAD,
SENSOR_TO_MIGRATE,
WINDY_API_KEY,
WINDY_ENABLED,
WINDY_LOGGER_ENABLED,
@ -41,7 +39,7 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.windy_data: dict[str, Any] = {}
self.windy_data_schema = {}
self.user_data: dict[str, str] = {}
self.user_data: dict[str, Any] = {}
self.user_data_schema = {}
self.sensors: dict[str, Any] = {}
self.migrate_schema = {}
@ -50,7 +48,7 @@ class ConfigOptionsFlowHandler(OptionsFlow):
def config_entry(self):
return self.hass.config_entries.async_get_entry(self.handler)
def _get_entry_data(self):
async def _get_entry_data(self):
"""Get entry data."""
self.user_data: dict[str, Any] = {
@ -61,16 +59,18 @@ class ConfigOptionsFlowHandler(OptionsFlow):
}
self.user_data_schema = {
vol.Required(API_ID, default=self.user_data[API_ID] or ""): str,
vol.Required(API_KEY, default=self.user_data[API_KEY] or ""): str,
vol.Optional(WSLINK, default=self.user_data[WSLINK]): bool or False,
vol.Optional(DEV_DBG, default=self.user_data[DEV_DBG]): bool or False,
vol.Required(API_ID, default=self.user_data.get(API_ID, "")): str,
vol.Required(API_KEY, default=self.user_data.get(API_KEY, "")): str,
vol.Optional(WSLINK, default=self.user_data.get(WSLINK, False)): bool,
vol.Optional(DEV_DBG, default=self.user_data.get(DEV_DBG, False)): bool,
}
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] = {
@ -83,34 +83,26 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.windy_data_schema = {
vol.Optional(
WINDY_API_KEY, default=self.windy_data[WINDY_API_KEY] or ""
WINDY_API_KEY, default=self.windy_data.get(WINDY_API_KEY, "")
): str,
vol.Optional(WINDY_ENABLED, default=self.windy_data[WINDY_ENABLED]): bool
or False,
vol.Optional(
WINDY_LOGGER_ENABLED,
default=self.windy_data[WINDY_LOGGER_ENABLED],
): bool or False,
}
self.migrate_schema = {
vol.Required(SENSOR_TO_MIGRATE): vol.In(
long_term_units_in_statistics_meta() or {}
),
vol.Optional("trigger_action", default=False): bool,
): 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."""
errors = {}
self._get_entry_data()
await self._get_entry_data()
if user_input is None:
return self.async_show_form(
@ -147,7 +139,7 @@ class ConfigOptionsFlowHandler(OptionsFlow):
"""Manage windy options."""
errors = {}
self._get_entry_data()
await self._get_entry_data()
if user_input is None:
return self.async_show_form(
@ -160,7 +152,7 @@ class ConfigOptionsFlowHandler(OptionsFlow):
errors[WINDY_API_KEY] = "windy_key_required"
return self.async_show_form(
step_id="windy",
data_schema=self.windy_data_schema,
data_schema=vol.Schema(self.windy_data_schema),
errors=errors,
)
@ -172,51 +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."""
# hj
errors = {}
self._get_entry_data()
if user_input is None:
return self.async_show_form(
step_id="migration",
data_schema=vol.Schema(self.migrate_schema),
errors=errors,
description_placeholders={
"migration_status": "-",
"migration_count": "-",
},
)
if user_input.get("trigger_action"):
# Akce se vykoná po zaškrtnutí
count = await self.hass.async_add_executor_job(
migrate_data, user_input.get(SENSOR_TO_MIGRATE)
)
return self.async_show_form(
step_id="migration",
data_schema=vol.Schema(self.migrate_schema),
errors=errors,
description_placeholders={
"migration_status": user_input.get(SENSOR_TO_MIGRATE),
"migration_count": 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

@ -23,8 +23,12 @@ WSLINK: Final = "wslink"
WINDY_API_KEY = "WINDY_API_KEY"
WINDY_ENABLED: Final = "windy_enabled_checkbox"
WINDY_LOGGER_ENABLED: Final = "windy_logger_checkbox"
WINDY_NOT_INSERTED: Final = "Data was succefuly sent to Windy, but not inserted by Windy API. Does anyone else sent data to Windy?"
WINDY_INVALID_KEY: Final = "Windy API KEY is invalid. Send data to Windy is now disabled. Check your API KEY and try again."
WINDY_NOT_INSERTED: Final = (
"Data was succefuly sent to Windy, but not inserted by Windy API. Does anyone else sent data to Windy?"
)
WINDY_INVALID_KEY: Final = (
"Windy API KEY is invalid. Send data to Windy is now disabled. Check your API KEY and try again."
)
WINDY_SUCCESS: Final = (
"Windy successfully sent data and data was successfully inserted by Windy API"
)
@ -63,11 +67,16 @@ 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"
WIND_AZIMUT: Final = "wind_azimut"
RAIN: Final = "rain"
HOURLY_RAIN: Final = "hourly_rain"
WEEKLY_RAIN: Final = "weekly_rain"
MONTHLY_RAIN: Final = "monthly_rain"
YEARLY_RAIN: Final = "yearly_rain"
DAILY_RAIN: Final = "daily_rain"
SOLAR_RADIATION: Final = "solar_radiation"
INDOOR_TEMP: Final = "indoor_temp"
@ -129,15 +138,18 @@ REMAP_WSLINK_ITEMS: dict = {
"t234c2cn": CH3_CONNECTION,
"t1chill": CHILL_INDEX,
"t1heat": HEAT_INDEX,
"t1rainhr": HOURLY_RAIN,
"t1rainwy": WEEKLY_RAIN,
"t1rainmth": MONTHLY_RAIN,
"t1rainyr": YEARLY_RAIN,
"t234c2tem": CH3_TEMP,
"t234c2hum": CH3_HUMIDITY,
"t1bat": OUTSIDE_BATTERY,
}
# 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
@ -149,6 +161,7 @@ DISABLED_BY_DEFAULT: Final = [
CH3_HUMIDITY,
CH4_TEMP,
CH4_HUMIDITY,
OUTSIDE_BATTERY,
]
@ -191,3 +204,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.5.3",
"version": "1.6.6",
"zeroconf": []
}

View File

@ -15,6 +15,7 @@ from .const import (
CHILL_INDEX,
DOMAIN,
HEAT_INDEX,
OUTSIDE_BATTERY,
OUTSIDE_HUMIDITY,
OUTSIDE_TEMP,
SENSORS_TO_LOAD,
@ -26,7 +27,7 @@ from .const import (
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 +131,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 == OUTSIDE_BATTERY:
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

@ -27,21 +27,26 @@ from .const import (
DAILY_RAIN,
DEW_POINT,
HEAT_INDEX,
HOURLY_RAIN,
INDOOR_HUMIDITY,
INDOOR_TEMP,
MONTHLY_RAIN,
OUTSIDE_BATTERY,
OUTSIDE_HUMIDITY,
OUTSIDE_TEMP,
RAIN,
SOLAR_RADIATION,
UV,
WEEKLY_RAIN,
WIND_AZIMUT,
WIND_DIR,
WIND_GUST,
WIND_SPEED,
YEARLY_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(
@ -139,10 +144,10 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
),
WeatherSensorEntityDescription(
key=RAIN,
native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
device_class=SensorDeviceClass.PRECIPITATION,
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.TOTAL,
suggested_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
suggested_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=RAIN,
@ -159,6 +164,50 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
translation_key=DAILY_RAIN,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=HOURLY_RAIN,
native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
suggested_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=HOURLY_RAIN,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=WEEKLY_RAIN,
native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
suggested_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=WEEKLY_RAIN,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=MONTHLY_RAIN,
native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
suggested_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=MONTHLY_RAIN,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=YEARLY_RAIN,
native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
suggested_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
suggested_display_precision=2,
icon="mdi:weather-pouring",
translation_key=YEARLY_RAIN,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=SOLAR_RADIATION,
native_unit_of_measurement=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
@ -196,25 +245,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,
@ -256,4 +305,11 @@ 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),
),
)

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

@ -112,6 +112,10 @@
"ch4_humidity": { "name": "Vlhkost sensoru 4" },
"heat_index": { "name": "Tepelný index" },
"chill_index": { "name": "Pocitová teplota" },
"hourly_rain": { "name": "Hodinový úhrn srážek" },
"weekly_rain": { "name": "Týdenní úhrn srážek" },
"monthly_rain": { "name": "Měsíční úhrn srážek" },
"yearly_rain": { "name": "Roční úhrn srážek" },
"wind_azimut": {
"name": "Azimut",
"state": {
@ -132,6 +136,14 @@
"nw": "SZ",
"nnw": "SSZ"
}
},
"outside_battery": {
"name": "Stav nabití venkovní baterie",
"state": {
"low": "Nízká",
"normal": "Normální",
"unknown": "Neznámá / zcela vybitá"
}
}
}
},

View File

@ -35,7 +35,6 @@
},
"step": {
"init": {
"title": "Configure SWS12500 Integration",
"description": "Choose what do you want to configure. If basic access or resending data for Windy site",
@ -83,8 +82,8 @@
"trigger_action": "Trigger migration"
},
"data_description": {
"sensor_to_migrate": "Select the correct sensor for statistics migration.\nThe sensor values will be preserved, they will not be recalculated, only the unit in the long-term statistics will be changed.",
"trigger_action": "Trigger the sensor statistics migration after checking."
"sensor_to_migrate": "Select the correct sensor for statistics migration.\nThe sensor values will be preserved, they will not be recalculated, only the unit in the long-term statistics will be changed.",
"trigger_action": "Trigger the sensor statistics migration after checking."
}
}
}
@ -113,6 +112,10 @@
"ch4_humidity": { "name": "Channel 4 humidity" },
"heat_index": { "name": "Apparent temperature" },
"chill_index": { "name": "Wind chill" },
"hourly_rain": { "name": "Hourly precipitation" },
"weekly_rain": { "name": "Weekly precipitation" },
"monthly_rain": { "name": "Monthly precipitation" },
"yearly_rain": { "name": "Yearly precipitation" },
"wind_azimut": {
"name": "Bearing",
"state": {
@ -133,6 +136,14 @@
"nw": "NW",
"nnw": "NNW"
}
},
"outside_battery": {
"name": "Outside 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
@ -284,7 +314,46 @@ def long_term_units_in_statistics_meta():
return sensor_units
def migrate_data(sensor_id: str | None = None):
async def migrate_data(hass: HomeAssistant, sensor_id: str | None = None) -> bool:
"""Migrate data from mm/d to mm."""
_LOGGER.debug("Sensor %s is required for data migration", sensor_id)
updated_rows = 0
if not Path(DATABASE_PATH).exists():
_LOGGER.error("Database file not found: %s", DATABASE_PATH)
return False
conn = sqlite3.connect(DATABASE_PATH)
db = conn.cursor()
try:
_LOGGER.info(sensor_id)
db.execute(
"""
UPDATE statistics_meta
SET unit_of_measurement = 'mm'
WHERE statistic_id = ?
AND unit_of_measurement = 'mm/d';
""",
(sensor_id,),
)
updated_rows = db.rowcount
conn.commit()
_LOGGER.info(
"Data migration completed successfully. Updated rows: %s for %s",
updated_rows,
sensor_id,
)
except sqlite3.Error as e:
_LOGGER.error("Error during data migration: %s", e)
finally:
conn.close()
return updated_rows
def migrate_data_old(sensor_id: str | None = None):
"""Migrate data from mm/d to mm."""
updated_rows = 0