1 """The Tomorrow.io integration."""
3 from __future__
import annotations
6 from datetime
import timedelta
10 from pytomorrowio
import TomorrowioV4
11 from pytomorrowio.const
import CURRENT, FORECASTS
12 from pytomorrowio.exceptions
import (
14 InvalidAPIKeyException,
33 TMRW_ATTR_CARBON_MONOXIDE,
35 TMRW_ATTR_CHINA_HEALTH_CONCERN,
36 TMRW_ATTR_CHINA_PRIMARY_POLLUTANT,
38 TMRW_ATTR_CLOUD_CEILING,
39 TMRW_ATTR_CLOUD_COVER,
43 TMRW_ATTR_EPA_HEALTH_CONCERN,
44 TMRW_ATTR_EPA_PRIMARY_POLLUTANT,
48 TMRW_ATTR_NITROGEN_DIOXIDE,
50 TMRW_ATTR_PARTICULATE_MATTER_10,
51 TMRW_ATTR_PARTICULATE_MATTER_25,
52 TMRW_ATTR_POLLEN_GRASS,
53 TMRW_ATTR_POLLEN_TREE,
54 TMRW_ATTR_POLLEN_WEED,
55 TMRW_ATTR_PRECIPITATION,
56 TMRW_ATTR_PRECIPITATION_PROBABILITY,
57 TMRW_ATTR_PRECIPITATION_TYPE,
59 TMRW_ATTR_PRESSURE_SURFACE_LEVEL,
61 TMRW_ATTR_SULPHUR_DIOXIDE,
62 TMRW_ATTR_TEMPERATURE,
63 TMRW_ATTR_TEMPERATURE_HIGH,
64 TMRW_ATTR_TEMPERATURE_LOW,
65 TMRW_ATTR_UV_HEALTH_CONCERN,
68 TMRW_ATTR_WIND_DIRECTION,
76 hass: HomeAssistant, api_key: str, exclude_entry: ConfigEntry |
None =
None
77 ) -> list[ConfigEntry]:
78 """Get all entries for a given API key."""
81 for entry
in hass.config_entries.async_entries(DOMAIN)
82 if entry.data[CONF_API_KEY] == api_key
83 and (exclude_entry
is None or exclude_entry != entry)
89 hass: HomeAssistant, api: TomorrowioV4, exclude_entry: ConfigEntry |
None =
None
91 """Calculate update_interval."""
98 (24 * 60 * len(entries) * api.num_api_requests)
99 / (api.max_requests_per_day * 0.9)
103 "Number of config entries: %s\n"
104 "Number of API Requests per call: %s\n"
105 "Max requests per day: %s\n"
106 "Update interval: %s minutes"
109 api.num_api_requests,
110 api.max_requests_per_day,
117 """Define an object to hold Tomorrow.io data."""
119 def __init__(self, hass: HomeAssistant, api: TomorrowioV4) ->
None:
123 self.entry_id_to_location_dict: dict[str, str] = {}
126 super().
__init__(hass, LOGGER, name=f
"{DOMAIN}_{self._api.api_key_masked}")
129 """Add an entry to the location dict."""
130 latitude = entry.data[CONF_LOCATION][CONF_LATITUDE]
131 longitude = entry.data[CONF_LOCATION][CONF_LONGITUDE]
132 self.entry_id_to_location_dict[entry.entry_id] = f
"{latitude},{longitude}"
135 """Load config entry into coordinator."""
142 "Setting up coordinator for API key %s, loading data for all entries",
143 self.
_api_api.api_key_masked,
149 "Loaded %s entries, initiating first refresh",
150 len(self.entry_id_to_location_dict),
159 if entry.entry_id
in self.entry_id_to_location_dict:
163 "Adding new entry to existing coordinator for API key %s, doing a "
166 self.
_api_api.api_key_masked,
179 """Unload a config entry from coordinator.
181 Returns whether coordinator can be removed as well because there are no
182 config entries tied to it anymore.
184 self.entry_id_to_location_dict.pop(entry.entry_id)
186 return not self.entry_id_to_location_dict
189 """Update data via library."""
190 data: dict[str, Any] = {}
194 entry_id
not in self.
datadatadata
for entry_id
in self.entry_id_to_location_dict
199 "Fetching data for %s entries",
200 len(set(self.entry_id_to_location_dict) - set(data)),
202 for entry_id, location
in self.entry_id_to_location_dict.items():
205 entry = self.
hasshass.config_entries.async_get_entry(entry_id)
208 data[entry_id] = await self.
_api_api.realtime_and_all_forecasts(
211 TMRW_ATTR_TEMPERATURE,
214 TMRW_ATTR_WIND_SPEED,
215 TMRW_ATTR_WIND_DIRECTION,
217 TMRW_ATTR_VISIBILITY,
220 TMRW_ATTR_CLOUD_COVER,
221 TMRW_ATTR_PRECIPITATION_TYPE,
223 TMRW_ATTR_CARBON_MONOXIDE,
225 TMRW_ATTR_CHINA_HEALTH_CONCERN,
226 TMRW_ATTR_CHINA_PRIMARY_POLLUTANT,
227 TMRW_ATTR_CLOUD_BASE,
228 TMRW_ATTR_CLOUD_CEILING,
229 TMRW_ATTR_CLOUD_COVER,
232 TMRW_ATTR_EPA_HEALTH_CONCERN,
233 TMRW_ATTR_EPA_PRIMARY_POLLUTANT,
234 TMRW_ATTR_FEELS_LIKE,
235 TMRW_ATTR_FIRE_INDEX,
236 TMRW_ATTR_NITROGEN_DIOXIDE,
238 TMRW_ATTR_PARTICULATE_MATTER_10,
239 TMRW_ATTR_PARTICULATE_MATTER_25,
240 TMRW_ATTR_POLLEN_GRASS,
241 TMRW_ATTR_POLLEN_TREE,
242 TMRW_ATTR_POLLEN_WEED,
243 TMRW_ATTR_PRECIPITATION_TYPE,
244 TMRW_ATTR_PRESSURE_SURFACE_LEVEL,
246 TMRW_ATTR_SULPHUR_DIOXIDE,
248 TMRW_ATTR_UV_HEALTH_CONCERN,
252 TMRW_ATTR_TEMPERATURE_LOW,
253 TMRW_ATTR_TEMPERATURE_HIGH,
256 TMRW_ATTR_WIND_SPEED,
257 TMRW_ATTR_WIND_DIRECTION,
259 TMRW_ATTR_PRECIPITATION,
260 TMRW_ATTR_PRECIPITATION_PROBABILITY,
262 nowcast_timestep=entry.options[CONF_TIMESTEP],
266 CantConnectException,
267 InvalidAPIKeyException,
268 RateLimitedException,
271 raise UpdateFailed
from error
None async_setup_entry(self, ConfigEntry entry)
None add_entry_to_location_dict(self, ConfigEntry entry)
dict[str, Any] _async_update_data(self)
bool|None async_unload_entry(self, ConfigEntry entry)
None __init__(self, HomeAssistant hass, TomorrowioV4 api)
None update_interval(self, timedelta|None value)
timedelta|None update_interval(self)
None async_config_entry_first_refresh(self)
None _schedule_refresh(self)
None _async_unsub_refresh(self)
list[ConfigEntry] async_get_entries_by_api_key(HomeAssistant hass, str api_key, ConfigEntry|None exclude_entry=None)
timedelta async_set_update_interval(HomeAssistant hass, TomorrowioV4 api, ConfigEntry|None exclude_entry=None)