Skip to content

Commit

Permalink
Auto-level AirVisual API calls (#34903)
Browse files Browse the repository at this point in the history
  • Loading branch information
bachya authored and frenck committed May 24, 2020
1 parent b266d3a commit 19f36eb
Showing 1 changed file with 41 additions and 2 deletions.
43 changes: 41 additions & 2 deletions homeassistant/components/airvisual/__init__.py
@@ -1,6 +1,7 @@
"""The airvisual component."""
import asyncio
from datetime import timedelta
from math import ceil

from pyairvisual import Client
from pyairvisual.errors import AirVisualError, NodeProError
Expand Down Expand Up @@ -37,7 +38,6 @@
PLATFORMS = ["air_quality", "sensor"]

DEFAULT_ATTRIBUTION = "Data provided by AirVisual"
DEFAULT_GEOGRAPHY_SCAN_INTERVAL = timedelta(minutes=10)
DEFAULT_NODE_PRO_SCAN_INTERVAL = timedelta(minutes=1)
DEFAULT_OPTIONS = {CONF_SHOW_ON_MAP: True}

Expand Down Expand Up @@ -88,6 +88,37 @@ def async_get_geography_id(geography_dict):
)


@callback
def async_get_cloud_api_update_interval(hass, api_key):
"""Get a leveled scan interval for a particular cloud API key.
This will shift based on the number of active consumers, thus keeping the user
under the monthly API limit.
"""
num_consumers = len(
{
config_entry
for config_entry in hass.config_entries.async_entries(DOMAIN)
if config_entry.data.get(CONF_API_KEY) == api_key
}
)

# Assuming 10,000 calls per month and a "smallest possible month" of 28 days; note
# that we give a buffer of 1500 API calls for any drift, restarts, etc.:
minutes_between_api_calls = ceil(1 / (8500 / 28 / 24 / 60 / num_consumers))
return timedelta(minutes=minutes_between_api_calls)


@callback
def async_reset_coordinator_update_intervals(hass, update_interval):
"""Update any existing data coordinators with a new update interval."""
if not hass.data[DOMAIN][DATA_COORDINATOR]:
return

for coordinator in hass.data[DOMAIN][DATA_COORDINATOR].values():
coordinator.update_interval = update_interval


async def async_setup(hass, config):
"""Set up the AirVisual component."""
hass.data[DOMAIN] = {DATA_COORDINATOR: {}}
Expand Down Expand Up @@ -163,6 +194,10 @@ async def async_setup_entry(hass, config_entry):

client = Client(api_key=config_entry.data[CONF_API_KEY], session=websession)

update_interval = async_get_cloud_api_update_interval(
hass, config_entry.data[CONF_API_KEY]
)

async def async_update_data():
"""Get new data from the API."""
if CONF_CITY in config_entry.data:
Expand All @@ -185,10 +220,14 @@ async def async_update_data():
hass,
LOGGER,
name="geography data",
update_interval=DEFAULT_GEOGRAPHY_SCAN_INTERVAL,
update_interval=update_interval,
update_method=async_update_data,
)

# Ensure any other, existing config entries that use this API key are updated
# with the new scan interval:
async_reset_coordinator_update_intervals(hass, update_interval)

# Only geography-based entries have options:
config_entry.add_update_listener(async_update_options)
else:
Expand Down

0 comments on commit 19f36eb

Please sign in to comment.