Compare commits

...

6 Commits

Author SHA1 Message Date
FigurinePanda43 732ff47036
Merge 58b9da9b80 into 5a1d04944e 2026-02-28 12:44:46 -05:00
SchiZzA 5a1d04944e
Bump version. 2026-02-28 18:43:18 +01:00
SchiZzA 30b88a0f13
Fix options flow and route switching after config updates
- Keep OptionsFlow state in sync by building defaults from entry data + options
- Store the config entry on the coordinator for consistent access
- Make route registry method-aware and switch handlers by url_path with
  awarness of POST/GET method.
- Fixed an issue, when on config update needs restart of HomeAssistant
  to reload integration.
2026-02-28 18:37:19 +01:00
SchiZzA 048bd6bd4c
Fix Windy credential validation for None/blank options
Normalize Windy station ID and password from config options and require both values before enabling Windy resend.
2026-02-26 19:33:36 +01:00
FigurinePanda43 58b9da9b80 Add support for channels 4-8
- Add CH4-CH8 constants and sensor definitions
- Fix REMAP_ITEMS to include soiltemp4f-7f mappings for Weather API
- Add battery support for all channels
- Add translations for new sensors
- Fix JSON structure in strings.json
- Update README.md with multi-channel documentation
2026-01-12 22:15:58 +01:00
FigurinePanda43 fa2aa9a925 Add support for channels 4-8 2026-01-12 22:08:32 +01:00
11 changed files with 549 additions and 67 deletions

View File

@ -129,6 +129,43 @@ So, deleteing integration and reinstalling will make sure, that sensors will be
- You are done. - You are done.
## Multi-channel sensor support (CH2-CH8)
This integration supports up to 8 external sensor channels for temperature, humidity, and battery monitoring.
### Supported channels
- **CH2-CH3**: Enabled by default
- **CH4-CH8**: Available but disabled by default (enable manually in Home Assistant)
### Available sensors per channel
Each channel provides:
- **Temperature sensor** (with configurable unit conversion)
- **Humidity sensor** (percentage)
- **Battery level sensor** (percentage)
- **Connection status** (connected/disconnected)
### Enabling additional channels
By default, channels 4-8 are disabled to avoid cluttering your interface. To enable them:
1. Go to **Settings** → **Devices & Services**
2. Find **Sencor SWS 12500** and click on it
3. You'll see all available entities, including disabled ones
4. Click on any disabled channel sensor (e.g., "Channel 5 Temperature")
5. Click the settings icon and enable the entity
6. Repeat for other sensors you want to use
### Station configuration
Your weather station must be configured to send data for these channels. Refer to your station's manual on how to pair and configure external sensors to specific channels.
**Note**: The integration automatically detects incoming data from any channel. If you don't see data for a channel you've enabled, verify that:
- The external sensor is properly paired with your station
- The sensor is sending data (check battery level)
- Your station firmware supports the channel you're trying to use
## WSLink notes ## WSLink notes
While your station is using WSLink you have to have Home Assistant in SSL mode or behind SSL proxy server. While your station is using WSLink you have to have Home Assistant in SSL mode or behind SSL proxy server.

View File

@ -52,6 +52,7 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
"""Init global updater.""" """Init global updater."""
self.hass = hass self.hass = hass
self.config = config self.config = config
self.config_entry = config
self.windy = WindyPush(hass, config) self.windy = WindyPush(hass, config)
self.pocasi: PocasiPush = PocasiPush(hass, config) self.pocasi: PocasiPush = PocasiPush(hass, config)
super().__init__(hass, _LOGGER, name=DOMAIN) super().__init__(hass, _LOGGER, name=DOMAIN)

View File

@ -40,9 +40,10 @@ class InvalidAuth(HomeAssistantError):
class ConfigOptionsFlowHandler(OptionsFlow): class ConfigOptionsFlowHandler(OptionsFlow):
"""Handle WeatherStation ConfigFlow.""" """Handle WeatherStation ConfigFlow."""
def __init__(self) -> None: def __init__(self, config_entry) -> None:
"""Initialize flow.""" """Initialize flow."""
super().__init__() super().__init__()
self.config_entry = config_entry
self.windy_data: dict[str, Any] = {} self.windy_data: dict[str, Any] = {}
self.windy_data_schema = {} self.windy_data_schema = {}
@ -53,18 +54,15 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.pocasi_cz: dict[str, Any] = {} self.pocasi_cz: dict[str, Any] = {}
self.pocasi_cz_schema = {} self.pocasi_cz_schema = {}
@property
def config_entry(self):
return self.hass.config_entries.async_get_entry(self.handler)
async def _get_entry_data(self): async def _get_entry_data(self):
"""Get entry data.""" """Get entry data."""
entry_data = {**self.config_entry.data, **self.config_entry.options}
self.user_data = { self.user_data = {
API_ID: self.config_entry.options.get(API_ID), API_ID: entry_data.get(API_ID),
API_KEY: self.config_entry.options.get(API_KEY), API_KEY: entry_data.get(API_KEY),
WSLINK: self.config_entry.options.get(WSLINK, False), WSLINK: entry_data.get(WSLINK, False),
DEV_DBG: self.config_entry.options.get(DEV_DBG, False), DEV_DBG: entry_data.get(DEV_DBG, False),
} }
self.user_data_schema = { self.user_data_schema = {
@ -76,19 +74,17 @@ class ConfigOptionsFlowHandler(OptionsFlow):
self.sensors = { self.sensors = {
SENSORS_TO_LOAD: ( SENSORS_TO_LOAD: (
self.config_entry.options.get(SENSORS_TO_LOAD) entry_data.get(SENSORS_TO_LOAD)
if isinstance(self.config_entry.options.get(SENSORS_TO_LOAD), list) if isinstance(entry_data.get(SENSORS_TO_LOAD), list)
else [] else []
) )
} }
self.windy_data = { self.windy_data = {
WINDY_STATION_ID: self.config_entry.options.get(WINDY_STATION_ID), WINDY_STATION_ID: entry_data.get(WINDY_STATION_ID),
WINDY_STATION_PW: self.config_entry.options.get(WINDY_STATION_PW), WINDY_STATION_PW: entry_data.get(WINDY_STATION_PW),
WINDY_ENABLED: self.config_entry.options.get(WINDY_ENABLED, False), WINDY_ENABLED: entry_data.get(WINDY_ENABLED, False),
WINDY_LOGGER_ENABLED: self.config_entry.options.get( WINDY_LOGGER_ENABLED: entry_data.get(WINDY_LOGGER_ENABLED, False),
WINDY_LOGGER_ENABLED, False
),
} }
self.windy_data_schema = { self.windy_data_schema = {
@ -107,15 +103,11 @@ class ConfigOptionsFlowHandler(OptionsFlow):
} }
self.pocasi_cz = { self.pocasi_cz = {
POCASI_CZ_API_ID: self.config_entry.options.get(POCASI_CZ_API_ID, ""), POCASI_CZ_API_ID: entry_data.get(POCASI_CZ_API_ID, ""),
POCASI_CZ_API_KEY: self.config_entry.options.get(POCASI_CZ_API_KEY, ""), POCASI_CZ_API_KEY: entry_data.get(POCASI_CZ_API_KEY, ""),
POCASI_CZ_ENABLED: self.config_entry.options.get(POCASI_CZ_ENABLED, False), POCASI_CZ_ENABLED: entry_data.get(POCASI_CZ_ENABLED, False),
POCASI_CZ_LOGGER_ENABLED: self.config_entry.options.get( POCASI_CZ_LOGGER_ENABLED: entry_data.get(POCASI_CZ_LOGGER_ENABLED, False),
POCASI_CZ_LOGGER_ENABLED, False POCASI_CZ_SEND_INTERVAL: entry_data.get(POCASI_CZ_SEND_INTERVAL, 30),
),
POCASI_CZ_SEND_INTERVAL: self.config_entry.options.get(
POCASI_CZ_SEND_INTERVAL, 30
),
} }
self.pocasi_cz_schema = { self.pocasi_cz_schema = {
@ -310,4 +302,4 @@ class ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
@callback @callback
def async_get_options_flow(config_entry) -> ConfigOptionsFlowHandler: def async_get_options_flow(config_entry) -> ConfigOptionsFlowHandler:
"""Get the options flow for this handler.""" """Get the options flow for this handler."""
return ConfigOptionsFlowHandler() return ConfigOptionsFlowHandler(config_entry)

View File

@ -112,9 +112,27 @@ 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"
CH3_BATTERY: Final = "ch3_battery"
CH4_TEMP: Final = "ch4_temp" CH4_TEMP: Final = "ch4_temp"
CH4_HUMIDITY: Final = "ch4_humidity" CH4_HUMIDITY: Final = "ch4_humidity"
CH4_CONNECTION: Final = "ch4_connection" CH4_CONNECTION: Final = "ch4_connection"
CH4_BATTERY: Final = "ch4_battery"
CH5_TEMP: Final = "ch5_temp"
CH5_HUMIDITY: Final = "ch5_humidity"
CH5_CONNECTION: Final = "ch5_connection"
CH5_BATTERY: Final = "ch5_battery"
CH6_TEMP: Final = "ch6_temp"
CH6_HUMIDITY: Final = "ch6_humidity"
CH6_CONNECTION: Final = "ch6_connection"
CH6_BATTERY: Final = "ch6_battery"
CH7_TEMP: Final = "ch7_temp"
CH7_HUMIDITY: Final = "ch7_humidity"
CH7_CONNECTION: Final = "ch7_connection"
CH7_BATTERY: Final = "ch7_battery"
CH8_TEMP: Final = "ch8_temp"
CH8_HUMIDITY: Final = "ch8_humidity"
CH8_CONNECTION: Final = "ch8_connection"
CH8_BATTERY: Final = "ch8_battery"
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" WBGT_TEMP: Final = "wbgt_temp"
@ -140,6 +158,14 @@ REMAP_ITEMS: dict[str, str] = {
"soilmoisture2": CH3_HUMIDITY, "soilmoisture2": CH3_HUMIDITY,
"soiltemp3f": CH4_TEMP, "soiltemp3f": CH4_TEMP,
"soilmoisture3": CH4_HUMIDITY, "soilmoisture3": CH4_HUMIDITY,
"soiltemp4f": CH5_TEMP,
"soilmoisture4": CH5_HUMIDITY,
"soiltemp5f": CH6_TEMP,
"soilmoisture5": CH6_HUMIDITY,
"soiltemp6f": CH7_TEMP,
"soilmoisture6": CH7_HUMIDITY,
"soiltemp7f": CH8_TEMP,
"soilmoisture7": CH8_HUMIDITY,
} }
REMAP_WSLINK_ITEMS: dict[str, str] = { REMAP_WSLINK_ITEMS: dict[str, str] = {
@ -161,6 +187,11 @@ REMAP_WSLINK_ITEMS: dict[str, str] = {
"t1cn": OUTSIDE_CONNECTION, "t1cn": OUTSIDE_CONNECTION,
"t234c1cn": CH2_CONNECTION, "t234c1cn": CH2_CONNECTION,
"t234c2cn": CH3_CONNECTION, "t234c2cn": CH3_CONNECTION,
"t234c3cn": CH4_CONNECTION,
"t234c4cn": CH5_CONNECTION,
"t234c5cn": CH6_CONNECTION,
"t234c6cn": CH7_CONNECTION,
"t234c7cn": CH8_CONNECTION,
"t1chill": CHILL_INDEX, "t1chill": CHILL_INDEX,
"t1heat": HEAT_INDEX, "t1heat": HEAT_INDEX,
"t1rainhr": HOURLY_RAIN, "t1rainhr": HOURLY_RAIN,
@ -169,9 +200,25 @@ REMAP_WSLINK_ITEMS: dict[str, str] = {
"t1rainyr": YEARLY_RAIN, "t1rainyr": YEARLY_RAIN,
"t234c2tem": CH3_TEMP, "t234c2tem": CH3_TEMP,
"t234c2hum": CH3_HUMIDITY, "t234c2hum": CH3_HUMIDITY,
"t234c3tem": CH4_TEMP,
"t234c3hum": CH4_HUMIDITY,
"t234c4tem": CH5_TEMP,
"t234c4hum": CH5_HUMIDITY,
"t234c5tem": CH6_TEMP,
"t234c5hum": CH6_HUMIDITY,
"t234c6tem": CH7_TEMP,
"t234c6hum": CH7_HUMIDITY,
"t234c7tem": CH8_TEMP,
"t234c7hum": CH8_HUMIDITY,
"t1bat": OUTSIDE_BATTERY, "t1bat": OUTSIDE_BATTERY,
"inbat": INDOOR_BATTERY, "inbat": INDOOR_BATTERY,
"t234c1bat": CH2_BATTERY, "t234c1bat": CH2_BATTERY,
"t234c2bat": CH3_BATTERY,
"t234c3bat": CH4_BATTERY,
"t234c4bat": CH5_BATTERY,
"t234c5bat": CH6_BATTERY,
"t234c6bat": CH7_BATTERY,
"t234c7bat": CH8_BATTERY,
"t1wbgt": WBGT_TEMP, "t1wbgt": WBGT_TEMP,
} }
@ -188,8 +235,22 @@ DISABLED_BY_DEFAULT: Final = [
CH2_BATTERY, CH2_BATTERY,
CH3_TEMP, CH3_TEMP,
CH3_HUMIDITY, CH3_HUMIDITY,
CH3_BATTERY,
CH4_TEMP, CH4_TEMP,
CH4_HUMIDITY, CH4_HUMIDITY,
CH4_BATTERY,
CH5_TEMP,
CH5_HUMIDITY,
CH5_BATTERY,
CH6_TEMP,
CH6_HUMIDITY,
CH6_BATTERY,
CH7_TEMP,
CH7_HUMIDITY,
CH7_BATTERY,
CH8_TEMP,
CH8_HUMIDITY,
CH8_BATTERY,
OUTSIDE_BATTERY, OUTSIDE_BATTERY,
WBGT_TEMP, WBGT_TEMP,
] ]
@ -198,6 +259,12 @@ BATTERY_LIST = [
OUTSIDE_BATTERY, OUTSIDE_BATTERY,
INDOOR_BATTERY, INDOOR_BATTERY,
CH2_BATTERY, CH2_BATTERY,
CH3_BATTERY,
CH4_BATTERY,
CH5_BATTERY,
CH6_BATTERY,
CH7_BATTERY,
CH8_BATTERY,
] ]

View File

@ -14,6 +14,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.8.1", "version": "1.8.3",
"zeroconf": [] "zeroconf": []
} }

View File

@ -33,8 +33,8 @@ class Routes:
def switch_route(self, coordinator: Callable, url_path: str): def switch_route(self, coordinator: Callable, url_path: str):
"""Switch route.""" """Switch route."""
for url, route in self.routes.items(): for route in self.routes.values():
if url == url_path: if route.url_path == url_path:
_LOGGER.info("New coordinator to route: %s", route.url_path) _LOGGER.info("New coordinator to route: %s", route.url_path)
route.enabled = True route.enabled = True
route.handler = coordinator route.handler = coordinator
@ -52,18 +52,20 @@ class Routes:
enabled: bool = False, enabled: bool = False,
): ):
"""Add route.""" """Add route."""
self.routes[url_path] = Route(url_path, route, handler, enabled) key = f"{route.method}:{url_path}"
self.routes[key] = Route(url_path, route, handler, enabled)
def get_route(self, url_path: str) -> Route: def get_route(self, url_path: str) -> Route | None:
"""Get route.""" """Get route."""
return self.routes.get(url_path, Route) for route in self.routes.values():
if route.url_path == url_path:
return route
return None
def get_enabled(self) -> str: def get_enabled(self) -> str:
"""Get enabled routes.""" """Get enabled routes."""
enabled_routes = [ enabled_routes = {route.url_path for route in self.routes.values() if route.enabled}
route.url_path for route in self.routes.values() if route.enabled return ", ".join(sorted(enabled_routes)) if enabled_routes else "None"
]
return "".join(enabled_routes) if enabled_routes else "None"
def __str__(self): def __str__(self):
"""Return string representation.""" """Return string representation."""

