Update pyipma to 2.0 (#30746)
* update ipma component for pyipma 2.0 * fix wind speed; refactor forecast * update requirements*.txt * fix tests; update CODEOWNERS; update pyipma to 2.0.1 * minor changes as suggested in PR * make lint happy * fix mocking coroutines * restore old unique id * fix station lat/lon; update pyipma version
This commit is contained in:
parent
c2df4f56a3
commit
2aff913d9b
6 changed files with 138 additions and 110 deletions
|
@ -3,7 +3,8 @@ from datetime import timedelta
|
|||
import logging
|
||||
|
||||
import async_timeout
|
||||
from pyipma import Station
|
||||
from pyipma.api import IPMA_API
|
||||
from pyipma.location import Location
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
|
@ -24,8 +25,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
ATTRIBUTION = "Instituto Português do Mar e Atmosfera"
|
||||
|
||||
ATTR_WEATHER_DESCRIPTION = "description"
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30)
|
||||
|
||||
CONDITION_CLASSES = {
|
||||
|
@ -68,9 +67,10 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||
_LOGGER.error("Latitude or longitude not set in Home Assistant config")
|
||||
return
|
||||
|
||||
station = await async_get_station(hass, latitude, longitude)
|
||||
api = await async_get_api(hass)
|
||||
location = await async_get_location(hass, api, latitude, longitude)
|
||||
|
||||
async_add_entities([IPMAWeather(station, config)], True)
|
||||
async_add_entities([IPMAWeather(location, api, config)], True)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
|
@ -78,61 +78,71 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
latitude = config_entry.data[CONF_LATITUDE]
|
||||
longitude = config_entry.data[CONF_LONGITUDE]
|
||||
|
||||
station = await async_get_station(hass, latitude, longitude)
|
||||
api = await async_get_api(hass)
|
||||
location = await async_get_location(hass, api, latitude, longitude)
|
||||
|
||||
async_add_entities([IPMAWeather(station, config_entry.data)], True)
|
||||
async_add_entities([IPMAWeather(location, api, config_entry.data)], True)
|
||||
|
||||
|
||||
async def async_get_station(hass, latitude, longitude):
|
||||
"""Retrieve weather station, station name to be used as the entity name."""
|
||||
|
||||
async def async_get_api(hass):
|
||||
"""Get the pyipma api object."""
|
||||
websession = async_get_clientsession(hass)
|
||||
return IPMA_API(websession)
|
||||
|
||||
|
||||
async def async_get_location(hass, api, latitude, longitude):
|
||||
"""Retrieve pyipma location, location name to be used as the entity name."""
|
||||
with async_timeout.timeout(10):
|
||||
station = await Station.get(websession, float(latitude), float(longitude))
|
||||
location = await Location.get(api, float(latitude), float(longitude))
|
||||
|
||||
_LOGGER.debug(
|
||||
"Initializing for coordinates %s, %s -> station %s",
|
||||
latitude,
|
||||
longitude,
|
||||
station.local,
|
||||
location.station,
|
||||
)
|
||||
|
||||
return station
|
||||
return location
|
||||
|
||||
|
||||
class IPMAWeather(WeatherEntity):
|
||||
"""Representation of a weather condition."""
|
||||
|
||||
def __init__(self, station, config):
|
||||
def __init__(self, location: Location, api: IPMA_API, config):
|
||||
"""Initialise the platform with a data instance and station name."""
|
||||
self._station_name = config.get(CONF_NAME, station.local)
|
||||
self._station = station
|
||||
self._condition = None
|
||||
self._api = api
|
||||
self._location_name = config.get(CONF_NAME, location.name)
|
||||
self._location = location
|
||||
self._observation = None
|
||||
self._forecast = None
|
||||
self._description = None
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
async def async_update(self):
|
||||
"""Update Condition and Forecast."""
|
||||
with async_timeout.timeout(10):
|
||||
_new_condition = await self._station.observation()
|
||||
if _new_condition is None:
|
||||
_LOGGER.warning("Could not update weather conditions")
|
||||
return
|
||||
self._condition = _new_condition
|
||||
new_observation = await self._location.observation(self._api)
|
||||
new_forecast = await self._location.forecast(self._api)
|
||||
|
||||
if new_observation:
|
||||
self._observation = new_observation
|
||||
else:
|
||||
_LOGGER.warning("Could not update weather observation")
|
||||
|
||||
if new_forecast:
|
||||
self._forecast = [f for f in new_forecast if f.forecasted_hours == 24]
|
||||
else:
|
||||
_LOGGER.warning("Could not update weather forecast")
|
||||
|
||||
_LOGGER.debug(
|
||||
"Updating station %s, condition %s",
|
||||
self._station.local,
|
||||
self._condition,
|
||||
"Updated location %s, observation %s",
|
||||
self._location.name,
|
||||
self._observation,
|
||||
)
|
||||
self._forecast = await self._station.forecast()
|
||||
self._description = self._forecast[0].description
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return a unique id."""
|
||||
return f"{self._station.latitude}, {self._station.longitude}"
|
||||
return f"{self._location.station_latitude}, {self._location.station_longitude}"
|
||||
|
||||
@property
|
||||
def attribution(self):
|
||||
|
@ -142,7 +152,7 @@ class IPMAWeather(WeatherEntity):
|
|||
@property
|
||||
def name(self):
|
||||
"""Return the name of the station."""
|
||||
return self._station_name
|
||||
return self._location_name
|
||||
|
||||
@property
|
||||
def condition(self):
|
||||
|
@ -154,7 +164,7 @@ class IPMAWeather(WeatherEntity):
|
|||
(
|
||||
k
|
||||
for k, v in CONDITION_CLASSES.items()
|
||||
if self._forecast[0].idWeatherType in v
|
||||
if self._forecast[0].weather_type in v
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
@ -162,42 +172,42 @@ class IPMAWeather(WeatherEntity):
|
|||
@property
|
||||
def temperature(self):
|
||||
"""Return the current temperature."""
|
||||
if not self._condition:
|
||||
if not self._observation:
|
||||
return None
|
||||
|
||||
return self._condition.temperature
|
||||
return self._observation.temperature
|
||||
|
||||
@property
|
||||
def pressure(self):
|
||||
"""Return the current pressure."""
|
||||
if not self._condition:
|
||||
if not self._observation:
|
||||
return None
|
||||
|
||||
return self._condition.pressure
|
||||
return self._observation.pressure
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
"""Return the name of the sensor."""
|
||||
if not self._condition:
|
||||
if not self._observation:
|
||||
return None
|
||||
|
||||
return self._condition.humidity
|
||||
return self._observation.humidity
|
||||
|
||||
@property
|
||||
def wind_speed(self):
|
||||
"""Return the current windspeed."""
|
||||
if not self._condition:
|
||||
if not self._observation:
|
||||
return None
|
||||
|
||||
return self._condition.windspeed
|
||||
return self._observation.wind_intensity_km
|
||||
|
||||
@property
|
||||
def wind_bearing(self):
|
||||
"""Return the current wind bearing (degrees)."""
|
||||
if not self._condition:
|
||||
if not self._observation:
|
||||
return None
|
||||
|
||||
return self._condition.winddirection
|
||||
return self._observation.wind_direction
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
|
@ -207,33 +217,25 @@ class IPMAWeather(WeatherEntity):
|
|||
@property
|
||||
def forecast(self):
|
||||
"""Return the forecast array."""
|
||||
if self._forecast:
|
||||
fcdata_out = []
|
||||
for data_in in self._forecast:
|
||||
data_out = {}
|
||||
data_out[ATTR_FORECAST_TIME] = data_in.forecastDate
|
||||
data_out[ATTR_FORECAST_CONDITION] = next(
|
||||
if not self._forecast:
|
||||
return []
|
||||
|
||||
fcdata_out = [
|
||||
{
|
||||
ATTR_FORECAST_TIME: data_in.forecast_date,
|
||||
ATTR_FORECAST_CONDITION: next(
|
||||
(
|
||||
k
|
||||
for k, v in CONDITION_CLASSES.items()
|
||||
if int(data_in.idWeatherType) in v
|
||||
if int(data_in.weather_type) in v
|
||||
),
|
||||
None,
|
||||
)
|
||||
data_out[ATTR_FORECAST_TEMP_LOW] = data_in.tMin
|
||||
data_out[ATTR_FORECAST_TEMP] = data_in.tMax
|
||||
data_out[ATTR_FORECAST_PRECIPITATION] = data_in.precipitaProb
|
||||
),
|
||||
ATTR_FORECAST_TEMP_LOW: data_in.min_temperature,
|
||||
ATTR_FORECAST_TEMP: data_in.max_temperature,
|
||||
ATTR_FORECAST_PRECIPITATION: data_in.precipitation_probability,
|
||||
}
|
||||
for data_in in self._forecast
|
||||
]
|
||||
|
||||
fcdata_out.append(data_out)
|
||||
|
||||
return fcdata_out
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
data = dict()
|
||||
|
||||
if self._description:
|
||||
data[ATTR_WEATHER_DESCRIPTION] = self._description
|
||||
|
||||
return data
|
||||
return fcdata_out
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue