mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add new attributes to Climacell (#48707)
* Add new attributes to Climacell * fix logic * test new properties
This commit is contained in:
parent
e38fce98c4
commit
34a1dd4120
@ -35,28 +35,34 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTRIBUTION,
|
ATTRIBUTION,
|
||||||
|
CC_ATTR_CLOUD_COVER,
|
||||||
CC_ATTR_CONDITION,
|
CC_ATTR_CONDITION,
|
||||||
CC_ATTR_HUMIDITY,
|
CC_ATTR_HUMIDITY,
|
||||||
CC_ATTR_OZONE,
|
CC_ATTR_OZONE,
|
||||||
CC_ATTR_PRECIPITATION,
|
CC_ATTR_PRECIPITATION,
|
||||||
CC_ATTR_PRECIPITATION_PROBABILITY,
|
CC_ATTR_PRECIPITATION_PROBABILITY,
|
||||||
|
CC_ATTR_PRECIPITATION_TYPE,
|
||||||
CC_ATTR_PRESSURE,
|
CC_ATTR_PRESSURE,
|
||||||
CC_ATTR_TEMPERATURE,
|
CC_ATTR_TEMPERATURE,
|
||||||
CC_ATTR_TEMPERATURE_HIGH,
|
CC_ATTR_TEMPERATURE_HIGH,
|
||||||
CC_ATTR_TEMPERATURE_LOW,
|
CC_ATTR_TEMPERATURE_LOW,
|
||||||
CC_ATTR_VISIBILITY,
|
CC_ATTR_VISIBILITY,
|
||||||
CC_ATTR_WIND_DIRECTION,
|
CC_ATTR_WIND_DIRECTION,
|
||||||
|
CC_ATTR_WIND_GUST,
|
||||||
CC_ATTR_WIND_SPEED,
|
CC_ATTR_WIND_SPEED,
|
||||||
|
CC_V3_ATTR_CLOUD_COVER,
|
||||||
CC_V3_ATTR_CONDITION,
|
CC_V3_ATTR_CONDITION,
|
||||||
CC_V3_ATTR_HUMIDITY,
|
CC_V3_ATTR_HUMIDITY,
|
||||||
CC_V3_ATTR_OZONE,
|
CC_V3_ATTR_OZONE,
|
||||||
CC_V3_ATTR_PRECIPITATION,
|
CC_V3_ATTR_PRECIPITATION,
|
||||||
CC_V3_ATTR_PRECIPITATION_DAILY,
|
CC_V3_ATTR_PRECIPITATION_DAILY,
|
||||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
||||||
|
CC_V3_ATTR_PRECIPITATION_TYPE,
|
||||||
CC_V3_ATTR_PRESSURE,
|
CC_V3_ATTR_PRESSURE,
|
||||||
CC_V3_ATTR_TEMPERATURE,
|
CC_V3_ATTR_TEMPERATURE,
|
||||||
CC_V3_ATTR_VISIBILITY,
|
CC_V3_ATTR_VISIBILITY,
|
||||||
CC_V3_ATTR_WIND_DIRECTION,
|
CC_V3_ATTR_WIND_DIRECTION,
|
||||||
|
CC_V3_ATTR_WIND_GUST,
|
||||||
CC_V3_ATTR_WIND_SPEED,
|
CC_V3_ATTR_WIND_SPEED,
|
||||||
CONF_TIMESTEP,
|
CONF_TIMESTEP,
|
||||||
DEFAULT_FORECAST_TYPE,
|
DEFAULT_FORECAST_TYPE,
|
||||||
@ -223,6 +229,9 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
CC_V3_ATTR_CONDITION,
|
CC_V3_ATTR_CONDITION,
|
||||||
CC_V3_ATTR_VISIBILITY,
|
CC_V3_ATTR_VISIBILITY,
|
||||||
CC_V3_ATTR_OZONE,
|
CC_V3_ATTR_OZONE,
|
||||||
|
CC_V3_ATTR_WIND_GUST,
|
||||||
|
CC_V3_ATTR_CLOUD_COVER,
|
||||||
|
CC_V3_ATTR_PRECIPITATION_TYPE,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
||||||
@ -276,6 +285,9 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
CC_ATTR_CONDITION,
|
CC_ATTR_CONDITION,
|
||||||
CC_ATTR_VISIBILITY,
|
CC_ATTR_VISIBILITY,
|
||||||
CC_ATTR_OZONE,
|
CC_ATTR_OZONE,
|
||||||
|
CC_ATTR_WIND_GUST,
|
||||||
|
CC_ATTR_CLOUD_COVER,
|
||||||
|
CC_ATTR_PRECIPITATION_TYPE,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
CC_ATTR_TEMPERATURE_LOW,
|
CC_ATTR_TEMPERATURE_LOW,
|
||||||
|
@ -35,6 +35,11 @@ MAX_FORECASTS = {
|
|||||||
NOWCAST: 30,
|
NOWCAST: 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Additional attributes
|
||||||
|
ATTR_WIND_GUST = "wind_gust"
|
||||||
|
ATTR_CLOUD_COVER = "cloud_cover"
|
||||||
|
ATTR_PRECIPITATION_TYPE = "precipitation_type"
|
||||||
|
|
||||||
# V4 constants
|
# V4 constants
|
||||||
CONDITIONS = {
|
CONDITIONS = {
|
||||||
WeatherCode.WIND: ATTR_CONDITION_WINDY,
|
WeatherCode.WIND: ATTR_CONDITION_WINDY,
|
||||||
@ -76,6 +81,9 @@ CC_ATTR_CONDITION = "weatherCode"
|
|||||||
CC_ATTR_VISIBILITY = "visibility"
|
CC_ATTR_VISIBILITY = "visibility"
|
||||||
CC_ATTR_PRECIPITATION = "precipitationIntensityAvg"
|
CC_ATTR_PRECIPITATION = "precipitationIntensityAvg"
|
||||||
CC_ATTR_PRECIPITATION_PROBABILITY = "precipitationProbability"
|
CC_ATTR_PRECIPITATION_PROBABILITY = "precipitationProbability"
|
||||||
|
CC_ATTR_WIND_GUST = "windGust"
|
||||||
|
CC_ATTR_CLOUD_COVER = "cloudCover"
|
||||||
|
CC_ATTR_PRECIPITATION_TYPE = "precipitationType"
|
||||||
|
|
||||||
# V3 constants
|
# V3 constants
|
||||||
CONDITIONS_V3 = {
|
CONDITIONS_V3 = {
|
||||||
@ -117,3 +125,6 @@ CC_V3_ATTR_VISIBILITY = "visibility"
|
|||||||
CC_V3_ATTR_PRECIPITATION = "precipitation"
|
CC_V3_ATTR_PRECIPITATION = "precipitation"
|
||||||
CC_V3_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation"
|
CC_V3_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation"
|
||||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability"
|
CC_V3_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability"
|
||||||
|
CC_V3_ATTR_WIND_GUST = "wind_gust"
|
||||||
|
CC_V3_ATTR_CLOUD_COVER = "cloud_cover"
|
||||||
|
CC_V3_ATTR_PRECIPITATION_TYPE = "precipitation_type"
|
||||||
|
@ -3,9 +3,17 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable, Mapping
|
||||||
|
|
||||||
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST, WeatherCode
|
from pyclimacell.const import (
|
||||||
|
CURRENT,
|
||||||
|
DAILY,
|
||||||
|
FORECASTS,
|
||||||
|
HOURLY,
|
||||||
|
NOWCAST,
|
||||||
|
PrecipitationType,
|
||||||
|
WeatherCode,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
ATTR_FORECAST_CONDITION,
|
ATTR_FORECAST_CONDITION,
|
||||||
@ -38,11 +46,16 @@ from homeassistant.util.pressure import convert as pressure_convert
|
|||||||
|
|
||||||
from . import ClimaCellEntity
|
from . import ClimaCellEntity
|
||||||
from .const import (
|
from .const import (
|
||||||
|
ATTR_CLOUD_COVER,
|
||||||
|
ATTR_PRECIPITATION_TYPE,
|
||||||
|
ATTR_WIND_GUST,
|
||||||
|
CC_ATTR_CLOUD_COVER,
|
||||||
CC_ATTR_CONDITION,
|
CC_ATTR_CONDITION,
|
||||||
CC_ATTR_HUMIDITY,
|
CC_ATTR_HUMIDITY,
|
||||||
CC_ATTR_OZONE,
|
CC_ATTR_OZONE,
|
||||||
CC_ATTR_PRECIPITATION,
|
CC_ATTR_PRECIPITATION,
|
||||||
CC_ATTR_PRECIPITATION_PROBABILITY,
|
CC_ATTR_PRECIPITATION_PROBABILITY,
|
||||||
|
CC_ATTR_PRECIPITATION_TYPE,
|
||||||
CC_ATTR_PRESSURE,
|
CC_ATTR_PRESSURE,
|
||||||
CC_ATTR_TEMPERATURE,
|
CC_ATTR_TEMPERATURE,
|
||||||
CC_ATTR_TEMPERATURE_HIGH,
|
CC_ATTR_TEMPERATURE_HIGH,
|
||||||
@ -50,13 +63,16 @@ from .const import (
|
|||||||
CC_ATTR_TIMESTAMP,
|
CC_ATTR_TIMESTAMP,
|
||||||
CC_ATTR_VISIBILITY,
|
CC_ATTR_VISIBILITY,
|
||||||
CC_ATTR_WIND_DIRECTION,
|
CC_ATTR_WIND_DIRECTION,
|
||||||
|
CC_ATTR_WIND_GUST,
|
||||||
CC_ATTR_WIND_SPEED,
|
CC_ATTR_WIND_SPEED,
|
||||||
|
CC_V3_ATTR_CLOUD_COVER,
|
||||||
CC_V3_ATTR_CONDITION,
|
CC_V3_ATTR_CONDITION,
|
||||||
CC_V3_ATTR_HUMIDITY,
|
CC_V3_ATTR_HUMIDITY,
|
||||||
CC_V3_ATTR_OZONE,
|
CC_V3_ATTR_OZONE,
|
||||||
CC_V3_ATTR_PRECIPITATION,
|
CC_V3_ATTR_PRECIPITATION,
|
||||||
CC_V3_ATTR_PRECIPITATION_DAILY,
|
CC_V3_ATTR_PRECIPITATION_DAILY,
|
||||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
||||||
|
CC_V3_ATTR_PRECIPITATION_TYPE,
|
||||||
CC_V3_ATTR_PRESSURE,
|
CC_V3_ATTR_PRESSURE,
|
||||||
CC_V3_ATTR_TEMPERATURE,
|
CC_V3_ATTR_TEMPERATURE,
|
||||||
CC_V3_ATTR_TEMPERATURE_HIGH,
|
CC_V3_ATTR_TEMPERATURE_HIGH,
|
||||||
@ -64,6 +80,7 @@ from .const import (
|
|||||||
CC_V3_ATTR_TIMESTAMP,
|
CC_V3_ATTR_TIMESTAMP,
|
||||||
CC_V3_ATTR_VISIBILITY,
|
CC_V3_ATTR_VISIBILITY,
|
||||||
CC_V3_ATTR_WIND_DIRECTION,
|
CC_V3_ATTR_WIND_DIRECTION,
|
||||||
|
CC_V3_ATTR_WIND_GUST,
|
||||||
CC_V3_ATTR_WIND_SPEED,
|
CC_V3_ATTR_WIND_SPEED,
|
||||||
CLEAR_CONDITIONS,
|
CLEAR_CONDITIONS,
|
||||||
CONDITIONS,
|
CONDITIONS,
|
||||||
@ -149,6 +166,38 @@ class BaseClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
|||||||
|
|
||||||
return {k: v for k, v in data.items() if v is not None}
|
return {k: v for k, v in data.items() if v is not None}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||||
|
"""Return additional state attributes."""
|
||||||
|
wind_gust = self.wind_gust
|
||||||
|
if wind_gust and self.hass.config.units.is_metric:
|
||||||
|
wind_gust = distance_convert(
|
||||||
|
self.wind_gust, LENGTH_MILES, LENGTH_KILOMETERS
|
||||||
|
)
|
||||||
|
cloud_cover = self.cloud_cover
|
||||||
|
if cloud_cover is not None:
|
||||||
|
cloud_cover /= 100
|
||||||
|
return {
|
||||||
|
ATTR_CLOUD_COVER: cloud_cover,
|
||||||
|
ATTR_WIND_GUST: wind_gust,
|
||||||
|
ATTR_PRECIPITATION_TYPE: self.precipitation_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cloud_cover(self):
|
||||||
|
"""Return cloud cover."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wind_gust(self):
|
||||||
|
"""Return wind gust speed."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def precipitation_type(self):
|
||||||
|
"""Return precipitation type."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class ClimaCellWeatherEntity(BaseClimaCellWeatherEntity):
|
class ClimaCellWeatherEntity(BaseClimaCellWeatherEntity):
|
||||||
"""Entity that talks to ClimaCell v4 API to retrieve weather data."""
|
"""Entity that talks to ClimaCell v4 API to retrieve weather data."""
|
||||||
@ -195,6 +244,24 @@ class ClimaCellWeatherEntity(BaseClimaCellWeatherEntity):
|
|||||||
"""Return the humidity."""
|
"""Return the humidity."""
|
||||||
return self._get_current_property(CC_ATTR_HUMIDITY)
|
return self._get_current_property(CC_ATTR_HUMIDITY)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wind_gust(self):
|
||||||
|
"""Return the wind gust speed."""
|
||||||
|
return self._get_current_property(CC_ATTR_WIND_GUST)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cloud_cover(self):
|
||||||
|
"""Reteurn the cloud cover."""
|
||||||
|
return self._get_current_property(CC_ATTR_CLOUD_COVER)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def precipitation_type(self):
|
||||||
|
"""Return precipitation type."""
|
||||||
|
precipitation_type = self._get_current_property(CC_ATTR_PRECIPITATION_TYPE)
|
||||||
|
if precipitation_type is None:
|
||||||
|
return None
|
||||||
|
return PrecipitationType(precipitation_type).name.lower()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wind_speed(self):
|
def wind_speed(self):
|
||||||
"""Return the wind speed."""
|
"""Return the wind speed."""
|
||||||
@ -338,6 +405,25 @@ class ClimaCellV3WeatherEntity(BaseClimaCellWeatherEntity):
|
|||||||
"""Return the humidity."""
|
"""Return the humidity."""
|
||||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_HUMIDITY)
|
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_HUMIDITY)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wind_gust(self):
|
||||||
|
"""Return the wind gust speed."""
|
||||||
|
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_GUST)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cloud_cover(self):
|
||||||
|
"""Reteurn the cloud cover."""
|
||||||
|
return self._get_cc_value(
|
||||||
|
self.coordinator.data[CURRENT], CC_V3_ATTR_CLOUD_COVER
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def precipitation_type(self):
|
||||||
|
"""Return precipitation type."""
|
||||||
|
return self._get_cc_value(
|
||||||
|
self.coordinator.data[CURRENT], CC_V3_ATTR_PRECIPITATION_TYPE
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wind_speed(self):
|
def wind_speed(self):
|
||||||
"""Return the wind speed."""
|
"""Return the wind speed."""
|
||||||
|
@ -13,7 +13,13 @@ from homeassistant.components.climacell.config_flow import (
|
|||||||
_get_config_schema,
|
_get_config_schema,
|
||||||
_get_unique_id,
|
_get_unique_id,
|
||||||
)
|
)
|
||||||
from homeassistant.components.climacell.const import ATTRIBUTION, DOMAIN
|
from homeassistant.components.climacell.const import (
|
||||||
|
ATTR_CLOUD_COVER,
|
||||||
|
ATTR_PRECIPITATION_TYPE,
|
||||||
|
ATTR_WIND_GUST,
|
||||||
|
ATTRIBUTION,
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
ATTR_CONDITION_CLOUDY,
|
ATTR_CONDITION_CLOUDY,
|
||||||
ATTR_CONDITION_RAINY,
|
ATTR_CONDITION_RAINY,
|
||||||
@ -222,6 +228,9 @@ async def test_v3_weather(
|
|||||||
assert weather_state.attributes[ATTR_WEATHER_VISIBILITY] == 9.994026240000002
|
assert weather_state.attributes[ATTR_WEATHER_VISIBILITY] == 9.994026240000002
|
||||||
assert weather_state.attributes[ATTR_WEATHER_WIND_BEARING] == 320.31
|
assert weather_state.attributes[ATTR_WEATHER_WIND_BEARING] == 320.31
|
||||||
assert weather_state.attributes[ATTR_WEATHER_WIND_SPEED] == 14.62893696
|
assert weather_state.attributes[ATTR_WEATHER_WIND_SPEED] == 14.62893696
|
||||||
|
assert weather_state.attributes[ATTR_CLOUD_COVER] == 1
|
||||||
|
assert weather_state.attributes[ATTR_WIND_GUST] == 24.075786240000003
|
||||||
|
assert weather_state.attributes[ATTR_PRECIPITATION_TYPE] == "rain"
|
||||||
|
|
||||||
|
|
||||||
async def test_v4_weather(
|
async def test_v4_weather(
|
||||||
@ -382,3 +391,6 @@ async def test_v4_weather(
|
|||||||
assert weather_state.attributes[ATTR_WEATHER_VISIBILITY] == 13.116153600000002
|
assert weather_state.attributes[ATTR_WEATHER_VISIBILITY] == 13.116153600000002
|
||||||
assert weather_state.attributes[ATTR_WEATHER_WIND_BEARING] == 315.14
|
assert weather_state.attributes[ATTR_WEATHER_WIND_BEARING] == 315.14
|
||||||
assert weather_state.attributes[ATTR_WEATHER_WIND_SPEED] == 15.01517952
|
assert weather_state.attributes[ATTR_WEATHER_WIND_SPEED] == 15.01517952
|
||||||
|
assert weather_state.attributes[ATTR_CLOUD_COVER] == 1
|
||||||
|
assert weather_state.attributes[ATTR_WIND_GUST] == 20.34210816
|
||||||
|
assert weather_state.attributes[ATTR_PRECIPITATION_TYPE] == "rain"
|
||||||
|
11
tests/fixtures/climacell/v3_realtime.json
vendored
11
tests/fixtures/climacell/v3_realtime.json
vendored
@ -32,6 +32,17 @@
|
|||||||
"value": 52.625,
|
"value": 52.625,
|
||||||
"units": "ppb"
|
"units": "ppb"
|
||||||
},
|
},
|
||||||
|
"wind_gust": {
|
||||||
|
"value": 14.96,
|
||||||
|
"units": "mph"
|
||||||
|
},
|
||||||
|
"precipitation_type": {
|
||||||
|
"value": "rain"
|
||||||
|
},
|
||||||
|
"cloud_cover": {
|
||||||
|
"value": 100,
|
||||||
|
"units": "%"
|
||||||
|
},
|
||||||
"observation_time": {
|
"observation_time": {
|
||||||
"value": "2021-03-07T18:54:06.055Z"
|
"value": "2021-03-07T18:54:06.055Z"
|
||||||
}
|
}
|
||||||
|
5
tests/fixtures/climacell/v4.json
vendored
5
tests/fixtures/climacell/v4.json
vendored
@ -7,7 +7,10 @@
|
|||||||
"windDirection": 315.14,
|
"windDirection": 315.14,
|
||||||
"weatherCode": 1000,
|
"weatherCode": 1000,
|
||||||
"visibility": 8.15,
|
"visibility": 8.15,
|
||||||
"pollutantO3": 46.53
|
"pollutantO3": 46.53,
|
||||||
|
"windGust": 12.64,
|
||||||
|
"cloudCover": 100,
|
||||||
|
"precipitationType": 1
|
||||||
},
|
},
|
||||||
"forecasts": {
|
"forecasts": {
|
||||||
"nowcast": [
|
"nowcast": [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user