mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Retire climacell entirely (#78901)
* Retire climacell entirely * remove fixtures * remove const file * Remove all traces of climacell integration * missed some
This commit is contained in:
parent
d1da6ea04d
commit
95e3572277
@ -177,8 +177,6 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/cisco_ios/ @fbradyirl
|
||||
/homeassistant/components/cisco_mobility_express/ @fbradyirl
|
||||
/homeassistant/components/cisco_webex_teams/ @fbradyirl
|
||||
/homeassistant/components/climacell/ @raman325
|
||||
/tests/components/climacell/ @raman325
|
||||
/homeassistant/components/climate/ @home-assistant/core
|
||||
/tests/components/climate/ @home-assistant/core
|
||||
/homeassistant/components/cloud/ @home-assistant/cloud
|
||||
|
@ -1,329 +0,0 @@
|
||||
"""The ClimaCell integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from math import ceil
|
||||
from typing import Any
|
||||
|
||||
from pyclimacell import ClimaCellV3, ClimaCellV4
|
||||
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST
|
||||
from pyclimacell.exceptions import (
|
||||
CantConnectException,
|
||||
InvalidAPIKeyException,
|
||||
RateLimitedException,
|
||||
UnknownException,
|
||||
)
|
||||
|
||||
from homeassistant.components.tomorrowio import DOMAIN as TOMORROW_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
UpdateFailed,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
ATTRIBUTION,
|
||||
CC_V3_ATTR_CLOUD_COVER,
|
||||
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_PRECIPITATION_TYPE,
|
||||
CC_V3_ATTR_PRESSURE,
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_VISIBILITY,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_WIND_GUST,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_SENSOR_TYPES,
|
||||
CONF_TIMESTEP,
|
||||
DEFAULT_TIMESTEP,
|
||||
DOMAIN,
|
||||
MAX_REQUESTS_PER_DAY,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
|
||||
|
||||
|
||||
def _set_update_interval(hass: HomeAssistant, current_entry: ConfigEntry) -> timedelta:
|
||||
"""Recalculate update_interval based on existing ClimaCell instances and update them."""
|
||||
api_calls = 4 if current_entry.data[CONF_API_VERSION] == 3 else 2
|
||||
# We check how many ClimaCell configured instances are using the same API key and
|
||||
# calculate interval to not exceed allowed numbers of requests. Divide 90% of
|
||||
# MAX_REQUESTS_PER_DAY by 4 because every update requires four API calls and we want
|
||||
# a buffer in the number of API calls left at the end of the day.
|
||||
other_instance_entry_ids = [
|
||||
entry.entry_id
|
||||
for entry in hass.config_entries.async_entries(DOMAIN)
|
||||
if entry.entry_id != current_entry.entry_id
|
||||
and entry.data[CONF_API_KEY] == current_entry.data[CONF_API_KEY]
|
||||
]
|
||||
|
||||
interval = timedelta(
|
||||
minutes=(
|
||||
ceil(
|
||||
(24 * 60 * (len(other_instance_entry_ids) + 1) * api_calls)
|
||||
/ (MAX_REQUESTS_PER_DAY * 0.9)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
for entry_id in other_instance_entry_ids:
|
||||
if entry_id in hass.data[DOMAIN]:
|
||||
hass.data[DOMAIN][entry_id].update_interval = interval
|
||||
|
||||
return interval
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up ClimaCell API from a config entry."""
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
params: dict[str, Any] = {}
|
||||
# If config entry options not set up, set them up
|
||||
if not entry.options:
|
||||
params["options"] = {
|
||||
CONF_TIMESTEP: DEFAULT_TIMESTEP,
|
||||
}
|
||||
else:
|
||||
# Use valid timestep if it's invalid
|
||||
timestep = 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 = entry.options.copy()
|
||||
new_options[CONF_TIMESTEP] = timestep
|
||||
params["options"] = new_options
|
||||
# Add API version if not found
|
||||
if CONF_API_VERSION not in entry.data:
|
||||
new_data = entry.data.copy()
|
||||
new_data[CONF_API_VERSION] = 3
|
||||
params["data"] = new_data
|
||||
|
||||
if params:
|
||||
hass.config_entries.async_update_entry(entry, **params)
|
||||
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
TOMORROW_DOMAIN,
|
||||
context={"source": SOURCE_IMPORT, "old_config_entry_id": entry.entry_id},
|
||||
data=entry.data,
|
||||
)
|
||||
)
|
||||
|
||||
# Eventually we will remove the code that sets up the platforms and force users to
|
||||
# migrate. This will only impact users still on the V3 API because we can't
|
||||
# automatically migrate them, but for V4 users, we can skip the platform setup.
|
||||
if entry.data[CONF_API_VERSION] == 4:
|
||||
return True
|
||||
|
||||
api = ClimaCellV3(
|
||||
entry.data[CONF_API_KEY],
|
||||
entry.data.get(CONF_LATITUDE, hass.config.latitude),
|
||||
entry.data.get(CONF_LONGITUDE, hass.config.longitude),
|
||||
session=async_get_clientsession(hass),
|
||||
)
|
||||
|
||||
coordinator = ClimaCellDataUpdateCoordinator(
|
||||
hass,
|
||||
entry,
|
||||
api,
|
||||
_set_update_interval(hass, entry),
|
||||
)
|
||||
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = coordinator
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(
|
||||
config_entry, PLATFORMS
|
||||
)
|
||||
|
||||
hass.data[DOMAIN].pop(config_entry.entry_id, None)
|
||||
if not hass.data[DOMAIN]:
|
||||
hass.data.pop(DOMAIN)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
class ClimaCellDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Define an object to hold ClimaCell data."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
api: ClimaCellV3 | ClimaCellV4,
|
||||
update_interval: timedelta,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
|
||||
self._config_entry = config_entry
|
||||
self._api_version = config_entry.data[CONF_API_VERSION]
|
||||
self._api = api
|
||||
self.name = config_entry.data[CONF_NAME]
|
||||
self.data = {CURRENT: {}, FORECASTS: {}}
|
||||
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=config_entry.data[CONF_NAME],
|
||||
update_interval=update_interval,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update data via library."""
|
||||
data: dict[str, Any] = {FORECASTS: {}}
|
||||
try:
|
||||
data[CURRENT] = await self._api.realtime(
|
||||
[
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_HUMIDITY,
|
||||
CC_V3_ATTR_PRESSURE,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_VISIBILITY,
|
||||
CC_V3_ATTR_OZONE,
|
||||
CC_V3_ATTR_WIND_GUST,
|
||||
CC_V3_ATTR_CLOUD_COVER,
|
||||
CC_V3_ATTR_PRECIPITATION_TYPE,
|
||||
*(sensor_type.key for sensor_type in CC_V3_SENSOR_TYPES),
|
||||
]
|
||||
)
|
||||
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(
|
||||
[
|
||||
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(
|
||||
[
|
||||
CC_V3_ATTR_TEMPERATURE,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CC_V3_ATTR_WIND_DIRECTION,
|
||||
CC_V3_ATTR_CONDITION,
|
||||
CC_V3_ATTR_PRECIPITATION,
|
||||
],
|
||||
None,
|
||||
timedelta(
|
||||
minutes=min(300, self._config_entry.options[CONF_TIMESTEP] * 30)
|
||||
),
|
||||
self._config_entry.options[CONF_TIMESTEP],
|
||||
)
|
||||
except (
|
||||
CantConnectException,
|
||||
InvalidAPIKeyException,
|
||||
RateLimitedException,
|
||||
UnknownException,
|
||||
) as error:
|
||||
raise UpdateFailed from error
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class ClimaCellEntity(CoordinatorEntity[ClimaCellDataUpdateCoordinator]):
|
||||
"""Base ClimaCell Entity."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config_entry: ConfigEntry,
|
||||
coordinator: ClimaCellDataUpdateCoordinator,
|
||||
api_version: int,
|
||||
) -> None:
|
||||
"""Initialize ClimaCell Entity."""
|
||||
super().__init__(coordinator)
|
||||
self.api_version = api_version
|
||||
self._config_entry = config_entry
|
||||
|
||||
@staticmethod
|
||||
def _get_cc_value(
|
||||
weather_dict: dict[str, Any], key: str
|
||||
) -> int | float | str | None:
|
||||
"""
|
||||
Return property from weather_dict.
|
||||
|
||||
Used for V3 API.
|
||||
"""
|
||||
items = weather_dict.get(key, {})
|
||||
# Handle cases where value returned is a list.
|
||||
# Optimistically find the best value to return.
|
||||
if isinstance(items, list):
|
||||
if len(items) == 1:
|
||||
return items[0].get("value")
|
||||
return next(
|
||||
(item.get("value") for item in items if "max" in item),
|
||||
next(
|
||||
(item.get("value") for item in items if "min" in item),
|
||||
items[0].get("value", None),
|
||||
),
|
||||
)
|
||||
|
||||
return items.get("value")
|
||||
|
||||
@property
|
||||
def attribution(self):
|
||||
"""Return the attribution."""
|
||||
return ATTRIBUTION
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device registry information."""
|
||||
return DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
identifiers={(DOMAIN, self._config_entry.data[CONF_API_KEY])},
|
||||
manufacturer="ClimaCell",
|
||||
name="ClimaCell",
|
||||
sw_version=f"v{self.api_version}",
|
||||
)
|
@ -1,52 +0,0 @@
|
||||
"""Config flow for ClimaCell integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import CONF_TIMESTEP, DEFAULT_TIMESTEP, DOMAIN
|
||||
|
||||
|
||||
class ClimaCellOptionsConfigFlow(config_entries.OptionsFlow):
|
||||
"""Handle ClimaCell options."""
|
||||
|
||||
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
|
||||
"""Initialize ClimaCell options flow."""
|
||||
self._config_entry = config_entry
|
||||
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Manage the ClimaCell options."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
options_schema = {
|
||||
vol.Required(
|
||||
CONF_TIMESTEP,
|
||||
default=self._config_entry.options.get(CONF_TIMESTEP, DEFAULT_TIMESTEP),
|
||||
): vol.In([1, 5, 15, 30]),
|
||||
}
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init", data_schema=vol.Schema(options_schema)
|
||||
)
|
||||
|
||||
|
||||
class ClimaCellConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for ClimaCell Weather API."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
config_entry: config_entries.ConfigEntry,
|
||||
) -> ClimaCellOptionsConfigFlow:
|
||||
"""Get the options flow for this handler."""
|
||||
return ClimaCellOptionsConfigFlow(config_entry)
|
@ -1,225 +0,0 @@
|
||||
"""Constants for the ClimaCell integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from enum import IntEnum
|
||||
|
||||
from pyclimacell.const import DAILY, HOURLY, NOWCAST, V3PollenIndex
|
||||
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorEntityDescription
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_CONDITION_CLEAR_NIGHT,
|
||||
ATTR_CONDITION_CLOUDY,
|
||||
ATTR_CONDITION_FOG,
|
||||
ATTR_CONDITION_HAIL,
|
||||
ATTR_CONDITION_LIGHTNING,
|
||||
ATTR_CONDITION_PARTLYCLOUDY,
|
||||
ATTR_CONDITION_POURING,
|
||||
ATTR_CONDITION_RAINY,
|
||||
ATTR_CONDITION_SNOWY,
|
||||
ATTR_CONDITION_SNOWY_RAINY,
|
||||
ATTR_CONDITION_SUNNY,
|
||||
ATTR_CONDITION_WINDY,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
)
|
||||
|
||||
CONF_TIMESTEP = "timestep"
|
||||
FORECAST_TYPES = [DAILY, HOURLY, NOWCAST]
|
||||
|
||||
DEFAULT_NAME = "ClimaCell"
|
||||
DEFAULT_TIMESTEP = 15
|
||||
DEFAULT_FORECAST_TYPE = DAILY
|
||||
DOMAIN = "climacell"
|
||||
ATTRIBUTION = "Powered by ClimaCell"
|
||||
|
||||
MAX_REQUESTS_PER_DAY = 100
|
||||
|
||||
CLEAR_CONDITIONS = {"night": ATTR_CONDITION_CLEAR_NIGHT, "day": ATTR_CONDITION_SUNNY}
|
||||
|
||||
MAX_FORECASTS = {
|
||||
DAILY: 14,
|
||||
HOURLY: 24,
|
||||
NOWCAST: 30,
|
||||
}
|
||||
|
||||
# Additional attributes
|
||||
ATTR_WIND_GUST = "wind_gust"
|
||||
ATTR_CLOUD_COVER = "cloud_cover"
|
||||
ATTR_PRECIPITATION_TYPE = "precipitation_type"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClimaCellSensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes a ClimaCell sensor entity."""
|
||||
|
||||
unit_imperial: str | None = None
|
||||
unit_metric: str | None = None
|
||||
metric_conversion: Callable[[float], float] | float = 1.0
|
||||
is_metric_check: bool | None = None
|
||||
device_class: str | None = None
|
||||
value_map: IntEnum | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""Post initialization."""
|
||||
units = (self.unit_imperial, self.unit_metric)
|
||||
if any(u is not None for u in units) and any(u is None for u in units):
|
||||
raise RuntimeError(
|
||||
"`unit_imperial` and `unit_metric` both need to be None or both need "
|
||||
"to be defined."
|
||||
)
|
||||
|
||||
|
||||
# V3 constants
|
||||
CONDITIONS_V3 = {
|
||||
"breezy": ATTR_CONDITION_WINDY,
|
||||
"freezing_rain_heavy": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"freezing_rain": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"freezing_rain_light": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"freezing_drizzle": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"ice_pellets_heavy": ATTR_CONDITION_HAIL,
|
||||
"ice_pellets": ATTR_CONDITION_HAIL,
|
||||
"ice_pellets_light": ATTR_CONDITION_HAIL,
|
||||
"snow_heavy": ATTR_CONDITION_SNOWY,
|
||||
"snow": ATTR_CONDITION_SNOWY,
|
||||
"snow_light": ATTR_CONDITION_SNOWY,
|
||||
"flurries": ATTR_CONDITION_SNOWY,
|
||||
"tstorm": ATTR_CONDITION_LIGHTNING,
|
||||
"rain_heavy": ATTR_CONDITION_POURING,
|
||||
"rain": ATTR_CONDITION_RAINY,
|
||||
"rain_light": ATTR_CONDITION_RAINY,
|
||||
"drizzle": ATTR_CONDITION_RAINY,
|
||||
"fog_light": ATTR_CONDITION_FOG,
|
||||
"fog": ATTR_CONDITION_FOG,
|
||||
"cloudy": ATTR_CONDITION_CLOUDY,
|
||||
"mostly_cloudy": ATTR_CONDITION_CLOUDY,
|
||||
"partly_cloudy": ATTR_CONDITION_PARTLYCLOUDY,
|
||||
}
|
||||
|
||||
# Weather attributes
|
||||
CC_V3_ATTR_TIMESTAMP = "observation_time"
|
||||
CC_V3_ATTR_TEMPERATURE = "temp"
|
||||
CC_V3_ATTR_TEMPERATURE_HIGH = "max"
|
||||
CC_V3_ATTR_TEMPERATURE_LOW = "min"
|
||||
CC_V3_ATTR_PRESSURE = "baro_pressure"
|
||||
CC_V3_ATTR_HUMIDITY = "humidity"
|
||||
CC_V3_ATTR_WIND_SPEED = "wind_speed"
|
||||
CC_V3_ATTR_WIND_DIRECTION = "wind_direction"
|
||||
CC_V3_ATTR_OZONE = "o3"
|
||||
CC_V3_ATTR_CONDITION = "weather_code"
|
||||
CC_V3_ATTR_VISIBILITY = "visibility"
|
||||
CC_V3_ATTR_PRECIPITATION = "precipitation"
|
||||
CC_V3_ATTR_PRECIPITATION_DAILY = "precipitation_accumulation"
|
||||
CC_V3_ATTR_PRECIPITATION_PROBABILITY = "precipitation_probability"
|
||||
CC_V3_ATTR_WIND_GUST = "wind_gust"
|
||||
CC_V3_ATTR_CLOUD_COVER = "cloud_cover"
|
||||
CC_V3_ATTR_PRECIPITATION_TYPE = "precipitation_type"
|
||||
|
||||
# Sensor attributes
|
||||
CC_V3_ATTR_PARTICULATE_MATTER_25 = "pm25"
|
||||
CC_V3_ATTR_PARTICULATE_MATTER_10 = "pm10"
|
||||
CC_V3_ATTR_NITROGEN_DIOXIDE = "no2"
|
||||
CC_V3_ATTR_CARBON_MONOXIDE = "co"
|
||||
CC_V3_ATTR_SULFUR_DIOXIDE = "so2"
|
||||
CC_V3_ATTR_EPA_AQI = "epa_aqi"
|
||||
CC_V3_ATTR_EPA_PRIMARY_POLLUTANT = "epa_primary_pollutant"
|
||||
CC_V3_ATTR_EPA_HEALTH_CONCERN = "epa_health_concern"
|
||||
CC_V3_ATTR_CHINA_AQI = "china_aqi"
|
||||
CC_V3_ATTR_CHINA_PRIMARY_POLLUTANT = "china_primary_pollutant"
|
||||
CC_V3_ATTR_CHINA_HEALTH_CONCERN = "china_health_concern"
|
||||
CC_V3_ATTR_POLLEN_TREE = "pollen_tree"
|
||||
CC_V3_ATTR_POLLEN_WEED = "pollen_weed"
|
||||
CC_V3_ATTR_POLLEN_GRASS = "pollen_grass"
|
||||
CC_V3_ATTR_FIRE_INDEX = "fire_index"
|
||||
|
||||
CC_V3_SENSOR_TYPES = (
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_OZONE,
|
||||
name="Ozone",
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_PARTICULATE_MATTER_25,
|
||||
name="Particulate Matter < 2.5 μm",
|
||||
unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||
unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
metric_conversion=3.2808399**3,
|
||||
is_metric_check=False,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_PARTICULATE_MATTER_10,
|
||||
name="Particulate Matter < 10 μm",
|
||||
unit_imperial=CONCENTRATION_MICROGRAMS_PER_CUBIC_FOOT,
|
||||
unit_metric=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
metric_conversion=3.2808399**3,
|
||||
is_metric_check=False,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_NITROGEN_DIOXIDE,
|
||||
name="Nitrogen Dioxide",
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_CARBON_MONOXIDE,
|
||||
name="Carbon Monoxide",
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_MILLION,
|
||||
unit_metric=CONCENTRATION_PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_SULFUR_DIOXIDE,
|
||||
name="Sulfur Dioxide",
|
||||
unit_imperial=CONCENTRATION_PARTS_PER_BILLION,
|
||||
unit_metric=CONCENTRATION_PARTS_PER_BILLION,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_EPA_AQI,
|
||||
name="US EPA Air Quality Index",
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_EPA_PRIMARY_POLLUTANT,
|
||||
name="US EPA Primary Pollutant",
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_EPA_HEALTH_CONCERN,
|
||||
name="US EPA Health Concern",
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_CHINA_AQI,
|
||||
name="China MEP Air Quality Index",
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_CHINA_PRIMARY_POLLUTANT,
|
||||
name="China MEP Primary Pollutant",
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_CHINA_HEALTH_CONCERN,
|
||||
name="China MEP Health Concern",
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_POLLEN_TREE,
|
||||
name="Tree Pollen Index",
|
||||
value_map=V3PollenIndex,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_POLLEN_WEED,
|
||||
name="Weed Pollen Index",
|
||||
value_map=V3PollenIndex,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_POLLEN_GRASS,
|
||||
name="Grass Pollen Index",
|
||||
value_map=V3PollenIndex,
|
||||
),
|
||||
ClimaCellSensorEntityDescription(
|
||||
key=CC_V3_ATTR_FIRE_INDEX,
|
||||
name="Fire Index",
|
||||
),
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"domain": "climacell",
|
||||
"name": "ClimaCell",
|
||||
"config_flow": false,
|
||||
"documentation": "https://www.home-assistant.io/integrations/climacell",
|
||||
"requirements": ["pyclimacell==0.18.2"],
|
||||
"after_dependencies": ["tomorrowio"],
|
||||
"codeowners": ["@raman325"],
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["pyclimacell"]
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
"""Sensor component that handles additional ClimaCell data for your location."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pyclimacell.const import CURRENT
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_VERSION, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import ClimaCellDataUpdateCoordinator, ClimaCellEntity
|
||||
from .const import CC_V3_SENSOR_TYPES, DOMAIN, ClimaCellSensorEntityDescription
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
api_version = config_entry.data[CONF_API_VERSION]
|
||||
entities = [
|
||||
ClimaCellV3SensorEntity(
|
||||
hass, config_entry, coordinator, api_version, description
|
||||
)
|
||||
for description in CC_V3_SENSOR_TYPES
|
||||
]
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ClimaCellV3SensorEntity(ClimaCellEntity, SensorEntity):
|
||||
"""Sensor entity that talks to ClimaCell v3 API to retrieve non-weather data."""
|
||||
|
||||
entity_description: ClimaCellSensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
coordinator: ClimaCellDataUpdateCoordinator,
|
||||
api_version: int,
|
||||
description: ClimaCellSensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize ClimaCell Sensor Entity."""
|
||||
super().__init__(config_entry, coordinator, api_version)
|
||||
self.entity_description = description
|
||||
self._attr_entity_registry_enabled_default = False
|
||||
self._attr_name = f"{self._config_entry.data[CONF_NAME]} - {description.name}"
|
||||
self._attr_unique_id = (
|
||||
f"{self._config_entry.unique_id}_{slugify(description.name)}"
|
||||
)
|
||||
self._attr_extra_state_attributes = {ATTR_ATTRIBUTION: self.attribution}
|
||||
self._attr_native_unit_of_measurement = (
|
||||
description.unit_metric
|
||||
if hass.config.units.is_metric
|
||||
else description.unit_imperial
|
||||
)
|
||||
|
||||
@property
|
||||
def native_value(self) -> str | int | float | None:
|
||||
"""Return the state."""
|
||||
state = self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], self.entity_description.key
|
||||
)
|
||||
if (
|
||||
state is not None
|
||||
and not isinstance(state, str)
|
||||
and self.entity_description.unit_imperial is not None
|
||||
and self.entity_description.metric_conversion != 1.0
|
||||
and self.entity_description.is_metric_check is not None
|
||||
and self.hass.config.units.is_metric
|
||||
== self.entity_description.is_metric_check
|
||||
):
|
||||
conversion = self.entity_description.metric_conversion
|
||||
# When conversion is a callable, we assume it's a single input function
|
||||
if callable(conversion):
|
||||
return round(conversion(state), 4)
|
||||
|
||||
return round(state * conversion, 4)
|
||||
|
||||
if self.entity_description.value_map is not None and state is not None:
|
||||
# mypy bug: "Literal[IntEnum.value]" not callable
|
||||
return self.entity_description.value_map(state).name.lower() # type: ignore[misc]
|
||||
|
||||
return state
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Update ClimaCell Options",
|
||||
"description": "If you choose to enable the `nowcast` forecast entity, you can configure the number of minutes between each forecast. The number of forecasts provided depends on the number of minutes chosen between forecasts.",
|
||||
"data": {
|
||||
"timestep": "Min. Between NowCast Forecasts"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__pollen_index": {
|
||||
"none": "None",
|
||||
"very_low": "Very Low",
|
||||
"low": "Low",
|
||||
"medium": "Medium",
|
||||
"high": "High",
|
||||
"very_high": "Very High"
|
||||
},
|
||||
"climacell__health_concern": {
|
||||
"good": "Good",
|
||||
"moderate": "Moderate",
|
||||
"unhealthy_for_sensitive_groups": "Unhealthy for Sensitive Groups",
|
||||
"unhealthy": "Unhealthy",
|
||||
"very_unhealthy": "Very Unhealthy",
|
||||
"hazardous": "Hazardous"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"none": "None",
|
||||
"rain": "Rain",
|
||||
"snow": "Snow",
|
||||
"freezing_rain": "Freezing Rain",
|
||||
"ice_pellets": "Ice Pellets"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Update [%key:component::climacell::title%] opties"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Minuts entre previsions NowCast"
|
||||
},
|
||||
"description": "Si decideixes activar l'entitat de previsi\u00f3 `nowcast`, podr\u00e0s configurar l'interval en minuts entre cada previsi\u00f3. El nombre de previsions proporcionades dep\u00e8n d'aquest interval de minuts.",
|
||||
"title": "Actualitzaci\u00f3 d'opcions de ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Minuten zwischen den NowCast Kurzvorhersagen"
|
||||
},
|
||||
"description": "Wenn du die Vorhersage-Entitit\u00e4t \"Kurzvorhersage\" aktivierst, kannst du die Anzahl der Minuten zwischen den einzelnen Vorhersagen konfigurieren. Die Anzahl der bereitgestellten Vorhersagen h\u00e4ngt von der Anzahl der zwischen den Vorhersagen gew\u00e4hlten Minuten ab.",
|
||||
"title": "ClimaCell-Optionen aktualisieren"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "\u039b\u03b5\u03c0\u03c4\u03ac \u03bc\u03b5\u03c4\u03b1\u03be\u03cd \u03c4\u03c9\u03bd \u03b4\u03b5\u03bb\u03c4\u03af\u03c9\u03bd NowCast"
|
||||
},
|
||||
"description": "\u0395\u03ac\u03bd \u03b5\u03c0\u03b9\u03bb\u03ad\u03be\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1 \u03b4\u03b5\u03bb\u03c4\u03af\u03c9\u03bd 'nowcast', \u03bc\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03bb\u03b5\u03c0\u03c4\u03ce\u03bd \u03bc\u03b5\u03c4\u03b1\u03be\u03cd \u03ba\u03ac\u03b8\u03b5 \u03b4\u03b5\u03bb\u03c4\u03af\u03bf\u03c5. \u039f \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc\u03c2 \u03c4\u03c9\u03bd \u03b4\u03b5\u03bb\u03c4\u03af\u03c9\u03bd \u03c0\u03bf\u03c5 \u03c0\u03b1\u03c1\u03ad\u03c7\u03bf\u03bd\u03c4\u03b1\u03b9 \u03b5\u03be\u03b1\u03c1\u03c4\u03ac\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03bb\u03b5\u03c0\u03c4\u03ce\u03bd \u03c0\u03bf\u03c5 \u03b5\u03c0\u03b9\u03bb\u03ad\u03b3\u03bf\u03bd\u03c4\u03b1\u03b9 \u03bc\u03b5\u03c4\u03b1\u03be\u03cd \u03c4\u03c9\u03bd \u03b4\u03b5\u03bb\u03c4\u03af\u03c9\u03bd.",
|
||||
"title": "\u0395\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ce\u03bd ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. Between NowCast 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.",
|
||||
"title": "Update ClimaCell Options"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. entre pron\u00f3sticos de NowCast"
|
||||
},
|
||||
"description": "Si elige habilitar la entidad de pron\u00f3stico \"nowcast\", puede configurar el n\u00famero de minutos entre cada pron\u00f3stico. El n\u00famero de pron\u00f3sticos proporcionados depende del n\u00famero de minutos elegidos entre los pron\u00f3sticos.",
|
||||
"title": "Actualizar opciones de ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. entre pron\u00f3sticos de NowCast"
|
||||
},
|
||||
"description": "Si eliges habilitar la entidad de pron\u00f3stico `nowcast`, puedes configurar la cantidad de minutos entre cada pron\u00f3stico. La cantidad de pron\u00f3sticos proporcionados depende de la cantidad de minutos elegidos entre los pron\u00f3sticos.",
|
||||
"title": "Actualizar opciones de ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Minuteid NowCasti prognooside vahel"
|
||||
},
|
||||
"description": "Kui otsustad lubada \"nowcast\" prognoosi\u00fcksuse, saad seadistada minutite arvu iga prognoosi vahel. Esitatavate prognooside arv s\u00f5ltub prognooside vahel valitud minutite arvust.",
|
||||
"title": "V\u00e4rskenda [%key:component::climacell::title%] suvandeid"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. entre les pr\u00e9visions NowCast"
|
||||
},
|
||||
"description": "Si vous choisissez d'activer l'entit\u00e9 de pr\u00e9vision \u00ab\u00a0nowcast\u00a0\u00bb, vous pouvez configurer le nombre de minutes entre chaque pr\u00e9vision. Le nombre de pr\u00e9visions fournies d\u00e9pend du nombre de minutes choisies entre les pr\u00e9visions.",
|
||||
"title": "Mettre \u00e0 jour les options ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. A NowCast el\u0151rejelz\u00e9sek k\u00f6z\u00f6tt"
|
||||
},
|
||||
"description": "Ha a `nowcast` el\u0151rejelz\u00e9si entit\u00e1s enged\u00e9lyez\u00e9s\u00e9t v\u00e1lasztja, be\u00e1ll\u00edthatja az egyes el\u0151rejelz\u00e9sek k\u00f6z\u00f6tti percek sz\u00e1m\u00e1t. A megadott el\u0151rejelz\u00e9sek sz\u00e1ma az el\u0151rejelz\u00e9sek k\u00f6z\u00f6tt kiv\u00e1lasztott percek sz\u00e1m\u00e1t\u00f3l f\u00fcgg.",
|
||||
"title": "ClimaCell be\u00e1ll\u00edt\u00e1sok friss\u00edt\u00e9se"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Jarak Interval Prakiraan NowCast dalam Menit"
|
||||
},
|
||||
"description": "Jika Anda memilih untuk mengaktifkan entitas prakiraan `nowcast`, Anda dapat mengonfigurasi jarak interval prakiraan dalam menit. Jumlah prakiraan yang diberikan tergantung pada nilai interval yang dipilih.",
|
||||
"title": "Perbarui Opsi ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Minuti tra le previsioni di NowCast"
|
||||
},
|
||||
"description": "Se scegli di abilitare l'entit\u00e0 di previsione `nowcast`, puoi configurare il numero di minuti tra ogni previsione. Il numero di previsioni fornite dipende dal numero di minuti scelti tra le previsioni.",
|
||||
"title": "Aggiorna le opzioni di ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "\u6700\u5c0f\u3002 NowCast \u4e88\u6e2c\u306e\u9593"
|
||||
},
|
||||
"description": "`nowcast` forecast(\u4e88\u6e2c) \u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u3092\u6709\u52b9\u306b\u3059\u308b\u3053\u3068\u3092\u9078\u629e\u3057\u305f\u5834\u5408\u3001\u5404\u4e88\u6e2c\u9593\u306e\u5206\u6570\u3092\u8a2d\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u63d0\u4f9b\u3055\u308c\u308bforecast(\u4e88\u6e2c)\u306e\u6570\u306f\u3001forecast(\u4e88\u6e2c)\u306e\u9593\u306b\u9078\u629e\u3057\u305f\u5206\u6570\u306b\u4f9d\u5b58\u3057\u307e\u3059\u3002",
|
||||
"title": "ClimaCell \u30aa\u30d7\u30b7\u30e7\u30f3\u306e\u66f4\u65b0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "\ub2e8\uae30\uc608\uce21 \uc77c\uae30\uc608\ubcf4 \uac04 \ucd5c\uc18c \uc2dc\uac04"
|
||||
},
|
||||
"description": "`nowcast` \uc77c\uae30\uc608\ubcf4 \uad6c\uc131\uc694\uc18c\ub97c \uc0ac\uc6a9\ud558\ub3c4\ub85d \uc120\ud0dd\ud55c \uacbd\uc6b0 \uac01 \uc77c\uae30\uc608\ubcf4 \uc0ac\uc774\uc758 \uc2dc\uac04(\ubd84)\uc744 \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc81c\uacf5\ub41c \uc77c\uae30\uc608\ubcf4 \ud69f\uc218\ub294 \uc608\uce21 \uac04 \uc120\ud0dd\ud55c \uc2dc\uac04(\ubd84)\uc5d0 \ub530\ub77c \ub2ec\ub77c\uc9d1\ub2c8\ub2e4.",
|
||||
"title": "[%key:component::climacell::title%] \uc635\uc158 \uc5c5\ub370\uc774\ud2b8\ud558\uae30"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. Tussen NowCast-voorspellingen"
|
||||
},
|
||||
"description": "Als u ervoor kiest om de `nowcast` voorspellingsentiteit in te schakelen, kan u het aantal minuten tussen elke voorspelling configureren. Het aantal voorspellingen hangt af van het aantal gekozen minuten tussen de voorspellingen.",
|
||||
"title": "Update ClimaCell Opties"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. mellom NowCast prognoser"
|
||||
},
|
||||
"description": "Hvis du velger \u00e5 aktivere \u00abnowcast\u00bb -varselentiteten, kan du konfigurere antall minutter mellom hver prognose. Antall angitte prognoser avhenger av antall minutter som er valgt mellom prognosene.",
|
||||
"title": "Oppdater ClimaCell-alternativer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Czas (min) mi\u0119dzy prognozami NowCast"
|
||||
},
|
||||
"description": "Je\u015bli zdecydujesz si\u0119 w\u0142\u0105czy\u0107 encj\u0119 prognozy \u201enowcast\u201d, mo\u017cesz skonfigurowa\u0107 liczb\u0119 minut mi\u0119dzy ka\u017cd\u0105 prognoz\u0105. Liczba dostarczonych prognoz zale\u017cy od liczby minut wybranych mi\u0119dzy prognozami.",
|
||||
"title": "Opcje aktualizacji ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "M\u00ednimo entre previs\u00f5es NowCast"
|
||||
},
|
||||
"description": "Se voc\u00ea optar por ativar a entidade de previs\u00e3o `nowcast`, poder\u00e1 configurar o n\u00famero de minutos entre cada previs\u00e3o. O n\u00famero de previs\u00f5es fornecidas depende do n\u00famero de minutos escolhidos entre as previs\u00f5es.",
|
||||
"title": "Atualizar as op\u00e7\u00f5es do ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f (\u0432 \u043c\u0438\u043d\u0443\u0442\u0430\u0445)"
|
||||
},
|
||||
"description": "\u0415\u0441\u043b\u0438 \u0412\u044b \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 'nowcast', \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430.",
|
||||
"title": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 ClimaCell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__precipitation_type": {
|
||||
"rain": "\u0414\u044a\u0436\u0434",
|
||||
"snow": "\u0421\u043d\u044f\u0433"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bo",
|
||||
"hazardous": "Perill\u00f3s",
|
||||
"moderate": "Moderat",
|
||||
"unhealthy": "Poc saludable",
|
||||
"unhealthy_for_sensitive_groups": "No saludable per a grups sensibles",
|
||||
"very_unhealthy": "Gens saludable"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Alt",
|
||||
"low": "Baix",
|
||||
"medium": "Mitj\u00e0",
|
||||
"none": "Cap",
|
||||
"very_high": "Molt alt",
|
||||
"very_low": "Molt baix"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Pluja congelada",
|
||||
"ice_pellets": "Gran\u00eds",
|
||||
"none": "Cap",
|
||||
"rain": "Pluja",
|
||||
"snow": "Neu"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Gut",
|
||||
"hazardous": "Gef\u00e4hrlich",
|
||||
"moderate": "M\u00e4\u00dfig",
|
||||
"unhealthy": "Ungesund",
|
||||
"unhealthy_for_sensitive_groups": "Ungesund f\u00fcr sensible Gruppen",
|
||||
"very_unhealthy": "Sehr ungesund"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Hoch",
|
||||
"low": "Niedrig",
|
||||
"medium": "Mittel",
|
||||
"none": "Keine",
|
||||
"very_high": "Sehr hoch",
|
||||
"very_low": "Sehr niedrig"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Gefrierender Regen",
|
||||
"ice_pellets": "Graupel",
|
||||
"none": "Keine",
|
||||
"rain": "Regen",
|
||||
"snow": "Schnee"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "\u039a\u03b1\u03bb\u03cc",
|
||||
"hazardous": "\u0395\u03c0\u03b9\u03ba\u03af\u03bd\u03b4\u03c5\u03bd\u03bf",
|
||||
"moderate": "\u039c\u03ad\u03c4\u03c1\u03b9\u03bf",
|
||||
"unhealthy": "\u0391\u03bd\u03b8\u03c5\u03b3\u03b9\u03b5\u03b9\u03bd\u03cc",
|
||||
"unhealthy_for_sensitive_groups": "\u0391\u03bd\u03b8\u03c5\u03b3\u03b9\u03b5\u03b9\u03bd\u03cc \u03b3\u03b9\u03b1 \u03b5\u03c5\u03b1\u03af\u03c3\u03b8\u03b7\u03c4\u03b5\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b5\u03c2",
|
||||
"very_unhealthy": "\u03a0\u03bf\u03bb\u03cd \u0391\u03bd\u03b8\u03c5\u03b3\u03b9\u03b5\u03b9\u03bd\u03cc"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "\u03a5\u03c8\u03b7\u03bb\u03cc",
|
||||
"low": "\u03a7\u03b1\u03bc\u03b7\u03bb\u03cc",
|
||||
"medium": "\u039c\u03b5\u03c3\u03b1\u03af\u03bf",
|
||||
"none": "\u03a4\u03af\u03c0\u03bf\u03c4\u03b1",
|
||||
"very_high": "\u03a0\u03bf\u03bb\u03cd \u03c5\u03c8\u03b7\u03bb\u03cc",
|
||||
"very_low": "\u03a0\u03bf\u03bb\u03cd \u03c7\u03b1\u03bc\u03b7\u03bb\u03cc"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "\u03a0\u03b1\u03b3\u03c9\u03bc\u03ad\u03bd\u03b7 \u03b2\u03c1\u03bf\u03c7\u03ae",
|
||||
"ice_pellets": "\u03a0\u03ad\u03bb\u03bb\u03b5\u03c4 \u03c0\u03ac\u03b3\u03bf\u03c5",
|
||||
"none": "\u03a4\u03af\u03c0\u03bf\u03c4\u03b1",
|
||||
"rain": "\u0392\u03c1\u03bf\u03c7\u03ae",
|
||||
"snow": "\u03a7\u03b9\u03cc\u03bd\u03b9"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Good",
|
||||
"hazardous": "Hazardous",
|
||||
"moderate": "Moderate",
|
||||
"unhealthy": "Unhealthy",
|
||||
"unhealthy_for_sensitive_groups": "Unhealthy for Sensitive Groups",
|
||||
"very_unhealthy": "Very Unhealthy"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "High",
|
||||
"low": "Low",
|
||||
"medium": "Medium",
|
||||
"none": "None",
|
||||
"very_high": "Very High",
|
||||
"very_low": "Very Low"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Freezing Rain",
|
||||
"ice_pellets": "Ice Pellets",
|
||||
"none": "None",
|
||||
"rain": "Rain",
|
||||
"snow": "Snow"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bueno",
|
||||
"hazardous": "Peligroso",
|
||||
"moderate": "Moderado",
|
||||
"unhealthy": "Insalubre",
|
||||
"unhealthy_for_sensitive_groups": "Insalubre para grupos sensibles",
|
||||
"very_unhealthy": "Muy poco saludable"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Alto",
|
||||
"low": "Bajo",
|
||||
"medium": "Medio",
|
||||
"none": "Ninguno",
|
||||
"very_high": "Muy alto",
|
||||
"very_low": "Muy bajo"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Lluvia helada",
|
||||
"ice_pellets": "Gr\u00e1nulos de hielo",
|
||||
"none": "Ninguno",
|
||||
"rain": "Lluvia",
|
||||
"snow": "Nieve"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bueno",
|
||||
"hazardous": "Peligroso",
|
||||
"moderate": "Moderado",
|
||||
"unhealthy": "No saludable",
|
||||
"unhealthy_for_sensitive_groups": "No es saludable para grupos sensibles",
|
||||
"very_unhealthy": "Muy poco saludable"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Alto",
|
||||
"low": "Bajo",
|
||||
"medium": "Medio",
|
||||
"none": "Ninguno",
|
||||
"very_high": "Muy alto",
|
||||
"very_low": "Muy bajo"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Lluvia helada",
|
||||
"ice_pellets": "Granizo",
|
||||
"none": "Ninguna",
|
||||
"rain": "Lluvia",
|
||||
"snow": "Nieve"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Normaalne",
|
||||
"hazardous": "Ohtlik",
|
||||
"moderate": "M\u00f5\u00f5dukas",
|
||||
"unhealthy": "Ebatervislik",
|
||||
"unhealthy_for_sensitive_groups": "Ebatervislik riskir\u00fchmale",
|
||||
"very_unhealthy": "V\u00e4ga ebatervislik"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "K\u00f5rge",
|
||||
"low": "Madal",
|
||||
"medium": "Keskmine",
|
||||
"none": "Puudub",
|
||||
"very_high": "V\u00e4ga k\u00f5rge",
|
||||
"very_low": "V\u00e4ga madal"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "J\u00e4\u00e4vihm",
|
||||
"ice_pellets": "J\u00e4\u00e4kruubid",
|
||||
"none": "Sademeid pole",
|
||||
"rain": "Vihm",
|
||||
"snow": "Lumi"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bon",
|
||||
"hazardous": "Dangereux",
|
||||
"moderate": "Mod\u00e9r\u00e9",
|
||||
"unhealthy": "Mauvais pour la sant\u00e9",
|
||||
"unhealthy_for_sensitive_groups": "Mauvaise qualit\u00e9 pour les groupes sensibles",
|
||||
"very_unhealthy": "Tr\u00e8s mauvais pour la sant\u00e9"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Haut",
|
||||
"low": "Faible",
|
||||
"medium": "Moyen",
|
||||
"none": "Aucun",
|
||||
"very_high": "Tr\u00e8s \u00e9lev\u00e9",
|
||||
"very_low": "Tr\u00e8s faible"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Pluie vergla\u00e7ante",
|
||||
"ice_pellets": "Gr\u00e9sil",
|
||||
"none": "Aucun",
|
||||
"rain": "Pluie",
|
||||
"snow": "Neige"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"unhealthy_for_sensitive_groups": "\u05dc\u05d0 \u05d1\u05e8\u05d9\u05d0 \u05dc\u05e7\u05d1\u05d5\u05e6\u05d5\u05ea \u05e8\u05d2\u05d9\u05e9\u05d5\u05ea"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "J\u00f3",
|
||||
"hazardous": "Vesz\u00e9lyes",
|
||||
"moderate": "M\u00e9rs\u00e9kelt",
|
||||
"unhealthy": "Eg\u00e9szs\u00e9gtelen",
|
||||
"unhealthy_for_sensitive_groups": "Eg\u00e9szs\u00e9gtelen \u00e9rz\u00e9keny csoportok sz\u00e1m\u00e1ra",
|
||||
"very_unhealthy": "Nagyon eg\u00e9szs\u00e9gtelen"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Magas",
|
||||
"low": "Alacsony",
|
||||
"medium": "K\u00f6zepes",
|
||||
"none": "Nincs",
|
||||
"very_high": "Nagyon magas",
|
||||
"very_low": "Nagyon alacsony"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Havas es\u0151",
|
||||
"ice_pellets": "\u00d3nos es\u0151",
|
||||
"none": "Nincs",
|
||||
"rain": "Es\u0151",
|
||||
"snow": "Havaz\u00e1s"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bagus",
|
||||
"hazardous": "Berbahaya",
|
||||
"moderate": "Sedang",
|
||||
"unhealthy": "Tidak Sehat",
|
||||
"unhealthy_for_sensitive_groups": "Tidak Sehat untuk Kelompok Sensitif",
|
||||
"very_unhealthy": "Sangat Tidak Sehat"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Tinggi",
|
||||
"low": "Rendah",
|
||||
"medium": "Sedang",
|
||||
"none": "Tidak Ada",
|
||||
"very_high": "Sangat Tinggi",
|
||||
"very_low": "Sangat Rendah"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Hujan Beku",
|
||||
"ice_pellets": "Hujan Es",
|
||||
"none": "Tidak Ada",
|
||||
"rain": "Hujan",
|
||||
"snow": "Salju"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"hazardous": "H\u00e6ttulegt",
|
||||
"unhealthy": "\u00d3hollt"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"rain": "Rigning",
|
||||
"snow": "Snj\u00f3r"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Buono",
|
||||
"hazardous": "Pericoloso",
|
||||
"moderate": "Moderato",
|
||||
"unhealthy": "Malsano",
|
||||
"unhealthy_for_sensitive_groups": "Malsano per gruppi sensibili",
|
||||
"very_unhealthy": "Molto malsano"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Alto",
|
||||
"low": "Basso",
|
||||
"medium": "Medio",
|
||||
"none": "Nessuno",
|
||||
"very_high": "Molto alto",
|
||||
"very_low": "Molto basso"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Grandine",
|
||||
"ice_pellets": "Pioggia gelata",
|
||||
"none": "Nessuno",
|
||||
"rain": "Pioggia",
|
||||
"snow": "Neve"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "\u826f\u597d",
|
||||
"hazardous": "\u5371\u967a",
|
||||
"moderate": "\u7a4f\u3084\u304b\u306a",
|
||||
"unhealthy": "\u4e0d\u5065\u5eb7",
|
||||
"unhealthy_for_sensitive_groups": "\u654f\u611f\u306a\u30b0\u30eb\u30fc\u30d7\u306b\u3068\u3063\u3066\u306f\u4e0d\u5065\u5eb7",
|
||||
"very_unhealthy": "\u975e\u5e38\u306b\u4e0d\u5065\u5eb7"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "\u9ad8\u3044",
|
||||
"low": "\u4f4e\u3044",
|
||||
"medium": "\u4e2d",
|
||||
"none": "\u306a\u3057",
|
||||
"very_high": "\u975e\u5e38\u306b\u9ad8\u3044",
|
||||
"very_low": "\u3068\u3066\u3082\u4f4e\u3044"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "\u51cd\u3066\u3064\u304f\u96e8",
|
||||
"ice_pellets": "\u51cd\u96e8",
|
||||
"none": "\u306a\u3057",
|
||||
"rain": "\u96e8",
|
||||
"snow": "\u96ea"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__precipitation_type": {
|
||||
"snow": "\ub208"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Labs",
|
||||
"hazardous": "B\u012bstams",
|
||||
"moderate": "M\u0113rens",
|
||||
"unhealthy": "Nevesel\u012bgs",
|
||||
"unhealthy_for_sensitive_groups": "Nevesel\u012bgs jut\u012bg\u0101m grup\u0101m",
|
||||
"very_unhealthy": "\u013boti nevesel\u012bgs"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Augsts",
|
||||
"low": "Zems",
|
||||
"medium": "Vid\u0113js",
|
||||
"none": "Nav",
|
||||
"very_high": "\u013boti augsts",
|
||||
"very_low": "\u013boti zems"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Sasalsto\u0161s lietus",
|
||||
"ice_pellets": "Krusa",
|
||||
"none": "Nav",
|
||||
"rain": "Lietus",
|
||||
"snow": "Sniegs"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Goed",
|
||||
"hazardous": "Gevaarlijk",
|
||||
"moderate": "Gematigd",
|
||||
"unhealthy": "Ongezond",
|
||||
"unhealthy_for_sensitive_groups": "Ongezond voor gevoelige groepen",
|
||||
"very_unhealthy": "Zeer ongezond"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Hoog",
|
||||
"low": "Laag",
|
||||
"medium": "Medium",
|
||||
"none": "Geen",
|
||||
"very_high": "Zeer Hoog",
|
||||
"very_low": "Zeer Laag"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "IJzel",
|
||||
"ice_pellets": "IJskorrels",
|
||||
"none": "Geen",
|
||||
"rain": "Regen",
|
||||
"snow": "Sneeuw"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bra",
|
||||
"hazardous": "Farlig",
|
||||
"moderate": "Moderat",
|
||||
"unhealthy": "Usunt",
|
||||
"unhealthy_for_sensitive_groups": "Usunt for sensitive grupper",
|
||||
"very_unhealthy": "Veldig usunt"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "H\u00f8y",
|
||||
"low": "Lav",
|
||||
"medium": "Medium",
|
||||
"none": "Ingen",
|
||||
"very_high": "Veldig h\u00f8y",
|
||||
"very_low": "Veldig lav"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Underkj\u00f8lt regn",
|
||||
"ice_pellets": "Is tapper",
|
||||
"none": "Ingen",
|
||||
"rain": "Regn",
|
||||
"snow": "Sn\u00f8"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "dobre",
|
||||
"hazardous": "niebezpieczne",
|
||||
"moderate": "umiarkowane",
|
||||
"unhealthy": "niezdrowe",
|
||||
"unhealthy_for_sensitive_groups": "niezdrowe dla grup wra\u017cliwych",
|
||||
"very_unhealthy": "bardzo niezdrowe"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "wysokie",
|
||||
"low": "niskie",
|
||||
"medium": "\u015brednie",
|
||||
"none": "brak",
|
||||
"very_high": "bardzo wysokie",
|
||||
"very_low": "bardzo niskie"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "marzn\u0105cy deszcz",
|
||||
"ice_pellets": "granulki lodu",
|
||||
"none": "brak",
|
||||
"rain": "deszcz",
|
||||
"snow": "\u015bnieg"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bom",
|
||||
"hazardous": "Perigosos",
|
||||
"moderate": "Moderado",
|
||||
"unhealthy": "Pouco saud\u00e1vel",
|
||||
"unhealthy_for_sensitive_groups": "Insalubre para grupos sens\u00edveis",
|
||||
"very_unhealthy": "Muito prejudicial \u00e0 sa\u00fade"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Alto",
|
||||
"low": "Baixo",
|
||||
"medium": "M\u00e9dio",
|
||||
"none": "Nenhum",
|
||||
"very_high": "Muito alto",
|
||||
"very_low": "Muito baixo"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Chuva congelante",
|
||||
"ice_pellets": "Granizo",
|
||||
"none": "Nenhum",
|
||||
"rain": "Chuva",
|
||||
"snow": "Neve"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"unhealthy_for_sensitive_groups": "Pouco saud\u00e1vel para grupos sens\u00edveis"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "\u0425\u043e\u0440\u043e\u0448\u043e",
|
||||
"hazardous": "\u041e\u043f\u0430\u0441\u043d\u043e",
|
||||
"moderate": "\u0421\u0440\u0435\u0434\u043d\u0435",
|
||||
"unhealthy": "\u0412\u0440\u0435\u0434\u043d\u043e",
|
||||
"unhealthy_for_sensitive_groups": "\u0412\u0440\u0435\u0434\u043d\u043e \u0434\u043b\u044f \u0443\u044f\u0437\u0432\u0438\u043c\u044b\u0445 \u0433\u0440\u0443\u043f\u043f",
|
||||
"very_unhealthy": "\u041e\u0447\u0435\u043d\u044c \u0432\u0440\u0435\u0434\u043d\u043e"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "\u0412\u044b\u0441\u043e\u043a\u0438\u0439",
|
||||
"low": "\u041d\u0438\u0437\u043a\u0438\u0439",
|
||||
"medium": "\u0421\u0440\u0435\u0434\u043d\u0438\u0439",
|
||||
"none": "\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442",
|
||||
"very_high": "\u041e\u0447\u0435\u043d\u044c \u0432\u044b\u0441\u043e\u043a\u0438\u0439",
|
||||
"very_low": "\u041e\u0447\u0435\u043d\u044c \u043d\u0438\u0437\u043a\u0438\u0439"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "\u041b\u0435\u0434\u044f\u043d\u043e\u0439 \u0434\u043e\u0436\u0434\u044c",
|
||||
"ice_pellets": "\u041b\u0435\u0434\u044f\u043d\u0430\u044f \u043a\u0440\u0443\u043f\u0430",
|
||||
"none": "\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442",
|
||||
"rain": "\u0414\u043e\u0436\u0434\u044c",
|
||||
"snow": "\u0421\u043d\u0435\u0433"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"unhealthy": "Nezdrav\u00e9"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "Bra",
|
||||
"hazardous": "Farligt",
|
||||
"moderate": "M\u00e5ttligt",
|
||||
"unhealthy": "Oh\u00e4lsosamt",
|
||||
"unhealthy_for_sensitive_groups": "Oh\u00e4lsosamt f\u00f6r k\u00e4nsliga grupper",
|
||||
"very_unhealthy": "Mycket oh\u00e4lsosamt"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "H\u00f6gt",
|
||||
"low": "L\u00e5gt",
|
||||
"medium": "Medium",
|
||||
"none": "Inget",
|
||||
"very_high": "V\u00e4ldigt h\u00f6gt",
|
||||
"very_low": "V\u00e4ldigt l\u00e5gt"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Underkylt regn",
|
||||
"ice_pellets": "Hagel",
|
||||
"none": "Ingen",
|
||||
"rain": "Regn",
|
||||
"snow": "Sn\u00f6"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "\u0130yi",
|
||||
"hazardous": "Tehlikeli",
|
||||
"moderate": "Il\u0131ml\u0131",
|
||||
"unhealthy": "Sa\u011fl\u0131ks\u0131z",
|
||||
"unhealthy_for_sensitive_groups": "Hassas Gruplar \u0130\u00e7in Sa\u011fl\u0131ks\u0131z",
|
||||
"very_unhealthy": "\u00c7ok Sa\u011fl\u0131ks\u0131z"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "Y\u00fcksek",
|
||||
"low": "D\u00fc\u015f\u00fck",
|
||||
"medium": "Orta",
|
||||
"none": "Hi\u00e7biri",
|
||||
"very_high": "\u00c7ok Y\u00fcksek",
|
||||
"very_low": "\u00c7ok D\u00fc\u015f\u00fck"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "Dondurucu Ya\u011fmur",
|
||||
"ice_pellets": "Buz Peletleri",
|
||||
"none": "Hi\u00e7biri",
|
||||
"rain": "Ya\u011fmur",
|
||||
"snow": "Kar"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"state": {
|
||||
"climacell__health_concern": {
|
||||
"good": "\u826f\u597d",
|
||||
"hazardous": "\u5371\u96aa",
|
||||
"moderate": "\u4e2d\u7b49",
|
||||
"unhealthy": "\u4e0d\u5065\u5eb7",
|
||||
"unhealthy_for_sensitive_groups": "\u5c0d\u654f\u611f\u65cf\u7fa4\u4e0d\u5065\u5eb7",
|
||||
"very_unhealthy": "\u975e\u5e38\u4e0d\u5065\u5eb7"
|
||||
},
|
||||
"climacell__pollen_index": {
|
||||
"high": "\u9ad8",
|
||||
"low": "\u4f4e",
|
||||
"medium": "\u4e2d",
|
||||
"none": "\u7121",
|
||||
"very_high": "\u6975\u9ad8",
|
||||
"very_low": "\u6975\u4f4e"
|
||||
},
|
||||
"climacell__precipitation_type": {
|
||||
"freezing_rain": "\u51cd\u96e8",
|
||||
"ice_pellets": "\u51b0\u73e0",
|
||||
"none": "\u7121",
|
||||
"rain": "\u4e0b\u96e8",
|
||||
"snow": "\u4e0b\u96ea"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. Mellan NowCast-prognoser"
|
||||
},
|
||||
"description": "Om du v\u00e4ljer att aktivera \"nowcast\"-prognosentiteten kan du konfigurera antalet minuter mellan varje prognos. Antalet prognoser som tillhandah\u00e5lls beror p\u00e5 antalet minuter som v\u00e4ljs mellan prognoserna.",
|
||||
"title": "Uppdatera ClimaCell-alternativ"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "Min. NowCast Tahminleri Aras\u0131nda"
|
||||
},
|
||||
"description": "'Nowcast' tahmin varl\u0131\u011f\u0131n\u0131 etkinle\u015ftirmeyi se\u00e7erseniz, her tahmin aras\u0131ndaki dakika say\u0131s\u0131n\u0131 yap\u0131land\u0131rabilirsiniz. Sa\u011flanan tahmin say\u0131s\u0131, tahminler aras\u0131nda se\u00e7ilen dakika say\u0131s\u0131na ba\u011fl\u0131d\u0131r.",
|
||||
"title": "ClimaCell Se\u00e7eneklerini G\u00fcncelleyin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"timestep": "NowCast \u9810\u5831\u9593\u9694\u5206\u9418"
|
||||
},
|
||||
"description": "\u5047\u5982\u9078\u64c7\u958b\u555f `nowcast` \u9810\u5831\u5be6\u9ad4\u3001\u5c07\u53ef\u4ee5\u8a2d\u5b9a\u9810\u5831\u983b\u7387\u9593\u9694\u5206\u9418\u6578\u3002\u6839\u64da\u6240\u8f38\u5165\u7684\u9593\u9694\u6642\u9593\u5c07\u6c7a\u5b9a\u9810\u5831\u7684\u6578\u76ee\u3002",
|
||||
"title": "\u66f4\u65b0 ClimaCell \u9078\u9805"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,361 +0,0 @@
|
||||
"""Weather component that handles meteorological data for your location."""
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import abstractmethod
|
||||
from collections.abc import Mapping
|
||||
from datetime import datetime
|
||||
from typing import Any, cast
|
||||
|
||||
from pyclimacell.const import CURRENT, DAILY, FORECASTS, HOURLY, NOWCAST
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_FORECAST_CONDITION,
|
||||
ATTR_FORECAST_NATIVE_PRECIPITATION,
|
||||
ATTR_FORECAST_NATIVE_TEMP,
|
||||
ATTR_FORECAST_NATIVE_TEMP_LOW,
|
||||
ATTR_FORECAST_NATIVE_WIND_SPEED,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_FORECAST_TIME,
|
||||
ATTR_FORECAST_WIND_BEARING,
|
||||
WeatherEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_VERSION,
|
||||
CONF_NAME,
|
||||
LENGTH_INCHES,
|
||||
LENGTH_MILES,
|
||||
PRESSURE_INHG,
|
||||
SPEED_MILES_PER_HOUR,
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.sun import is_up
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.util.speed import convert as speed_convert
|
||||
|
||||
from . import ClimaCellDataUpdateCoordinator, ClimaCellEntity
|
||||
from .const import (
|
||||
ATTR_CLOUD_COVER,
|
||||
ATTR_PRECIPITATION_TYPE,
|
||||
ATTR_WIND_GUST,
|
||||
CC_V3_ATTR_CLOUD_COVER,
|
||||
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_PRECIPITATION_TYPE,
|
||||
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_GUST,
|
||||
CC_V3_ATTR_WIND_SPEED,
|
||||
CLEAR_CONDITIONS,
|
||||
CONDITIONS_V3,
|
||||
CONF_TIMESTEP,
|
||||
DEFAULT_FORECAST_TYPE,
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
api_version = config_entry.data[CONF_API_VERSION]
|
||||
entities = [
|
||||
ClimaCellV3WeatherEntity(config_entry, coordinator, api_version, forecast_type)
|
||||
for forecast_type in (DAILY, HOURLY, NOWCAST)
|
||||
]
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class BaseClimaCellWeatherEntity(ClimaCellEntity, WeatherEntity):
|
||||
"""Base ClimaCell weather entity."""
|
||||
|
||||
_attr_native_precipitation_unit = LENGTH_INCHES
|
||||
_attr_native_pressure_unit = PRESSURE_INHG
|
||||
_attr_native_temperature_unit = TEMP_FAHRENHEIT
|
||||
_attr_native_visibility_unit = LENGTH_MILES
|
||||
_attr_native_wind_speed_unit = SPEED_MILES_PER_HOUR
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config_entry: ConfigEntry,
|
||||
coordinator: ClimaCellDataUpdateCoordinator,
|
||||
api_version: int,
|
||||
forecast_type: str,
|
||||
) -> None:
|
||||
"""Initialize ClimaCell Weather Entity."""
|
||||
super().__init__(config_entry, coordinator, api_version)
|
||||
self.forecast_type = forecast_type
|
||||
self._attr_entity_registry_enabled_default = (
|
||||
forecast_type == DEFAULT_FORECAST_TYPE
|
||||
)
|
||||
self._attr_name = f"{config_entry.data[CONF_NAME]} - {forecast_type.title()}"
|
||||
self._attr_unique_id = f"{config_entry.unique_id}_{forecast_type}"
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def _translate_condition(
|
||||
condition: str | int | None, sun_is_up: bool = True
|
||||
) -> str | None:
|
||||
"""Translate ClimaCell condition into an HA condition."""
|
||||
|
||||
def _forecast_dict(
|
||||
self,
|
||||
forecast_dt: datetime,
|
||||
use_datetime: bool,
|
||||
condition: int | str,
|
||||
precipitation: float | None,
|
||||
precipitation_probability: float | None,
|
||||
temp: float | None,
|
||||
temp_low: float | None,
|
||||
wind_direction: float | None,
|
||||
wind_speed: float | None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return formatted Forecast dict from ClimaCell forecast data."""
|
||||
if use_datetime:
|
||||
translated_condition = self._translate_condition(
|
||||
condition, is_up(self.hass, forecast_dt)
|
||||
)
|
||||
else:
|
||||
translated_condition = self._translate_condition(condition, True)
|
||||
|
||||
data = {
|
||||
ATTR_FORECAST_TIME: forecast_dt.isoformat(),
|
||||
ATTR_FORECAST_CONDITION: translated_condition,
|
||||
ATTR_FORECAST_NATIVE_PRECIPITATION: precipitation,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: precipitation_probability,
|
||||
ATTR_FORECAST_NATIVE_TEMP: temp,
|
||||
ATTR_FORECAST_NATIVE_TEMP_LOW: temp_low,
|
||||
ATTR_FORECAST_WIND_BEARING: wind_direction,
|
||||
ATTR_FORECAST_NATIVE_WIND_SPEED: wind_speed,
|
||||
}
|
||||
|
||||
return {k: v for k, v in data.items() if v is not None}
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||
"""Return additional state attributes."""
|
||||
cloud_cover = self.cloud_cover
|
||||
attrs = {
|
||||
ATTR_CLOUD_COVER: cloud_cover,
|
||||
ATTR_PRECIPITATION_TYPE: self.precipitation_type,
|
||||
}
|
||||
if (wind_gust := self.wind_gust) is not None:
|
||||
attrs[ATTR_WIND_GUST] = round(
|
||||
speed_convert(wind_gust, SPEED_MILES_PER_HOUR, self._wind_speed_unit), 4
|
||||
)
|
||||
return attrs
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def cloud_cover(self):
|
||||
"""Return cloud cover."""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def wind_gust(self):
|
||||
"""Return wind gust speed."""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def precipitation_type(self):
|
||||
"""Return precipitation type."""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def _pressure(self):
|
||||
"""Return the raw pressure."""
|
||||
|
||||
@property
|
||||
def native_pressure(self):
|
||||
"""Return the pressure."""
|
||||
return self._pressure
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def _wind_speed(self):
|
||||
"""Return the raw wind speed."""
|
||||
|
||||
@property
|
||||
def native_wind_speed(self):
|
||||
"""Return the wind speed."""
|
||||
return self._wind_speed
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def _visibility(self):
|
||||
"""Return the raw visibility."""
|
||||
|
||||
@property
|
||||
def native_visibility(self):
|
||||
"""Return the visibility."""
|
||||
return self._visibility
|
||||
|
||||
|
||||
class ClimaCellV3WeatherEntity(BaseClimaCellWeatherEntity):
|
||||
"""Entity that talks to ClimaCell v3 API to retrieve weather data."""
|
||||
|
||||
@staticmethod
|
||||
def _translate_condition(
|
||||
condition: int | str | None, sun_is_up: bool = True
|
||||
) -> str | None:
|
||||
"""Translate ClimaCell condition into an HA condition."""
|
||||
if not condition:
|
||||
return None
|
||||
condition = cast(str, condition)
|
||||
if "clear" in condition.lower():
|
||||
if sun_is_up:
|
||||
return CLEAR_CONDITIONS["day"]
|
||||
return CLEAR_CONDITIONS["night"]
|
||||
return CONDITIONS_V3[condition]
|
||||
|
||||
@property
|
||||
def native_temperature(self):
|
||||
"""Return the platform temperature."""
|
||||
return self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_TEMPERATURE
|
||||
)
|
||||
|
||||
@property
|
||||
def _pressure(self):
|
||||
"""Return the raw pressure."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_PRESSURE)
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
"""Return the humidity."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_HUMIDITY)
|
||||
|
||||
@property
|
||||
def wind_gust(self):
|
||||
"""Return the wind gust speed."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_GUST)
|
||||
|
||||
@property
|
||||
def cloud_cover(self):
|
||||
"""Return the cloud cover."""
|
||||
return self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_CLOUD_COVER
|
||||
)
|
||||
|
||||
@property
|
||||
def precipitation_type(self):
|
||||
"""Return precipitation type."""
|
||||
return self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_PRECIPITATION_TYPE
|
||||
)
|
||||
|
||||
@property
|
||||
def _wind_speed(self):
|
||||
"""Return the raw wind speed."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_SPEED)
|
||||
|
||||
@property
|
||||
def wind_bearing(self):
|
||||
"""Return the wind bearing."""
|
||||
return self._get_cc_value(
|
||||
self.coordinator.data[CURRENT], CC_V3_ATTR_WIND_DIRECTION
|
||||
)
|
||||
|
||||
@property
|
||||
def ozone(self):
|
||||
"""Return the O3 (ozone) level."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_OZONE)
|
||||
|
||||
@property
|
||||
def condition(self):
|
||||
"""Return the condition."""
|
||||
return self._translate_condition(
|
||||
self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_CONDITION),
|
||||
is_up(self.hass),
|
||||
)
|
||||
|
||||
@property
|
||||
def _visibility(self):
|
||||
"""Return the raw visibility."""
|
||||
return self._get_cc_value(self.coordinator.data[CURRENT], CC_V3_ATTR_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 = []
|
||||
|
||||
# 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(
|
||||
self._get_cc_value(forecast, CC_V3_ATTR_TIMESTAMP)
|
||||
)
|
||||
use_datetime = True
|
||||
condition = self._get_cc_value(forecast, CC_V3_ATTR_CONDITION)
|
||||
precipitation = self._get_cc_value(forecast, CC_V3_ATTR_PRECIPITATION)
|
||||
precipitation_probability = self._get_cc_value(
|
||||
forecast, CC_V3_ATTR_PRECIPITATION_PROBABILITY
|
||||
)
|
||||
temp = self._get_cc_value(forecast, CC_V3_ATTR_TEMPERATURE)
|
||||
temp_low = None
|
||||
wind_direction = self._get_cc_value(forecast, CC_V3_ATTR_WIND_DIRECTION)
|
||||
wind_speed = self._get_cc_value(forecast, CC_V3_ATTR_WIND_SPEED)
|
||||
|
||||
if self.forecast_type == DAILY:
|
||||
use_datetime = False
|
||||
forecast_dt = dt_util.start_of_local_day(forecast_dt)
|
||||
precipitation = self._get_cc_value(
|
||||
forecast, CC_V3_ATTR_PRECIPITATION_DAILY
|
||||
)
|
||||
temp = next(
|
||||
(
|
||||
self._get_cc_value(item, CC_V3_ATTR_TEMPERATURE_HIGH)
|
||||
for item in forecast[CC_V3_ATTR_TEMPERATURE]
|
||||
if "max" in item
|
||||
),
|
||||
temp,
|
||||
)
|
||||
temp_low = next(
|
||||
(
|
||||
self._get_cc_value(item, CC_V3_ATTR_TEMPERATURE_LOW)
|
||||
for item in forecast[CC_V3_ATTR_TEMPERATURE]
|
||||
if "min" in item
|
||||
),
|
||||
temp_low,
|
||||
)
|
||||
elif self.forecast_type == NOWCAST and precipitation:
|
||||
# Precipitation is forecasted in CONF_TIMESTEP increments but in a
|
||||
# per hour rate, so value needs to be converted to an amount.
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
return forecasts
|
@ -17,7 +17,7 @@ from pytomorrowio.exceptions import (
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_LATITUDE,
|
||||
@ -25,8 +25,8 @@ from homeassistant.const import (
|
||||
CONF_LONGITUDE,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
@ -123,86 +123,10 @@ def async_set_update_interval(
|
||||
return timedelta(minutes=minutes)
|
||||
|
||||
|
||||
@callback
|
||||
def async_migrate_entry_from_climacell(
|
||||
hass: HomeAssistant,
|
||||
dev_reg: dr.DeviceRegistry,
|
||||
entry: ConfigEntry,
|
||||
device: dr.DeviceEntry,
|
||||
) -> None:
|
||||
"""Migrate a config entry from a Climacell entry."""
|
||||
# Remove the old config entry ID from the entry data so we don't try this again
|
||||
# on the next setup
|
||||
data = entry.data.copy()
|
||||
old_config_entry_id = data.pop("old_config_entry_id")
|
||||
hass.config_entries.async_update_entry(entry, data=data)
|
||||
LOGGER.debug(
|
||||
(
|
||||
"Setting up imported climacell entry %s for the first time as "
|
||||
"tomorrowio entry %s"
|
||||
),
|
||||
old_config_entry_id,
|
||||
entry.entry_id,
|
||||
)
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
for entity_entry in er.async_entries_for_config_entry(ent_reg, old_config_entry_id):
|
||||
old_platform = entity_entry.platform
|
||||
# In case the API key has changed due to a V3 -> V4 change, we need to
|
||||
# generate the new entity's unique ID
|
||||
new_unique_id = (
|
||||
f"{entry.data[CONF_API_KEY]}_"
|
||||
f"{'_'.join(entity_entry.unique_id.split('_')[1:])}"
|
||||
)
|
||||
ent_reg.async_update_entity_platform(
|
||||
entity_entry.entity_id,
|
||||
DOMAIN,
|
||||
new_unique_id=new_unique_id,
|
||||
new_config_entry_id=entry.entry_id,
|
||||
new_device_id=device.id,
|
||||
)
|
||||
assert entity_entry
|
||||
LOGGER.debug(
|
||||
"Migrated %s from %s to %s",
|
||||
entity_entry.entity_id,
|
||||
old_platform,
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
# We only have one device in the registry but we will do a loop just in case
|
||||
for old_device in dr.async_entries_for_config_entry(dev_reg, old_config_entry_id):
|
||||
if old_device.name_by_user:
|
||||
dev_reg.async_update_device(device.id, name_by_user=old_device.name_by_user)
|
||||
|
||||
# Remove the old config entry and now the entry is fully migrated
|
||||
hass.async_create_task(hass.config_entries.async_remove(old_config_entry_id))
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Tomorrow.io API from a config entry."""
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
# Let's precreate the device so that if this is a first time setup for a config
|
||||
# entry imported from a ClimaCell entry, we can apply customizations from the old
|
||||
# device.
|
||||
dev_reg = dr.async_get(hass)
|
||||
device = dev_reg.async_get_or_create(
|
||||
config_entry_id=entry.entry_id,
|
||||
identifiers={(DOMAIN, entry.data[CONF_API_KEY])},
|
||||
name=INTEGRATION_NAME,
|
||||
manufacturer=INTEGRATION_NAME,
|
||||
sw_version="v4",
|
||||
entry_type=dr.DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
# If this is an import and we still have the old config entry ID in the entry data,
|
||||
# it means we are setting this entry up for the first time after a migration from
|
||||
# ClimaCell to Tomorrow.io. In order to preserve any customizations on the ClimaCell
|
||||
# entities, we need to remove each old entity, creating a new entity in its place
|
||||
# but attached to this entry.
|
||||
if entry.source == SOURCE_IMPORT and "old_config_entry_id" in entry.data:
|
||||
async_migrate_entry_from_climacell(hass, dev_reg, entry, device)
|
||||
|
||||
api_key = entry.data[CONF_API_KEY]
|
||||
# If coordinator already exists for this API key, we'll use that, otherwise
|
||||
# we have to create a new one
|
||||
@ -408,10 +332,10 @@ class TomorrowioEntity(CoordinatorEntity[TomorrowioDataUpdateCoordinator]):
|
||||
self._config_entry = config_entry
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, self._config_entry.data[CONF_API_KEY])},
|
||||
name="Tomorrow.io",
|
||||
manufacturer="Tomorrow.io",
|
||||
name=INTEGRATION_NAME,
|
||||
manufacturer=INTEGRATION_NAME,
|
||||
sw_version=f"v{self.api_version}",
|
||||
entry_type=dr.DeviceEntryType.SERVICE,
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
def _get_current_property(self, property_name: str) -> int | str | float | None:
|
||||
|
@ -17,7 +17,6 @@ from homeassistant import config_entries, core
|
||||
from homeassistant.components.zone import async_active_zone
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_FRIENDLY_NAME,
|
||||
CONF_LATITUDE,
|
||||
CONF_LOCATION,
|
||||
@ -30,14 +29,10 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.selector import LocationSelector, LocationSelectorConfig
|
||||
|
||||
from .const import (
|
||||
AUTO_MIGRATION_MESSAGE,
|
||||
CC_DOMAIN,
|
||||
CONF_TIMESTEP,
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_TIMESTEP,
|
||||
DOMAIN,
|
||||
INTEGRATION_NAME,
|
||||
MANUAL_MIGRATION_MESSAGE,
|
||||
TMRW_ATTR_TEMPERATURE,
|
||||
)
|
||||
|
||||
@ -62,10 +57,6 @@ def _get_config_schema(
|
||||
vol.Required(CONF_API_KEY, default=input_dict.get(CONF_API_KEY)): str,
|
||||
}
|
||||
|
||||
# For imports we just need to ask for the API key
|
||||
if source == config_entries.SOURCE_IMPORT:
|
||||
return vol.Schema(api_key_schema, extra=vol.REMOVE_EXTRA)
|
||||
|
||||
default_location = (
|
||||
input_dict[CONF_LOCATION]
|
||||
if CONF_LOCATION in input_dict
|
||||
@ -125,11 +116,6 @@ class TomorrowioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize config flow."""
|
||||
self._showed_import_message = 0
|
||||
self._import_config: dict[str, Any] | None = None
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
@ -144,18 +130,6 @@ class TomorrowioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
# Grab the API key and add it to the rest of the config before continuing
|
||||
if self._import_config:
|
||||
self._import_config[CONF_API_KEY] = user_input[CONF_API_KEY]
|
||||
self._import_config[CONF_LOCATION] = {
|
||||
CONF_LATITUDE: self._import_config.pop(
|
||||
CONF_LATITUDE, self.hass.config.latitude
|
||||
),
|
||||
CONF_LONGITUDE: self._import_config.pop(
|
||||
CONF_LONGITUDE, self.hass.config.longitude
|
||||
),
|
||||
}
|
||||
user_input = self._import_config.copy()
|
||||
await self.async_set_unique_id(
|
||||
unique_id=_get_unique_id(self.hass, user_input)
|
||||
)
|
||||
@ -189,15 +163,6 @@ class TomorrowioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
if not errors:
|
||||
options: Mapping[str, Any] = {CONF_TIMESTEP: DEFAULT_TIMESTEP}
|
||||
# Store the old config entry ID and retrieve options to recreate the entry
|
||||
if self.source == config_entries.SOURCE_IMPORT:
|
||||
old_config_entry_id = self.context["old_config_entry_id"]
|
||||
old_config_entry = self.hass.config_entries.async_get_entry(
|
||||
old_config_entry_id
|
||||
)
|
||||
assert old_config_entry
|
||||
options = dict(old_config_entry.options)
|
||||
user_input["old_config_entry_id"] = old_config_entry_id
|
||||
return self.async_create_entry(
|
||||
title=user_input[CONF_NAME],
|
||||
data=user_input,
|
||||
@ -209,24 +174,3 @@ class TomorrowioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
data_schema=_get_config_schema(self.hass, self.source, user_input),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_import(self, import_config: dict) -> FlowResult:
|
||||
"""Import from config."""
|
||||
# Store import config for later
|
||||
self._import_config = dict(import_config)
|
||||
if self._import_config.pop(CONF_API_VERSION, 3) == 3:
|
||||
# Clear API key from import config
|
||||
self._import_config[CONF_API_KEY] = ""
|
||||
self.hass.components.persistent_notification.async_create(
|
||||
MANUAL_MIGRATION_MESSAGE,
|
||||
INTEGRATION_NAME,
|
||||
f"{CC_DOMAIN}_to_{DOMAIN}_new_api_key_needed",
|
||||
)
|
||||
return await self.async_step_user()
|
||||
|
||||
self.hass.components.persistent_notification.async_create(
|
||||
AUTO_MIGRATION_MESSAGE,
|
||||
INTEGRATION_NAME,
|
||||
f"{CC_DOMAIN}_to_{DOMAIN}",
|
||||
)
|
||||
return await self.async_step_user(self._import_config)
|
||||
|
@ -27,7 +27,6 @@ FORECAST_TYPES = [DAILY, HOURLY, NOWCAST]
|
||||
|
||||
DEFAULT_TIMESTEP = 15
|
||||
DEFAULT_FORECAST_TYPE = DAILY
|
||||
CC_DOMAIN = "climacell"
|
||||
DOMAIN = "tomorrowio"
|
||||
INTEGRATION_NAME = "Tomorrow.io"
|
||||
DEFAULT_NAME = INTEGRATION_NAME
|
||||
@ -116,32 +115,3 @@ TMRW_ATTR_PRESSURE_SURFACE_LEVEL = "pressureSurfaceLevel"
|
||||
TMRW_ATTR_SOLAR_GHI = "solarGHI"
|
||||
TMRW_ATTR_CLOUD_BASE = "cloudBase"
|
||||
TMRW_ATTR_CLOUD_CEILING = "cloudCeiling"
|
||||
|
||||
MANUAL_MIGRATION_MESSAGE = (
|
||||
"As part of [ClimaCell's rebranding to Tomorrow.io](https://www.tomorrow.io/blog/my-last-day-as-ceo-of-climacell/) "
|
||||
"we will migrate your existing ClimaCell config entry (or config "
|
||||
"entries) to the new Tomorrow.io integration, but because **the "
|
||||
" V3 API is now deprecated**, you will need to get a new V4 API "
|
||||
"key from [Tomorrow.io](https://app.tomorrow.io/development/keys)."
|
||||
" Once that is done, visit the "
|
||||
"[Integrations Configuration](/config/integrations) page and "
|
||||
"click Configure on the Tomorrow.io card(s) to submit the new "
|
||||
"key. Once your key has been validated, your config entry will "
|
||||
"automatically be migrated. The new integration is a drop in "
|
||||
"replacement and your existing entities will be migrated over, "
|
||||
"just note that the location of the integration card on the "
|
||||
"[Integrations Configuration](/config/integrations) page has changed "
|
||||
"since the integration name has changed."
|
||||
)
|
||||
|
||||
AUTO_MIGRATION_MESSAGE = (
|
||||
"As part of [ClimaCell's rebranding to Tomorrow.io](https://www.tomorrow.io/blog/my-last-day-as-ceo-of-climacell/) "
|
||||
"we have automatically migrated your existing ClimaCell config entry "
|
||||
"(or as many of your ClimaCell config entries as we could) to the new "
|
||||
"Tomorrow.io integration. There is nothing you need to do since the "
|
||||
"new integration is a drop in replacement and your existing entities "
|
||||
"have been migrated over, just note that the location of the "
|
||||
"integration card on the "
|
||||
"[Integrations Configuration](/config/integrations) page has changed "
|
||||
"since the integration name has changed."
|
||||
)
|
||||
|
@ -1480,9 +1480,6 @@ pychromecast==12.1.4
|
||||
# homeassistant.components.pocketcasts
|
||||
pycketcasts==1.0.1
|
||||
|
||||
# homeassistant.components.climacell
|
||||
pyclimacell==0.18.2
|
||||
|
||||
# homeassistant.components.cmus
|
||||
pycmus==0.1.1
|
||||
|
||||
|
@ -1044,9 +1044,6 @@ pycfdns==1.2.2
|
||||
# homeassistant.components.cast
|
||||
pychromecast==12.1.4
|
||||
|
||||
# homeassistant.components.climacell
|
||||
pyclimacell==0.18.2
|
||||
|
||||
# homeassistant.components.comfoconnect
|
||||
pycomfoconnect==0.4
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
"""Tests for the ClimaCell Weather API integration."""
|
@ -1,26 +0,0 @@
|
||||
"""Configure py.test."""
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.common import load_fixture
|
||||
|
||||
|
||||
@pytest.fixture(name="climacell_config_entry_update")
|
||||
def climacell_config_entry_update_fixture():
|
||||
"""Mock valid climacell config entry setup."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.realtime",
|
||||
return_value=json.loads(load_fixture("v3_realtime.json", "climacell")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_hourly",
|
||||
return_value=json.loads(load_fixture("v3_forecast_hourly.json", "climacell")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_daily",
|
||||
return_value=json.loads(load_fixture("v3_forecast_daily.json", "climacell")),
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_nowcast",
|
||||
return_value=json.loads(load_fixture("v3_forecast_nowcast.json", "climacell")),
|
||||
):
|
||||
yield
|
@ -1,19 +0,0 @@
|
||||
"""Constants for climacell tests."""
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
)
|
||||
|
||||
API_KEY = "aa"
|
||||
|
||||
API_V3_ENTRY_DATA = {
|
||||
CONF_NAME: "ClimaCell",
|
||||
CONF_API_KEY: API_KEY,
|
||||
CONF_LATITUDE: 80.0,
|
||||
CONF_LONGITUDE: 80.0,
|
||||
CONF_API_VERSION: 3,
|
||||
}
|
@ -1,992 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
@ -1,752 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
@ -1,782 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
@ -1,102 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"wind_gust": {
|
||||
"value": 14.96,
|
||||
"units": "mph"
|
||||
},
|
||||
"precipitation_type": {
|
||||
"value": "rain"
|
||||
},
|
||||
"cloud_cover": {
|
||||
"value": 100,
|
||||
"units": "%"
|
||||
},
|
||||
"fire_index": {
|
||||
"value": 9
|
||||
},
|
||||
"epa_aqi": {
|
||||
"value": 22.3125
|
||||
},
|
||||
"epa_primary_pollutant": {
|
||||
"value": "pm25"
|
||||
},
|
||||
"china_aqi": {
|
||||
"value": 27
|
||||
},
|
||||
"china_primary_pollutant": {
|
||||
"value": "pm10"
|
||||
},
|
||||
"pm25": {
|
||||
"value": 5.3125,
|
||||
"units": "\u00b5g/m3"
|
||||
},
|
||||
"pm10": {
|
||||
"value": 27,
|
||||
"units": "\u00b5g/m3"
|
||||
},
|
||||
"no2": {
|
||||
"value": 14.1875,
|
||||
"units": "ppb"
|
||||
},
|
||||
"co": {
|
||||
"value": 0.875,
|
||||
"units": "ppm"
|
||||
},
|
||||
"so2": {
|
||||
"value": 2,
|
||||
"units": "ppb"
|
||||
},
|
||||
"epa_health_concern": {
|
||||
"value": "Good"
|
||||
},
|
||||
"china_health_concern": {
|
||||
"value": "Good"
|
||||
},
|
||||
"pollen_tree": {
|
||||
"value": 0,
|
||||
"units": "Climacell Pollen Index"
|
||||
},
|
||||
"pollen_weed": {
|
||||
"value": 0,
|
||||
"units": "Climacell Pollen Index"
|
||||
},
|
||||
"pollen_grass": {
|
||||
"value": 0,
|
||||
"units": "Climacell Pollen Index"
|
||||
},
|
||||
"observation_time": {
|
||||
"value": "2021-03-07T18:54:06.055Z"
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
"""Test the ClimaCell config flow."""
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.components.climacell.const import (
|
||||
CONF_TIMESTEP,
|
||||
DEFAULT_TIMESTEP,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import API_V3_ENTRY_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_options_flow(
|
||||
hass: HomeAssistant, climacell_config_entry_update: None
|
||||
) -> None:
|
||||
"""Test options config flow for climacell."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=API_V3_ENTRY_DATA,
|
||||
source=SOURCE_USER,
|
||||
unique_id="test",
|
||||
version=1,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
||||
assert entry.options[CONF_TIMESTEP] == DEFAULT_TIMESTEP
|
||||
assert CONF_TIMESTEP not in entry.data
|
||||
|
||||
result = await hass.config_entries.options.async_init(entry.entry_id, data=None)
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||
assert result["step_id"] == "init"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"], user_input={CONF_TIMESTEP: 1}
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == ""
|
||||
assert result["data"][CONF_TIMESTEP] == 1
|
||||
assert entry.options[CONF_TIMESTEP] == 1
|
@ -1,14 +0,0 @@
|
||||
"""Tests for ClimaCell const."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.climacell.const import ClimaCellSensorEntityDescription
|
||||
from homeassistant.const import TEMP_FAHRENHEIT
|
||||
|
||||
|
||||
async def test_post_init():
|
||||
"""Test post initialization check for ClimaCellSensorEntityDescription."""
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
ClimaCellSensorEntityDescription(
|
||||
key="a", name="b", unit_imperial=TEMP_FAHRENHEIT
|
||||
)
|
@ -1,106 +0,0 @@
|
||||
"""Tests for Climacell init."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.climacell.const import CONF_TIMESTEP, DOMAIN
|
||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||
from homeassistant.const import CONF_API_VERSION
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import API_V3_ENTRY_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_load_and_unload(
|
||||
hass: HomeAssistant,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test loading and unloading entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=API_V3_ENTRY_DATA,
|
||||
unique_id="test",
|
||||
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
|
||||
|
||||
|
||||
async def test_v3_load_and_unload(
|
||||
hass: HomeAssistant,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test loading and unloading v3 entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={k: v for k, v in API_V3_ENTRY_DATA.items() if k != CONF_API_VERSION},
|
||||
unique_id="test",
|
||||
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
|
||||
|
||||
|
||||
async def test_v4_load_and_unload(
|
||||
hass: HomeAssistant,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test loading and unloading v3 entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_API_VERSION: 4,
|
||||
**{k: v for k, v in API_V3_ENTRY_DATA.items() if k != CONF_API_VERSION},
|
||||
},
|
||||
unique_id="test",
|
||||
version=1,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
with patch(
|
||||
"homeassistant.components.tomorrowio.async_setup_entry", return_value=True
|
||||
):
|
||||
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)) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"old_timestep, new_timestep", [(2, 1), (7, 5), (20, 15), (21, 30)]
|
||||
)
|
||||
async def test_migrate_timestep(
|
||||
hass: HomeAssistant,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
old_timestep: int,
|
||||
new_timestep: int,
|
||||
) -> None:
|
||||
"""Test migration to standardized timestep."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=API_V3_ENTRY_DATA,
|
||||
options={CONF_TIMESTEP: old_timestep},
|
||||
unique_id="test",
|
||||
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
|
@ -1,148 +0,0 @@
|
||||
"""Tests for Climacell sensor entities."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.climacell.const import ATTRIBUTION, DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.const import ATTR_ATTRIBUTION
|
||||
from homeassistant.core import HomeAssistant, State, callback
|
||||
from homeassistant.helpers.entity_registry import async_get
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import API_V3_ENTRY_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
CC_SENSOR_ENTITY_ID = "sensor.climacell_{}"
|
||||
|
||||
O3 = "ozone"
|
||||
CO = "carbon_monoxide"
|
||||
NO2 = "nitrogen_dioxide"
|
||||
SO2 = "sulfur_dioxide"
|
||||
PM25 = "particulate_matter_2_5_mm"
|
||||
PM10 = "particulate_matter_10_mm"
|
||||
MEP_AQI = "china_mep_air_quality_index"
|
||||
MEP_HEALTH_CONCERN = "china_mep_health_concern"
|
||||
MEP_PRIMARY_POLLUTANT = "china_mep_primary_pollutant"
|
||||
EPA_AQI = "us_epa_air_quality_index"
|
||||
EPA_HEALTH_CONCERN = "us_epa_health_concern"
|
||||
EPA_PRIMARY_POLLUTANT = "us_epa_primary_pollutant"
|
||||
FIRE_INDEX = "fire_index"
|
||||
GRASS_POLLEN = "grass_pollen_index"
|
||||
WEED_POLLEN = "weed_pollen_index"
|
||||
TREE_POLLEN = "tree_pollen_index"
|
||||
FEELS_LIKE = "feels_like"
|
||||
DEW_POINT = "dew_point"
|
||||
PRESSURE_SURFACE_LEVEL = "pressure_surface_level"
|
||||
SNOW_ACCUMULATION = "snow_accumulation"
|
||||
ICE_ACCUMULATION = "ice_accumulation"
|
||||
GHI = "global_horizontal_irradiance"
|
||||
CLOUD_BASE = "cloud_base"
|
||||
CLOUD_COVER = "cloud_cover"
|
||||
CLOUD_CEILING = "cloud_ceiling"
|
||||
WIND_GUST = "wind_gust"
|
||||
PRECIPITATION_TYPE = "precipitation_type"
|
||||
|
||||
V3_FIELDS = [
|
||||
O3,
|
||||
CO,
|
||||
NO2,
|
||||
SO2,
|
||||
PM25,
|
||||
PM10,
|
||||
MEP_AQI,
|
||||
MEP_HEALTH_CONCERN,
|
||||
MEP_PRIMARY_POLLUTANT,
|
||||
EPA_AQI,
|
||||
EPA_HEALTH_CONCERN,
|
||||
EPA_PRIMARY_POLLUTANT,
|
||||
FIRE_INDEX,
|
||||
GRASS_POLLEN,
|
||||
WEED_POLLEN,
|
||||
TREE_POLLEN,
|
||||
]
|
||||
|
||||
V4_FIELDS = [
|
||||
*V3_FIELDS,
|
||||
FEELS_LIKE,
|
||||
DEW_POINT,
|
||||
PRESSURE_SURFACE_LEVEL,
|
||||
GHI,
|
||||
CLOUD_BASE,
|
||||
CLOUD_COVER,
|
||||
CLOUD_CEILING,
|
||||
WIND_GUST,
|
||||
PRECIPITATION_TYPE,
|
||||
]
|
||||
|
||||
|
||||
@callback
|
||||
def _enable_entity(hass: HomeAssistant, 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: HomeAssistant, sensors: list[str], 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=dt_util.UTC),
|
||||
):
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=config,
|
||||
unique_id="test",
|
||||
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()
|
||||
for entity_name in sensors:
|
||||
_enable_entity(hass, CC_SENSOR_ENTITY_ID.format(entity_name))
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == len(sensors)
|
||||
|
||||
|
||||
def check_sensor_state(hass: HomeAssistant, entity_name: str, value: str):
|
||||
"""Check the state of a ClimaCell sensor."""
|
||||
state = hass.states.get(CC_SENSOR_ENTITY_ID.format(entity_name))
|
||||
assert state
|
||||
assert state.state == value
|
||||
assert state.attributes[ATTR_ATTRIBUTION] == ATTRIBUTION
|
||||
|
||||
|
||||
async def test_v3_sensor(
|
||||
hass: HomeAssistant,
|
||||
climacell_config_entry_update: pytest.fixture,
|
||||
) -> None:
|
||||
"""Test v3 sensor data."""
|
||||
await _setup(hass, V3_FIELDS, API_V3_ENTRY_DATA)
|
||||
check_sensor_state(hass, O3, "52.625")
|
||||
check_sensor_state(hass, CO, "0.875")
|
||||
check_sensor_state(hass, NO2, "14.1875")
|
||||
check_sensor_state(hass, SO2, "2")
|
||||
check_sensor_state(hass, PM25, "5.3125")
|
||||
check_sensor_state(hass, PM10, "27")
|
||||
check_sensor_state(hass, MEP_AQI, "27")
|
||||
check_sensor_state(hass, MEP_HEALTH_CONCERN, "Good")
|
||||
check_sensor_state(hass, MEP_PRIMARY_POLLUTANT, "pm10")
|
||||
check_sensor_state(hass, EPA_AQI, "22.3125")
|
||||
check_sensor_state(hass, EPA_HEALTH_CONCERN, "Good")
|
||||
check_sensor_state(hass, EPA_PRIMARY_POLLUTANT, "pm25")
|
||||
check_sensor_state(hass, FIRE_INDEX, "9")
|
||||
check_sensor_state(hass, GRASS_POLLEN, "minimal_to_none")
|
||||
check_sensor_state(hass, WEED_POLLEN, "minimal_to_none")
|
||||
check_sensor_state(hass, TREE_POLLEN, "minimal_to_none")
|
@ -1,223 +0,0 @@
|
||||
"""Tests for Climacell weather entity."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.climacell.const import (
|
||||
ATTR_CLOUD_COVER,
|
||||
ATTR_PRECIPITATION_TYPE,
|
||||
ATTR_WIND_GUST,
|
||||
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_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 HomeAssistant, State, callback
|
||||
from homeassistant.helpers.entity_registry import async_get
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import API_V3_ENTRY_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@callback
|
||||
def _enable_entity(hass: HomeAssistant, 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: HomeAssistant, 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=dt_util.UTC),
|
||||
):
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=config,
|
||||
unique_id="test",
|
||||
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()
|
||||
for entity_name in ("hourly", "nowcast"):
|
||||
_enable_entity(hass, f"weather.climacell_{entity_name}")
|
||||
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: HomeAssistant,
|
||||
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-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 7.2,
|
||||
ATTR_FORECAST_TEMP_LOW: -4.7,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-08T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 9.7,
|
||||
ATTR_FORECAST_TEMP_LOW: -4.0,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-09T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 19.4,
|
||||
ATTR_FORECAST_TEMP_LOW: -0.3,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-10T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 18.5,
|
||||
ATTR_FORECAST_TEMP_LOW: 3.0,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-11T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 5,
|
||||
ATTR_FORECAST_TEMP: 19.7,
|
||||
ATTR_FORECAST_TEMP_LOW: 9.3,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-12T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.05,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 25,
|
||||
ATTR_FORECAST_TEMP: 19.9,
|
||||
ATTR_FORECAST_TEMP_LOW: 12.1,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-13T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 25,
|
||||
ATTR_FORECAST_TEMP: 15.8,
|
||||
ATTR_FORECAST_TEMP_LOW: 7.5,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_RAINY,
|
||||
ATTR_FORECAST_TIME: "2021-03-14T00:00:00-08:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 1.07,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 75,
|
||||
ATTR_FORECAST_TEMP: 6.4,
|
||||
ATTR_FORECAST_TEMP_LOW: 3.2,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_SNOWY,
|
||||
ATTR_FORECAST_TIME: "2021-03-15T00:00:00-07:00", # DST starts
|
||||
ATTR_FORECAST_PRECIPITATION: 7.31,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 95,
|
||||
ATTR_FORECAST_TEMP: 1.2,
|
||||
ATTR_FORECAST_TEMP_LOW: 0.2,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-16T00:00:00-07:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.01,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 5,
|
||||
ATTR_FORECAST_TEMP: 6.1,
|
||||
ATTR_FORECAST_TEMP_LOW: -1.6,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-17T00:00:00-07:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 0,
|
||||
ATTR_FORECAST_TEMP: 11.3,
|
||||
ATTR_FORECAST_TEMP_LOW: 1.3,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-18T00:00:00-07:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 5,
|
||||
ATTR_FORECAST_TEMP: 12.3,
|
||||
ATTR_FORECAST_TEMP_LOW: 5.6,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-19T00:00:00-07:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.18,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 45,
|
||||
ATTR_FORECAST_TEMP: 9.4,
|
||||
ATTR_FORECAST_TEMP_LOW: 4.7,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_RAINY,
|
||||
ATTR_FORECAST_TIME: "2021-03-20T00:00:00-07:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 1.23,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 55,
|
||||
ATTR_FORECAST_TEMP: 5.0,
|
||||
ATTR_FORECAST_TEMP_LOW: 3.1,
|
||||
},
|
||||
{
|
||||
ATTR_FORECAST_CONDITION: ATTR_CONDITION_CLOUDY,
|
||||
ATTR_FORECAST_TIME: "2021-03-21T00:00:00-07:00",
|
||||
ATTR_FORECAST_PRECIPITATION: 0.04,
|
||||
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 20,
|
||||
ATTR_FORECAST_TEMP: 6.8,
|
||||
ATTR_FORECAST_TEMP_LOW: 0.9,
|
||||
},
|
||||
]
|
||||
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.12
|
||||
assert weather_state.attributes[ATTR_WEATHER_TEMPERATURE] == 6.6
|
||||
assert weather_state.attributes[ATTR_WEATHER_VISIBILITY] == 9.99
|
||||
assert weather_state.attributes[ATTR_WEATHER_WIND_BEARING] == 320.31
|
||||
assert weather_state.attributes[ATTR_WEATHER_WIND_SPEED] == 14.63
|
||||
assert weather_state.attributes[ATTR_CLOUD_COVER] == 100
|
||||
assert weather_state.attributes[ATTR_WIND_GUST] == 24.0758
|
||||
assert weather_state.attributes[ATTR_PRECIPITATION_TYPE] == "rain"
|
@ -33,22 +33,3 @@ def tomorrowio_config_entry_update_fixture():
|
||||
mock_max_requests_per_day.return_value = 100
|
||||
mock_num_api_requests.return_value = 2
|
||||
yield mock_update
|
||||
|
||||
|
||||
@pytest.fixture(name="climacell_config_entry_update")
|
||||
def climacell_config_entry_update_fixture():
|
||||
"""Mock valid climacell config entry setup."""
|
||||
with patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.realtime",
|
||||
return_value={},
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_hourly",
|
||||
return_value={},
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_daily",
|
||||
return_value={},
|
||||
), patch(
|
||||
"homeassistant.components.climacell.ClimaCellV3.forecast_nowcast",
|
||||
return_value={},
|
||||
):
|
||||
yield
|
||||
|
@ -9,7 +9,6 @@ from pytomorrowio.exceptions import (
|
||||
)
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.components.climacell import DOMAIN as CC_DOMAIN
|
||||
from homeassistant.components.tomorrowio.config_flow import (
|
||||
_get_config_schema,
|
||||
_get_unique_id,
|
||||
@ -20,10 +19,9 @@ from homeassistant.components.tomorrowio.const import (
|
||||
DEFAULT_TIMESTEP,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, ConfigEntryState
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LOCATION,
|
||||
CONF_LONGITUDE,
|
||||
@ -36,7 +34,6 @@ from homeassistant.setup import async_setup_component
|
||||
from .const import API_KEY, MIN_CONFIG
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.climacell.const import API_V3_ENTRY_DATA
|
||||
|
||||
|
||||
async def test_user_flow_minimum_fields(hass: HomeAssistant) -> None:
|
||||
@ -210,73 +207,3 @@ async def test_options_flow(hass: HomeAssistant) -> None:
|
||||
assert result["title"] == ""
|
||||
assert result["data"][CONF_TIMESTEP] == 1
|
||||
assert entry.options[CONF_TIMESTEP] == 1
|
||||
|
||||
|
||||
async def test_import_flow_v4(hass: HomeAssistant) -> None:
|
||||
"""Test import flow for climacell v4 config entry."""
|
||||
user_config = API_V3_ENTRY_DATA.copy()
|
||||
user_config[CONF_API_VERSION] = 4
|
||||
old_entry = MockConfigEntry(
|
||||
domain=CC_DOMAIN,
|
||||
data=user_config,
|
||||
source=SOURCE_USER,
|
||||
unique_id="test",
|
||||
version=1,
|
||||
)
|
||||
old_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(old_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert old_entry.state != ConfigEntryState.LOADED
|
||||
|
||||
assert len(hass.config_entries.async_entries(CC_DOMAIN)) == 0
|
||||
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
|
||||
entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
assert "old_config_entry_id" not in entry.data
|
||||
assert CONF_API_VERSION not in entry.data
|
||||
|
||||
|
||||
async def test_import_flow_v3(
|
||||
hass: HomeAssistant, climacell_config_entry_update
|
||||
) -> None:
|
||||
"""Test import flow for climacell v3 config entry."""
|
||||
user_config = API_V3_ENTRY_DATA
|
||||
old_entry = MockConfigEntry(
|
||||
domain=CC_DOMAIN,
|
||||
data=user_config,
|
||||
source=SOURCE_USER,
|
||||
unique_id="test",
|
||||
version=1,
|
||||
)
|
||||
old_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(old_entry.entry_id)
|
||||
assert old_entry.state == ConfigEntryState.LOADED
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT, "old_config_entry_id": old_entry.entry_id},
|
||||
data=old_entry.data,
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_API_KEY: "this is a test"}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||
assert result["data"] == {
|
||||
CONF_API_KEY: "this is a test",
|
||||
CONF_LOCATION: {
|
||||
CONF_LATITUDE: 80.0,
|
||||
CONF_LONGITUDE: 80.0,
|
||||
},
|
||||
CONF_NAME: "ClimaCell",
|
||||
"old_config_entry_id": old_entry.entry_id,
|
||||
}
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.config_entries.async_entries(CC_DOMAIN)) == 0
|
||||
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
|
||||
entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
assert "old_config_entry_id" not in entry.data
|
||||
assert CONF_API_VERSION not in entry.data
|
||||
|
@ -2,30 +2,20 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.climacell import CONF_TIMESTEP, DOMAIN as CC_DOMAIN
|
||||
from homeassistant.components.tomorrowio.config_flow import (
|
||||
_get_config_schema,
|
||||
_get_unique_id,
|
||||
)
|
||||
from homeassistant.components.tomorrowio.const import DOMAIN
|
||||
from homeassistant.components.tomorrowio.const import CONF_TIMESTEP, DOMAIN
|
||||
from homeassistant.components.weather import DOMAIN as WEATHER_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_API_VERSION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LOCATION,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_API_KEY, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import MIN_CONFIG
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
from tests.components.climacell.const import API_V3_ENTRY_DATA
|
||||
|
||||
NEW_NAME = "New Name"
|
||||
|
||||
@ -126,118 +116,3 @@ async def test_update_intervals(
|
||||
assert len(tomorrowio_config_entry_update.call_args_list) == 2
|
||||
|
||||
tomorrowio_config_entry_update.reset_mock()
|
||||
|
||||
|
||||
async def test_climacell_migration_logic(
|
||||
hass: HomeAssistant, climacell_config_entry_update
|
||||
) -> None:
|
||||
"""Test that climacell config entry is properly migrated."""
|
||||
old_data = API_V3_ENTRY_DATA.copy()
|
||||
old_data[CONF_API_KEY] = "v3apikey"
|
||||
old_config_entry = MockConfigEntry(
|
||||
domain=CC_DOMAIN,
|
||||
data=old_data,
|
||||
unique_id="v3apikey_80.0_80.0",
|
||||
version=1,
|
||||
)
|
||||
old_config_entry.add_to_hass(hass)
|
||||
# Let's create a device and update its name
|
||||
dev_reg = dr.async_get(hass)
|
||||
old_device = dev_reg.async_get_or_create(
|
||||
config_entry_id=old_config_entry.entry_id,
|
||||
identifiers={(CC_DOMAIN, old_data[CONF_API_KEY])},
|
||||
manufacturer="ClimaCell",
|
||||
sw_version="v4",
|
||||
entry_type="service",
|
||||
name="ClimaCell",
|
||||
)
|
||||
dev_reg.async_update_device(old_device.id, name_by_user=NEW_NAME)
|
||||
# Now let's create some entity and update some things to see if everything migrates
|
||||
# over
|
||||
ent_reg = er.async_get(hass)
|
||||
old_entity_daily = ent_reg.async_get_or_create(
|
||||
"weather",
|
||||
CC_DOMAIN,
|
||||
"v3apikey_80.0_80.0_daily",
|
||||
config_entry=old_config_entry,
|
||||
original_name="ClimaCell - Daily",
|
||||
suggested_object_id="climacell_daily",
|
||||
device_id=old_device.id,
|
||||
)
|
||||
old_entity_hourly = ent_reg.async_get_or_create(
|
||||
"weather",
|
||||
CC_DOMAIN,
|
||||
"v3apikey_80.0_80.0_hourly",
|
||||
config_entry=old_config_entry,
|
||||
original_name="ClimaCell - Hourly",
|
||||
suggested_object_id="climacell_hourly",
|
||||
device_id=old_device.id,
|
||||
disabled_by=er.RegistryEntryDisabler.USER,
|
||||
)
|
||||
old_entity_nowcast = ent_reg.async_get_or_create(
|
||||
"weather",
|
||||
CC_DOMAIN,
|
||||
"v3apikey_80.0_80.0_nowcast",
|
||||
config_entry=old_config_entry,
|
||||
original_name="ClimaCell - Nowcast",
|
||||
suggested_object_id="climacell_nowcast",
|
||||
device_id=old_device.id,
|
||||
)
|
||||
ent_reg.async_update_entity(old_entity_daily.entity_id, name=NEW_NAME)
|
||||
|
||||
# Now let's create a new tomorrowio config entry that is supposedly created from a
|
||||
# climacell import and see what happens - we are also changing the API key to ensure
|
||||
# that things work as expected
|
||||
new_data = API_V3_ENTRY_DATA.copy()
|
||||
new_data[CONF_LOCATION] = {
|
||||
CONF_LATITUDE: float(new_data.pop(CONF_LATITUDE)),
|
||||
CONF_LONGITUDE: float(new_data.pop(CONF_LONGITUDE)),
|
||||
}
|
||||
new_data[CONF_API_VERSION] = 4
|
||||
new_data["old_config_entry_id"] = old_config_entry.entry_id
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=new_data,
|
||||
unique_id=_get_unique_id(hass, new_data),
|
||||
version=1,
|
||||
source=SOURCE_IMPORT,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Check that the old device no longer exists
|
||||
assert dev_reg.async_get(old_device.id) is None
|
||||
|
||||
# Check that the new device was created and that it has the correct name
|
||||
assert (
|
||||
dr.async_entries_for_config_entry(dev_reg, config_entry.entry_id)[
|
||||
0
|
||||
].name_by_user
|
||||
== NEW_NAME
|
||||
)
|
||||
|
||||
# Check that the new entities match the old ones (minus the default name)
|
||||
new_entity_daily = ent_reg.async_get(old_entity_daily.entity_id)
|
||||
assert new_entity_daily.platform == DOMAIN
|
||||
assert new_entity_daily.name == NEW_NAME
|
||||
assert new_entity_daily.original_name == "ClimaCell - Daily"
|
||||
assert new_entity_daily.device_id != old_device.id
|
||||
assert new_entity_daily.unique_id == f"{_get_unique_id(hass, new_data)}_daily"
|
||||
assert new_entity_daily.disabled_by is None
|
||||
|
||||
new_entity_hourly = ent_reg.async_get(old_entity_hourly.entity_id)
|
||||
assert new_entity_hourly.platform == DOMAIN
|
||||
assert new_entity_hourly.name is None
|
||||
assert new_entity_hourly.original_name == "ClimaCell - Hourly"
|
||||
assert new_entity_hourly.device_id != old_device.id
|
||||
assert new_entity_hourly.unique_id == f"{_get_unique_id(hass, new_data)}_hourly"
|
||||
assert new_entity_hourly.disabled_by == er.RegistryEntryDisabler.USER
|
||||
|
||||
new_entity_nowcast = ent_reg.async_get(old_entity_nowcast.entity_id)
|
||||
assert new_entity_nowcast.platform == DOMAIN
|
||||
assert new_entity_nowcast.name is None
|
||||
assert new_entity_nowcast.original_name == "ClimaCell - Nowcast"
|
||||
assert new_entity_nowcast.device_id != old_device.id
|
||||
assert new_entity_nowcast.unique_id == f"{_get_unique_id(hass, new_data)}_nowcast"
|
||||
assert new_entity_nowcast.disabled_by is None
|
||||
|
Loading…
x
Reference in New Issue
Block a user