Additional cleanup of IQVIA integration (#23403)
* Additional cleanup of IQVIA integration * Task * Moved import * Fixed exception * Member comments (round 1) * Member comments (round 2) * Member comments
This commit is contained in:
parent
606dbb85d2
commit
8fe95f4bab
3 changed files with 115 additions and 122 deletions
|
@ -1,18 +1,22 @@
|
||||||
"""Support for IQVIA."""
|
"""Support for IQVIA."""
|
||||||
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from pyiqvia import Client
|
||||||
|
from pyiqvia.errors import IQVIAError, InvalidZipError
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS
|
||||||
ATTR_ATTRIBUTION, CONF_MONITORED_CONDITIONS, CONF_SCAN_INTERVAL)
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import (
|
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||||
aiohttp_client, config_validation as cv, discovery)
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
async_dispatcher_connect, async_dispatcher_send)
|
async_dispatcher_connect, async_dispatcher_send)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.util.decorator import Registry
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DATA_CLIENT, DATA_LISTENER, DOMAIN, SENSORS, TOPIC_DATA_UPDATE,
|
DATA_CLIENT, DATA_LISTENER, DOMAIN, SENSORS, TOPIC_DATA_UPDATE,
|
||||||
|
@ -24,6 +28,7 @@ from .const import (
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
CONF_ZIP_CODE = 'zip_code'
|
CONF_ZIP_CODE = 'zip_code'
|
||||||
|
|
||||||
DATA_CONFIG = 'config'
|
DATA_CONFIG = 'config'
|
||||||
|
@ -31,8 +36,18 @@ DATA_CONFIG = 'config'
|
||||||
DEFAULT_ATTRIBUTION = 'Data provided by IQVIA™'
|
DEFAULT_ATTRIBUTION = 'Data provided by IQVIA™'
|
||||||
DEFAULT_SCAN_INTERVAL = timedelta(minutes=30)
|
DEFAULT_SCAN_INTERVAL = timedelta(minutes=30)
|
||||||
|
|
||||||
NOTIFICATION_ID = 'iqvia_setup'
|
FETCHER_MAPPING = {
|
||||||
NOTIFICATION_TITLE = 'IQVIA Setup'
|
(TYPE_ALLERGY_FORECAST,): (TYPE_ALLERGY_FORECAST, TYPE_ALLERGY_OUTLOOK),
|
||||||
|
(TYPE_ALLERGY_HISTORIC,): (TYPE_ALLERGY_HISTORIC,),
|
||||||
|
(TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW, TYPE_ALLERGY_YESTERDAY): (
|
||||||
|
TYPE_ALLERGY_INDEX,),
|
||||||
|
(TYPE_ASTHMA_FORECAST,): (TYPE_ASTHMA_FORECAST,),
|
||||||
|
(TYPE_ASTHMA_HISTORIC,): (TYPE_ASTHMA_HISTORIC,),
|
||||||
|
(TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW, TYPE_ASTHMA_YESTERDAY): (
|
||||||
|
TYPE_ASTHMA_INDEX,),
|
||||||
|
(TYPE_DISEASE_FORECAST,): (TYPE_DISEASE_FORECAST,),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema({
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
DOMAIN: vol.Schema({
|
DOMAIN: vol.Schema({
|
||||||
|
@ -45,16 +60,10 @@ CONFIG_SCHEMA = vol.Schema({
|
||||||
|
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Set up the IQVIA component."""
|
"""Set up the IQVIA component."""
|
||||||
from pyiqvia import Client
|
|
||||||
from pyiqvia.errors import IQVIAError
|
|
||||||
|
|
||||||
hass.data[DOMAIN] = {}
|
hass.data[DOMAIN] = {}
|
||||||
hass.data[DOMAIN][DATA_CLIENT] = {}
|
hass.data[DOMAIN][DATA_CLIENT] = {}
|
||||||
hass.data[DOMAIN][DATA_LISTENER] = {}
|
hass.data[DOMAIN][DATA_LISTENER] = {}
|
||||||
|
|
||||||
if DOMAIN not in config:
|
|
||||||
return True
|
|
||||||
|
|
||||||
conf = config[DOMAIN]
|
conf = config[DOMAIN]
|
||||||
|
|
||||||
websession = aiohttp_client.async_get_clientsession(hass)
|
websession = aiohttp_client.async_get_clientsession(hass)
|
||||||
|
@ -66,17 +75,12 @@ async def async_setup(hass, config):
|
||||||
await iqvia.async_update()
|
await iqvia.async_update()
|
||||||
except IQVIAError as err:
|
except IQVIAError as err:
|
||||||
_LOGGER.error('Unable to set up IQVIA: %s', err)
|
_LOGGER.error('Unable to set up IQVIA: %s', err)
|
||||||
hass.components.persistent_notification.create(
|
|
||||||
'Error: {0}<br />'
|
|
||||||
'You will need to restart hass after fixing.'
|
|
||||||
''.format(err),
|
|
||||||
title=NOTIFICATION_TITLE,
|
|
||||||
notification_id=NOTIFICATION_ID)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
hass.data[DOMAIN][DATA_CLIENT] = iqvia
|
hass.data[DOMAIN][DATA_CLIENT] = iqvia
|
||||||
|
|
||||||
discovery.load_platform(hass, 'sensor', DOMAIN, {}, conf)
|
hass.async_create_task(
|
||||||
|
async_load_platform(hass, 'sensor', DOMAIN, {}, config))
|
||||||
|
|
||||||
async def refresh(event_time):
|
async def refresh(event_time):
|
||||||
"""Refresh IQVIA data."""
|
"""Refresh IQVIA data."""
|
||||||
|
@ -86,9 +90,7 @@ async def async_setup(hass, config):
|
||||||
|
|
||||||
hass.data[DOMAIN][DATA_LISTENER] = async_track_time_interval(
|
hass.data[DOMAIN][DATA_LISTENER] = async_track_time_interval(
|
||||||
hass, refresh,
|
hass, refresh,
|
||||||
timedelta(
|
DEFAULT_SCAN_INTERVAL)
|
||||||
seconds=conf.get(
|
|
||||||
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL.seconds)))
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -103,94 +105,81 @@ class IQVIAData:
|
||||||
self.sensor_types = sensor_types
|
self.sensor_types = sensor_types
|
||||||
self.zip_code = client.zip_code
|
self.zip_code = client.zip_code
|
||||||
|
|
||||||
async def _get_data(self, method, key):
|
self.fetchers = Registry()
|
||||||
"""Return API data from a specific call."""
|
self.fetchers.register(TYPE_ALLERGY_FORECAST)(
|
||||||
from pyiqvia.errors import IQVIAError
|
self._client.allergens.extended)
|
||||||
|
self.fetchers.register(TYPE_ALLERGY_HISTORIC)(
|
||||||
try:
|
self._client.allergens.historic)
|
||||||
data = await method()
|
self.fetchers.register(TYPE_ALLERGY_OUTLOOK)(
|
||||||
self.data[key] = data
|
self._client.allergens.outlook)
|
||||||
except IQVIAError as err:
|
self.fetchers.register(TYPE_ALLERGY_INDEX)(
|
||||||
_LOGGER.error('Unable to get "%s" data: %s', key, err)
|
self._client.allergens.current)
|
||||||
self.data[key] = {}
|
self.fetchers.register(TYPE_ASTHMA_FORECAST)(
|
||||||
|
self._client.asthma.extended)
|
||||||
|
self.fetchers.register(TYPE_ASTHMA_HISTORIC)(
|
||||||
|
self._client.asthma.historic)
|
||||||
|
self.fetchers.register(TYPE_ASTHMA_INDEX)(self._client.asthma.current)
|
||||||
|
self.fetchers.register(TYPE_DISEASE_FORECAST)(
|
||||||
|
self._client.disease.extended)
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update IQVIA data."""
|
"""Update IQVIA data."""
|
||||||
from pyiqvia.errors import InvalidZipError
|
tasks = {}
|
||||||
|
|
||||||
|
for conditions, fetcher_types in FETCHER_MAPPING.items():
|
||||||
|
if not any(c in self.sensor_types for c in conditions):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for fetcher_type in fetcher_types:
|
||||||
|
tasks[fetcher_type] = self.fetchers[fetcher_type]()
|
||||||
|
|
||||||
|
results = await asyncio.gather(*tasks.values(), return_exceptions=True)
|
||||||
|
|
||||||
# IQVIA sites require a bit more complicated error handling, given that
|
# IQVIA sites require a bit more complicated error handling, given that
|
||||||
# it sometimes has parts (but not the whole thing) go down:
|
# they sometimes have parts (but not the whole thing) go down:
|
||||||
#
|
|
||||||
# 1. If `InvalidZipError` is thrown, quit everything immediately.
|
# 1. If `InvalidZipError` is thrown, quit everything immediately.
|
||||||
# 2. If an individual request throws any other error, try the others.
|
# 2. If a single request throws any other error, try the others.
|
||||||
try:
|
for key, result in zip(tasks, results):
|
||||||
if TYPE_ALLERGY_FORECAST in self.sensor_types:
|
if isinstance(result, InvalidZipError):
|
||||||
await self._get_data(
|
_LOGGER.error("No data for ZIP: %s", self._client.zip_code)
|
||||||
self._client.allergens.extended, TYPE_ALLERGY_FORECAST)
|
|
||||||
await self._get_data(
|
|
||||||
self._client.allergens.outlook, TYPE_ALLERGY_OUTLOOK)
|
|
||||||
|
|
||||||
if TYPE_ALLERGY_HISTORIC in self.sensor_types:
|
|
||||||
await self._get_data(
|
|
||||||
self._client.allergens.historic, TYPE_ALLERGY_HISTORIC)
|
|
||||||
|
|
||||||
if any(s in self.sensor_types
|
|
||||||
for s in [TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
|
||||||
TYPE_ALLERGY_YESTERDAY]):
|
|
||||||
await self._get_data(
|
|
||||||
self._client.allergens.current, TYPE_ALLERGY_INDEX)
|
|
||||||
|
|
||||||
if TYPE_ASTHMA_FORECAST in self.sensor_types:
|
|
||||||
await self._get_data(
|
|
||||||
self._client.asthma.extended, TYPE_ASTHMA_FORECAST)
|
|
||||||
|
|
||||||
if TYPE_ASTHMA_HISTORIC in self.sensor_types:
|
|
||||||
await self._get_data(
|
|
||||||
self._client.asthma.historic, TYPE_ASTHMA_HISTORIC)
|
|
||||||
|
|
||||||
if any(s in self.sensor_types
|
|
||||||
for s in [TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
|
||||||
TYPE_ASTHMA_YESTERDAY]):
|
|
||||||
await self._get_data(
|
|
||||||
self._client.asthma.current, TYPE_ASTHMA_INDEX)
|
|
||||||
|
|
||||||
if TYPE_DISEASE_FORECAST in self.sensor_types:
|
|
||||||
await self._get_data(
|
|
||||||
self._client.disease.extended, TYPE_DISEASE_FORECAST)
|
|
||||||
|
|
||||||
_LOGGER.debug("New data retrieved: %s", self.data)
|
|
||||||
except InvalidZipError:
|
|
||||||
_LOGGER.error(
|
|
||||||
"Cannot retrieve data for ZIP code: %s", self._client.zip_code)
|
|
||||||
self.data = {}
|
self.data = {}
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(result, IQVIAError):
|
||||||
|
_LOGGER.error('Unable to get %s data: %s', key, result)
|
||||||
|
self.data[key] = {}
|
||||||
|
continue
|
||||||
|
|
||||||
|
_LOGGER.debug('Loaded new %s data', key)
|
||||||
|
self.data[key] = result
|
||||||
|
|
||||||
|
|
||||||
class IQVIAEntity(Entity):
|
class IQVIAEntity(Entity):
|
||||||
"""Define a base IQVIA entity."""
|
"""Define a base IQVIA entity."""
|
||||||
|
|
||||||
def __init__(self, iqvia, kind, name, icon, zip_code):
|
def __init__(self, iqvia, sensor_type, name, icon, zip_code):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
self._async_unsub_dispatcher_connect = None
|
self._async_unsub_dispatcher_connect = None
|
||||||
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
|
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
|
||||||
self._icon = icon
|
self._icon = icon
|
||||||
self._iqvia = iqvia
|
self._iqvia = iqvia
|
||||||
self._kind = kind
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._state = None
|
self._state = None
|
||||||
|
self._type = sensor_type
|
||||||
self._zip_code = zip_code
|
self._zip_code = zip_code
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
if self._kind in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
if self._type in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
||||||
TYPE_ALLERGY_YESTERDAY):
|
TYPE_ALLERGY_YESTERDAY):
|
||||||
return self._iqvia.data.get(TYPE_ALLERGY_INDEX) is not None
|
return self._iqvia.data.get(TYPE_ALLERGY_INDEX) is not None
|
||||||
|
|
||||||
if self._kind in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
if self._type in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
||||||
TYPE_ASTHMA_YESTERDAY):
|
TYPE_ASTHMA_YESTERDAY):
|
||||||
return self._iqvia.data.get(TYPE_ASTHMA_INDEX) is not None
|
return self._iqvia.data.get(TYPE_ASTHMA_INDEX) is not None
|
||||||
|
|
||||||
return self._iqvia.data.get(self._kind) is not None
|
return self._iqvia.data.get(self._type) is not None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
|
@ -215,7 +204,7 @@ class IQVIAEntity(Entity):
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique, HASS-friendly identifier for this entity."""
|
"""Return a unique, HASS-friendly identifier for this entity."""
|
||||||
return '{0}_{1}'.format(self._zip_code, self._kind)
|
return '{0}_{1}'.format(self._zip_code, self._type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
|
|
|
@ -22,24 +22,15 @@ TYPE_ASTHMA_YESTERDAY = 'asthma_index_yesterday'
|
||||||
TYPE_DISEASE_FORECAST = 'disease_average_forecasted'
|
TYPE_DISEASE_FORECAST = 'disease_average_forecasted'
|
||||||
|
|
||||||
SENSORS = {
|
SENSORS = {
|
||||||
TYPE_ALLERGY_FORECAST: (
|
TYPE_ALLERGY_FORECAST: ('Allergy Index: Forecasted Average', 'mdi:flower'),
|
||||||
'ForecastSensor', 'Allergy Index: Forecasted Average', 'mdi:flower'),
|
TYPE_ALLERGY_HISTORIC: ('Allergy Index: Historical Average', 'mdi:flower'),
|
||||||
TYPE_ALLERGY_HISTORIC: (
|
TYPE_ALLERGY_TODAY: ('Allergy Index: Today', 'mdi:flower'),
|
||||||
'HistoricalSensor', 'Allergy Index: Historical Average', 'mdi:flower'),
|
TYPE_ALLERGY_TOMORROW: ('Allergy Index: Tomorrow', 'mdi:flower'),
|
||||||
TYPE_ALLERGY_TODAY: ('IndexSensor', 'Allergy Index: Today', 'mdi:flower'),
|
TYPE_ALLERGY_YESTERDAY: ('Allergy Index: Yesterday', 'mdi:flower'),
|
||||||
TYPE_ALLERGY_TOMORROW: (
|
TYPE_ASTHMA_TODAY: ('Asthma Index: Today', 'mdi:flower'),
|
||||||
'IndexSensor', 'Allergy Index: Tomorrow', 'mdi:flower'),
|
TYPE_ASTHMA_TOMORROW: ('Asthma Index: Tomorrow', 'mdi:flower'),
|
||||||
TYPE_ALLERGY_YESTERDAY: (
|
TYPE_ASTHMA_YESTERDAY: ('Asthma Index: Yesterday', 'mdi:flower'),
|
||||||
'IndexSensor', 'Allergy Index: Yesterday', 'mdi:flower'),
|
TYPE_ASTHMA_FORECAST: ('Asthma Index: Forecasted Average', 'mdi:flower'),
|
||||||
TYPE_ASTHMA_TODAY: ('IndexSensor', 'Asthma Index: Today', 'mdi:flower'),
|
TYPE_ASTHMA_HISTORIC: ('Asthma Index: Historical Average', 'mdi:flower'),
|
||||||
TYPE_ASTHMA_TOMORROW: (
|
TYPE_DISEASE_FORECAST: ('Cold & Flu: Forecasted Average', 'mdi:snowflake')
|
||||||
'IndexSensor', 'Asthma Index: Tomorrow', 'mdi:flower'),
|
|
||||||
TYPE_ASTHMA_YESTERDAY: (
|
|
||||||
'IndexSensor', 'Asthma Index: Yesterday', 'mdi:flower'),
|
|
||||||
TYPE_ASTHMA_FORECAST: (
|
|
||||||
'ForecastSensor', 'Asthma Index: Forecasted Average', 'mdi:flower'),
|
|
||||||
TYPE_ASTHMA_HISTORIC: (
|
|
||||||
'HistoricalSensor', 'Asthma Index: Historical Average', 'mdi:flower'),
|
|
||||||
TYPE_DISEASE_FORECAST: (
|
|
||||||
'ForecastSensor', 'Cold & Flu: Forecasted Average', 'mdi:snowflake')
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,15 @@
|
||||||
import logging
|
import logging
|
||||||
from statistics import mean
|
from statistics import mean
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from homeassistant.components.iqvia import (
|
from homeassistant.components.iqvia import (
|
||||||
DATA_CLIENT, DOMAIN, SENSORS, TYPE_ALLERGY_FORECAST, TYPE_ALLERGY_OUTLOOK,
|
DATA_CLIENT, DOMAIN, SENSORS, TYPE_ALLERGY_FORECAST, TYPE_ALLERGY_HISTORIC,
|
||||||
TYPE_ALLERGY_INDEX, TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
TYPE_ALLERGY_OUTLOOK, TYPE_ALLERGY_INDEX, TYPE_ALLERGY_TODAY,
|
||||||
TYPE_ALLERGY_YESTERDAY, TYPE_ASTHMA_INDEX, TYPE_ASTHMA_TODAY,
|
TYPE_ALLERGY_TOMORROW, TYPE_ALLERGY_YESTERDAY, TYPE_ASTHMA_FORECAST,
|
||||||
TYPE_ASTHMA_TOMORROW, TYPE_ASTHMA_YESTERDAY, IQVIAEntity)
|
TYPE_ASTHMA_HISTORIC, TYPE_ASTHMA_INDEX, TYPE_ASTHMA_TODAY,
|
||||||
|
TYPE_ASTHMA_TOMORROW, TYPE_ASTHMA_YESTERDAY, TYPE_DISEASE_FORECAST,
|
||||||
|
IQVIAEntity)
|
||||||
from homeassistant.const import ATTR_STATE
|
from homeassistant.const import ATTR_STATE
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -53,11 +57,25 @@ async def async_setup_platform(
|
||||||
"""Configure the platform and add the sensors."""
|
"""Configure the platform and add the sensors."""
|
||||||
iqvia = hass.data[DOMAIN][DATA_CLIENT]
|
iqvia = hass.data[DOMAIN][DATA_CLIENT]
|
||||||
|
|
||||||
|
sensor_class_mapping = {
|
||||||
|
TYPE_ALLERGY_FORECAST: ForecastSensor,
|
||||||
|
TYPE_ALLERGY_HISTORIC: HistoricalSensor,
|
||||||
|
TYPE_ALLERGY_TODAY: IndexSensor,
|
||||||
|
TYPE_ALLERGY_TOMORROW: IndexSensor,
|
||||||
|
TYPE_ALLERGY_YESTERDAY: IndexSensor,
|
||||||
|
TYPE_ASTHMA_FORECAST: ForecastSensor,
|
||||||
|
TYPE_ASTHMA_HISTORIC: HistoricalSensor,
|
||||||
|
TYPE_ASTHMA_TODAY: IndexSensor,
|
||||||
|
TYPE_ASTHMA_TOMORROW: IndexSensor,
|
||||||
|
TYPE_ASTHMA_YESTERDAY: IndexSensor,
|
||||||
|
TYPE_DISEASE_FORECAST: ForecastSensor,
|
||||||
|
}
|
||||||
|
|
||||||
sensors = []
|
sensors = []
|
||||||
for kind in iqvia.sensor_types:
|
for sensor_type in iqvia.sensor_types:
|
||||||
sensor_class, name, icon = SENSORS[kind]
|
klass = sensor_class_mapping[sensor_type]
|
||||||
sensors.append(
|
name, icon = SENSORS[sensor_type]
|
||||||
globals()[sensor_class](iqvia, kind, name, icon, iqvia.zip_code))
|
sensors.append(klass(iqvia, sensor_type, name, icon, iqvia.zip_code))
|
||||||
|
|
||||||
async_add_entities(sensors, True)
|
async_add_entities(sensors, True)
|
||||||
|
|
||||||
|
@ -72,8 +90,6 @@ def calculate_average_rating(indices):
|
||||||
|
|
||||||
def calculate_trend(indices):
|
def calculate_trend(indices):
|
||||||
"""Calculate the "moving average" of a set of indices."""
|
"""Calculate the "moving average" of a set of indices."""
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
def moving_average(data, samples):
|
def moving_average(data, samples):
|
||||||
"""Determine the "moving average" (http://tinyurl.com/yaereb3c)."""
|
"""Determine the "moving average" (http://tinyurl.com/yaereb3c)."""
|
||||||
ret = np.cumsum(data, dtype=float)
|
ret = np.cumsum(data, dtype=float)
|
||||||
|
@ -92,11 +108,10 @@ class ForecastSensor(IQVIAEntity):
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the sensor."""
|
"""Update the sensor."""
|
||||||
await self._iqvia.async_update()
|
|
||||||
if not self._iqvia.data:
|
if not self._iqvia.data:
|
||||||
return
|
return
|
||||||
|
|
||||||
data = self._iqvia.data[self._kind].get('Location')
|
data = self._iqvia.data[self._type].get('Location')
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -115,7 +130,7 @@ class ForecastSensor(IQVIAEntity):
|
||||||
ATTR_ZIP_CODE: data['ZIP']
|
ATTR_ZIP_CODE: data['ZIP']
|
||||||
})
|
})
|
||||||
|
|
||||||
if self._kind == TYPE_ALLERGY_FORECAST:
|
if self._type == TYPE_ALLERGY_FORECAST:
|
||||||
outlook = self._iqvia.data[TYPE_ALLERGY_OUTLOOK]
|
outlook = self._iqvia.data[TYPE_ALLERGY_OUTLOOK]
|
||||||
self._attrs[ATTR_OUTLOOK] = outlook.get('Outlook')
|
self._attrs[ATTR_OUTLOOK] = outlook.get('Outlook')
|
||||||
self._attrs[ATTR_SEASON] = outlook.get('Season')
|
self._attrs[ATTR_SEASON] = outlook.get('Season')
|
||||||
|
@ -128,11 +143,10 @@ class HistoricalSensor(IQVIAEntity):
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the sensor."""
|
"""Update the sensor."""
|
||||||
await self._iqvia.async_update()
|
|
||||||
if not self._iqvia.data:
|
if not self._iqvia.data:
|
||||||
return
|
return
|
||||||
|
|
||||||
data = self._iqvia.data[self._kind].get('Location')
|
data = self._iqvia.data[self._type].get('Location')
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -155,22 +169,21 @@ class IndexSensor(IQVIAEntity):
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the sensor."""
|
"""Update the sensor."""
|
||||||
await self._iqvia.async_update()
|
|
||||||
if not self._iqvia.data:
|
if not self._iqvia.data:
|
||||||
return
|
return
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
if self._kind in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
if self._type in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
||||||
TYPE_ALLERGY_YESTERDAY):
|
TYPE_ALLERGY_YESTERDAY):
|
||||||
data = self._iqvia.data[TYPE_ALLERGY_INDEX].get('Location')
|
data = self._iqvia.data[TYPE_ALLERGY_INDEX].get('Location')
|
||||||
elif self._kind in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
elif self._type in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
||||||
TYPE_ASTHMA_YESTERDAY):
|
TYPE_ASTHMA_YESTERDAY):
|
||||||
data = self._iqvia.data[TYPE_ASTHMA_INDEX].get('Location')
|
data = self._iqvia.data[TYPE_ASTHMA_INDEX].get('Location')
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
key = self._kind.split('_')[-1].title()
|
key = self._type.split('_')[-1].title()
|
||||||
[period] = [p for p in data['periods'] if p['Type'] == key]
|
[period] = [p for p in data['periods'] if p['Type'] == key]
|
||||||
[rating] = [
|
[rating] = [
|
||||||
i['label'] for i in RATING_MAPPING
|
i['label'] for i in RATING_MAPPING
|
||||||
|
@ -184,7 +197,7 @@ class IndexSensor(IQVIAEntity):
|
||||||
ATTR_ZIP_CODE: data['ZIP']
|
ATTR_ZIP_CODE: data['ZIP']
|
||||||
})
|
})
|
||||||
|
|
||||||
if self._kind in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
if self._type in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
|
||||||
TYPE_ALLERGY_YESTERDAY):
|
TYPE_ALLERGY_YESTERDAY):
|
||||||
for idx, attrs in enumerate(period['Triggers']):
|
for idx, attrs in enumerate(period['Triggers']):
|
||||||
index = idx + 1
|
index = idx + 1
|
||||||
|
@ -196,7 +209,7 @@ class IndexSensor(IQVIAEntity):
|
||||||
'{0}_{1}'.format(ATTR_ALLERGEN_TYPE, index):
|
'{0}_{1}'.format(ATTR_ALLERGEN_TYPE, index):
|
||||||
attrs['PlantType'],
|
attrs['PlantType'],
|
||||||
})
|
})
|
||||||
elif self._kind in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
elif self._type in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW,
|
||||||
TYPE_ASTHMA_YESTERDAY):
|
TYPE_ASTHMA_YESTERDAY):
|
||||||
for idx, attrs in enumerate(period['Triggers']):
|
for idx, attrs in enumerate(period['Triggers']):
|
||||||
index = idx + 1
|
index = idx + 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue