Compare commits

..

2 Commits
v1.7.0 ... main

17 changed files with 317 additions and 771 deletions

View File

@ -1,21 +0,0 @@
name: Build & Attach ZIP asset
on:
release:
types: [published]
jobs:
build-zip:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create ZIP
run: |
mkdir -p dist
cd custom_components/sws12500
zip -r ../../dist/weather-station.zip . -x "*/__pycache__/*"
- name: Upload ZIP to release
uses: softprops/action-gh-release@v2
with:
files: dist/weather-station.zip

View File

@ -1,6 +1,3 @@
![GitHub Downloads](https://img.shields.io/github/downloads/schizza/SWS-12500-custom-component/total?label=downloads%20%28all%20releases%29)
![Latest release downloads](https://img.shields.io/github/downloads/schizza/SWS-12500-custom-component/latest/total?label=downloads%20%28latest%29)
# Integrates your Sencor SWS 12500 or 16600, GARNI, BRESSER weather stations seamlessly into Home Assistant
This integration will listen for data from your station and passes them to respective sensors. It also provides the ability to push data to Windy API.
@ -102,16 +99,6 @@ As soon as the integration is added into Home Assistant it will listen for incom
- You are done.
## Resending data to Pocasi Meteo
- If you are willing to use [Pocasi Meteo Application](https://pocasimeteo.cz) you can enable resending your data to their servers
- You must have account at Pocasi Meteo, where you will recieve `ID` and `KEY`, which are needed to connect to server
- In `Settings` -> `Devices & services` find SWS12500 and click `Configure`.
- In dialog box choose `Pocasi Meteo configuration`.
- Fill in `ID` and `KEY` you were provided at `Pocasi Meteo`.
- Tick `Enable` checkbox.
- You are done.
## WSLink notes
While your station is using WSLink you have to have Home Assistant in SSL mode or behind SSL proxy server.

View File

@ -17,13 +17,11 @@ from .const import (
DEFAULT_URL,
DEV_DBG,
DOMAIN,
POCASI_CZ_ENABLED,
SENSORS_TO_LOAD,
WINDY_ENABLED,
WSLINK,
WSLINK_URL,
)
from .pocasti_cz import PocasiPush
from .routes import Routes, unregistred
from .utils import (
anonymize,
@ -53,7 +51,6 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
self.hass = hass
self.config = config
self.windy = WindyPush(hass, config)
self.pocasi: PocasiPush = PocasiPush(hass, config)
super().__init__(hass, _LOGGER, name=DOMAIN)
async def recieved_data(self, webdata):
@ -88,9 +85,6 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
if self.config_entry.options.get(WINDY_ENABLED):
response = await self.windy.push_data_to_windy(data)
if self.config.options.get(POCASI_CZ_ENABLED):
await self.pocasi.push_data_to_server(data, "WSLINK" if _wslink else "WU")
remaped_items = (
remap_wslink_items(data)
if self.config_entry.options.get(WSLINK)

View File

@ -1,12 +1,15 @@
"""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, ConfigFlowResult, OptionsFlow
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,
@ -14,18 +17,18 @@ from .const import (
DEV_DBG,
DOMAIN,
INVALID_CREDENTIALS,
POCASI_CZ_API_ID,
POCASI_CZ_API_KEY,
POCASI_CZ_ENABLED,
POCASI_CZ_LOGGER_ENABLED,
POCASI_CZ_SEND_INTERVAL,
POCASI_CZ_SEND_MINIMUM,
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):
@ -49,8 +52,13 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.user_data_schema = {}
self.sensors: dict[str, Any] = {}
self.migrate_schema = {}
self.pocasi_cz: dict[str, Any] = {}
self.pocasi_cz_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):
@ -59,7 +67,7 @@ class ConfigOptionsFlowHandler(OptionsFlow):
async def _get_entry_data(self):
"""Get entry data."""
self.user_data = {
self.user_data: dict[str, Any] = {
API_ID: self.config_entry.options.get(API_ID),
API_KEY: self.config_entry.options.get(API_KEY),
WSLINK: self.config_entry.options.get(WSLINK, False),
@ -73,15 +81,13 @@ class ConfigOptionsFlowHandler(OptionsFlow):
vol.Optional(DEV_DBG, default=self.user_data.get(DEV_DBG, False)): bool,
}
self.sensors = {
SENSORS_TO_LOAD: (
self.config_entry.options.get(SENSORS_TO_LOAD)
if isinstance(self.config_entry.options.get(SENSORS_TO_LOAD), list)
else []
)
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 []
}
self.windy_data = {
self.windy_data: dict[str, Any] = {
WINDY_API_KEY: self.config_entry.options.get(WINDY_API_KEY),
WINDY_ENABLED: self.config_entry.options.get(WINDY_ENABLED, False),
WINDY_LOGGER_ENABLED: self.config_entry.options.get(
@ -101,42 +107,39 @@ class ConfigOptionsFlowHandler(OptionsFlow):
): bool or False,
}
self.pocasi_cz = {
POCASI_CZ_API_ID: self.config_entry.options.get(POCASI_CZ_API_ID, ""),
POCASI_CZ_API_KEY: self.config_entry.options.get(POCASI_CZ_API_KEY, ""),
POCASI_CZ_ENABLED: self.config_entry.options.get(POCASI_CZ_ENABLED, False),
POCASI_CZ_LOGGER_ENABLED: self.config_entry.options.get(
POCASI_CZ_LOGGER_ENABLED, False
),
POCASI_CZ_SEND_INTERVAL: self.config_entry.options.get(
POCASI_CZ_SEND_INTERVAL, 30
self.migrate_sensor_select = {
vol.Required(SENSOR_TO_MIGRATE): vol.In(
await self.load_sensors_to_migrate() or {}
),
}
self.pocasi_cz_schema = {
vol.Required(
POCASI_CZ_API_ID, default=self.pocasi_cz.get(POCASI_CZ_API_ID)
): str,
vol.Required(
POCASI_CZ_API_KEY, default=self.pocasi_cz.get(POCASI_CZ_API_KEY)
): str,
vol.Required(
POCASI_CZ_SEND_INTERVAL,
default=self.pocasi_cz.get(POCASI_CZ_SEND_INTERVAL),
): int,
vol.Optional(
POCASI_CZ_ENABLED, default=self.pocasi_cz.get(POCASI_CZ_ENABLED)
): bool,
vol.Optional(
POCASI_CZ_LOGGER_ENABLED,
default=self.pocasi_cz.get(POCASI_CZ_LOGGER_ENABLED),
): bool,
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"}
}
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", "pocasi"]
step_id="init", menu_options=["basic", "windy", "migration"]
)
async def async_step_basic(self, user_input=None):
@ -165,9 +168,6 @@ class ConfigOptionsFlowHandler(OptionsFlow):
# retain sensors
user_input.update(self.sensors)
# retain pocasi data
user_input.update(self.pocasi_cz)
return self.async_create_entry(title=DOMAIN, data=user_input)
self.user_data = user_input
@ -206,54 +206,155 @@ class ConfigOptionsFlowHandler(OptionsFlow):
# retain senors
user_input.update(self.sensors)
# retain pocasi cz
user_input.update(self.pocasi_cz)
return self.async_create_entry(title=DOMAIN, data=user_input)
async def async_step_pocasi(self, user_input: Any = None) -> ConfigFlowResult:
"""Handle the pocasi step."""
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="pocasi",
data_schema=vol.Schema(self.pocasi_cz_schema),
step_id="migration",
data_schema=vol.Schema(self.migrate_sensor_select),
errors=errors,
description_placeholders={
"migration_status": "-",
"migration_count": "-",
},
)
if user_input.get(POCASI_CZ_SEND_INTERVAL, 0) < POCASI_CZ_SEND_MINIMUM:
errors[POCASI_CZ_SEND_INTERVAL] = "pocasi_send_minimum"
self.selected_sensor = user_input.get(SENSOR_TO_MIGRATE)
if user_input.get(POCASI_CZ_ENABLED):
if user_input.get(POCASI_CZ_API_ID) == "":
errors[POCASI_CZ_API_ID] = "pocasi_id_required"
if user_input.get(POCASI_CZ_API_KEY) == "":
errors[POCASI_CZ_API_KEY] = "pocasi_key_required"
return await self.async_step_migration_units()
if len(errors) > 0:
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="pocasi",
data_schema=vol.Schema(self.pocasi_cz_schema),
errors=errors,
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),
},
)
# retain user data
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)
# retain windy
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 ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
class ConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Sencor SWS 12500 Weather Station."""
data_schema = {

View File

@ -9,9 +9,6 @@ WSLINK_URL = "/data/upload.php"
WINDY_URL = "https://stations.windy.com/pws/update/"
DATABASE_PATH = "/config/home-assistant_v2.db"
POCASI_CZ_URL: Final = "http://ms.pocasimeteo.cz"
POCASI_CZ_SEND_MINIMUM: Final = 12 # minimal time to resend data
ICON = "mdi:weather"
API_KEY = "API_KEY"
@ -23,19 +20,6 @@ SENSOR_TO_MIGRATE: Final = "sensor_to_migrate"
DEV_DBG: Final = "dev_debug_checkbox"
WSLINK: Final = "wslink"
POCASI_CZ_API_KEY = "POCASI_CZ_API_KEY"
POCASI_CZ_API_ID = "POCASI_CZ_API_ID"
POCASI_CZ_SEND_INTERVAL = "POCASI_SEND_INTERVAL"
POCASI_CZ_ENABLED = "pocasi_enabled_chcekbox"
POCASI_CZ_LOGGER_ENABLED = "pocasi_logger_checkbox"
POCASI_INVALID_KEY: Final = (
"Pocasi Meteo refused to accept data. Invalid ID/Key combination?"
)
POCASI_CZ_SUCCESS: Final = "Successfully sent data to Pocasi Meteo"
POCASI_CZ_UNEXPECTED: Final = (
"Pocasti Meteo responded unexpectedly 3 times in row. Resendig is now disabled!"
)
WINDY_API_KEY = "WINDY_API_KEY"
WINDY_ENABLED: Final = "windy_enabled_checkbox"
WINDY_LOGGER_ENABLED: Final = "windy_logger_checkbox"
@ -73,20 +57,12 @@ PURGE_DATA: Final = [
"dailyrainin",
]
PURGE_DATA_POCAS: Final = [
"ID",
"PASSWORD",
"action",
"rtfreq",
]
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"
OUTSIDE_BATTERY: Final = "outside_battery"
WIND_SPEED: Final = "wind_speed"
WIND_GUST: Final = "wind_gust"
WIND_DIR: Final = "wind_dir"
@ -100,12 +76,10 @@ 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"
@ -114,10 +88,9 @@ CH4_HUMIDITY: Final = "ch4_humidity"
CH4_CONNECTION: Final = "ch4_connection"
HEAT_INDEX: Final = "heat_index"
CHILL_INDEX: Final = "chill_index"
WBGT_TEMP: Final = "wbgt_temp"
REMAP_ITEMS: dict[str, str] = {
REMAP_ITEMS: dict = {
"baromin": BARO_PRESSURE,
"tempf": OUTSIDE_TEMP,
"dewptf": DEW_POINT,
@ -139,7 +112,7 @@ REMAP_ITEMS: dict[str, str] = {
"soilmoisture3": CH4_HUMIDITY,
}
REMAP_WSLINK_ITEMS: dict[str, str] = {
REMAP_WSLINK_ITEMS: dict = {
"intem": INDOOR_TEMP,
"inhum": INDOOR_HUMIDITY,
"t1tem": OUTSIDE_TEMP,
@ -164,12 +137,6 @@ REMAP_WSLINK_ITEMS: dict[str, str] = {
"t1rainwy": WEEKLY_RAIN,
"t1rainmth": MONTHLY_RAIN,
"t1rainyr": YEARLY_RAIN,
"t234c2tem": CH3_TEMP,
"t234c2hum": CH3_HUMIDITY,
"t1bat": OUTSIDE_BATTERY,
"inbat": INDOOR_BATTERY,
"t234c1bat": CH2_BATTERY,
"t1wbgt": WBGT_TEMP,
}
# TODO: Add more sensors
@ -182,19 +149,10 @@ REMAP_WSLINK_ITEMS: dict[str, str] = {
DISABLED_BY_DEFAULT: Final = [
CH2_TEMP,
CH2_HUMIDITY,
CH2_BATTERY,
CH3_TEMP,
CH3_HUMIDITY,
CH4_TEMP,
CH4_HUMIDITY,
OUTSIDE_BATTERY,
WBGT_TEMP,
]
BATTERY_LIST = [
OUTSIDE_BATTERY,
INDOOR_BATTERY,
CH2_BATTERY,
]
@ -237,18 +195,3 @@ 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.9",
"version": "1.6.2",
"zeroconf": []
}

View File

@ -1,143 +0,0 @@
"""Pocasi CZ resend functions."""
from datetime import datetime, timedelta
import logging
from typing import Any, Literal
from aiohttp import ClientError
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (
DEFAULT_URL,
POCASI_CZ_API_ID,
POCASI_CZ_API_KEY,
POCASI_CZ_ENABLED,
POCASI_CZ_LOGGER_ENABLED,
POCASI_CZ_SEND_INTERVAL,
POCASI_CZ_SUCCESS,
POCASI_CZ_UNEXPECTED,
POCASI_CZ_URL,
POCASI_INVALID_KEY,
WSLINK_URL,
)
from .utils import update_options
_LOGGER = logging.getLogger(__name__)
class PocasiNotInserted(Exception):
"""NotInserted state."""
class PocasiSuccess(Exception):
"""WindySucces state."""
class PocasiApiKeyError(Exception):
"""Windy API Key error."""
class PocasiPush:
"""Push data to Windy."""
def __init__(self, hass: HomeAssistant, config: ConfigEntry) -> None:
"""Init."""
self.hass = hass
self.config = config
self._interval = int(self.config.options.get(POCASI_CZ_SEND_INTERVAL, 30))
self.last_update = datetime.now()
self.next_update = datetime.now() + timedelta(seconds=self._interval)
self.log = self.config.options.get(POCASI_CZ_LOGGER_ENABLED)
self.invalid_response_count = 0
def verify_response(
self,
response: str,
) -> PocasiNotInserted | PocasiSuccess | PocasiApiKeyError | None:
"""Verify answer form server."""
if self.log:
_LOGGER.debug("Pocasi CZ responded: %s", response)
# Server does not provide any responses.
# This is placeholder if future state is changed
return None
async def push_data_to_server(
self, data: dict[str, Any], mode: Literal["WU", "WSLINK"]
):
"""Pushes weather data to server."""
_data = data.copy()
_api_id = self.config.options.get(POCASI_CZ_API_ID)
_api_key = self.config.options.get(POCASI_CZ_API_KEY)
if self.log:
_LOGGER.info(
"Pocasi CZ last update = %s, next update at: %s",
str(self.last_update),
str(self.next_update),
)
if self.next_update > datetime.now():
_LOGGER.debug(
"Triggered update interval limit of %s seconds. Next possilbe update is set to: %s",
self._interval,
self.next_update,
)
return False
request_url: str = ""
if mode == "WSLINK":
_data["wsid"] = _api_id
_data["wspw"] = _api_key
request_url = f"{POCASI_CZ_URL}{WSLINK_URL}"
if mode == "WU":
_data["ID"] = _api_id
_data["PASSWORD"] = _api_key
request_url = f"{POCASI_CZ_URL}{DEFAULT_URL}"
session = async_get_clientsession(self.hass, verify_ssl=False)
_LOGGER.debug(
"Payload for Pocasi Meteo server: [mode=%s] [request_url=%s] = %s",
mode,
request_url,
_data,
)
try:
async with session.get(request_url, params=_data) as resp:
status = await resp.text()
try:
self.verify_response(status)
except PocasiApiKeyError:
# log despite of settings
_LOGGER.critical(POCASI_INVALID_KEY)
await update_options(
self.hass, self.config, POCASI_CZ_ENABLED, False
)
except PocasiSuccess:
if self.log:
_LOGGER.info(POCASI_CZ_SUCCESS)
except ClientError as ex:
_LOGGER.critical("Invalid response from Pocasi Meteo: %s", str(ex))
self.invalid_response_count += 1
if self.invalid_response_count > 3:
_LOGGER.critical(POCASI_CZ_UNEXPECTED)
await update_options(self.hass, self.config, POCASI_CZ_ENABLED, False)
self.last_update = datetime.now()
self.next_update = datetime.now() + timedelta(seconds=self._interval)
if self.log:
_LOGGER.info("Next update: %s", str(self.next_update))
return None

View File

@ -15,7 +15,6 @@ from .const import (
CHILL_INDEX,
DOMAIN,
HEAT_INDEX,
OUTSIDE_BATTERY,
OUTSIDE_HUMIDITY,
OUTSIDE_TEMP,
SENSORS_TO_LOAD,
@ -23,12 +22,11 @@ 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, battery_level_to_icon, battery_level_to_text
from .utils import chill_index, heat_index
_LOGGER = logging.getLogger(__name__)
@ -132,27 +130,13 @@ 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

@ -122,8 +122,7 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
key=WIND_DIR,
native_unit_of_measurement=DEGREE,
state_class=SensorStateClass.MEASUREMENT_ANGLE,
device_class=SensorDeviceClass.WIND_DIRECTION,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=None,
icon="mdi:sign-direction",
translation_key=WIND_DIR,

View File

@ -19,8 +19,6 @@ from .const import (
BARO_PRESSURE,
CH2_HUMIDITY,
CH2_TEMP,
CH2_BATTERY,
INDOOR_BATTERY,
CH3_HUMIDITY,
CH3_TEMP,
CH4_HUMIDITY,
@ -29,29 +27,25 @@ 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,
YEARLY_RAIN,
UnitOfDir,
WBGT_TEMP,
MONTHLY_RAIN,
YEARLY_RAIN,
HOURLY_RAIN,
WEEKLY_RAIN,
)
from .sensors_common import WeatherSensorEntityDescription
from .utils import battery_level_to_icon, battery_level_to_text, wind_dir_to_text
from .utils import wind_dir_to_text
SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
@ -132,8 +126,7 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
key=WIND_DIR,
native_unit_of_measurement=DEGREE,
state_class=SensorStateClass.MEASUREMENT_ANGLE,
device_class=SensorDeviceClass.WIND_DIRECTION,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=None,
icon="mdi:sign-direction",
translation_key=WIND_DIR,
@ -150,8 +143,8 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
WeatherSensorEntityDescription(
key=RAIN,
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.TOTAL,
suggested_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=2,
icon="mdi:weather-pouring",
@ -250,25 +243,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.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=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=CH4_TEMP,
# native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,
@ -310,35 +303,4 @@ 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),
),
WeatherSensorEntityDescription(
key=WBGT_TEMP,
translation_key=WBGT_TEMP,
icon="mdi:thermometer",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
value_fn=lambda data: cast("int", data),
),
)

View File

@ -5,6 +5,7 @@
"valid_credentials_key": "Provide valid API KEY.",
"valid_credentials_match": "API ID and API KEY should not be the same."
},
"step": {
"user": {
"description": "Provide API ID and API KEY so the Weather Station can access HomeAssistant",
@ -24,6 +25,7 @@
}
}
},
"options": {
"error": {
"valid_credentials_api": "Provide valid API ID.",
@ -31,6 +33,7 @@
"valid_credentials_match": "API ID and API KEY should not be the same.",
"windy_key_required": "Windy API key is required if you want to enable this function."
},
"step": {
"init": {
"title": "Configure SWS12500 Integration",
@ -40,6 +43,7 @@
"windy": "Windy configuration"
}
},
"basic": {
"description": "Provide API ID and API KEY so the Weather Station can access HomeAssistant",
"title": "Configure credentials",
@ -56,6 +60,7 @@
"WSLINK": "Enable WSLink API if the station is set to send data via WSLink."
}
},
"windy": {
"description": "Resend weather data to your Windy stations.",
"title": "Configure Windy",
@ -69,24 +74,6 @@
"windy_logger_checkbox": "Enable only if you want to send debuging data to the developer."
}
},
"pocasi": {
"description": "Resend data to Pocasi Meteo CZ",
"title": "Configure Pocasi Meteo CZ",
"data": {
"POCASI_API_ID": "ID from your Pocasi Meteo APP",
"POCASI_API_KEY": "Key from your Pocasi Meteo APP",
"POCASI_SEND_INTERVAL": "Resend interval in seconds",
"pocasi_enabled_checkbox": "Enable resending data to Pocasi Meteo",
"pocasi_logger_checkbox": "Log data and responses"
},
"data_description": {
"POCASI_API_ID": "You can obtain your ID in Pocasi Meteo App",
"POCASI_API_KEY": "You can obtain your KEY in Pocasi Meteo App",
"POCASI_SEND_INTERVAL": "Resend interval in seconds (minimum 12s, default 30s)",
"pocasi_enabled_checkbox": "Enables resending data to Pocasi Meteo",
"pocasi_logger_checkbox": "Enable only if you want to send debbug data to the developer"
}
},
"migration": {
"title": "Statistic migration.",
"description": "For the correct functioning of long-term statistics, it is necessary to migrate the sensor unit in the long-term statistics. The original unit of long-term statistics for daily precipitation was in mm/d, however, the station only sends data in mm without time differentiation.\n\n The sensor to be migrated is for daily precipitation. If the correct value is already in the list for the daily precipitation sensor (mm), then the migration is already complete.\n\n Migration result for the sensor: {migration_status}, a total of {migration_count} rows converted.",
@ -101,71 +88,30 @@
}
}
},
"entity": {
"sensor": {
"indoor_temp": {
"name": "Indoor temperature"
},
"indoor_humidity": {
"name": "Indoor humidity"
},
"outside_temp": {
"name": "Outside Temperature"
},
"outside_humidity": {
"name": "Outside humidity"
},
"uv": {
"name": "UV index"
},
"baro_pressure": {
"name": "Barometric pressure"
},
"dew_point": {
"name": "Dew point"
},
"wind_speed": {
"name": "Wind speed"
},
"wind_dir": {
"name": "Wind direction"
},
"wind_gust": {
"name": "Wind gust"
},
"rain": {
"name": "Rain"
},
"daily_rain": {
"name": "Daily precipitation"
},
"solar_radiation": {
"name": "Solar irradiance"
},
"ch2_temp": {
"name": "Channel 2 temperature"
},
"ch2_humidity": {
"name": "Channel 2 humidity"
},
"ch3_temp": {
"name": "Channel 3 temperature"
},
"ch3_humidity": {
"name": "Channel 3 humidity"
},
"ch4_temp": {
"name": "Channel 4 temperature"
},
"ch4_humidity": {
"name": "Channel 4 humidity"
},
"heat_index": {
"name": "Apparent temperature"
},
"chill_index": {
"name": "Wind chill"
},
"indoor_temp": { "name": "Indoor temperature" },
"indoor_humidity": { "name": "Indoor humidity" },
"outside_temp": { "name": "Outside Temperature" },
"outside_humidity": { "name": "Outside humidity" },
"uv": { "name": "UV index" },
"baro_pressure": { "name": "Barometric pressure" },
"dew_point": { "name": "Dew point" },
"wind_speed": { "name": "Wind speed" },
"wind_dir": { "name": "Wind direction" },
"wind_gust": { "name": "Wind gust" },
"rain": { "name": "Rain" },
"daily_rain": { "name": "Daily precipitation" },
"solar_radiation": { "name": "Solar irradiance" },
"ch2_temp": { "name": "Channel 2 temperature" },
"ch2_humidity": { "name": "Channel 2 humidity" },
"ch3_temp": { "name": "Channel 3 temperature" },
"ch3_humidity": { "name": "Channel 3 humidity" },
"ch4_temp": { "name": "Channel 4 temperature" },
"ch4_humidity": { "name": "Channel 4 humidity" },
"heat_index": { "name": "Apparent temperature" },
"chill_index": { "name": "Wind chill" },
"wind_azimut": {
"name": "Bearing",
"state": {
@ -185,14 +131,6 @@
"wnw": "WNW",
"nw": "NW",
"nnw": "NNW"
},
"outside_battery": {
"name": "Outside battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
}
}
}

View File

@ -24,16 +24,15 @@
}
}
},
"options": {
"error": {
"valid_credentials_api": "Vyplňte platné API ID",
"valid_credentials_key": "Vyplňte platný API KEY",
"valid_credentials_match": "API ID a API KEY nesmějí být stejné!",
"windy_key_required": "Je vyžadován Windy API key, pokud chcete aktivovat přeposílání dat na Windy",
"pocasi_id_required": "Je vyžadován Počasí ID, pokud chcete aktivovat přeposílání dat na Počasí Meteo CZ",
"pocasi_key_required": "Klíč k účtu Počasí Meteo je povinný.",
"pocasi_send_minimum": "Minimální interval pro přeposílání je 12 sekund."
"windy_key_required": "Je vyžadován Windy API key, pokud chcete aktivovat přeposílání dat na Windy"
},
"step": {
"init": {
"title": "Nastavení integrace SWS12500",
@ -41,10 +40,10 @@
"menu_options": {
"basic": "Základní - přístupové údaje (přihlášení)",
"windy": "Nastavení pro přeposílání dat na Windy",
"pocasi": "Nastavení pro přeposlání dat na Počasí Meteo CZ",
"migration": "Migrace statistiky senzoru"
}
},
"basic": {
"description": "Zadejte API ID a API KEY, aby meteostanice mohla komunikovat s HomeAssistantem",
"title": "Nastavení přihlášení",
@ -61,6 +60,7 @@
"wslink": "WSLink API zapněte, pokud je stanice nastavena na zasílání dat přes WSLink."
}
},
"windy": {
"description": "Přeposílání dat z metostanice na Windy",
"title": "Konfigurace Windy",
@ -70,28 +70,10 @@
"windy_logger_checkbox": "Logovat data a odpovědi z Windy"
},
"data_description": {
"WINDY_API_KEY": "Klíč API KEY získaný z https://api.windy.com/keys",
"WINDY_API_KEY": "Klíč API KEY získaný z https://https://api.windy.com/keys",
"windy_logger_checkbox": "Zapnout pouze v případě, že chcete poslat ladící informace vývojáři."
}
},
"pocasi": {
"description": "Přeposílání dat do aplikace Počasí Meteo",
"title": "Konfigurace Počasí Meteo",
"data": {
"POCASI_CZ_API_ID": "ID účtu na Počasí Meteo",
"POCASI_CZ_API_KEY": "Klíč (Key) k účtu Počasí Meteo",
"POCASI_CZ_SEND_INTERVAL": "Interval v sekundách",
"pocasi_enabled_chcekbox": "Povolit přeposílání dat na server Počasí Meteo",
"pocasi_logger_checkbox": "Logovat data a odpovědi z Počasí Meteo"
},
"data_description": {
"POCASI_API_ID": "ID získáte ve své aplikaci Počasí Meteo",
"POCASI_API_KEY": "Klíč (Key) získáte ve své aplikaci Počasí Meteo",
"POCASI_SEND_INTERVAL": "Interval v jakém se mají data na server přeposílat (minimum 12s, defaultně 30s)",
"pocasi_enabled_checkbox": "Zapne přeposílání data na server Počasí Meteo",
"pocasi_logger_checkbox": "Zapnout pouze v případě, že chcete zaslat ladící informace vývojáři."
}
},
"migration": {
"title": "Migrace statistiky senzoru.",
"description": "Pro správnou funkci dlouhodobé statistiky je nutné provést migraci jednotky senzoru v dlouhodobé statistice. Původní jednotka dlouhodobé statistiky pro denní úhrn srážek byla v mm/d, nicméně stanice zasílá pouze data v mm bez časového rozlišení.\n\n Senzor, který má být migrován je pro denní úhrn srážek. Pokud je v seznamu již správná hodnota u senzoru pro denní úhrn (mm), pak je již migrace hotová.\n\n Výsledek migrace pro senzor: {migration_status}, přepvedeno celkem {migration_count} řádků.",
@ -106,86 +88,34 @@
}
}
},
"entity": {
"sensor": {
"indoor_temp": {
"name": "Vnitřní teplota"
},
"indoor_humidity": {
"name": "Vnitřní vlhkost vzduchu"
},
"outside_temp": {
"name": "Venkovní teplota"
},
"outside_humidity": {
"name": "Venkovní vlhkost vzduchu"
},
"uv": {
"name": "UV index"
},
"baro_pressure": {
"name": "Tlak vzduchu"
},
"dew_point": {
"name": "Rosný bod"
},
"wind_speed": {
"name": "Rychlost větru"
},
"wind_dir": {
"name": "Směr větru"
},
"wind_gust": {
"name": "Poryvy větru"
},
"rain": {
"name": "Srážky"
},
"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"
},
"ch3_temp": {
"name": "Teplota senzoru 3"
},
"ch3_humidity": {
"name": "Vlhkost sensoru 3"
},
"ch4_temp": {
"name": "Teplota senzoru 4"
},
"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"
},
"wbgt_temp": {
"name": "WBGT index"
},
"indoor_temp": { "name": "Vnitřní teplota" },
"indoor_humidity": { "name": "Vnitřní vlhkost vzduchu" },
"outside_temp": { "name": "Venkovní teplota" },
"outside_humidity": { "name": "Venkovní vlhkost vzduchu" },
"uv": { "name": "UV index" },
"baro_pressure": { "name": "Tlak vzduchu" },
"dew_point": { "name": "Rosný bod" },
"wind_speed": { "name": "Rychlost větru" },
"wind_dir": { "name": "Směr větru" },
"wind_gust": { "name": "Poryvy větru" },
"rain": { "name": "Srážky" },
"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" },
"ch3_temp": { "name": "Teplota senzoru 3" },
"ch3_humidity": { "name": "Vlhkost sensoru 3" },
"ch4_temp": { "name": "Teplota senzoru 4" },
"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": {
@ -206,30 +136,6 @@
"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

@ -5,6 +5,7 @@
"valid_credentials_key": "Provide valid API KEY.",
"valid_credentials_match": "API ID and API KEY should not be the same."
},
"step": {
"user": {
"description": "Provide API ID and API KEY so the Weather Station can access HomeAssistant",
@ -24,6 +25,7 @@
}
}
},
"options": {
"error": {
"valid_credentials_api": "Provide valid API ID.",
@ -31,6 +33,7 @@
"valid_credentials_match": "API ID and API KEY should not be the same.",
"windy_key_required": "Windy API key is required if you want to enable this function."
},
"step": {
"init": {
"title": "Configure SWS12500 Integration",
@ -40,6 +43,7 @@
"windy": "Windy configuration"
}
},
"basic": {
"description": "Provide API ID and API KEY so the Weather Station can access HomeAssistant",
"title": "Configure credentials",
@ -56,6 +60,7 @@
"WSLINK": "Enable WSLink API if the station is set to send data via WSLink."
}
},
"windy": {
"description": "Resend weather data to your Windy stations.",
"title": "Configure Windy",
@ -69,24 +74,6 @@
"windy_logger_checkbox": "Enable only if you want to send debuging data to the developer."
}
},
"pocasi": {
"description": "Resend data to Pocasi Meteo CZ",
"title": "Configure Pocasi Meteo CZ",
"data": {
"POCASI_API_ID": "ID from your Pocasi Meteo APP",
"POCASI_API_KEY": "Key from your Pocasi Meteo APP",
"POCASI_SEND_INTERVAL": "Resend interval in seconds",
"pocasi_enabled_checkbox": "Enable resending data to Pocasi Meteo",
"pocasi_logger_checkbox": "Log data and responses"
},
"data_description": {
"POCASI_API_ID": "You can obtain your ID in Pocasi Meteo App",
"POCASI_API_KEY": "You can obtain your KEY in Pocasi Meteo App",
"POCASI_SEND_INTERVAL": "Resend interval in seconds (minimum 12s, default 30s)",
"pocasi_enabled_checkbox": "Enables resending data to Pocasi Meteo",
"pocasi_logger_checkbox": "Enable only if you want to send debbug data to the developer"
}
},
"migration": {
"title": "Statistic migration.",
"description": "For the correct functioning of long-term statistics, it is necessary to migrate the sensor unit in the long-term statistics. The original unit of long-term statistics for daily precipitation was in mm/d, however, the station only sends data in mm without time differentiation.\n\n The sensor to be migrated is for daily precipitation. If the correct value is already in the list for the daily precipitation sensor (mm), then the migration is already complete.\n\n Migration result for the sensor: {migration_status}, a total of {migration_count} rows converted.",
@ -101,86 +88,34 @@
}
}
},
"entity": {
"sensor": {
"indoor_temp": {
"name": "Indoor temperature"
},
"indoor_humidity": {
"name": "Indoor humidity"
},
"outside_temp": {
"name": "Outside Temperature"
},
"outside_humidity": {
"name": "Outside humidity"
},
"uv": {
"name": "UV index"
},
"baro_pressure": {
"name": "Barometric pressure"
},
"dew_point": {
"name": "Dew point"
},
"wind_speed": {
"name": "Wind speed"
},
"wind_dir": {
"name": "Wind direction"
},
"wind_gust": {
"name": "Wind gust"
},
"rain": {
"name": "Rain"
},
"daily_rain": {
"name": "Daily precipitation"
},
"solar_radiation": {
"name": "Solar irradiance"
},
"ch2_temp": {
"name": "Channel 2 temperature"
},
"ch2_humidity": {
"name": "Channel 2 humidity"
},
"ch3_temp": {
"name": "Channel 3 temperature"
},
"ch3_humidity": {
"name": "Channel 3 humidity"
},
"ch4_temp": {
"name": "Channel 4 temperature"
},
"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"
},
"wbgt_index": {
"name": "WBGT index"
},
"indoor_temp": { "name": "Indoor temperature" },
"indoor_humidity": { "name": "Indoor humidity" },
"outside_temp": { "name": "Outside Temperature" },
"outside_humidity": { "name": "Outside humidity" },
"uv": { "name": "UV index" },
"baro_pressure": { "name": "Barometric pressure" },
"dew_point": { "name": "Dew point" },
"wind_speed": { "name": "Wind speed" },
"wind_dir": { "name": "Wind direction" },
"wind_gust": { "name": "Wind gust" },
"rain": { "name": "Rain" },
"daily_rain": { "name": "Daily precipitation" },
"solar_radiation": { "name": "Solar irradiance" },
"ch2_temp": { "name": "Channel 2 temperature" },
"ch2_humidity": { "name": "Channel 2 humidity" },
"ch3_temp": { "name": "Channel 3 temperature" },
"ch3_humidity": { "name": "Channel 3 humidity" },
"ch4_temp": { "name": "Channel 4 temperature" },
"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": {
@ -201,30 +136,6 @@
"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,7 +20,6 @@ from homeassistant.helpers.translation import async_get_translations
from .const import (
AZIMUT,
BATTERY_LEVEL,
DATABASE_PATH,
DEV_DBG,
OUTSIDE_HUMIDITY,
@ -30,7 +29,6 @@ from .const import (
SENSORS_TO_LOAD,
WIND_SPEED,
UnitOfDir,
UnitOfBat,
)
_LOGGER = logging.getLogger(__name__)
@ -183,32 +181,6 @@ 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
@ -295,12 +267,10 @@ 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

View File

@ -106,7 +106,7 @@ class WindyPush:
if self.next_update > datetime.now():
return False
purged_data = data.copy()
purged_data = dict(data)
for purge in PURGE_DATA:
if purge in purged_data:

View File

@ -0,0 +1,17 @@
"""Shared keys and helpers for storing integration runtime state in hass.data.
This integration uses `hass.data[DOMAIN][entry_id]` as a per-entry dictionary.
Keeping keys in one place prevents subtle bugs where different modules store
different value types under the same key.
"""
from __future__ import annotations
from typing import Final
# Per-entry dict keys stored under hass.data[DOMAIN][entry_id]
ENTRY_COORDINATOR: Final[str] = "coordinator"
ENTRY_ADD_ENTITIES: Final[str] = "async_add_entities"
ENTRY_DESCRIPTIONS: Final[str] = "sensor_descriptions"
ENTRY_LAST_OPTIONS: Final[str] = "last_options"

View File

@ -1,6 +1,4 @@
{
"name": "Sencor SWS 12500 Weather station",
"filename": "weather-station.zip",
"render_readme": true,
"zip_release": true
"render_readme": true
}