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
19 changed files with 5973 additions and 219 deletions
|
@ -145,7 +145,6 @@ omit =
|
||||||
homeassistant/components/clickatell/notify.py
|
homeassistant/components/clickatell/notify.py
|
||||||
homeassistant/components/clicksend/notify.py
|
homeassistant/components/clicksend/notify.py
|
||||||
homeassistant/components/clicksend_tts/notify.py
|
homeassistant/components/clicksend_tts/notify.py
|
||||||
homeassistant/components/climacell/weather.py
|
|
||||||
homeassistant/components/cmus/media_player.py
|
homeassistant/components/cmus/media_player.py
|
||||||
homeassistant/components/co2signal/*
|
homeassistant/components/co2signal/*
|
||||||
homeassistant/components/coinbase/*
|
homeassistant/components/coinbase/*
|
||||||
|
|
|
@ -7,14 +7,9 @@ import logging
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pyclimacell import ClimaCell
|
from pyclimacell import ClimaCellV3, ClimaCellV4
|
||||||
from pyclimacell.const import (
|
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST
|
||||||
FORECAST_DAILY,
|
from pyclimacell.exceptions import (
|
||||||
FORECAST_HOURLY,
|
|
||||||
FORECAST_NOWCAST,
|
|
||||||
REALTIME,
|
|
||||||
)
|
|
||||||
from pyclimacell.pyclimacell import (
|
|
||||||
CantConnectException,
|
CantConnectException,
|
||||||
InvalidAPIKeyException,
|
InvalidAPIKeyException,
|
||||||
RateLimitedException,
|
RateLimitedException,
|
||||||
|
@ -23,7 +18,13 @@ from pyclimacell.pyclimacell import (
|
||||||
|
|
||||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntry
|
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.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
@ -34,15 +35,34 @@ from homeassistant.helpers.update_coordinator import (
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTRIBUTION,
|
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,
|
CONF_TIMESTEP,
|
||||||
CURRENT,
|
DEFAULT_FORECAST_TYPE,
|
||||||
DAILY,
|
|
||||||
DEFAULT_TIMESTEP,
|
DEFAULT_TIMESTEP,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FORECASTS,
|
|
||||||
HOURLY,
|
|
||||||
MAX_REQUESTS_PER_DAY,
|
MAX_REQUESTS_PER_DAY,
|
||||||
NOWCAST,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -54,6 +74,7 @@ def _set_update_interval(
|
||||||
hass: HomeAssistantType, current_entry: ConfigEntry
|
hass: HomeAssistantType, current_entry: ConfigEntry
|
||||||
) -> timedelta:
|
) -> timedelta:
|
||||||
"""Recalculate update_interval based on existing ClimaCell instances and update them."""
|
"""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
|
# 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
|
# 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
|
# 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(
|
interval = timedelta(
|
||||||
minutes=(
|
minutes=(
|
||||||
ceil(
|
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)
|
/ (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."""
|
"""Set up ClimaCell API from a config entry."""
|
||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
|
||||||
|
params = {}
|
||||||
# If config entry options not set up, set them up
|
# If config entry options not set up, set them up
|
||||||
if not config_entry.options:
|
if not config_entry.options:
|
||||||
hass.config_entries.async_update_entry(
|
params["options"] = {
|
||||||
config_entry,
|
CONF_TIMESTEP: DEFAULT_TIMESTEP,
|
||||||
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(
|
coordinator = ClimaCellDataUpdateCoordinator(
|
||||||
hass,
|
hass,
|
||||||
config_entry,
|
config_entry,
|
||||||
ClimaCell(
|
api,
|
||||||
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),
|
|
||||||
),
|
|
||||||
_set_update_interval(hass, config_entry),
|
_set_update_interval(hass, config_entry),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -145,12 +190,13 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
self,
|
self,
|
||||||
hass: HomeAssistantType,
|
hass: HomeAssistantType,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
api: ClimaCell,
|
api: ClimaCellV3 | ClimaCellV4,
|
||||||
update_interval: timedelta,
|
update_interval: timedelta,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
|
|
||||||
self._config_entry = config_entry
|
self._config_entry = config_entry
|
||||||
|
self._api_version = config_entry.data[CONF_API_VERSION]
|
||||||
self._api = api
|
self._api = api
|
||||||
self.name = config_entry.data[CONF_NAME]
|
self.name = config_entry.data[CONF_NAME]
|
||||||
self.data = {CURRENT: {}, FORECASTS: {}}
|
self.data = {CURRENT: {}, FORECASTS: {}}
|
||||||
|
@ -166,27 +212,81 @@ class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
"""Update data via library."""
|
"""Update data via library."""
|
||||||
data = {FORECASTS: {}}
|
data = {FORECASTS: {}}
|
||||||
try:
|
try:
|
||||||
data[CURRENT] = await self._api.realtime(
|
if self._api_version == 3:
|
||||||
self._api.available_fields(REALTIME)
|
data[CURRENT] = await self._api.realtime(
|
||||||
)
|
[
|
||||||
data[FORECASTS][HOURLY] = await self._api.forecast_hourly(
|
CC_V3_ATTR_TEMPERATURE,
|
||||||
self._api.available_fields(FORECAST_HOURLY),
|
CC_V3_ATTR_HUMIDITY,
|
||||||
None,
|
CC_V3_ATTR_PRESSURE,
|
||||||
timedelta(hours=24),
|
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(
|
data[FORECASTS][DAILY] = await self._api.forecast_daily(
|
||||||
self._api.available_fields(FORECAST_DAILY), None, timedelta(days=14)
|
[
|
||||||
)
|
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(
|
data[FORECASTS][NOWCAST] = await self._api.forecast_nowcast(
|
||||||
self._api.available_fields(FORECAST_NOWCAST),
|
[
|
||||||
None,
|
CC_V3_ATTR_TEMPERATURE,
|
||||||
timedelta(
|
CC_V3_ATTR_WIND_SPEED,
|
||||||
minutes=min(300, self._config_entry.options[CONF_TIMESTEP] * 30)
|
CC_V3_ATTR_WIND_DIRECTION,
|
||||||
),
|
CC_V3_ATTR_CONDITION,
|
||||||
self._config_entry.options[CONF_TIMESTEP],
|
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 (
|
except (
|
||||||
CantConnectException,
|
CantConnectException,
|
||||||
InvalidAPIKeyException,
|
InvalidAPIKeyException,
|
||||||
|
@ -202,10 +302,16 @@ class ClimaCellEntity(CoordinatorEntity):
|
||||||
"""Base ClimaCell Entity."""
|
"""Base ClimaCell Entity."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, config_entry: ConfigEntry, coordinator: ClimaCellDataUpdateCoordinator
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
coordinator: ClimaCellDataUpdateCoordinator,
|
||||||
|
forecast_type: str,
|
||||||
|
api_version: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize ClimaCell Entity."""
|
"""Initialize ClimaCell Entity."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
|
self.api_version = api_version
|
||||||
|
self.forecast_type = forecast_type
|
||||||
self._config_entry = config_entry
|
self._config_entry = config_entry
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -229,15 +335,23 @@ class ClimaCellEntity(CoordinatorEntity):
|
||||||
|
|
||||||
return items.get("value")
|
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
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
"""Return the name of the entity."""
|
"""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
|
@property
|
||||||
def unique_id(self) -> str:
|
def unique_id(self) -> str:
|
||||||
"""Return the unique id of the entity."""
|
"""Return the unique id of the entity."""
|
||||||
return self._config_entry.unique_id
|
return f"{self._config_entry.unique_id}_{self.forecast_type}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attribution(self):
|
def attribution(self):
|
||||||
|
|
|
@ -4,23 +4,36 @@ from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pyclimacell import ClimaCell
|
from pyclimacell import ClimaCellV3
|
||||||
from pyclimacell.const import REALTIME
|
|
||||||
from pyclimacell.exceptions import (
|
from pyclimacell.exceptions import (
|
||||||
CantConnectException,
|
CantConnectException,
|
||||||
InvalidAPIKeyException,
|
InvalidAPIKeyException,
|
||||||
RateLimitedException,
|
RateLimitedException,
|
||||||
)
|
)
|
||||||
|
from pyclimacell.pyclimacell import ClimaCellV4
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries, core
|
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.core import callback
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -43,6 +56,7 @@ def _get_config_schema(
|
||||||
CONF_NAME, default=input_dict.get(CONF_NAME, DEFAULT_NAME)
|
CONF_NAME, default=input_dict.get(CONF_NAME, DEFAULT_NAME)
|
||||||
): str,
|
): str,
|
||||||
vol.Required(CONF_API_KEY, default=input_dict.get(CONF_API_KEY)): 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(
|
vol.Inclusive(
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
"location",
|
"location",
|
||||||
|
@ -85,7 +99,7 @@ class ClimaCellOptionsConfigFlow(config_entries.OptionsFlow):
|
||||||
vol.Required(
|
vol.Required(
|
||||||
CONF_TIMESTEP,
|
CONF_TIMESTEP,
|
||||||
default=self._config_entry.options.get(CONF_TIMESTEP, DEFAULT_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(
|
return self.async_show_form(
|
||||||
|
@ -119,12 +133,18 @@ class ClimaCellConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
self._abort_if_unique_id_configured()
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
try:
|
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],
|
user_input[CONF_API_KEY],
|
||||||
str(user_input.get(CONF_LATITUDE, self.hass.config.latitude)),
|
str(user_input.get(CONF_LATITUDE, self.hass.config.latitude)),
|
||||||
str(user_input.get(CONF_LONGITUDE, self.hass.config.longitude)),
|
str(user_input.get(CONF_LONGITUDE, self.hass.config.longitude)),
|
||||||
session=async_get_clientsession(self.hass),
|
session=async_get_clientsession(self.hass),
|
||||||
).realtime(ClimaCell.first_field(REALTIME))
|
).realtime([field])
|
||||||
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=user_input[CONF_NAME], data=user_input
|
title=user_input[CONF_NAME], data=user_input
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Constants for the ClimaCell integration."""
|
"""Constants for the ClimaCell integration."""
|
||||||
|
from pyclimacell.const import DAILY, HOURLY, NOWCAST, WeatherCode
|
||||||
|
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
ATTR_CONDITION_CLEAR_NIGHT,
|
ATTR_CONDITION_CLEAR_NIGHT,
|
||||||
|
@ -16,15 +17,8 @@ from homeassistant.components.weather import (
|
||||||
)
|
)
|
||||||
|
|
||||||
CONF_TIMESTEP = "timestep"
|
CONF_TIMESTEP = "timestep"
|
||||||
|
|
||||||
DAILY = "daily"
|
|
||||||
HOURLY = "hourly"
|
|
||||||
NOWCAST = "nowcast"
|
|
||||||
FORECAST_TYPES = [DAILY, HOURLY, NOWCAST]
|
FORECAST_TYPES = [DAILY, HOURLY, NOWCAST]
|
||||||
|
|
||||||
CURRENT = "current"
|
|
||||||
FORECASTS = "forecasts"
|
|
||||||
|
|
||||||
DEFAULT_NAME = "ClimaCell"
|
DEFAULT_NAME = "ClimaCell"
|
||||||
DEFAULT_TIMESTEP = 15
|
DEFAULT_TIMESTEP = 15
|
||||||
DEFAULT_FORECAST_TYPE = DAILY
|
DEFAULT_FORECAST_TYPE = DAILY
|
||||||
|
@ -33,7 +27,58 @@ ATTRIBUTION = "Powered by ClimaCell"
|
||||||
|
|
||||||
MAX_REQUESTS_PER_DAY = 1000
|
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 = {
|
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,
|
"breezy": ATTR_CONDITION_WINDY,
|
||||||
"freezing_rain_heavy": ATTR_CONDITION_SNOWY_RAINY,
|
"freezing_rain_heavy": ATTR_CONDITION_SNOWY_RAINY,
|
||||||
"freezing_rain": ATTR_CONDITION_SNOWY_RAINY,
|
"freezing_rain": ATTR_CONDITION_SNOWY_RAINY,
|
||||||
|
@ -58,24 +103,17 @@ CONDITIONS = {
|
||||||
"partly_cloudy": ATTR_CONDITION_PARTLYCLOUDY,
|
"partly_cloudy": ATTR_CONDITION_PARTLYCLOUDY,
|
||||||
}
|
}
|
||||||
|
|
||||||
CLEAR_CONDITIONS = {"night": ATTR_CONDITION_CLEAR_NIGHT, "day": ATTR_CONDITION_SUNNY}
|
CC_V3_ATTR_TIMESTAMP = "observation_time"
|
||||||
|
CC_V3_ATTR_TEMPERATURE = "temp"
|
||||||
CC_ATTR_TIMESTAMP = "observation_time"
|
CC_V3_ATTR_TEMPERATURE_HIGH = "max"
|
||||||
CC_ATTR_TEMPERATURE = "temp"
|
CC_V3_ATTR_TEMPERATURE_LOW = "min"
|
||||||
CC_ATTR_TEMPERATURE_HIGH = "max"
|
CC_V3_ATTR_PRESSURE = "baro_pressure"
|
||||||
CC_ATTR_TEMPERATURE_LOW = "min"
|
CC_V3_ATTR_HUMIDITY = "humidity"
|
||||||
CC_ATTR_PRESSURE = "baro_pressure"
|
CC_V3_ATTR_WIND_SPEED = "wind_speed"
|
||||||
CC_ATTR_HUMIDITY = "humidity"
|
CC_V3_ATTR_WIND_DIRECTION = "wind_direction"
|
||||||
CC_ATTR_WIND_SPEED = "wind_speed"
|
CC_V3_ATTR_OZONE = "o3"
|
||||||
CC_ATTR_WIND_DIRECTION = "wind_direction"
|
CC_V3_ATTR_CONDITION = "weather_code"
|
||||||
CC_ATTR_OZONE = "o3"
|
CC_V3_ATTR_VISIBILITY = "visibility"
|
||||||
CC_ATTR_CONDITION = "weather_code"
|
CC_V3_ATTR_PRECIPITATION = "precipitation"
|
||||||
CC_ATTR_VISIBILITY = "visibility"
|
CC_V3_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation"
|
||||||
CC_ATTR_PRECIPITATION = "precipitation"
|
CC_V3_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability"
|
||||||
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"
|
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
"name": "ClimaCell",
|
"name": "ClimaCell",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/climacell",
|
"documentation": "https://www.home-assistant.io/integrations/climacell",
|
||||||
"requirements": ["pyclimacell==0.14.0"],
|
"requirements": ["pyclimacell==0.18.0"],
|
||||||
"codeowners": ["@raman325"]
|
"codeowners": ["@raman325"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"data": {
|
"data": {
|
||||||
"name": "[%key:common::config_flow::data::name%]",
|
"name": "[%key:common::config_flow::data::name%]",
|
||||||
"api_key": "[%key:common::config_flow::data::api_key%]",
|
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||||
|
"api_version": "API Version",
|
||||||
"latitude": "[%key:common::config_flow::data::latitude%]",
|
"latitude": "[%key:common::config_flow::data::latitude%]",
|
||||||
"longitude": "[%key:common::config_flow::data::longitude%]"
|
"longitude": "[%key:common::config_flow::data::longitude%]"
|
||||||
}
|
}
|
||||||
|
@ -25,8 +26,7 @@
|
||||||
"title": "Update [%key:component::climacell::title%] Options",
|
"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.",
|
"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": {
|
"data": {
|
||||||
"timestep": "Min. Between NowCast Forecasts",
|
"timestep": "Min. Between NowCast Forecasts"
|
||||||
"forecast_types": "Forecast Type(s)"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST, WeatherCode
|
||||||
|
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
ATTR_FORECAST_CONDITION,
|
ATTR_FORECAST_CONDITION,
|
||||||
ATTR_FORECAST_PRECIPITATION,
|
ATTR_FORECAST_PRECIPITATION,
|
||||||
|
@ -18,6 +20,7 @@ from homeassistant.components.weather import (
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
CONF_API_VERSION,
|
||||||
LENGTH_FEET,
|
LENGTH_FEET,
|
||||||
LENGTH_KILOMETERS,
|
LENGTH_KILOMETERS,
|
||||||
LENGTH_METERS,
|
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.distance import convert as distance_convert
|
||||||
from homeassistant.util.pressure import convert as pressure_convert
|
from homeassistant.util.pressure import convert as pressure_convert
|
||||||
|
|
||||||
from . import ClimaCellDataUpdateCoordinator, ClimaCellEntity
|
from . import ClimaCellEntity
|
||||||
from .const import (
|
from .const import (
|
||||||
CC_ATTR_CONDITION,
|
CC_ATTR_CONDITION,
|
||||||
CC_ATTR_HUMIDITY,
|
CC_ATTR_HUMIDITY,
|
||||||
CC_ATTR_OZONE,
|
CC_ATTR_OZONE,
|
||||||
CC_ATTR_PRECIPITATION,
|
CC_ATTR_PRECIPITATION,
|
||||||
CC_ATTR_PRECIPITATION_DAILY,
|
|
||||||
CC_ATTR_PRECIPITATION_PROBABILITY,
|
CC_ATTR_PRECIPITATION_PROBABILITY,
|
||||||
CC_ATTR_PRESSURE,
|
CC_ATTR_PRESSURE,
|
||||||
CC_ATTR_TEMPERATURE,
|
CC_ATTR_TEMPERATURE,
|
||||||
|
@ -49,16 +51,26 @@ from .const import (
|
||||||
CC_ATTR_VISIBILITY,
|
CC_ATTR_VISIBILITY,
|
||||||
CC_ATTR_WIND_DIRECTION,
|
CC_ATTR_WIND_DIRECTION,
|
||||||
CC_ATTR_WIND_SPEED,
|
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,
|
CLEAR_CONDITIONS,
|
||||||
CONDITIONS,
|
CONDITIONS,
|
||||||
|
CONDITIONS_V3,
|
||||||
CONF_TIMESTEP,
|
CONF_TIMESTEP,
|
||||||
CURRENT,
|
|
||||||
DAILY,
|
|
||||||
DEFAULT_FORECAST_TYPE,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FORECASTS,
|
MAX_FORECASTS,
|
||||||
HOURLY,
|
|
||||||
NOWCAST,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||||
|
@ -66,57 +78,6 @@ from .const import (
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_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(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistantType,
|
hass: HomeAssistantType,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
|
@ -124,49 +85,97 @@ async def async_setup_entry(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up a config entry."""
|
"""Set up a config entry."""
|
||||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
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 = [
|
entities = [
|
||||||
ClimaCellWeatherEntity(config_entry, coordinator, forecast_type)
|
api_class(config_entry, coordinator, forecast_type, api_version)
|
||||||
for forecast_type in [DAILY, HOURLY, NOWCAST]
|
for forecast_type in [DAILY, HOURLY, NOWCAST]
|
||||||
]
|
]
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
class BaseClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
"""Entity that talks to ClimaCell API to retrieve weather data."""
|
"""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,
|
self,
|
||||||
config_entry: ConfigEntry,
|
forecast_dt: datetime,
|
||||||
coordinator: ClimaCellDataUpdateCoordinator,
|
use_datetime: bool,
|
||||||
forecast_type: str,
|
condition: str,
|
||||||
) -> None:
|
precipitation: float | None,
|
||||||
"""Initialize ClimaCell weather entity."""
|
precipitation_probability: float | None,
|
||||||
super().__init__(config_entry, coordinator)
|
temp: float | None,
|
||||||
self.forecast_type = forecast_type
|
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
|
if self.hass.config.units.is_metric:
|
||||||
def entity_registry_enabled_default(self) -> bool:
|
if precipitation:
|
||||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
precipitation = (
|
||||||
if self.forecast_type == DEFAULT_FORECAST_TYPE:
|
distance_convert(precipitation / 12, LENGTH_FEET, LENGTH_METERS)
|
||||||
return True
|
* 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
|
return {k: v for k, v in data.items() if v is not None}
|
||||||
def name(self) -> str:
|
|
||||||
"""Return the name of the entity."""
|
|
||||||
return f"{super().name} - {self.forecast_type.title()}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self) -> str:
|
class ClimaCellWeatherEntity(BaseClimaCellWeatherEntity):
|
||||||
"""Return the unique id of the entity."""
|
"""Entity that talks to ClimaCell v4 API to retrieve weather data."""
|
||||||
return f"{super().unique_id}_{self.forecast_type}"
|
|
||||||
|
@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
|
@property
|
||||||
def temperature(self):
|
def temperature(self):
|
||||||
"""Return the platform temperature."""
|
"""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
|
@property
|
||||||
def temperature_unit(self):
|
def temperature_unit(self):
|
||||||
|
@ -176,7 +185,7 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
@property
|
@property
|
||||||
def pressure(self):
|
def pressure(self):
|
||||||
"""Return the pressure."""
|
"""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:
|
if self.hass.config.units.is_metric and pressure:
|
||||||
return pressure_convert(pressure, PRESSURE_INHG, PRESSURE_HPA)
|
return pressure_convert(pressure, PRESSURE_INHG, PRESSURE_HPA)
|
||||||
return pressure
|
return pressure
|
||||||
|
@ -184,13 +193,156 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
@property
|
@property
|
||||||
def humidity(self):
|
def humidity(self):
|
||||||
"""Return the humidity."""
|
"""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
|
@property
|
||||||
def wind_speed(self):
|
def wind_speed(self):
|
||||||
"""Return the wind speed."""
|
"""Return the wind speed."""
|
||||||
wind_speed = self._get_cc_value(
|
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:
|
if self.hass.config.units.is_metric and wind_speed:
|
||||||
return distance_convert(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS)
|
return distance_convert(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||||
|
@ -200,19 +352,19 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
def wind_bearing(self):
|
def wind_bearing(self):
|
||||||
"""Return the wind bearing."""
|
"""Return the wind bearing."""
|
||||||
return self._get_cc_value(
|
return self._get_cc_value(
|
||||||
self.coordinator.data[CURRENT], CC_ATTR_WIND_DIRECTION
|
self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_DIRECTION
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ozone(self):
|
def ozone(self):
|
||||||
"""Return the O3 (ozone) level."""
|
"""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
|
@property
|
||||||
def condition(self):
|
def condition(self):
|
||||||
"""Return the condition."""
|
"""Return the condition."""
|
||||||
return _translate_condition(
|
return self._translate_condition(
|
||||||
self._get_cc_value(self.coordinator.data[CURRENT], CC_ATTR_CONDITION),
|
self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_CONDITION),
|
||||||
is_up(self.hass),
|
is_up(self.hass),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -220,7 +372,7 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
def visibility(self):
|
def visibility(self):
|
||||||
"""Return the visibility."""
|
"""Return the visibility."""
|
||||||
visibility = self._get_cc_value(
|
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:
|
if self.hass.config.units.is_metric and visibility:
|
||||||
return distance_convert(visibility, LENGTH_MILES, LENGTH_KILOMETERS)
|
return distance_convert(visibility, LENGTH_MILES, LENGTH_KILOMETERS)
|
||||||
|
@ -230,46 +382,47 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
def forecast(self):
|
def forecast(self):
|
||||||
"""Return the forecast."""
|
"""Return the forecast."""
|
||||||
# Check if forecasts are available
|
# 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
|
return None
|
||||||
|
|
||||||
forecasts = []
|
forecasts = []
|
||||||
|
|
||||||
# Set default values (in cases where keys don't exist), None will be
|
# Set default values (in cases where keys don't exist), None will be
|
||||||
# returned. Override properties per forecast type as needed
|
# 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(
|
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
|
use_datetime = True
|
||||||
condition = self._get_cc_value(forecast, CC_ATTR_CONDITION)
|
condition = self._get_cc_value(forecast, CC_V3_ATTR_CONDITION)
|
||||||
precipitation = self._get_cc_value(forecast, CC_ATTR_PRECIPITATION)
|
precipitation = self._get_cc_value(forecast, CC_V3_ATTR_PRECIPITATION)
|
||||||
precipitation_probability = self._get_cc_value(
|
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
|
temp_low = None
|
||||||
wind_direction = self._get_cc_value(forecast, CC_ATTR_WIND_DIRECTION)
|
wind_direction = self._get_cc_value(forecast, CC_V3_ATTR_WIND_DIRECTION)
|
||||||
wind_speed = self._get_cc_value(forecast, CC_ATTR_WIND_SPEED)
|
wind_speed = self._get_cc_value(forecast, CC_V3_ATTR_WIND_SPEED)
|
||||||
|
|
||||||
if self.forecast_type == DAILY:
|
if self.forecast_type == DAILY:
|
||||||
use_datetime = False
|
use_datetime = False
|
||||||
forecast_dt = dt_util.start_of_local_day(forecast_dt)
|
forecast_dt = dt_util.start_of_local_day(forecast_dt)
|
||||||
precipitation = self._get_cc_value(
|
precipitation = self._get_cc_value(
|
||||||
forecast, CC_ATTR_PRECIPITATION_DAILY
|
forecast, CC_V3_ATTR_PRECIPITATION_DAILY
|
||||||
)
|
)
|
||||||
temp = next(
|
temp = next(
|
||||||
(
|
(
|
||||||
self._get_cc_value(item, CC_ATTR_TEMPERATURE_HIGH)
|
self._get_cc_value(item, CC_V3_ATTR_TEMPERATURE_HIGH)
|
||||||
for item in forecast[CC_ATTR_TEMPERATURE]
|
for item in forecast[CC_V3_ATTR_TEMPERATURE]
|
||||||
if "max" in item
|
if "max" in item
|
||||||
),
|
),
|
||||||
temp,
|
temp,
|
||||||
)
|
)
|
||||||
temp_low = next(
|
temp_low = next(
|
||||||
(
|
(
|
||||||
self._get_cc_value(item, CC_ATTR_TEMPERATURE_LOW)
|
self._get_cc_value(item, CC_V3_ATTR_TEMPERATURE_LOW)
|
||||||
for item in forecast[CC_ATTR_TEMPERATURE]
|
for item in forecast[CC_V3_ATTR_TEMPERATURE]
|
||||||
if "min" in item
|
if "min" in item
|
||||||
),
|
),
|
||||||
temp_low,
|
temp_low,
|
||||||
|
@ -282,8 +435,7 @@ class ClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||||
)
|
)
|
||||||
|
|
||||||
forecasts.append(
|
forecasts.append(
|
||||||
_forecast_dict(
|
self._forecast_dict(
|
||||||
self.hass,
|
|
||||||
forecast_dt,
|
forecast_dt,
|
||||||
use_datetime,
|
use_datetime,
|
||||||
condition,
|
condition,
|
||||||
|
|
|
@ -1310,7 +1310,7 @@ pychromecast==9.1.1
|
||||||
pycketcasts==1.0.0
|
pycketcasts==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.climacell
|
# homeassistant.components.climacell
|
||||||
pyclimacell==0.14.0
|
pyclimacell==0.18.0
|
||||||
|
|
||||||
# homeassistant.components.cmus
|
# homeassistant.components.cmus
|
||||||
pycmus==0.1.1
|
pycmus==0.1.1
|
||||||
|
|
|
@ -702,7 +702,7 @@ pycfdns==1.2.1
|
||||||
pychromecast==9.1.1
|
pychromecast==9.1.1
|
||||||
|
|
||||||
# homeassistant.components.climacell
|
# homeassistant.components.climacell
|
||||||
pyclimacell==0.14.0
|
pyclimacell==0.18.0
|
||||||
|
|
||||||
# homeassistant.components.comfoconnect
|
# homeassistant.components.comfoconnect
|
||||||
pycomfoconnect==0.4
|
pycomfoconnect==0.4
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
"""Configure py.test."""
|
"""Configure py.test."""
|
||||||
|
import json
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from tests.common import load_fixture
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="skip_notifications", autouse=True)
|
@pytest.fixture(name="skip_notifications", autouse=True)
|
||||||
def skip_notifications_fixture():
|
def skip_notifications_fixture():
|
||||||
|
@ -17,7 +20,10 @@ def skip_notifications_fixture():
|
||||||
def climacell_config_flow_connect():
|
def climacell_config_flow_connect():
|
||||||
"""Mock valid climacell config flow setup."""
|
"""Mock valid climacell config flow setup."""
|
||||||
with patch(
|
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={},
|
return_value={},
|
||||||
):
|
):
|
||||||
yield
|
yield
|
||||||
|
@ -27,16 +33,19 @@ def climacell_config_flow_connect():
|
||||||
def climacell_config_entry_update_fixture():
|
def climacell_config_entry_update_fixture():
|
||||||
"""Mock valid climacell config entry setup."""
|
"""Mock valid climacell config entry setup."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.climacell.ClimaCell.realtime",
|
"homeassistant.components.climacell.ClimaCellV3.realtime",
|
||||||
return_value={},
|
return_value=json.loads(load_fixture("climacell/v3_realtime.json")),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.climacell.ClimaCell.forecast_hourly",
|
"homeassistant.components.climacell.ClimaCellV3.forecast_hourly",
|
||||||
return_value=[],
|
return_value=json.loads(load_fixture("climacell/v3_forecast_hourly.json")),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.climacell.ClimaCell.forecast_daily",
|
"homeassistant.components.climacell.ClimaCellV3.forecast_daily",
|
||||||
return_value=[],
|
return_value=json.loads(load_fixture("climacell/v3_forecast_daily.json")),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.climacell.ClimaCell.forecast_nowcast",
|
"homeassistant.components.climacell.ClimaCellV3.forecast_nowcast",
|
||||||
return_value=[],
|
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
|
yield
|
||||||
|
|
|
@ -1,9 +1,38 @@
|
||||||
"""Constants for climacell tests."""
|
"""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"
|
API_KEY = "aa"
|
||||||
|
|
||||||
MIN_CONFIG = {
|
MIN_CONFIG = {
|
||||||
CONF_API_KEY: API_KEY,
|
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,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_USER
|
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 homeassistant.helpers.typing import HomeAssistantType
|
||||||
|
|
||||||
from .const import API_KEY, MIN_CONFIG
|
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["title"] == DEFAULT_NAME
|
||||||
assert result["data"][CONF_NAME] == DEFAULT_NAME
|
assert result["data"][CONF_NAME] == DEFAULT_NAME
|
||||||
assert result["data"][CONF_API_KEY] == API_KEY
|
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_LATITUDE] == hass.config.latitude
|
||||||
assert result["data"][CONF_LONGITUDE] == hass.config.longitude
|
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,
|
data=user_input,
|
||||||
source=SOURCE_USER,
|
source=SOURCE_USER,
|
||||||
unique_id=_get_unique_id(hass, user_input),
|
unique_id=_get_unique_id(hass, user_input),
|
||||||
|
version=2,
|
||||||
).add_to_hass(hass)
|
).add_to_hass(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
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:
|
async def test_user_flow_cannot_connect(hass: HomeAssistantType) -> None:
|
||||||
"""Test user config flow when ClimaCell can't connect."""
|
"""Test user config flow when ClimaCell can't connect."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||||
side_effect=CantConnectException,
|
side_effect=CantConnectException,
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
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:
|
async def test_user_flow_invalid_api(hass: HomeAssistantType) -> None:
|
||||||
"""Test user config flow when API key is invalid."""
|
"""Test user config flow when API key is invalid."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||||
side_effect=InvalidAPIKeyException,
|
side_effect=InvalidAPIKeyException,
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
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:
|
async def test_user_flow_rate_limited(hass: HomeAssistantType) -> None:
|
||||||
"""Test user config flow when API key is rate limited."""
|
"""Test user config flow when API key is rate limited."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||||
side_effect=RateLimitedException,
|
side_effect=RateLimitedException,
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
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:
|
async def test_user_flow_unknown_exception(hass: HomeAssistantType) -> None:
|
||||||
"""Test user config flow when unknown error occurs."""
|
"""Test user config flow when unknown error occurs."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.climacell.config_flow.ClimaCell.realtime",
|
"homeassistant.components.climacell.config_flow.ClimaCellV4.realtime",
|
||||||
side_effect=UnknownException,
|
side_effect=UnknownException,
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
@ -144,6 +177,7 @@ async def test_options_flow(hass: HomeAssistantType) -> None:
|
||||||
data=user_config,
|
data=user_config,
|
||||||
source=SOURCE_USER,
|
source=SOURCE_USER,
|
||||||
unique_id=_get_unique_id(hass, user_config),
|
unique_id=_get_unique_id(hass, user_config),
|
||||||
|
version=1,
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,12 @@ from homeassistant.components.climacell.config_flow import (
|
||||||
_get_config_schema,
|
_get_config_schema,
|
||||||
_get_unique_id,
|
_get_unique_id,
|
||||||
)
|
)
|
||||||
from homeassistant.components.climacell.const import DOMAIN
|
from homeassistant.components.climacell.const import CONF_TIMESTEP, DOMAIN
|
||||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||||
|
from homeassistant.const import CONF_API_VERSION
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
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
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
@ -23,10 +24,12 @@ async def test_load_and_unload(
|
||||||
climacell_config_entry_update: pytest.fixture,
|
climacell_config_entry_update: pytest.fixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test loading and unloading entry."""
|
"""Test loading and unloading entry."""
|
||||||
|
data = _get_config_schema(hass)(MIN_CONFIG)
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
data=_get_config_schema(hass)(MIN_CONFIG),
|
data=data,
|
||||||
unique_id=_get_unique_id(hass, _get_config_schema(hass)(MIN_CONFIG)),
|
unique_id=_get_unique_id(hass, data),
|
||||||
|
version=1,
|
||||||
)
|
)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
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)
|
assert await hass.config_entries.async_remove(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 0
|
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…
Add table
Add a link
Reference in a new issue