Update Windy integration to use station ID and password authentication
- Replace API key with station ID and password for authentication - Change Windy API endpoint to v2 observation update - Adapt data conversion for WSLink to Windy format - Update config flow and translations accordinglyecowitt_support
parent
2cbc198fd0
commit
aff850492d
|
|
@ -161,7 +161,7 @@ class WeatherDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
# Optional forwarding to external services. This is kept here (in the webhook handler)
|
# Optional forwarding to external services. This is kept here (in the webhook handler)
|
||||||
# to avoid additional background polling tasks.
|
# to avoid additional background polling tasks.
|
||||||
if self.config.options.get(WINDY_ENABLED, False):
|
if self.config.options.get(WINDY_ENABLED, False):
|
||||||
await self.windy.push_data_to_windy(data)
|
await self.windy.push_data_to_windy(data, _wslink)
|
||||||
|
|
||||||
if self.config.options.get(POCASI_CZ_ENABLED, False):
|
if self.config.options.get(POCASI_CZ_ENABLED, False):
|
||||||
await self.pocasi.push_data_to_server(data, "WSLINK" if _wslink else "WU")
|
await self.pocasi.push_data_to_server(data, "WSLINK" if _wslink else "WU")
|
||||||
|
|
|
||||||
|
|
@ -95,16 +95,23 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
||||||
}
|
}
|
||||||
|
|
||||||
self.windy_data = {
|
self.windy_data = {
|
||||||
WINDY_STATION_ID: entry_data.get(WINDY_STATION_ID),
|
WINDY_STATION_ID: self.config_entry.options.get(WINDY_STATION_ID, ""),
|
||||||
WINDY_STATION_PW: entry_data.get(WINDY_STATION_PW),
|
WINDY_STATION_PW: self.config_entry.options.get(WINDY_STATION_PW, ""),
|
||||||
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 = {
|
||||||
vol.Optional(WINDY_STATION_ID, default=self.windy_data.get(WINDY_STATION_ID, "")): str,
|
vol.Optional(
|
||||||
vol.Optional(WINDY_STATION_PW, default=self.windy_data.get(WINDY_STATION_PW, "")): str,
|
WINDY_STATION_ID, default=self.windy_data.get(WINDY_STATION_ID, "")
|
||||||
vol.Optional(WINDY_ENABLED, default=self.windy_data[WINDY_ENABLED]): bool or False,
|
): str,
|
||||||
|
vol.Optional(
|
||||||
|
WINDY_STATION_PW,
|
||||||
|
default=self.windy_data.get(WINDY_STATION_PW, ""),
|
||||||
|
): str,
|
||||||
|
vol.Optional(WINDY_ENABLED, default=self.windy_data[WINDY_ENABLED]): bool
|
||||||
|
or False,
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
WINDY_LOGGER_ENABLED,
|
WINDY_LOGGER_ENABLED,
|
||||||
default=self.windy_data[WINDY_LOGGER_ENABLED],
|
default=self.windy_data[WINDY_LOGGER_ENABLED],
|
||||||
|
|
@ -190,19 +197,15 @@ class ConfigOptionsFlowHandler(OptionsFlow):
|
||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
station_id = (user_input.get(WINDY_STATION_ID) or "").strip()
|
if (user_input[WINDY_ENABLED] is True) and (
|
||||||
station_pw = (user_input.get(WINDY_STATION_PW) or "").strip()
|
(user_input[WINDY_STATION_ID] == "") or (user_input[WINDY_STATION_PW] == "")
|
||||||
if user_input.get(WINDY_ENABLED):
|
):
|
||||||
if not station_id:
|
errors[WINDY_STATION_ID] = "windy_key_required"
|
||||||
errors[WINDY_STATION_ID] = "windy_id_required"
|
return self.async_show_form(
|
||||||
if not station_pw:
|
step_id="windy",
|
||||||
errors[WINDY_STATION_PW] = "windy_pw_required"
|
data_schema=vol.Schema(self.windy_data_schema),
|
||||||
if errors:
|
errors=errors,
|
||||||
return self.async_show_form(
|
)
|
||||||
step_id="windy",
|
|
||||||
data_schema=vol.Schema(self.windy_data_schema),
|
|
||||||
errors=errors,
|
|
||||||
)
|
|
||||||
|
|
||||||
user_input = self.retain_data(user_input)
|
user_input = self.retain_data(user_input)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
},
|
},
|
||||||
"data_description": {
|
"data_description": {
|
||||||
"WINDY_STATION_ID": "ID stanice získaný z https://stations.windy.com/station",
|
"WINDY_STATION_ID": "ID stanice získaný z https://stations.windy.com/station",
|
||||||
"WINDY_STATION_PWD": "Heslo stanice získané z https://stations.windy.com/station",
|
"WINDY_STATION_PWD": "Heslo stanice získané z https://stations.windy.com/station",
|
||||||
"windy_logger_checkbox": "Zapnout pouze v případě, že chcete poslat ladící informace vývojáři."
|
"windy_logger_checkbox": "Zapnout pouze v případě, že chcete poslat ladící informace vývojáři."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from aiohttp.client_exceptions import ClientError
|
from aiohttp.client_exceptions import ClientError
|
||||||
from py_typecheck.core import checked
|
from py_typecheck import checked
|
||||||
|
|
||||||
from homeassistant.components import persistent_notification
|
from homeassistant.components import persistent_notification
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
|
@ -86,7 +86,34 @@ class WindyPush:
|
||||||
if "Unauthorized" in response:
|
if "Unauthorized" in response:
|
||||||
raise WindyApiKeyError
|
raise WindyApiKeyError
|
||||||
|
|
||||||
async def push_data_to_windy(self, data: dict[str, str]) -> bool:
|
def _covert_wslink_to_pws(self, indata: dict[str, str]) -> dict[str, str]:
|
||||||
|
"""Convert WSLink API data to Windy API data protocol."""
|
||||||
|
if "t1ws" in indata:
|
||||||
|
indata["wind"] = indata.pop("t1ws")
|
||||||
|
if "t1wgust" in indata:
|
||||||
|
indata["gust"] = indata.pop("t1wgust")
|
||||||
|
if "t1wdir" in indata:
|
||||||
|
indata["winddir"] = indata.pop("t1wdir")
|
||||||
|
if "t1hum" in indata:
|
||||||
|
indata["humidity"] = indata.pop("t1hum")
|
||||||
|
if "t1dew" in indata:
|
||||||
|
indata["dewpoint"] = indata.pop("t1dew")
|
||||||
|
if "t1tem" in indata:
|
||||||
|
indata["temp"] = indata.pop("t1tem")
|
||||||
|
if "rbar" in indata:
|
||||||
|
indata["mbar"] = indata.pop("rbar")
|
||||||
|
if "t1rainhr" in indata:
|
||||||
|
indata["precip"] = indata.pop("t1rainhr")
|
||||||
|
if "t1uvi" in indata:
|
||||||
|
indata["uv"] = indata.pop("t1uvi")
|
||||||
|
if "t1solrad" in indata:
|
||||||
|
indata["solarradiation"] = indata.pop("t1solrad")
|
||||||
|
|
||||||
|
return indata
|
||||||
|
|
||||||
|
async def push_data_to_windy(
|
||||||
|
self, data: dict[str, str], wslink: bool = False
|
||||||
|
) -> bool:
|
||||||
"""Pushes weather data do Windy stations.
|
"""Pushes weather data do Windy stations.
|
||||||
|
|
||||||
Interval is 5 minutes, otherwise Windy would not accepts data.
|
Interval is 5 minutes, otherwise Windy would not accepts data.
|
||||||
|
|
@ -113,40 +140,37 @@ class WindyPush:
|
||||||
|
|
||||||
if wslink:
|
if wslink:
|
||||||
# WSLink -> Windy params
|
# WSLink -> Windy params
|
||||||
if "t1ws" in purged_data:
|
self._covert_wslink_to_pws(purged_data)
|
||||||
purged_data["wind"] = purged_data.pop("t1ws")
|
|
||||||
if "t1wgust" in purged_data:
|
|
||||||
purged_data["gust"] = purged_data.pop("t1wgust")
|
|
||||||
if "t1wdir" in purged_data:
|
|
||||||
purged_data["winddir"] = purged_data.pop("t1wdir")
|
|
||||||
if "t1hum" in purged_data:
|
|
||||||
purged_data["humidity"] = purged_data.pop("t1hum")
|
|
||||||
if "t1dew" in purged_data:
|
|
||||||
purged_data["dewpoint"] = purged_data.pop("t1dew")
|
|
||||||
if "t1tem" in purged_data:
|
|
||||||
purged_data["temp"] = purged_data.pop("t1tem")
|
|
||||||
if "rbar" in purged_data:
|
|
||||||
purged_data["mbar"] = purged_data.pop("rbar")
|
|
||||||
if "t1rainhr" in purged_data:
|
|
||||||
purged_data["precip"] = purged_data.pop("t1rainhr")
|
|
||||||
if "t1uvi" in purged_data:
|
|
||||||
purged_data["uv"] = purged_data.pop("t1uvi")
|
|
||||||
if "t1solrad" in purged_data:
|
|
||||||
purged_data["solarradiation"] = purged_data.pop("t1solrad")
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
windy_api_key := checked(self.config.options.get(WINDY_API_KEY), str)
|
windy_station_id := checked(self.config.options.get(WINDY_STATION_ID), str)
|
||||||
) is None:
|
) is None:
|
||||||
_LOGGER.error("Windy API key is not provided! Check your configuration.")
|
_LOGGER.error("Windy API key is not provided! Check your configuration.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
request_url = f"{WINDY_URL}{windy_api_key}"
|
if (
|
||||||
|
windy_station_pw := checked(self.config.options.get(WINDY_STATION_PW), str)
|
||||||
|
) is None:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Windy station password is missing! Check your configuration."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
request_url = f"{WINDY_URL}"
|
||||||
|
|
||||||
|
purged_data["id"] = windy_station_id
|
||||||
|
|
||||||
|
purged_data["time"] = "now"
|
||||||
|
|
||||||
|
headers = {"Authorization": f"Bearer {windy_station_pw}"}
|
||||||
|
|
||||||
if self.log:
|
if self.log:
|
||||||
_LOGGER.info("Dataset for windy: %s", purged_data)
|
_LOGGER.info("Dataset for windy: %s", purged_data)
|
||||||
session = async_get_clientsession(self.hass, verify_ssl=False)
|
session = async_get_clientsession(self.hass, verify_ssl=False)
|
||||||
try:
|
try:
|
||||||
async with session.get(request_url, params=purged_data, headers=headers) as resp:
|
async with session.get(
|
||||||
|
request_url, params=purged_data, headers=headers
|
||||||
|
) as resp:
|
||||||
status = await resp.text()
|
status = await resp.text()
|
||||||
try:
|
try:
|
||||||
self.verify_windy_response(status)
|
self.verify_windy_response(status)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue