Compare commits

..

2 Commits
v1.6.8 ... main

10 changed files with 250 additions and 220 deletions

View File

@ -1,12 +1,15 @@
"""Config flow for Sencor SWS 12500 Weather Station integration.""" """Config flow for Sencor SWS 12500 Weather Station integration."""
import logging
from typing import Any from typing import Any
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, OptionsFlow from homeassistant.config_entries import ConfigFlow, OptionsFlow
from homeassistant.const import UnitOfPrecipitationDepth, UnitOfVolumetricFlux
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.entity_registry as er
from .const import ( from .const import (
API_ID, API_ID,
@ -14,12 +17,18 @@ from .const import (
DEV_DBG, DEV_DBG,
DOMAIN, DOMAIN,
INVALID_CREDENTIALS, INVALID_CREDENTIALS,
MIG_FROM,
MIG_TO,
SENSOR_TO_MIGRATE,
SENSORS_TO_LOAD, SENSORS_TO_LOAD,
WINDY_API_KEY, WINDY_API_KEY,
WINDY_ENABLED, WINDY_ENABLED,
WINDY_LOGGER_ENABLED, WINDY_LOGGER_ENABLED,
WSLINK, WSLINK,
) )
from .utils import long_term_units_in_statistics_meta, migrate_data
_LOGGER = logging.getLogger(__name__)
class CannotConnect(HomeAssistantError): class CannotConnect(HomeAssistantError):
@ -43,6 +52,13 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.user_data_schema = {} self.user_data_schema = {}
self.sensors: dict[str, Any] = {} self.sensors: dict[str, Any] = {}
self.migrate_schema = {} 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 @property
def config_entry(self): def config_entry(self):
@ -66,11 +82,9 @@ class ConfigOptionsFlowHandler(OptionsFlow):
} }
self.sensors: dict[str, Any] = { self.sensors: dict[str, Any] = {
SENSORS_TO_LOAD: ( SENSORS_TO_LOAD: self.config_entry.options.get(SENSORS_TO_LOAD)
self.config_entry.options.get(SENSORS_TO_LOAD)
if isinstance(self.config_entry.options.get(SENSORS_TO_LOAD), list) if isinstance(self.config_entry.options.get(SENSORS_TO_LOAD), list)
else [] else []
)
} }
self.windy_data: dict[str, Any] = { self.windy_data: dict[str, Any] = {
@ -90,13 +104,43 @@ class ConfigOptionsFlowHandler(OptionsFlow):
vol.Optional( vol.Optional(
WINDY_LOGGER_ENABLED, WINDY_LOGGER_ENABLED,
default=self.windy_data[WINDY_LOGGER_ENABLED], default=self.windy_data[WINDY_LOGGER_ENABLED],
): bool ): bool or False,
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"}
} }
async def async_step_init(self, user_input=None): async def async_step_init(self, user_input=None):
"""Manage the options - show menu first.""" """Manage the options - show menu first."""
return self.async_show_menu(step_id="init", menu_options=["basic", "windy"]) return self.async_show_menu(
step_id="init", menu_options=["basic", "windy", "migration"]
)
async def async_step_basic(self, user_input=None): async def async_step_basic(self, user_input=None):
"""Manage basic options - credentials.""" """Manage basic options - credentials."""
@ -164,6 +208,151 @@ class ConfigOptionsFlowHandler(OptionsFlow):
return self.async_create_entry(title=DOMAIN, data=user_input) 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): class ConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Sencor SWS 12500 Weather Station.""" """Handle a config flow for Sencor SWS 12500 Weather Station."""

View File

@ -63,7 +63,6 @@ OUTSIDE_TEMP: Final = "outside_temp"
DEW_POINT: Final = "dew_point" DEW_POINT: Final = "dew_point"
OUTSIDE_HUMIDITY: Final = "outside_humidity" OUTSIDE_HUMIDITY: Final = "outside_humidity"
OUTSIDE_CONNECTION: Final = "outside_connection" OUTSIDE_CONNECTION: Final = "outside_connection"
OUTSIDE_BATTERY: Final = "outside_battery"
WIND_SPEED: Final = "wind_speed" WIND_SPEED: Final = "wind_speed"
WIND_GUST: Final = "wind_gust" WIND_GUST: Final = "wind_gust"
WIND_DIR: Final = "wind_dir" WIND_DIR: Final = "wind_dir"
@ -77,12 +76,10 @@ DAILY_RAIN: Final = "daily_rain"
SOLAR_RADIATION: Final = "solar_radiation" SOLAR_RADIATION: Final = "solar_radiation"
INDOOR_TEMP: Final = "indoor_temp" INDOOR_TEMP: Final = "indoor_temp"
INDOOR_HUMIDITY: Final = "indoor_humidity" INDOOR_HUMIDITY: Final = "indoor_humidity"
INDOOR_BATTERY: Final = "indoor_battery"
UV: Final = "uv" UV: Final = "uv"
CH2_TEMP: Final = "ch2_temp" CH2_TEMP: Final = "ch2_temp"
CH2_HUMIDITY: Final = "ch2_humidity" CH2_HUMIDITY: Final = "ch2_humidity"
CH2_CONNECTION: Final = "ch2_connection" CH2_CONNECTION: Final = "ch2_connection"
CH2_BATTERY: Final = "ch2_battery"
CH3_TEMP: Final = "ch3_temp" CH3_TEMP: Final = "ch3_temp"
CH3_HUMIDITY: Final = "ch3_humidity" CH3_HUMIDITY: Final = "ch3_humidity"
CH3_CONNECTION: Final = "ch3_connection" CH3_CONNECTION: Final = "ch3_connection"
@ -91,10 +88,9 @@ CH4_HUMIDITY: Final = "ch4_humidity"
CH4_CONNECTION: Final = "ch4_connection" CH4_CONNECTION: Final = "ch4_connection"
HEAT_INDEX: Final = "heat_index" HEAT_INDEX: Final = "heat_index"
CHILL_INDEX: Final = "chill_index" CHILL_INDEX: Final = "chill_index"
WBGT_TEMP: Final = "wbgt_temp"
REMAP_ITEMS: dict[str, str] = { REMAP_ITEMS: dict = {
"baromin": BARO_PRESSURE, "baromin": BARO_PRESSURE,
"tempf": OUTSIDE_TEMP, "tempf": OUTSIDE_TEMP,
"dewptf": DEW_POINT, "dewptf": DEW_POINT,
@ -116,7 +112,7 @@ REMAP_ITEMS: dict[str, str] = {
"soilmoisture3": CH4_HUMIDITY, "soilmoisture3": CH4_HUMIDITY,
} }
REMAP_WSLINK_ITEMS: dict[str, str] = { REMAP_WSLINK_ITEMS: dict = {
"intem": INDOOR_TEMP, "intem": INDOOR_TEMP,
"inhum": INDOOR_HUMIDITY, "inhum": INDOOR_HUMIDITY,
"t1tem": OUTSIDE_TEMP, "t1tem": OUTSIDE_TEMP,
@ -141,12 +137,6 @@ REMAP_WSLINK_ITEMS: dict[str, str] = {
"t1rainwy": WEEKLY_RAIN, "t1rainwy": WEEKLY_RAIN,
"t1rainmth": MONTHLY_RAIN, "t1rainmth": MONTHLY_RAIN,
"t1rainyr": YEARLY_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 # TODO: Add more sensors
@ -159,19 +149,10 @@ REMAP_WSLINK_ITEMS: dict[str, str] = {
DISABLED_BY_DEFAULT: Final = [ DISABLED_BY_DEFAULT: Final = [
CH2_TEMP, CH2_TEMP,
CH2_HUMIDITY, CH2_HUMIDITY,
CH2_BATTERY,
CH3_TEMP, CH3_TEMP,
CH3_HUMIDITY, CH3_HUMIDITY,
CH4_TEMP, CH4_TEMP,
CH4_HUMIDITY, CH4_HUMIDITY,
OUTSIDE_BATTERY,
WBGT_TEMP,
]
BATTERY_LIST = [
OUTSIDE_BATTERY,
INDOOR_BATTERY,
CH2_BATTERY,
] ]
@ -214,18 +195,3 @@ AZIMUT: list[UnitOfDir] = [
UnitOfDir.NNW, UnitOfDir.NNW,
UnitOfDir.N, 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", "issue_tracker": "https://github.com/schizza/SWS-12500-custom-component/issues",
"requirements": [], "requirements": [],
"ssdp": [], "ssdp": [],
"version": "1.6.8", "version": "1.6.2",
"zeroconf": [] "zeroconf": []
} }

View File

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

View File

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

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

View File

@ -116,7 +116,6 @@
"weekly_rain": { "name": "Týdenní úhrn srážek" }, "weekly_rain": { "name": "Týdenní úhrn srážek" },
"monthly_rain": { "name": "Měsíční úhrn srážek" }, "monthly_rain": { "name": "Měsíční úhrn srážek" },
"yearly_rain": { "name": "Roční úhrn srážek" }, "yearly_rain": { "name": "Roční úhrn srážek" },
"wbgt_temp": { "name": "WBGT index" },
"wind_azimut": { "wind_azimut": {
"name": "Azimut", "name": "Azimut",
"state": { "state": {
@ -137,30 +136,6 @@
"nw": "SZ", "nw": "SZ",
"nnw": "SSZ" "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

@ -116,7 +116,6 @@
"weekly_rain": { "name": "Weekly precipitation" }, "weekly_rain": { "name": "Weekly precipitation" },
"monthly_rain": { "name": "Monthly precipitation" }, "monthly_rain": { "name": "Monthly precipitation" },
"yearly_rain": { "name": "Yearly precipitation" }, "yearly_rain": { "name": "Yearly precipitation" },
"wbgt_index": { "name": "WBGT index" },
"wind_azimut": { "wind_azimut": {
"name": "Bearing", "name": "Bearing",
"state": { "state": {
@ -137,30 +136,6 @@
"nw": "NW", "nw": "NW",
"nnw": "NNW" "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 ( from .const import (
AZIMUT, AZIMUT,
BATTERY_LEVEL,
DATABASE_PATH, DATABASE_PATH,
DEV_DBG, DEV_DBG,
OUTSIDE_HUMIDITY, OUTSIDE_HUMIDITY,
@ -30,7 +29,6 @@ from .const import (
SENSORS_TO_LOAD, SENSORS_TO_LOAD,
WIND_SPEED, WIND_SPEED,
UnitOfDir, UnitOfDir,
UnitOfBat,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -183,32 +181,6 @@ def wind_dir_to_text(deg: float) -> UnitOfDir | None:
return 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: def fahrenheit_to_celsius(fahrenheit: float) -> float:
"""Convert Fahrenheit to Celsius.""" """Convert Fahrenheit to Celsius."""
return (fahrenheit - 32) * 5.0 / 9.0 return (fahrenheit - 32) * 5.0 / 9.0
@ -295,12 +267,10 @@ def long_term_units_in_statistics_meta():
db = conn.cursor() db = conn.cursor()
try: try:
db.execute( db.execute("""
"""
SELECT statistic_id, unit_of_measurement from statistics_meta SELECT statistic_id, unit_of_measurement from statistics_meta
WHERE statistic_id LIKE 'sensor.weather_station_sws%' WHERE statistic_id LIKE 'sensor.weather_station_sws%'
""" """)
)
rows = db.fetchall() rows = db.fetchall()
sensor_units = { sensor_units = {
statistic_id: f"{statistic_id} ({unit})" for statistic_id, unit in rows statistic_id: f"{statistic_id} ({unit})" for statistic_id, unit in rows

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"