View File

@ -23,6 +23,14 @@ from .const import (
CH3_TEMP, CH3_TEMP,
CH4_HUMIDITY, CH4_HUMIDITY,
CH4_TEMP, CH4_TEMP,
CH5_HUMIDITY,
CH5_TEMP,
CH6_HUMIDITY,
CH6_TEMP,
CH7_HUMIDITY,
CH7_TEMP,
CH8_HUMIDITY,
CH8_TEMP,
CHILL_INDEX, CHILL_INDEX,
DAILY_RAIN, DAILY_RAIN,
DEW_POINT, DEW_POINT,
@ -234,6 +242,82 @@ SENSOR_TYPES_WEATHER_API: tuple[WeatherSensorEntityDescription, ...] = (
translation_key=CH4_HUMIDITY, translation_key=CH4_HUMIDITY,
value_fn=lambda data: cast("int", data), value_fn=lambda data: cast("int", data),
), ),
WeatherSensorEntityDescription(
key=CH5_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=CH5_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH5_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH5_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH6_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=CH6_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH6_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH6_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH7_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=CH7_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH7_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH7_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH8_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=CH8_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH8_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH8_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription( WeatherSensorEntityDescription(
key=HEAT_INDEX, key=HEAT_INDEX,
native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT,

View File

@ -20,8 +20,24 @@ from .const import (
CH2_BATTERY, CH2_BATTERY,
CH2_HUMIDITY, CH2_HUMIDITY,
CH2_TEMP, CH2_TEMP,
CH3_BATTERY,
CH3_HUMIDITY, CH3_HUMIDITY,
CH3_TEMP, CH3_TEMP,
CH4_BATTERY,
CH4_HUMIDITY,
CH4_TEMP,
CH5_BATTERY,
CH5_HUMIDITY,
CH5_TEMP,
CH6_BATTERY,
CH6_HUMIDITY,
CH6_TEMP,
CH7_BATTERY,
CH7_HUMIDITY,
CH7_TEMP,
CH8_BATTERY,
CH8_HUMIDITY,
CH8_TEMP,
CHILL_INDEX, CHILL_INDEX,
DAILY_RAIN, DAILY_RAIN,
DEW_POINT, DEW_POINT,
@ -265,25 +281,101 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
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.CELSIUS,
# 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=CH4_TEMP, translation_key=CH4_TEMP,
# value_fn=lambda data: cast(float, data), value_fn=lambda data: cast("float", data),
# ), ),
# WeatherSensorEntityDescription( WeatherSensorEntityDescription(
# key=CH4_HUMIDITY, key=CH4_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=CH4_HUMIDITY, translation_key=CH4_HUMIDITY,
# value_fn=lambda data: cast(int, data), value_fn=lambda data: cast("int", data),
# ), ),
WeatherSensorEntityDescription(
key=CH5_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=CH5_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH5_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH5_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH6_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=CH6_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH6_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH6_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH7_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=CH7_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH7_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH7_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription(
key=CH8_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=CH8_TEMP,
value_fn=lambda data: cast("float", data),
),
WeatherSensorEntityDescription(
key=CH8_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.HUMIDITY,
icon="mdi:weather-sunny",
translation_key=CH8_HUMIDITY,
value_fn=lambda data: cast("int", data),
),
WeatherSensorEntityDescription( WeatherSensorEntityDescription(
key=HEAT_INDEX, key=HEAT_INDEX,
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
@ -320,6 +412,48 @@ SENSOR_TYPES_WSLINK: tuple[WeatherSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data), value_fn=lambda data: (data),
), ),
WeatherSensorEntityDescription(
key=CH3_BATTERY,
translation_key=CH3_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data),
),
WeatherSensorEntityDescription(
key=CH4_BATTERY,
translation_key=CH4_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data),
),
WeatherSensorEntityDescription(
key=CH5_BATTERY,
translation_key=CH5_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data),
),
WeatherSensorEntityDescription(
key=CH6_BATTERY,
translation_key=CH6_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data),
),
WeatherSensorEntityDescription(
key=CH7_BATTERY,
translation_key=CH7_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data),
),
WeatherSensorEntityDescription(
key=CH8_BATTERY,
translation_key=CH8_BATTERY,
icon="mdi:battery-unknown",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: (data),
),
WeatherSensorEntityDescription( WeatherSensorEntityDescription(
key=INDOOR_BATTERY, key=INDOOR_BATTERY,
translation_key=INDOOR_BATTERY, translation_key=INDOOR_BATTERY,

View File

@ -160,6 +160,30 @@
"ch4_humidity": { "ch4_humidity": {
"name": "Channel 4 humidity" "name": "Channel 4 humidity"
}, },
"ch5_temp": {
"name": "Channel 5 temperature"
},
"ch5_humidity": {
"name": "Channel 5 humidity"
},
"ch6_temp": {
"name": "Channel 6 temperature"
},
"ch6_humidity": {
"name": "Channel 6 humidity"
},
"ch7_temp": {
"name": "Channel 7 temperature"
},
"ch7_humidity": {
"name": "Channel 7 humidity"
},
"ch8_temp": {
"name": "Channel 8 temperature"
},
"ch8_humidity": {
"name": "Channel 8 humidity"
},
"heat_index": { "heat_index": {
"name": "Apparent temperature" "name": "Apparent temperature"
}, },
@ -185,6 +209,7 @@
"wnw": "WNW", "wnw": "WNW",
"nw": "NW", "nw": "NW",
"nnw": "NNW" "nnw": "NNW"
}
}, },
"outside_battery": { "outside_battery": {
"name": "Outside battery level", "name": "Outside battery level",
@ -193,7 +218,73 @@
"low": "Low", "low": "Low",
"unknown": "Unknown / drained out" "unknown": "Unknown / drained out"
} }
},
"indoor_battery": {
"name": "Indoor 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"
}
},
"ch3_battery": {
"name": "Channel 3 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch4_battery": {
"name": "Channel 4 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch5_battery": {
"name": "Channel 5 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch6_battery": {
"name": "Channel 6 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch7_battery": {
"name": "Channel 7 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch8_battery": {
"name": "Channel 8 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"wbgt_temp": {
"name": "WBGT temperature"
} }
} }
}, },

View File

@ -163,6 +163,30 @@
"ch4_humidity": { "ch4_humidity": {
"name": "Channel 4 humidity" "name": "Channel 4 humidity"
}, },
"ch5_temp": {
"name": "Channel 5 temperature"
},
"ch5_humidity": {
"name": "Channel 5 humidity"
},
"ch6_temp": {
"name": "Channel 6 temperature"
},
"ch6_humidity": {
"name": "Channel 6 humidity"
},
"ch7_temp": {
"name": "Channel 7 temperature"
},
"ch7_humidity": {
"name": "Channel 7 humidity"
},
"ch8_temp": {
"name": "Channel 8 temperature"
},
"ch8_humidity": {
"name": "Channel 8 humidity"
},
"heat_index": { "heat_index": {
"name": "Apparent temperature" "name": "Apparent temperature"
}, },
@ -221,6 +245,54 @@
"unknown": "Unknown / drained out" "unknown": "Unknown / drained out"
} }
}, },
"ch3_battery": {
"name": "Channel 3 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch4_battery": {
"name": "Channel 4 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch5_battery": {
"name": "Channel 5 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch6_battery": {
"name": "Channel 6 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch7_battery": {
"name": "Channel 7 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"ch8_battery": {
"name": "Channel 8 battery level",
"state": {
"normal": "OK",
"low": "Low",
"unknown": "Unknown / drained out"
}
},
"indoor_battery": { "indoor_battery": {
"name": "Console battery level", "name": "Console battery level",
"state": { "state": {

View File

@ -139,10 +139,12 @@ class WindyPush:
if "t1solrad" in purged_data: if "t1solrad" in purged_data:
purged_data["solarradiation"] = purged_data.pop("t1solrad") purged_data["solarradiation"] = purged_data.pop("t1solrad")
windy_station_id = self.config.options.get(WINDY_STATION_ID, "") windy_station_id = (self.config.options.get(WINDY_STATION_ID) or "").strip()
windy_station_pw = self.config.options.get(WINDY_STATION_PW, "") windy_station_pw = (self.config.options.get(WINDY_STATION_PW) or "").strip()
if windy_station_id == "" or windy_station_pw == "": # Both values are required. Options can sometimes be None, so normalize to
# empty string and strip whitespace before validating.
if not windy_station_id or not windy_station_pw:
_LOGGER.error( _LOGGER.error(
"Windy ID or PASSWORD is not set correctly. Please reconfigure your WINDY resend credentials. Disabling WINDY resend for now!" "Windy ID or PASSWORD is not set correctly. Please reconfigure your WINDY resend credentials. Disabling WINDY resend for now!"
) )