mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 09:17:53 +00:00
Add ClimaCell v4 API support (#47575)
* Add ClimaCell v4 API support * fix tests * use constants * fix logic and update tests * revert accidental changes and enable hourly and nowcast forecast entities in test * use variable instead of accessing dictionary multiple times * only grab necessary fields * add _translate_condition method ot base class * bump pyclimacell again to fix bug * switch typehints back to new format * more typehint fixes * fix tests * revert merge conflict change * handle 'migration' in async_setup_entry so we don't have to bump config entry versions * parametrize timestep test
This commit is contained in:
parent
0f757c3db2
commit
d0b3f76a6f
@ -145,7 +145,6 @@ omit =
|
||||
homeassistant/components/clickatell/notify.py
|
||||
homeassistant/components/clicksend/notify.py
|
||||
homeassistant/components/clicksend_tts/notify.py
|
||||
homeassistant/components/climacell/weather.py
|
||||
homeassistant/components/cmus/media_player.py
|
||||
homeassistant/components/co2signal/*
|
||||
homeassistant/components/coinbase/*
|
||||
|
@ -7,14 +7,9 @@ import logging
|
||||
from math import ceil
|
||||
from typing import Any
|
||||
|
||||
from pyclimacell import ClimaCell
|
||||
from pyclimacell.const import (
|
||||
FORECAST_DAILY,
|
||||
FORECAST_HOURLY,
|
||||
FORECAST_NOWCAST,
|
||||
REALTIME,
|
||||
)
|
||||
from pyclimacell.pyclimacell import (
|
||||
from pyclimacell import ClimaCellV3, ClimaCellV4
|
||||
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST
|
||||
from pyclimacell.exceptions import (
|
||||
CantConnectException,
|
||||
InvalidAPIKeyException,
|
||||
RateLimitedException,
|
||||
@ -23,7 +18,13 @@ from pyclimacell.pyclimacell import (
|
||||
|
||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
@ -34,15 +35,34 @@ from homeassistant.helpers.update_coordinator import (
|
||||
|
||||
from .const import (
|
||||
ATTRIBUTION,
|
||||
CC_ATTR_CONDITION,
|
||||
CC_ATTR_HUMIDITY,
|
||||
CC_ATTR_OZONE,
|
||||
CC_ATTR_PRECIPITATION,
|
||||
CC_ATTR_PRECIPITATION_PROBABILITY,
|
||||
CC_ATTR_PRESSURE,
|
||||
CC_ATTR_TEMPERATURE,
|
||||
CC_ATTR_TEMPERATURE_HIGH,
|
||||
CC_ATTR_TEMPERATURE_LOW,
|
||||
CC_ATTR_VISIBILITY,
|
||||
CC_ATTR_WIND_DIRECTION,
|
||||
CC_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_HUMIDITY,
|
||||
CC_V3_ATTR_OZONE,
|
||||
CC_V3_ATTR_PRECIPITATION,
|
||||
CC_V3_ATTR_PRECIPITATION_DAILY,
|
||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
||||
CC_V3_ATTR_PRESSURE,
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_VISIBILITY,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CONF_TIMESTEP,
|
||||
CURRENT,
|
||||
DAILY,
|
||||
DEFAULT_FORECAST_TYPE,
|
||||
DEFAULT_TIMESTEP,
|
||||
DOMAIN,
|
||||
FORECASTS,
|
||||
HOURLY,
|
||||
MAX_REQUESTS_PER_DAY,
|
||||
NOWCAST,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -54,6 +74,7 @@ def _set_update_interval(
|
||||
hass: HomeAssistantType, current_entry: ConfigEntry
|
||||
) -> timedelta:
|
||||
"""Recalculate update_interval based on existing ClimaCell instances and update them."""
|
||||
api_calls = 4 if current_entry.data[CONF_API_VERSION] == 3 else 2
|
||||
# We check how many ClimaCell configured instances are using the same API key and
|
||||
# calculate interval to not exceed allowed numbers of requests. Divide 90% of
|
||||
# MAX_REQUESTS_PER_DAY by 4 because every update requires four API calls and we want
|
||||
@ -68,7 +89,7 @@ def _set_update_interval(
|
||||
interval = timedelta(
|
||||
minutes=(
|
||||
ceil(
|
||||
(24 * 60 * (len(other_instance_entry_ids) + 1) * 4)
|
||||
(24 * 60 * (len(other_instance_entry_ids) + 1) * api_calls)
|
||||
/ (MAX_REQUESTS_PER_DAY * 0.9)
|
||||
)
|
||||
)
|
||||
@ -85,24 +106,48 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry)
|
||||
"""Set up ClimaCell API from a config entry."""
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
params = {}
|
||||
# If config entry options not set up, set them up
|
||||
if not config_entry.options:
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
options={
|
||||
CONF_TIMESTEP: DEFAULT_TIMESTEP,
|
||||
},
|
||||
)
|
||||
params["options"] = {
|
||||
CONF_TIMESTEP: DEFAULT_TIMESTEP,
|
||||
}
|
||||
else:
|
||||
# Use valid timestep if it's invalid
|
||||
timestep = config_entry.options[CONF_TIMESTEP]
|
||||
if timestep not in (1, 5, 15, 30):
|
||||
if timestep <= 2:
|
||||
timestep = 1
|
||||
elif timestep <= 7:
|
||||
timestep = 5
|
||||
elif timestep <= 20:
|
||||
timestep = 15
|
||||
else:
|
||||
timestep = 30
|
||||
new_options = config_entry.options.copy()
|
||||
new_options[CONF_TIMESTEP] = timestep
|
||||
params["options"] = new_options
|
||||
# Add API version if not found
|
||||
if CONF_API_VERSION not in config_entry.data:
|
||||
new_data = config_entry.data.copy()
|
||||
new_data[CONF_API_VERSION] = 3
|
||||
params["data"] = new_data
|
||||
|
||||
if params:
|
||||
hass.config_entries.async_update_entry(config_entry, **params)
|
||||
|
||||
api_class = ClimaCellV3 if config_entry.data[CONF_API_VERSION] == 3 else ClimaCellV4
|
||||
api = api_class(
|
||||
config_entry.data[CONF_API_KEY],
|
||||
config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
|
||||
config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
|
||||
session=async_get_clientsession(hass),
|
||||
)
|
||||
|
||||
coordinator = ClimaCellDataUpdateCoordinator(
|
||||
hass,
|
||||
config_entry,
|
||||
ClimaCell(
|
||||
config_entry.data[CONF_API_KEY],
|
||||
config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
|
||||
config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
|
||||
session=async_get_clientsession(hass),
|
||||
),
|
||||
api,
|
||||
_set_update_interval(hass, config_entry),
|
||||
)
|
||||
|
||||
@ -145,12 +190,13 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
self,
|
||||
hass: HomeAssistantType,
|
||||
config_entry: ConfigEntry,
|
||||
api: ClimaCell,
|
||||
api: ClimaCellV3 | ClimaCellV4,
|
||||
update_interval: timedelta,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
|
||||
self._config_entry = config_entry
|
||||
self._api_version = config_entry.data[CONF_API_VERSION]
|
||||
self._api = api
|
||||
self.name = config_entry.data[CONF_NAME]
|
||||
self.data = {CURRENT: {}, FORECASTS: {}}
|
||||
@ -166,27 +212,81 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Update data via library."""
|
||||
data = {FORECASTS: {}}
|
||||
try:
|
||||
data[CURRENT] = await self._api.realtime(
|
||||
self._api.available_fields(REALTIME)
|
||||
)
|
||||
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
||||
self._api.available_fields(FORECAST_HOURLY),
|
||||
None,
|
||||
timedelta(hours=24),
|
||||
)
|
||||
if self._api_version == 3:
|
||||
data[CURRENT] = await self._api.realtime(
|
||||
[
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_HUMIDITY,
|
||||
CC_V3_ATTR_PRESSURE,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_VISIBILITY,
|
||||
CC_V3_ATTR_OZONE,
|
||||
]
|
||||
)
|
||||
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
||||
[
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_PRECIPITATION,
|
||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
||||
],
|
||||
None,
|
||||
timedelta(hours=24),
|
||||
)
|
||||
|
||||
data[FORECASTS][DAILY] = await self._api.forecast_daily(
|
||||
self._api.available_fields(FORECAST_DAILY), None, timedelta(days=14)
|
||||
)
|
||||
data[FORECASTS][DAILY] = await self._api.forecast_daily(
|
||||
[
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_PRECIPITATION_DAILY,
|
||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
||||
],
|
||||
None,
|
||||
timedelta(days=14),
|
||||
)
|
||||
|
||||
data[FORECASTS][NOWCAST] = await self._api.forecast_nowcast(
|
||||
self._api.available_fields(FORECAST_NOWCAST),
|
||||
None,
|
||||
timedelta(
|
||||
minutes=min(300, self._config_entry.options[CONF_TIMESTEP] * 30)
|
||||
),
|
||||
self._config_entry.options[CONF_TIMESTEP],
|
||||
)
|
||||
data[FORECASTS][NOWCAST] = await self._api.forecast_nowcast(
|
||||
[
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_PRECIPITATION,
|
||||
],
|
||||
None,
|
||||
timedelta(
|
||||
minutes=min(300, self._config_entry.options[CONF_TIMESTEP] * 30)
|
||||
),
|
||||
self._config_entry.options[CONF_TIMESTEP],
|
||||
)
|
||||
else:
|
||||
return await self._api.realtime_and_all_forecasts(
|
||||
[
|
||||
CC_ATTR_TEMPERATURE,
|
||||
CC_ATTR_HUMIDITY,
|
||||
CC_ATTR_PRESSURE,
|
||||
CC_ATTR_WIND_SPEED,
|
||||
CC_ATTR_WIND_DIRECTION,
|
||||
CC_ATTR_CONDITION,
|
||||
CC_ATTR_VISIBILITY,
|
||||
CC_ATTR_OZONE,
|
||||
],
|
||||
[
|
||||
CC_ATTR_TEMPERATURE_LOW,
|
||||
CC_ATTR_TEMPERATURE_HIGH,
|
||||
CC_ATTR_WIND_SPEED,
|
||||
CC_ATTR_WIND_DIRECTION,
|
||||
CC_ATTR_CONDITION,
|
||||
CC_ATTR_PRECIPITATION,
|
||||
CC_ATTR_PRECIPITATION_PROBABILITY,
|
||||
],
|
||||
)
|
||||
except (
|
||||
CantConnectException,
|
||||
InvalidAPIKeyException,
|
||||
@ -202,10 +302,16 @@ class ClimaCellEntity(CoordinatorEntity):
|
||||
"""Base ClimaCell Entity."""
|
||||
|
||||
def __init__(
|
||||
self, config_entry: ConfigEntry, coordinator: ClimaCellDataUpdateCoordinator
|
||||
self,
|
||||
config_entry: ConfigEntry,
|
||||
coordinator: ClimaCellDataUpdateCoordinator,
|
||||
forecast_type: str,
|
||||
api_version: int,
|
||||
) -> None:
|
||||
"""Initialize ClimaCell Entity."""
|
||||
super().__init__(coordinator)
|
||||
self.api_version = api_version
|
||||
self.forecast_type = forecast_type
|
||||
self._config_entry = config_entry
|
||||
|
||||
@staticmethod
|
||||
@ -229,15 +335,23 @@ class ClimaCellEntity(CoordinatorEntity):
|
||||
|
||||
return items.get("value")
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
if self.forecast_type == DEFAULT_FORECAST_TYPE:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the entity."""
|
||||
return self._config_entry.data[CONF_NAME]
|
||||
return f"{self._config_entry.data[CONF_NAME]} - {self.forecast_type.title()}"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique id of the entity."""
|
||||
return self._config_entry.unique_id
|
||||
return f"{self._config_entry.unique_id}_{self.forecast_type}"
|
||||
|
||||
@property
|
||||
def attribution(self):
|
||||
|
@ -4,23 +4,36 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pyclimacell import ClimaCell
|
||||
from pyclimacell.const import REALTIME
|
||||
from pyclimacell import ClimaCellV3
|
||||
from pyclimacell.exceptions import (
|
||||
CantConnectException,
|
||||
InvalidAPIKeyException,
|
||||
RateLimitedException,
|
||||
)
|
||||
from pyclimacell.pyclimacell import ClimaCellV4
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import CONF_TIMESTEP, DEFAULT_NAME, DEFAULT_TIMESTEP, DOMAIN
|
||||
from .const import (
|
||||
CC_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CONF_TIMESTEP,
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_TIMESTEP,
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -43,6 +56,7 @@ def _get_config_schema(
|
||||
CONF_NAME, default=input_dict.get(CONF_NAME, DEFAULT_NAME)
|
||||
): str,
|
||||
vol.Required(CONF_API_KEY, default=input_dict.get(CONF_API_KEY)): str,
|
||||
vol.Required(CONF_API_VERSION, default=4): vol.In([3, 4]),
|
||||
vol.Inclusive(
|
||||
CONF_LATITUDE,
|
||||
"location",
|
||||
@ -85,7 +99,7 @@ class ClimaCellOptionsConfigFlow(config_entries.OptionsFlow):
|
||||
vol.Required(
|
||||
CONF_TIMESTEP,
|
||||
default=self._config_entry.options.get(CONF_TIMESTEP, DEFAULT_TIMESTEP),
|
||||
): vol.All(vol.Coerce(int), vol.Range(min=1, max=60)),
|
||||
): vol.In([1, 5, 15, 30]),
|
||||
}
|
||||
|
||||
return self.async_show_form(
|
||||
@ -119,12 +133,18 @@ class ClimaCellConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
try:
|
||||
await ClimaCell(
|
||||
if user_input[CONF_API_VERSION] == 3:
|
||||
api_class = ClimaCellV3
|
||||
field = CC_V3_ATTR_TEMPERATURE
|
||||
else:
|
||||
api_class = ClimaCellV4
|
||||
field = CC_ATTR_TEMPERATURE
|
||||
await api_class(
|
||||
user_input[CONF_API_KEY],
|
||||
str(user_input.get(CONF_LATITUDE, self.hass.config.latitude)),
|
||||
str(user_input.get(CONF_LONGITUDE, self.hass.config.longitude)),
|
||||
session=async_get_clientsession(self.hass),
|
||||
).realtime(ClimaCell.first_field(REALTIME))
|
||||
).realtime([field])
|
||||
|
||||
return self.async_create_entry(
|
||||
title=user_input[CONF_NAME], data=user_input
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Constants for the ClimaCell integration."""
|
||||
from pyclimacell.const import DAILY, HOURLY, NOWCAST, WeatherCode
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_CONDITION_CLEAR_NIGHT,
|
||||
@ -16,15 +17,8 @@ from homeassistant.components.weather import (
|
||||
)
|
||||
|
||||
CONF_TIMESTEP = "timestep"
|
||||
|
||||
DAILY = "daily"
|
||||
HOURLY = "hourly"
|
||||
NOWCAST = "nowcast"
|
||||
FORECAST_TYPES = [DAILY, HOURLY, NOWCAST]
|
||||
|
||||
CURRENT = "current"
|
||||
FORECASTS = "forecasts"
|
||||
|
||||
DEFAULT_NAME = "ClimaCell"
|
||||
DEFAULT_TIMESTEP = 15
|
||||
DEFAULT_FORECAST_TYPE = DAILY
|
||||
@ -33,7 +27,58 @@ ATTRIBUTION = "Powered by ClimaCell"
|
||||
|
||||
MAX_REQUESTS_PER_DAY = 1000
|
||||
|
||||
CLEAR_CONDITIONS = {"night": ATTR_CONDITION_CLEAR_NIGHT, "day": ATTR_CONDITION_SUNNY}
|
||||
|
||||
MAX_FORECASTS = {
|
||||
DAILY: 14,
|
||||
HOURLY: 24,
|
||||
NOWCAST: 30,
|
||||
}
|
||||
|
||||
# V4 constants
|
||||
CONDITIONS = {
|
||||
WeatherCode.WIND: ATTR_CONDITION_WINDY,
|
||||
WeatherCode.LIGHT_WIND: ATTR_CONDITION_WINDY,
|
||||
WeatherCode.STRONG_WIND: ATTR_CONDITION_WINDY,
|
||||
WeatherCode.FREEZING_RAIN: ATTR_CONDITION_SNOWY_RAINY,
|
||||
WeatherCode.HEAVY_FREEZING_RAIN: ATTR_CONDITION_SNOWY_RAINY,
|
||||
WeatherCode.LIGHT_FREEZING_RAIN: ATTR_CONDITION_SNOWY_RAINY,
|
||||
WeatherCode.FREEZING_DRIZZLE: ATTR_CONDITION_SNOWY_RAINY,
|
||||
WeatherCode.ICE_PELLETS: ATTR_CONDITION_HAIL,
|
||||
WeatherCode.HEAVY_ICE_PELLETS: ATTR_CONDITION_HAIL,
|
||||
WeatherCode.LIGHT_ICE_PELLETS: ATTR_CONDITION_HAIL,
|
||||
WeatherCode.SNOW: ATTR_CONDITION_SNOWY,
|
||||
WeatherCode.HEAVY_SNOW: ATTR_CONDITION_SNOWY,
|
||||
WeatherCode.LIGHT_SNOW: ATTR_CONDITION_SNOWY,
|
||||
WeatherCode.FLURRIES: ATTR_CONDITION_SNOWY,
|
||||
WeatherCode.THUNDERSTORM: ATTR_CONDITION_LIGHTNING,
|
||||
WeatherCode.RAIN: ATTR_CONDITION_POURING,
|
||||
WeatherCode.HEAVY_RAIN: ATTR_CONDITION_RAINY,
|
||||
WeatherCode.LIGHT_RAIN: ATTR_CONDITION_RAINY,
|
||||
WeatherCode.DRIZZLE: ATTR_CONDITION_RAINY,
|
||||
WeatherCode.FOG: ATTR_CONDITION_FOG,
|
||||
WeatherCode.LIGHT_FOG: ATTR_CONDITION_FOG,
|
||||
WeatherCode.CLOUDY: ATTR_CONDITION_CLOUDY,
|
||||
WeatherCode.MOSTLY_CLOUDY: ATTR_CONDITION_CLOUDY,
|
||||
WeatherCode.PARTLY_CLOUDY: ATTR_CONDITION_PARTLYCLOUDY,
|
||||
}
|
||||
|
||||
CC_ATTR_TIMESTAMP = "startTime"
|
||||
CC_ATTR_TEMPERATURE = "temperature"
|
||||
CC_ATTR_TEMPERATURE_HIGH = "temperatureMax"
|
||||
CC_ATTR_TEMPERATURE_LOW = "temperatureMin"
|
||||
CC_ATTR_PRESSURE = "pressureSeaLevel"
|
||||
CC_ATTR_HUMIDITY = "humidity"
|
||||
CC_ATTR_WIND_SPEED = "windSpeed"
|
||||
CC_ATTR_WIND_DIRECTION = "windDirection"
|
||||
CC_ATTR_OZONE = "pollutantO3"
|
||||
CC_ATTR_CONDITION = "weatherCode"
|
||||
CC_ATTR_VISIBILITY = "visibility"
|
||||
CC_ATTR_PRECIPITATION = "precipitationIntensityAvg"
|
||||
CC_ATTR_PRECIPITATION_PROBABILITY = "precipitationProbability"
|
||||
|
||||
# V3 constants
|
||||
CONDITIONS_V3 = {
|
||||
"breezy": ATTR_CONDITION_WINDY,
|
||||
"freezing_rain_heavy": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"freezing_rain": ATTR_CONDITION_SNOWY_RAINY,
|
||||
@ -58,24 +103,17 @@ CONDITIONS = {
|
||||
"partly_cloudy": ATTR_CONDITION_PARTLYCLOUDY,
|
||||
}
|
||||
|
||||
CLEAR_CONDITIONS = {"night": ATTR_CONDITION_CLEAR_NIGHT, "day": ATTR_CONDITION_SUNNY}
|
||||
|
||||
CC_ATTR_TIMESTAMP = "observation_time"
|
||||
CC_ATTR_TEMPERATURE = "temp"
|
||||
CC_ATTR_TEMPERATURE_HIGH = "max"
|
||||
CC_ATTR_TEMPERATURE_LOW = "min"
|
||||
CC_ATTR_PRESSURE = "baro_pressure"
|
||||
CC_ATTR_HUMIDITY = "humidity"
|
||||
CC_ATTR_WIND_SPEED = "wind_speed"
|
||||
CC_ATTR_WIND_DIRECTION = "wind_direction"
|
||||
CC_ATTR_OZONE = "o3"
|
||||
CC_ATTR_CONDITION = "weather_code"
|
||||
CC_ATTR_VISIBILITY = "visibility"
|
||||
CC_ATTR_PRECIPITATION = "precipitation"
|
||||
CC_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation"
|
||||
CC_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability"
|
||||
CC_ATTR_PM_2_5 = "pm25"
|
||||
CC_ATTR_PM_10 = "pm10"
|
||||
CC_ATTR_CARBON_MONOXIDE = "co"
|
||||
CC_ATTR_SULPHUR_DIOXIDE = "so2"
|
||||
CC_ATTR_NITROGEN_DIOXIDE = "no2"
|
||||
CC_V3_ATTR_TIMESTAMP = "observation_time"
|
||||
CC_V3_ATTR_TEMPERATURE = "temp"
|
||||
CC_V3_ATTR_TEMPERATURE_HIGH = "max"
|
||||
CC_V3_ATTR_TEMPERATURE_LOW = "min"
|
||||
CC_V3_ATTR_PRESSURE = "baro_pressure"
|
||||
CC_V3_ATTR_HUMIDITY = "humidity"
|
||||
CC_V3_ATTR_WIND_SPEED = "wind_speed"
|
||||
CC_V3_ATTR_WIND_DIRECTION = "wind_direction"
|
||||
CC_V3_ATTR_OZONE = "o3"
|
||||
CC_V3_ATTR_CONDITION = "weather_code"
|
||||
CC_V3_ATTR_VISIBILITY = "visibility"
|
||||
CC_V3_ATTR_PRECIPITATION = "precipitation"
|
||||
CC_V3_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation"
|
||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability"
|
||||
|
@ -3,6 +3,6 @@
|
||||
"name": "ClimaCell",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/climacell",
|
||||
"requirements": ["pyclimacell==0.14.0"],
|
||||
"requirements": ["pyclimacell==0.18.0"],
|
||||
"codeowners": ["@raman325"]
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
"data": {
|
||||
"name": "[%key:common::config_flow::data::name%]",
|
||||
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||
"api_version": "API Version",
|
||||
"latitude": "[%key:common::config_flow::data::latitude%]",
|
||||
"longitude": "[%key:common::config_flow::data::longitude%]"
|
||||
}
|
||||
@ -25,8 +26,7 @@
|
||||
"title": "Update [%key:component::climacell::title%] Options",
|
||||
"description": "If you choose to enable the `nowcast` forecast entity, you can configure the number of minutes between each forecast. The number of forecasts provided depends on the number of minutes chosen between forecasts.",
|
||||
"data": {
|
||||
"timestep": "Min. Between NowCast Forecasts",
|
||||
"forecast_types": "Forecast Type(s)"
|
||||
"timestep": "Min. Between NowCast Forecasts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ from datetime import datetime
|
||||
import logging
|
||||
from typing import Any, Callable
|
||||
|
||||
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST, WeatherCode
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_FORECAST_CONDITION,
|
||||
ATTR_FORECAST_PRECIPITATION,
|
||||
@ -18,6 +20,7 @@ from homeassistant.components.weather import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_VERSION,
|
||||
LENGTH_FEET,
|
||||
LENGTH_KILOMETERS,
|
||||
LENGTH_METERS,
|
||||
@ -33,13 +36,12 @@ from homeassistant.util import dt as dt_util
|
||||
from homeassistant.util.distance import convert as distance_convert
|
||||
from homeassistant.util.pressure import convert as pressure_convert
|
||||
|
||||
from . import ClimaCellDataUpdateCoordinator, ClimaCellEntity
|
||||
from . import ClimaCellEntity
|
||||
from .const import (
|
||||
CC_ATTR_CONDITION,
|
||||
CC_ATTR_HUMIDITY,
|
||||
CC_ATTR_OZONE,
|
||||
CC_ATTR_PRECIPITATION,
|
||||
CC_ATTR_PRECIPITATION_DAILY,
|
||||
CC_ATTR_PRECIPITATION_PROBABILITY,
|
||||
CC_ATTR_PRESSURE,
|
||||
CC_ATTR_TEMPERATURE,
|
||||
@ -49,16 +51,26 @@ from .const import (
|
||||
CC_ATTR_VISIBILITY,
|
||||
CC_ATTR_WIND_DIRECTION,
|
||||
CC_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_HUMIDITY,
|
||||
CC_V3_ATTR_OZONE,
|
||||
CC_V3_ATTR_PRECIPITATION,
|
||||
CC_V3_ATTR_PRECIPITATION_DAILY,
|
||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY,
|
||||
CC_V3_ATTR_PRESSURE,
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_TEMPERATURE_HIGH,
|
||||
CC_V3_ATTR_TEMPERATURE_LOW,
|
||||
CC_V3_ATTR_TIMESTAMP,
|
||||
CC_V3_ATTR_VISIBILITY,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CLEAR_CONDITIONS,
|
||||
CONDITIONS,
|
||||
CONDITIONS_V3,
|
||||
CONF_TIMESTEP,
|
||||
CURRENT,
|
||||
DAILY,
|
||||
DEFAULT_FORECAST_TYPE,
|
||||
DOMAIN,
|
||||
FORECASTS,
|
||||
HOURLY,
|
||||
NOWCAST,
|
||||
MAX_FORECASTS,
|
||||
)
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
@ -66,57 +78,6 @@ from .const import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _translate_condition(condition: str | None, sun_is_up: bool = True) -> str | None:
|
||||
"""Translate ClimaCell condition into an HA condition."""
|
||||
if not condition:
|
||||
return None
|
||||
if "clear" in condition.lower():
|
||||
if sun_is_up:
|
||||
return CLEAR_CONDITIONS["day"]
|
||||
return CLEAR_CONDITIONS["night"]
|
||||
return CONDITIONS[condition]
|
||||
|
||||
|
||||
def _forecast_dict(
|
||||
hass: HomeAssistantType,
|
||||
forecast_dt: datetime,
|
||||
use_datetime: bool,
|
||||
condition: str,
|
||||
precipitation: float | None,
|
||||
precipitation_probability: float | None,
|
||||
temp: float | None,
|
||||
temp_low: float | None,
|
||||
wind_direction: float | None,
|
||||
wind_speed: float | None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return formatted Forecast dict from ClimaCell forecast data."""
|
||||
if use_datetime:
|
||||
translated_condition = _translate_condition(condition, is_up(hass, forecast_dt))
|
||||
else:
|
||||
translated_condition = _translate_condition(condition, True)
|
||||
|
||||
if hass.config.units.is_metric:
|
||||
if precipitation:
|
||||
precipitation = (
|
||||
distance_convert(precipitation / 12, LENGTH_FEET, LENGTH_METERS) * 1000
|
||||
)
|
||||
if wind_speed:
|
||||
wind_speed = distance_convert(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||
|
||||
data = {
|
||||
ATTR_FORECAST_TIME: forecast_dt.isoformat(),
|
||||
ATTR_FORECAST_CONDITION: translated_condition,
|
||||
ATTR_FORECAST_PRECIPITATION: precipitation,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: precipitation_probability,
|
||||
ATTR_FORECAST_TEMP: temp,
|
||||
ATTR_FORECAST_TEMP_LOW: temp_low,
|
||||
ATTR_FORECAST_WIND_BEARING: wind_direction,
|
||||
ATTR_FORECAST_WIND_SPEED: wind_speed,
|
||||
}
|
||||
|
||||
return {k: v for k, v in data.items() if v is not None}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistantType,
|
||||
config_entry: ConfigEntry,
|
||||
@ -124,49 +85,97 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
api_version = config_entry.data[CONF_API_VERSION]
|
||||
|
||||
api_class = ClimaCellV3WeatherEntity if api_version == 3 else ClimaCellWeatherEntity
|
||||
entities = [
|
||||
ClimaCellWeatherEntity(config_entry, coordinator, forecast_type)
|
||||
api_class(config_entry, coordinator, forecast_type, api_version)
|
||||
for forecast_type in [DAILY, HOURLY, NOWCAST]
|
||||
]
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
"""Entity that talks to ClimaCell API to retrieve weather data."""
|
||||
class BaseClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
"""Base ClimaCell weather entity."""
|
||||
|
||||
def __init__(
|
||||
@staticmethod
|
||||
def _translate_condition(
|
||||
condition: int | None, sun_is_up: bool = True
|
||||
) -> str | None:
|
||||
"""Translate ClimaCell condition into an HA condition."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _forecast_dict(
|
||||
self,
|
||||
config_entry: ConfigEntry,
|
||||
coordinator: ClimaCellDataUpdateCoordinator,
|
||||
forecast_type: str,
|
||||
) -> None:
|
||||
"""Initialize ClimaCell weather entity."""
|
||||
super().__init__(config_entry, coordinator)
|
||||
self.forecast_type = forecast_type
|
||||
forecast_dt: datetime,
|
||||
use_datetime: bool,
|
||||
condition: str,
|
||||
precipitation: float | None,
|
||||
precipitation_probability: float | None,
|
||||
temp: float | None,
|
||||
temp_low: float | None,
|
||||
wind_direction: float | None,
|
||||
wind_speed: float | None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return formatted Forecast dict from ClimaCell forecast data."""
|
||||
if use_datetime:
|
||||
translated_condition = self._translate_condition(
|
||||
condition, is_up(self.hass, forecast_dt)
|
||||
)
|
||||
else:
|
||||
translated_condition = self._translate_condition(condition, True)
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
if self.forecast_type == DEFAULT_FORECAST_TYPE:
|
||||
return True
|
||||
if self.hass.config.units.is_metric:
|
||||
if precipitation:
|
||||
precipitation = (
|
||||
distance_convert(precipitation / 12, LENGTH_FEET, LENGTH_METERS)
|
||||
* 1000
|
||||
)
|
||||
if wind_speed:
|
||||
wind_speed = distance_convert(
|
||||
wind_speed, LENGTH_MILES, LENGTH_KILOMETERS
|
||||
)
|
||||
|
||||
return False
|
||||
data = {
|
||||
ATTR_FORECAST_TIME: forecast_dt.isoformat(),
|
||||
ATTR_FORECAST_CONDITION: translated_condition,
|
||||
ATTR_FORECAST_PRECIPITATION: precipitation,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: precipitation_probability,
|
||||
ATTR_FORECAST_TEMP: temp,
|
||||
ATTR_FORECAST_TEMP_LOW: temp_low,
|
||||
ATTR_FORECAST_WIND_BEARING: wind_direction,
|
||||
ATTR_FORECAST_WIND_SPEED: wind_speed,
|
||||
}
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the entity."""
|
||||
return f"{super().name} - {self.forecast_type.title()}"
|
||||
return {k: v for k, v in data.items() if v is not None}
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique id of the entity."""
|
||||
return f"{super().unique_id}_{self.forecast_type}"
|
||||
|
||||
class ClimaCellWeatherEntity(BaseClimaCellWeatherEntity):
|
||||
"""Entity that talks to ClimaCell v4 API to retrieve weather data."""
|
||||
|
||||
@staticmethod
|
||||
def _translate_condition(
|
||||
condition: int | None, sun_is_up: bool = True
|
||||
) -> str | None:
|
||||
"""Translate ClimaCell condition into an HA condition."""
|
||||
if condition is None:
|
||||
return None
|
||||
# We won't guard here, instead we will fail hard
|
||||
condition = WeatherCode(condition)
|
||||
if condition in (WeatherCode.CLEAR, WeatherCode.MOSTLY_CLEAR):
|
||||
if sun_is_up:
|
||||
return CLEAR_CONDITIONS["day"]
|
||||
return CLEAR_CONDITIONS["night"]
|
||||
return CONDITIONS[condition]
|
||||
|
||||
def _get_current_property(self, property_name: str) -> int | str | float | None:
|
||||
"""Get property from current conditions."""
|
||||
return self.coordinator.data.get(CURRENT, {}).get(property_name)
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
"""Return the platform temperature."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_ATTR_TEMPERATURE)
|
||||
return self._get_current_property(CC_ATTR_TEMPERATURE)
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
@ -176,7 +185,7 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
@property
|
||||
def pressure(self):
|
||||
"""Return the pressure."""
|
||||
pressure = self._get_cc_value(self.coordinator.data[CURRENT], CC_ATTR_PRESSURE)
|
||||
pressure = self._get_current_property(CC_ATTR_PRESSURE)
|
||||
if self.hass.config.units.is_metric and pressure:
|
||||
return pressure_convert(pressure, PRESSURE_INHG, PRESSURE_HPA)
|
||||
return pressure
|
||||
@ -184,13 +193,156 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
@property
|
||||
def humidity(self):
|
||||
"""Return the humidity."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_ATTR_HUMIDITY)
|
||||
return self._get_current_property(CC_ATTR_HUMIDITY)
|
||||
|
||||
@property
|
||||
def wind_speed(self):
|
||||
"""Return the wind speed."""
|
||||
wind_speed = self._get_current_property(CC_ATTR_WIND_SPEED)
|
||||
if self.hass.config.units.is_metric and wind_speed:
|
||||
return distance_convert(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||
return wind_speed
|
||||
|
||||
@property
|
||||
def wind_bearing(self):
|
||||
"""Return the wind bearing."""
|
||||
return self._get_current_property(CC_ATTR_WIND_DIRECTION)
|
||||
|
||||
@property
|
||||
def ozone(self):
|
||||
"""Return the O3 (ozone) level."""
|
||||
return self._get_current_property(CC_ATTR_OZONE)
|
||||
|
||||
@property
|
||||
def condition(self):
|
||||
"""Return the condition."""
|
||||
return self._translate_condition(
|
||||
self._get_current_property(CC_ATTR_CONDITION),
|
||||
is_up(self.hass),
|
||||
)
|
||||
|
||||
@property
|
||||
def visibility(self):
|
||||
"""Return the visibility."""
|
||||
visibility = self._get_current_property(CC_ATTR_VISIBILITY)
|
||||
if self.hass.config.units.is_metric and visibility:
|
||||
return distance_convert(visibility, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||
return visibility
|
||||
|
||||
@property
|
||||
def forecast(self):
|
||||
"""Return the forecast."""
|
||||
# Check if forecasts are available
|
||||
raw_forecasts = self.coordinator.data.get(FORECASTS, {}).get(self.forecast_type)
|
||||
if not raw_forecasts:
|
||||
return None
|
||||
|
||||
forecasts = []
|
||||
max_forecasts = MAX_FORECASTS[self.forecast_type]
|
||||
forecast_count = 0
|
||||
|
||||
# Set default values (in cases where keys don't exist), None will be
|
||||
# returned. Override properties per forecast type as needed
|
||||
for forecast in raw_forecasts:
|
||||
forecast_dt = dt_util.parse_datetime(forecast[CC_ATTR_TIMESTAMP])
|
||||
|
||||
# Throw out past data
|
||||
if forecast_dt.date() < dt_util.utcnow().date():
|
||||
continue
|
||||
|
||||
values = forecast["values"]
|
||||
use_datetime = True
|
||||
|
||||
condition = values.get(CC_ATTR_CONDITION)
|
||||
precipitation = values.get(CC_ATTR_PRECIPITATION)
|
||||
precipitation_probability = values.get(CC_ATTR_PRECIPITATION_PROBABILITY)
|
||||
|
||||
temp = values.get(CC_ATTR_TEMPERATURE_HIGH)
|
||||
temp_low = values.get(CC_ATTR_TEMPERATURE_LOW)
|
||||
wind_direction = values.get(CC_ATTR_WIND_DIRECTION)
|
||||
wind_speed = values.get(CC_ATTR_WIND_SPEED)
|
||||
|
||||
if self.forecast_type == DAILY:
|
||||
use_datetime = False
|
||||
if precipitation:
|
||||
precipitation = precipitation * 24
|
||||
elif self.forecast_type == NOWCAST:
|
||||
# Precipitation is forecasted in CONF_TIMESTEP increments but in a
|
||||
# per hour rate, so value needs to be converted to an amount.
|
||||
if precipitation:
|
||||
precipitation = (
|
||||
precipitation / 60 * self._config_entry.options[CONF_TIMESTEP]
|
||||
)
|
||||
|
||||
forecasts.append(
|
||||
self._forecast_dict(
|
||||
forecast_dt,
|
||||
use_datetime,
|
||||
condition,
|
||||
precipitation,
|
||||
precipitation_probability,
|
||||
temp,
|
||||
temp_low,
|
||||
wind_direction,
|
||||
wind_speed,
|
||||
)
|
||||
)
|
||||
|
||||
forecast_count += 1
|
||||
if forecast_count == max_forecasts:
|
||||
break
|
||||
|
||||
return forecasts
|
||||
|
||||
|
||||
class ClimaCellV3WeatherEntity(BaseClimaCellWeatherEntity):
|
||||
"""Entity that talks to ClimaCell v3 API to retrieve weather data."""
|
||||
|
||||
@staticmethod
|
||||
def _translate_condition(
|
||||
condition: str | None, sun_is_up: bool = True
|
||||
) -> str | None:
|
||||
"""Translate ClimaCell condition into an HA condition."""
|
||||
if not condition:
|
||||
return None
|
||||
if "clear" in condition.lower():
|
||||
if sun_is_up:
|
||||
return CLEAR_CONDITIONS["day"]
|
||||
return CLEAR_CONDITIONS["night"]
|
||||
return CONDITIONS_V3[condition]
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
"""Return the platform temperature."""
|
||||
return self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_TEMPERATURE
|
||||
)
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
return TEMP_FAHRENHEIT
|
||||
|
||||
@property
|
||||
def pressure(self):
|
||||
"""Return the pressure."""
|
||||
pressure = self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_PRESSURE
|
||||
)
|
||||
if self.hass.config.units.is_metric and pressure:
|
||||
return pressure_convert(pressure, PRESSURE_INHG, PRESSURE_HPA)
|
||||
return pressure
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
"""Return the humidity."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_HUMIDITY)
|
||||
|
||||
@property
|
||||
def wind_speed(self):
|
||||
"""Return the wind speed."""
|
||||
wind_speed = self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_ATTR_WIND_SPEED
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_SPEED
|
||||
)
|
||||
if self.hass.config.units.is_metric and wind_speed:
|
||||
return distance_convert(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||
@ -200,19 +352,19 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
def wind_bearing(self):
|
||||
"""Return the wind bearing."""
|
||||
return self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_ATTR_WIND_DIRECTION
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_DIRECTION
|
||||
)
|
||||
|
||||
@property
|
||||
def ozone(self):
|
||||
"""Return the O3 (ozone) level."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_ATTR_OZONE)
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_OZONE)
|
||||
|
||||
@property
|
||||
def condition(self):
|
||||
"""Return the condition."""
|
||||
return _translate_condition(
|
||||
self._get_cc_value(self.coordinator.data[CURRENT], CC_ATTR_CONDITION),
|
||||
return self._translate_condition(
|
||||
self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_CONDITION),
|
||||
is_up(self.hass),
|
||||
)
|
||||
|
||||
@ -220,7 +372,7 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
def visibility(self):
|
||||
"""Return the visibility."""
|
||||
visibility = self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_ATTR_VISIBILITY
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_VISIBILITY
|
||||
)
|
||||
if self.hass.config.units.is_metric and visibility:
|
||||
return distance_convert(visibility, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||
@ -230,46 +382,47 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
def forecast(self):
|
||||
"""Return the forecast."""
|
||||
# Check if forecasts are available
|
||||
if not self.coordinator.data[FORECASTS].get(self.forecast_type):
|
||||
raw_forecasts = self.coordinator.data.get(FORECASTS, {}).get(self.forecast_type)
|
||||
if not raw_forecasts:
|
||||
return None
|
||||
|
||||
forecasts = []
|
||||
|
||||
# Set default values (in cases where keys don't exist), None will be
|
||||
# returned. Override properties per forecast type as needed
|
||||
for forecast in self.coordinator.data[FORECASTS][self.forecast_type]:
|
||||
for forecast in raw_forecasts:
|
||||
forecast_dt = dt_util.parse_datetime(
|
||||
self._get_cc_value(forecast, CC_ATTR_TIMESTAMP)
|
||||
self._get_cc_value(forecast, CC_V3_ATTR_TIMESTAMP)
|
||||
)
|
||||
use_datetime = True
|
||||
condition = self._get_cc_value(forecast, CC_ATTR_CONDITION)
|
||||
precipitation = self._get_cc_value(forecast, CC_ATTR_PRECIPITATION)
|
||||
condition = self._get_cc_value(forecast, CC_V3_ATTR_CONDITION)
|
||||
precipitation = self._get_cc_value(forecast, CC_V3_ATTR_PRECIPITATION)
|
||||
precipitation_probability = self._get_cc_value(
|
||||
forecast, CC_ATTR_PRECIPITATION_PROBABILITY
|
||||
forecast, CC_V3_ATTR_PRECIPITATION_PROBABILITY
|
||||
)
|
||||
temp = self._get_cc_value(forecast, CC_ATTR_TEMPERATURE)
|
||||
temp = self._get_cc_value(forecast, CC_V3_ATTR_TEMPERATURE)
|
||||
temp_low = None
|
||||
wind_direction = self._get_cc_value(forecast, CC_ATTR_WIND_DIRECTION)
|
||||
wind_speed = self._get_cc_value(forecast, CC_ATTR_WIND_SPEED)
|
||||
wind_direction = self._get_cc_value(forecast, CC_V3_ATTR_WIND_DIRECTION)
|
||||
wind_speed = self._get_cc_value(forecast, CC_V3_ATTR_WIND_SPEED)
|
||||
|
||||
if self.forecast_type == DAILY:
|
||||
use_datetime = False
|
||||
forecast_dt = dt_util.start_of_local_day(forecast_dt)
|
||||
precipitation = self._get_cc_value(
|
||||
forecast, CC_ATTR_PRECIPITATION_DAILY
|
||||
forecast, CC_V3_ATTR_PRECIPITATION_DAILY
|
||||
)
|
||||
temp = next(
|
||||
(
|
||||
self._get_cc_value(item, CC_ATTR_TEMPERATURE_HIGH)
|
||||
for item in forecast[CC_ATTR_TEMPERATURE]
|
||||
self._get_cc_value(item, CC_V3_ATTR_TEMPERATURE_HIGH)
|
||||
for item in forecast[CC_V3_ATTR_TEMPERATURE]
|
||||
if "max" in item
|
||||
),
|
||||
temp,
|
||||
)
|
||||
temp_low = next(
|
||||
(
|
||||
self._get_cc_value(item, CC_ATTR_TEMPERATURE_LOW)
|
||||
for item in forecast[CC_ATTR_TEMPERATURE]
|
||||
self._get_cc_value(item, CC_V3_ATTR_TEMPERATURE_LOW)
|
||||
for item in forecast[CC_V3_ATTR_TEMPERATURE]
|
||||
if "min" in item
|
||||
),
|
||||
temp_low,
|
||||
@ -282,8 +435,7 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
)
|
||||
|
||||
forecasts.append(
|
||||
_forecast_dict(
|
||||
self.hass,
|
||||
self._forecast_dict(
|
||||
forecast_dt,
|
||||
use_datetime,
|
||||
condition,
|
||||
|
@ -1310,7 +1310,7 @@ pychromecast==9.1.1
|
||||
pycketcasts==1.0.0
|
||||
|
||||
# homeassistant.components.climacell
|
||||
pyclimacell==0.14.0
|
||||
pyclimacell==0.18.0
|
||||
|
||||
# homeassistant.components.cmus
|
||||
pycmus==0.1.1
|
||||
|
@ -702,7 +702,7 @@ pycfdns==1.2.1
|
||||
pychromecast==9.1.1
|
||||
|
||||
# homeassistant.components.climacell
|
||||
pyclimacell==0.14.0
|
||||
pyclimacell==0.18.0
|
||||
|
||||
# homeassistant.components.comfoconnect
|
||||
pycomfoconnect==0.4
|
||||
|
@ -1,8 +1,11 @@
|
||||
"""Configure py.test."""
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.common import load_fixture
|
||||
|
||||
|
||||
@pytest.fixture(name="skip_notifications", autouse=True)
|
||||
def skip_notifications_fixture():
|
||||
@ -17,7 +20,10 @@ def skip_notifications_fixture():
|
||||
def climacell_config_flow_connect():
|
||||
"""Mock valid climacell config flow setup."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
||||
"homeassistant.components.climacell.config_flow.ClimaCellV3.realtime",
|
||||
return_value={},
|
||||
), patch(
|
||||
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||
return_value={},
|
||||
):
|
||||
yield
|
||||
@ -27,16 +33,19 @@ def climacell_config_flow_connect():
|
||||
def climacell_config_entry_update_fixture():
|
||||
"""Mock valid climacell config entry setup."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.ClimaCell.realtime",
|
||||
return_value={},
|
||||
"homeassistant.components.climacell.ClimaCellV3.realtime",
|
||||
return_value=json.loads(load_fixture("climacell/v3_realtime.json")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCell.forecast_hourly",
|
||||
return_value=[],
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_hourly",
|
||||
return_value=json.loads(load_fixture("climacell/v3_forecast_hourly.json")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCell.forecast_daily",
|
||||
return_value=[],
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_daily",
|
||||
return_value=json.loads(load_fixture("climacell/v3_forecast_daily.json")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCell.forecast_nowcast",
|
||||
return_value=[],
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_nowcast",
|
||||
return_value=json.loads(load_fixture("climacell/v3_forecast_nowcast.json")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV4.realtime_and_all_forecasts",
|
||||
return_value=json.loads(load_fixture("climacell/v4.json")),
|
||||
):
|
||||
yield
|
||||
|
@ -1,9 +1,38 @@
|
||||
"""Constants for climacell tests."""
|
||||
|
||||
from homeassistant.const import CONF_API_KEY
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
)
|
||||
|
||||
API_KEY = "aa"
|
||||
|
||||
MIN_CONFIG = {
|
||||
CONF_API_KEY: API_KEY,
|
||||
}
|
||||
|
||||
V1_ENTRY_DATA = {
|
||||
CONF_NAME: "ClimaCell",
|
||||
CONF_API_KEY: API_KEY,
|
||||
CONF_LATITUDE: 80,
|
||||
CONF_LONGITUDE: 80,
|
||||
}
|
||||
|
||||
API_V3_ENTRY_DATA = {
|
||||
CONF_NAME: "ClimaCell",
|
||||
CONF_API_KEY: API_KEY,
|
||||
CONF_LATITUDE: 80,
|
||||
CONF_LONGITUDE: 80,
|
||||
CONF_API_VERSION: 3,
|
||||
}
|
||||
|
||||
API_V4_ENTRY_DATA = {
|
||||
CONF_NAME: "ClimaCell",
|
||||
CONF_API_KEY: API_KEY,
|
||||
CONF_LATITUDE: 80,
|
||||
CONF_LONGITUDE: 80,
|
||||
CONF_API_VERSION: 4,
|
||||
}
|
||||
|
@ -21,7 +21,13 @@ from homeassistant.components.climacell.const import (
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
)
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import API_KEY, MIN_CONFIG
|
||||
@ -48,6 +54,32 @@ async def test_user_flow_minimum_fields(hass: HomeAssistantType) -> None:
|
||||
assert result["title"] == DEFAULT_NAME
|
||||
assert result["data"][CONF_NAME] == DEFAULT_NAME
|
||||
assert result["data"][CONF_API_KEY] == API_KEY
|
||||
assert result["data"][CONF_API_VERSION] == 4
|
||||
assert result["data"][CONF_LATITUDE] == hass.config.latitude
|
||||
assert result["data"][CONF_LONGITUDE] == hass.config.longitude
|
||||
|
||||
|
||||
async def test_user_flow_v3(hass: HomeAssistantType) -> None:
|
||||
"""Test user config flow with v3 API."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
data = _get_config_schema(hass, MIN_CONFIG)(MIN_CONFIG)
|
||||
data[CONF_API_VERSION] = 3
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=data,
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == DEFAULT_NAME
|
||||
assert result["data"][CONF_NAME] == DEFAULT_NAME
|
||||
assert result["data"][CONF_API_KEY] == API_KEY
|
||||
assert result["data"][CONF_API_VERSION] == 3
|
||||
assert result["data"][CONF_LATITUDE] == hass.config.latitude
|
||||
assert result["data"][CONF_LONGITUDE] == hass.config.longitude
|
||||
|
||||
@ -60,6 +92,7 @@ async def test_user_flow_same_unique_ids(hass: HomeAssistantType) -> None:
|
||||
data=user_input,
|
||||
source=SOURCE_USER,
|
||||
unique_id=_get_unique_id(hass, user_input),
|
||||
version=2,
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -75,7 +108,7 @@ async def test_user_flow_same_unique_ids(hass: HomeAssistantType) -> None:
|
||||
async def test_user_flow_cannot_connect(hass: HomeAssistantType) -> None:
|
||||
"""Test user config flow when ClimaCell can't connect."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
||||
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||
side_effect=CantConnectException,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -91,7 +124,7 @@ async def test_user_flow_cannot_connect(hass: HomeAssistantType) -> None:
|
||||
async def test_user_flow_invalid_api(hass: HomeAssistantType) -> None:
|
||||
"""Test user config flow when API key is invalid."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
||||
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||
side_effect=InvalidAPIKeyException,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -107,7 +140,7 @@ async def test_user_flow_invalid_api(hass: HomeAssistantType) -> None:
|
||||
async def test_user_flow_rate_limited(hass: HomeAssistantType) -> None:
|
||||
"""Test user config flow when API key is rate limited."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
||||
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||
side_effect=RateLimitedException,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -123,7 +156,7 @@ async def test_user_flow_rate_limited(hass: HomeAssistantType) -> None:
|
||||
async def test_user_flow_unknown_exception(hass: HomeAssistantType) -> None:
|
||||
"""Test user config flow when unknown error occurs."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
||||
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||
side_effect=UnknownException,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -144,6 +177,7 @@ async def test_options_flow(hass: HomeAssistantType) -> None:
|
||||
data=user_config,
|
||||
source=SOURCE_USER,
|
||||
unique_id=_get_unique_id(hass, user_config),
|
||||
version=1,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -7,11 +7,12 @@ from homeassistant.components.climacell.config_flow import (
|
||||
_get_config_schema,
|
||||
_get_unique_id,
|
||||
)
|
||||
from homeassistant.components.climacell.const import DOMAIN
|
||||
from homeassistant.components.climacell.const import CONF_TIMESTEP, DOMAIN
|
||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||
from homeassistant.const import CONF_API_VERSION
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import MIN_CONFIG
|
||||
from .const import API_V3_ENTRY_DATA, MIN_CONFIG, V1_ENTRY_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
@ -23,10 +24,12 @@ async def test_load_and_unload(
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test loading and unloading entry."""
|
||||
data = _get_config_schema(hass)(MIN_CONFIG)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=_get_config_schema(hass)(MIN_CONFIG),
|
||||
unique_id=_get_unique_id(hass, _get_config_schema(hass)(MIN_CONFIG)),
|
||||
data=data,
|
||||
unique_id=_get_unique_id(hass, data),
|
||||
version=1,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
@ -36,3 +39,53 @@ async def test_load_and_unload(
|
||||
assert await hass.config_entries.async_remove(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 0
|
||||
|
||||
|
||||
async def test_v3_load_and_unload(
|
||||
hass: HomeAssistantType,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test loading and unloading v3 entry."""
|
||||
data = _get_config_schema(hass)(API_V3_ENTRY_DATA)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=data,
|
||||
unique_id=_get_unique_id(hass, data),
|
||||
version=1,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 1
|
||||
|
||||
assert await hass.config_entries.async_remove(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"old_timestep, new_timestep", [(2, 1), (7, 5), (20, 15), (21, 30)]
|
||||
)
|
||||
async def test_migrate_timestep(
|
||||
hass: HomeAssistantType,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
old_timestep: int,
|
||||
new_timestep: int,
|
||||
) -> None:
|
||||
"""Test migration to standardized timestep."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=V1_ENTRY_DATA,
|
||||
options={CONF_TIMESTEP: old_timestep},
|
||||
unique_id=_get_unique_id(hass, V1_ENTRY_DATA),
|
||||
version=1,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.version == 1
|
||||
assert (
|
||||
CONF_API_VERSION in config_entry.data
|
||||
and config_entry.data[CONF_API_VERSION] == 3
|
||||
)
|
||||
assert config_entry.options[CONF_TIMESTEP] == new_timestep
|
||||
|
382
tests/components/climacell/test_weather.py
Normal file
382
tests/components/climacell/test_weather.py
Normal file
@ -0,0 +1,382 @@
|
||||
"""Tests for Climacell weather entity."""
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from homeassistant.components.climacell.config_flow import (
|
||||
_get_config_schema,
|
||||
_get_unique_id,
|
||||
)
|
||||
from homeassistant.components.climacell.const import ATTRIBUTION, DOMAIN
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_CONDITION_CLOUDY,
|
||||
ATTR_CONDITION_RAINY,
|
||||
ATTR_CONDITION_SNOWY,
|
||||
ATTR_CONDITION_SUNNY,
|
||||
ATTR_FORECAST,
|
||||
ATTR_FORECAST_CONDITION,
|
||||
ATTR_FORECAST_PRECIPITATION,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_FORECAST_TEMP,
|
||||
ATTR_FORECAST_TEMP_LOW,
|
||||
ATTR_FORECAST_TIME,
|
||||
ATTR_FORECAST_WIND_BEARING,
|
||||
ATTR_FORECAST_WIND_SPEED,
|
||||
ATTR_WEATHER_HUMIDITY,
|
||||
ATTR_WEATHER_OZONE,
|
||||
ATTR_WEATHER_PRESSURE,
|
||||
ATTR_WEATHER_TEMPERATURE,
|
||||
ATTR_WEATHER_VISIBILITY,
|
||||
ATTR_WEATHER_WIND_BEARING,
|
||||
ATTR_WEATHER_WIND_SPEED,
|
||||
DOMAIN as WEATHER_DOMAIN,
|
||||
)
|
||||
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_FRIENDLY_NAME
|
||||
from homeassistant.core import State
|
||||
from homeassistant.helpers.entity_registry import async_get
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import API_V3_ENTRY_DATA, API_V4_ENTRY_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _enable_entity(hass: HomeAssistantType, entity_name: str) -> None:
|
||||
"""Enable disabled entity."""
|
||||
ent_reg = async_get(hass)
|
||||
entry = ent_reg.async_get(entity_name)
|
||||
updated_entry = ent_reg.async_update_entity(
|
||||
entry.entity_id, **{"disabled_by": None}
|
||||
)
|
||||
assert updated_entry != entry
|
||||
assert updated_entry.disabled is False
|
||||
|
||||
|
||||
async def _setup(hass: HomeAssistantType, config: Dict[str, Any]) -> State:
|
||||
"""Set up entry and return entity state."""
|
||||
with patch(
|
||||
"homeassistant.util.dt.utcnow",
|
||||
return_value=datetime(2021, 3, 6, 23, 59, 59, tzinfo=pytz.UTC),
|
||||
):
|
||||
data = _get_config_schema(hass)(config)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=data,
|
||||
unique_id=_get_unique_id(hass, data),
|
||||
version=1,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await _enable_entity(hass, "weather.climacell_hourly")
|
||||
await _enable_entity(hass, "weather.climacell_nowcast")
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 3
|
||||
|
||||
return hass.states.get("weather.climacell_daily")
|
||||
|
||||
|
||||
async def test_v3_weather(
|
||||
hass: HomeAssistantType,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test v3 weather data."""
|
||||
weather_state = await _setup(hass, API_V3_ENTRY_DATA)
|
||||
assert weather_state.state == ATTR_CONDITION_SUNNY
|
||||
assert weather_state.attributes[ATTR_ATTRIBUTION] == ATTRIBUTION
|
||||
assert weather_state.attributes[ATTR_FORECAST] == [
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_SUNNY,
|
||||
ATTR_FORECAST_TIME: "2021-03-07T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 7,
|
||||
ATTR_FORECAST_TEMP_LOW: -5,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-08T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 10,
|
||||
ATTR_FORECAST_TEMP_LOW: -4,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-09T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 19,
|
||||
ATTR_FORECAST_TEMP_LOW: 0,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-10T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 18,
|
||||
ATTR_FORECAST_TEMP_LOW: 3,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-11T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 5,
|
||||
ATTR_FORECAST_TEMP: 20,
|
||||
ATTR_FORECAST_TEMP_LOW: 9,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-12T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.04572,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 25,
|
||||
ATTR_FORECAST_TEMP: 20,
|
||||
ATTR_FORECAST_TEMP_LOW: 12,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-13T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 25,
|
||||
ATTR_FORECAST_TEMP: 16,
|
||||
ATTR_FORECAST_TEMP_LOW: 7,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_RAINY,
|
||||
ATTR_FORECAST_TIME: "2021-03-14T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 1.07442,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 75,
|
||||
ATTR_FORECAST_TEMP: 6,
|
||||
ATTR_FORECAST_TEMP_LOW: 3,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_SNOWY,
|
||||
ATTR_FORECAST_TIME: "2021-03-15T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 7.305040000000001,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 95,
|
||||
ATTR_FORECAST_TEMP: 1,
|
||||
ATTR_FORECAST_TEMP_LOW: 0,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-16T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.00508,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 5,
|
||||
ATTR_FORECAST_TEMP: 6,
|
||||
ATTR_FORECAST_TEMP_LOW: -2,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-17T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 11,
|
||||
ATTR_FORECAST_TEMP_LOW: 1,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-18T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 5,
|
||||
ATTR_FORECAST_TEMP: 12,
|
||||
ATTR_FORECAST_TEMP_LOW: 6,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-19T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.1778,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 45,
|
||||
ATTR_FORECAST_TEMP: 9,
|
||||
ATTR_FORECAST_TEMP_LOW: 5,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_RAINY,
|
||||
ATTR_FORECAST_TIME: "2021-03-20T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 1.2319,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 55,
|
||||
ATTR_FORECAST_TEMP: 5,
|
||||
ATTR_FORECAST_TEMP_LOW: 3,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-21T00:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.043179999999999996,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 20,
|
||||
ATTR_FORECAST_TEMP: 7,
|
||||
ATTR_FORECAST_TEMP_LOW: 1,
|
||||
},
|
||||
]
|
||||
assert weather_state.attributes[ATTR_FRIENDLY_NAME] == "ClimaCell - Daily"
|
||||
assert weather_state.attributes[ATTR_WEATHER_HUMIDITY] == 24
|
||||
assert weather_state.attributes[ATTR_WEATHER_OZONE] == 52.625
|
||||
assert weather_state.attributes[ATTR_WEATHER_PRESSURE] == 1028.124632345
|
||||
assert weather_state.attributes[ATTR_WEATHER_TEMPERATURE] == 7
|
||||
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_SPEED] == 14.62893696
|
||||
|
||||
|
||||
async def test_v4_weather(
|
||||
hass: HomeAssistantType,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test v4 weather data."""
|
||||
weather_state = await _setup(hass, API_V4_ENTRY_DATA)
|
||||
assert weather_state.state == ATTR_CONDITION_SUNNY
|
||||
assert weather_state.attributes[ATTR_ATTRIBUTION] == ATTRIBUTION
|
||||
assert weather_state.attributes[ATTR_FORECAST] == [
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_SUNNY,
|
||||
ATTR_FORECAST_TIME: "2021-03-07T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 8,
|
||||
ATTR_FORECAST_TEMP_LOW: -3,
|
||||
ATTR_FORECAST_WIND_BEARING: 239.6,
|
||||
ATTR_FORECAST_WIND_SPEED: 15.272674560000002,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-08T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 10,
|
||||
ATTR_FORECAST_TEMP_LOW: -3,
|
||||
ATTR_FORECAST_WIND_BEARING: 262.82,
|
||||
ATTR_FORECAST_WIND_SPEED: 11.65165056,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-09T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 19,
|
||||
ATTR_FORECAST_TEMP_LOW: 0,
|
||||
ATTR_FORECAST_WIND_BEARING: 229.3,
|
||||
ATTR_FORECAST_WIND_SPEED: 11.3458752,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-10T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 18,
|
||||
ATTR_FORECAST_TEMP_LOW: 3,
|
||||
ATTR_FORECAST_WIND_BEARING: 149.91,
|
||||
ATTR_FORECAST_WIND_SPEED: 17.123420160000002,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-11T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 19,
|
||||
ATTR_FORECAST_TEMP_LOW: 9,
|
||||
ATTR_FORECAST_WIND_BEARING: 210.45,
|
||||
ATTR_FORECAST_WIND_SPEED: 25.250607360000004,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "rainy",
|
||||
ATTR_FORECAST_TIME: "2021-03-12T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.12192000000000001,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 25,
|
||||
ATTR_FORECAST_TEMP: 20,
|
||||
ATTR_FORECAST_TEMP_LOW: 12,
|
||||
ATTR_FORECAST_WIND_BEARING: 217.98,
|
||||
ATTR_FORECAST_WIND_SPEED: 19.794931200000004,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-13T11:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 25,
|
||||
ATTR_FORECAST_TEMP: 12,
|
||||
ATTR_FORECAST_TEMP_LOW: 6,
|
||||
ATTR_FORECAST_WIND_BEARING: 58.79,
|
||||
ATTR_FORECAST_WIND_SPEED: 15.642823680000001,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "snowy",
|
||||
ATTR_FORECAST_TIME: "2021-03-14T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 23.95728,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 95,
|
||||
ATTR_FORECAST_TEMP: 6,
|
||||
ATTR_FORECAST_TEMP_LOW: 1,
|
||||
ATTR_FORECAST_WIND_BEARING: 70.25,
|
||||
ATTR_FORECAST_WIND_SPEED: 26.15184,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "snowy",
|
||||
ATTR_FORECAST_TIME: "2021-03-15T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 1.46304,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 55,
|
||||
ATTR_FORECAST_TEMP: 6,
|
||||
ATTR_FORECAST_TEMP_LOW: -1,
|
||||
ATTR_FORECAST_WIND_BEARING: 84.47,
|
||||
ATTR_FORECAST_WIND_SPEED: 25.57247616,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-16T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 6,
|
||||
ATTR_FORECAST_TEMP_LOW: -2,
|
||||
ATTR_FORECAST_WIND_BEARING: 103.85,
|
||||
ATTR_FORECAST_WIND_SPEED: 10.79869824,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-17T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 11,
|
||||
ATTR_FORECAST_TEMP_LOW: 1,
|
||||
ATTR_FORECAST_WIND_BEARING: 145.41,
|
||||
ATTR_FORECAST_WIND_SPEED: 11.69993088,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "cloudy",
|
||||
ATTR_FORECAST_TIME: "2021-03-18T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 10,
|
||||
ATTR_FORECAST_TEMP: 12,
|
||||
ATTR_FORECAST_TEMP_LOW: 5,
|
||||
ATTR_FORECAST_WIND_BEARING: 62.99,
|
||||
ATTR_FORECAST_WIND_SPEED: 10.58948352,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "rainy",
|
||||
ATTR_FORECAST_TIME: "2021-03-19T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 2.92608,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 55,
|
||||
ATTR_FORECAST_TEMP: 9,
|
||||
ATTR_FORECAST_TEMP_LOW: 4,
|
||||
ATTR_FORECAST_WIND_BEARING: 68.54,
|
||||
ATTR_FORECAST_WIND_SPEED: 22.38597504,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: "snowy",
|
||||
ATTR_FORECAST_TIME: "2021-03-20T10:00:00+00:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 1.2192,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 33.3,
|
||||
ATTR_FORECAST_TEMP: 5,
|
||||
ATTR_FORECAST_TEMP_LOW: 2,
|
||||
ATTR_FORECAST_WIND_BEARING: 56.98,
|
||||
ATTR_FORECAST_WIND_SPEED: 27.922118400000002,
|
||||
},
|
||||
]
|
||||
assert weather_state.attributes[ATTR_FRIENDLY_NAME] == "ClimaCell - Daily"
|
||||
assert weather_state.attributes[ATTR_WEATHER_HUMIDITY] == 23
|
||||
assert weather_state.attributes[ATTR_WEATHER_OZONE] == 46.53
|
||||
assert weather_state.attributes[ATTR_WEATHER_PRESSURE] == 1027.7690615000001
|
||||
assert weather_state.attributes[ATTR_WEATHER_TEMPERATURE] == 7
|
||||
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_SPEED] == 15.01517952
|
992
tests/fixtures/climacell/v3_forecast_daily.json
vendored
Normal file
992
tests/fixtures/climacell/v3_forecast_daily.json
vendored
Normal file
@ -0,0 +1,992 @@
|
||||
[
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-07T11:00:00Z",
|
||||
"min": {
|
||||
"value": 23.47,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-07T21:00:00Z",
|
||||
"max": {
|
||||
"value": 44.88,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-08T00:00:00Z",
|
||||
"min": {
|
||||
"value": 2.58,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-07T19:00:00Z",
|
||||
"max": {
|
||||
"value": 7.67,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-08T00:00:00Z",
|
||||
"min": {
|
||||
"value": 72.1,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-07T19:00:00Z",
|
||||
"max": {
|
||||
"value": 313.49,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-08T11:00:00Z",
|
||||
"min": {
|
||||
"value": 24.79,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-08T21:00:00Z",
|
||||
"max": {
|
||||
"value": 49.42,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-08T22:00:00Z",
|
||||
"min": {
|
||||
"value": 1.97,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-08T13:00:00Z",
|
||||
"max": {
|
||||
"value": 7.24,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-08T22:00:00Z",
|
||||
"min": {
|
||||
"value": 268.74,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-08T13:00:00Z",
|
||||
"max": {
|
||||
"value": 324.8,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-09T11:00:00Z",
|
||||
"min": {
|
||||
"value": 31.48,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-09T21:00:00Z",
|
||||
"max": {
|
||||
"value": 66.98,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-09T22:00:00Z",
|
||||
"min": {
|
||||
"value": 3.35,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-09T19:00:00Z",
|
||||
"max": {
|
||||
"value": 7.05,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-09T22:00:00Z",
|
||||
"min": {
|
||||
"value": 279.37,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-09T19:00:00Z",
|
||||
"max": {
|
||||
"value": 253.12,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "mostly_cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-09"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-10T11:00:00Z",
|
||||
"min": {
|
||||
"value": 37.32,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-10T20:00:00Z",
|
||||
"max": {
|
||||
"value": 65.28,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-10T05:00:00Z",
|
||||
"min": {
|
||||
"value": 2.13,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-10T21:00:00Z",
|
||||
"max": {
|
||||
"value": 9.42,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-10T05:00:00Z",
|
||||
"min": {
|
||||
"value": 342.01,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-10T21:00:00Z",
|
||||
"max": {
|
||||
"value": 193.22,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-10"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-11T12:00:00Z",
|
||||
"min": {
|
||||
"value": 48.69,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-11T21:00:00Z",
|
||||
"max": {
|
||||
"value": 67.37,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 5,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-11T02:00:00Z",
|
||||
"min": {
|
||||
"value": 8.82,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-12T01:00:00Z",
|
||||
"max": {
|
||||
"value": 14.47,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-11T02:00:00Z",
|
||||
"min": {
|
||||
"value": 176.84,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-12T01:00:00Z",
|
||||
"max": {
|
||||
"value": 210.63,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-11"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-12T12:00:00Z",
|
||||
"min": {
|
||||
"value": 53.83,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-12T18:00:00Z",
|
||||
"max": {
|
||||
"value": 67.91,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.0018,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 25,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-13T00:00:00Z",
|
||||
"min": {
|
||||
"value": 4.98,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-12T02:00:00Z",
|
||||
"max": {
|
||||
"value": 15.69,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-13T00:00:00Z",
|
||||
"min": {
|
||||
"value": 329.35,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-12T02:00:00Z",
|
||||
"max": {
|
||||
"value": 211.47,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-12"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-14T00:00:00Z",
|
||||
"min": {
|
||||
"value": 45.48,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-13T03:00:00Z",
|
||||
"max": {
|
||||
"value": 60.42,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 25,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-13T03:00:00Z",
|
||||
"min": {
|
||||
"value": 2.91,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-13T21:00:00Z",
|
||||
"max": {
|
||||
"value": 9.72,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-13T03:00:00Z",
|
||||
"min": {
|
||||
"value": 202.04,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-13T21:00:00Z",
|
||||
"max": {
|
||||
"value": 64.38,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-13"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-15T00:00:00Z",
|
||||
"min": {
|
||||
"value": 37.81,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-14T03:00:00Z",
|
||||
"max": {
|
||||
"value": 43.58,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.0423,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 75,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-14T06:00:00Z",
|
||||
"min": {
|
||||
"value": 5.34,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-14T21:00:00Z",
|
||||
"max": {
|
||||
"value": 16.25,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-14T06:00:00Z",
|
||||
"min": {
|
||||
"value": 57.52,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-14T21:00:00Z",
|
||||
"max": {
|
||||
"value": 83.23,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "rain_light"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-14"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-16T00:00:00Z",
|
||||
"min": {
|
||||
"value": 32.31,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-15T09:00:00Z",
|
||||
"max": {
|
||||
"value": 34.21,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.2876,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 95,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-16T00:00:00Z",
|
||||
"min": {
|
||||
"value": 11.7,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-15T18:00:00Z",
|
||||
"max": {
|
||||
"value": 15.89,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-16T00:00:00Z",
|
||||
"min": {
|
||||
"value": 63.67,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-15T18:00:00Z",
|
||||
"max": {
|
||||
"value": 59.49,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "snow_heavy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-15"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-16T12:00:00Z",
|
||||
"min": {
|
||||
"value": 29.1,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-16T21:00:00Z",
|
||||
"max": {
|
||||
"value": 43,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.0002,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 5,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-16T18:00:00Z",
|
||||
"min": {
|
||||
"value": 4.98,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-16T03:00:00Z",
|
||||
"max": {
|
||||
"value": 9.77,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-16T18:00:00Z",
|
||||
"min": {
|
||||
"value": 80.47,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-16T03:00:00Z",
|
||||
"max": {
|
||||
"value": 58.98,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-16"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-17T12:00:00Z",
|
||||
"min": {
|
||||
"value": 34.32,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-17T21:00:00Z",
|
||||
"max": {
|
||||
"value": 52.4,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-18T00:00:00Z",
|
||||
"min": {
|
||||
"value": 4.49,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-17T03:00:00Z",
|
||||
"max": {
|
||||
"value": 6.71,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-18T00:00:00Z",
|
||||
"min": {
|
||||
"value": 116.64,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-17T03:00:00Z",
|
||||
"max": {
|
||||
"value": 111.51,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-17"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-18T12:00:00Z",
|
||||
"min": {
|
||||
"value": 41.99,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-18T21:00:00Z",
|
||||
"max": {
|
||||
"value": 54.07,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 5,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-18T06:00:00Z",
|
||||
"min": {
|
||||
"value": 2.77,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-18T03:00:00Z",
|
||||
"max": {
|
||||
"value": 5.22,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-18T06:00:00Z",
|
||||
"min": {
|
||||
"value": 119.5,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-18T03:00:00Z",
|
||||
"max": {
|
||||
"value": 135.5,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-18"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-19T12:00:00Z",
|
||||
"min": {
|
||||
"value": 40.48,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-19T18:00:00Z",
|
||||
"max": {
|
||||
"value": 48.94,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.007,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 45,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-19T03:00:00Z",
|
||||
"min": {
|
||||
"value": 5.43,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-20T00:00:00Z",
|
||||
"max": {
|
||||
"value": 11.1,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-19T03:00:00Z",
|
||||
"min": {
|
||||
"value": 50.18,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-20T00:00:00Z",
|
||||
"max": {
|
||||
"value": 86.96,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-19"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-21T00:00:00Z",
|
||||
"min": {
|
||||
"value": 37.56,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-20T03:00:00Z",
|
||||
"max": {
|
||||
"value": 41.05,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.0485,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 55,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-20T03:00:00Z",
|
||||
"min": {
|
||||
"value": 10.9,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-20T21:00:00Z",
|
||||
"max": {
|
||||
"value": 17.35,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-20T03:00:00Z",
|
||||
"min": {
|
||||
"value": 70.56,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-20T21:00:00Z",
|
||||
"max": {
|
||||
"value": 58.55,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "drizzle"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-20"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
},
|
||||
{
|
||||
"temp": [
|
||||
{
|
||||
"observation_time": "2021-03-21T12:00:00Z",
|
||||
"min": {
|
||||
"value": 33.66,
|
||||
"units": "F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-21T21:00:00Z",
|
||||
"max": {
|
||||
"value": 44.3,
|
||||
"units": "F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"precipitation_accumulation": {
|
||||
"value": 0.0017,
|
||||
"units": "in"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 20,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": [
|
||||
{
|
||||
"observation_time": "2021-03-22T00:00:00Z",
|
||||
"min": {
|
||||
"value": 8.65,
|
||||
"units": "mph"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-21T03:00:00Z",
|
||||
"max": {
|
||||
"value": 16.53,
|
||||
"units": "mph"
|
||||
}
|
||||
}
|
||||
],
|
||||
"wind_direction": [
|
||||
{
|
||||
"observation_time": "2021-03-22T00:00:00Z",
|
||||
"min": {
|
||||
"value": 64.92,
|
||||
"units": "degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"observation_time": "2021-03-21T03:00:00Z",
|
||||
"max": {
|
||||
"value": 57.74,
|
||||
"units": "degrees"
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-21"
|
||||
},
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012
|
||||
}
|
||||
]
|
752
tests/fixtures/climacell/v3_forecast_hourly.json
vendored
Normal file
752
tests/fixtures/climacell/v3_forecast_hourly.json
vendored
Normal file
@ -0,0 +1,752 @@
|
||||
[
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 42.75,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 8.99,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 44.29,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.65,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 45.3,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.28,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 322.01,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T20:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 45.26,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.12,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 323.71,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T21:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 44.83,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 7.27,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 319.88,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T22:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 41.7,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.37,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.69,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T23:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 38.04,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.45,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 351.54,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T00:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 35.88,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.31,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 20.6,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T01:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 34.34,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.78,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 11.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T02:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 33.3,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.73,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 15.46,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T03:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 31.74,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.44,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 26.07,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T04:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 29.98,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.33,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 23.7,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T05:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 27.34,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.7,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 354.56,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T06:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 26.61,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.94,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 349.63,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T07:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 25.96,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.61,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 336.74,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T08:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 25.72,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.22,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 332.71,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T09:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 25.68,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.56,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 328.58,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T10:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 31.02,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 2.8,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 322.27,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T11:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lon": -77.03012,
|
||||
"lat": 38.90694,
|
||||
"temp": {
|
||||
"value": 31.04,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 2.82,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 325.27,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T12:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 29.95,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 7.24,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 324.8,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "mostly_clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T13:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 34.02,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 6.28,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 335.16,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "partly_cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T14:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 37.78,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.8,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 324.49,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T15:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 40.57,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.5,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 310.68,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "mostly_cloudy"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T16:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 42.83,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 5.47,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 304.18,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "mostly_clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T17:00:00.000Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 45.07,
|
||||
"units": "F"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"precipitation_probability": {
|
||||
"value": 0,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 4.88,
|
||||
"units": "mph"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 301.19,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-08T18:00:00.000Z"
|
||||
}
|
||||
}
|
||||
]
|
782
tests/fixtures/climacell/v3_forecast_nowcast.json
vendored
Normal file
782
tests/fixtures/climacell/v3_forecast_nowcast.json
vendored
Normal file
@ -0,0 +1,782 @@
|
||||
[
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.14,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.58,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:54:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.17,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.59,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:55:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.19,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.6,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:56:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.22,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.61,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:57:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.24,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.62,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:58:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.27,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.64,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.22,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:59:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.29,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.65,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:00:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.31,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.64,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:01:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.33,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.63,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:02:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.34,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.63,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:03:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.36,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.62,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:04:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.38,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.61,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:05:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.4,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.61,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:06:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.41,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.6,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:07:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.43,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.6,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:08:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.45,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.59,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:09:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.46,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.58,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:10:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.48,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.58,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:11:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.5,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.57,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:12:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.51,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.57,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:13:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.53,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.56,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:14:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.55,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.55,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:15:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.56,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.55,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:16:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.58,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.54,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:17:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.6,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.54,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:18:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.61,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.53,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:19:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.63,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.52,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:20:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.65,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.52,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:21:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.66,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.51,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:22:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 44.68,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.51,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation": {
|
||||
"value": 0,
|
||||
"units": "in/hr"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 326.14,
|
||||
"units": "degrees"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T19:23:06.493Z"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
}
|
||||
}
|
||||
]
|
38
tests/fixtures/climacell/v3_realtime.json
vendored
Normal file
38
tests/fixtures/climacell/v3_realtime.json
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"lat": 38.90694,
|
||||
"lon": -77.03012,
|
||||
"temp": {
|
||||
"value": 43.93,
|
||||
"units": "F"
|
||||
},
|
||||
"wind_speed": {
|
||||
"value": 9.09,
|
||||
"units": "mph"
|
||||
},
|
||||
"baro_pressure": {
|
||||
"value": 30.3605,
|
||||
"units": "inHg"
|
||||
},
|
||||
"visibility": {
|
||||
"value": 6.21,
|
||||
"units": "mi"
|
||||
},
|
||||
"humidity": {
|
||||
"value": 24.5,
|
||||
"units": "%"
|
||||
},
|
||||
"wind_direction": {
|
||||
"value": 320.31,
|
||||
"units": "degrees"
|
||||
},
|
||||
"weather_code": {
|
||||
"value": "clear"
|
||||
},
|
||||
"o3": {
|
||||
"value": 52.625,
|
||||
"units": "ppb"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:54:06.055Z"
|
||||
}
|
||||
}
|
2360
tests/fixtures/climacell/v4.json
vendored
Normal file
2360
tests/fixtures/climacell/v4.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user