core/homeassistant/components/iqvia/sensor.py

195 lines
5.9 KiB
Python

"""Support for IQVIA sensors."""
import logging
from statistics import mean
import numpy as np
from homeassistant.components.iqvia import (
DATA_CLIENT, DOMAIN, SENSORS, TYPE_ALLERGY_FORECAST, TYPE_ALLERGY_OUTLOOK,
TYPE_ALLERGY_INDEX, TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW,
TYPE_ASTHMA_FORECAST, TYPE_ASTHMA_INDEX, TYPE_ASTHMA_TODAY,
TYPE_ASTHMA_TOMORROW, TYPE_DISEASE_FORECAST, TYPE_DISEASE_INDEX,
TYPE_DISEASE_TODAY, IQVIAEntity)
from homeassistant.const import ATTR_STATE
_LOGGER = logging.getLogger(__name__)
ATTR_ALLERGEN_AMOUNT = 'allergen_amount'
ATTR_ALLERGEN_GENUS = 'allergen_genus'
ATTR_ALLERGEN_NAME = 'allergen_name'
ATTR_ALLERGEN_TYPE = 'allergen_type'
ATTR_CITY = 'city'
ATTR_OUTLOOK = 'outlook'
ATTR_RATING = 'rating'
ATTR_SEASON = 'season'
ATTR_TREND = 'trend'
ATTR_ZIP_CODE = 'zip_code'
RATING_MAPPING = [{
'label': 'Low',
'minimum': 0.0,
'maximum': 2.4
}, {
'label': 'Low/Medium',
'minimum': 2.5,
'maximum': 4.8
}, {
'label': 'Medium',
'minimum': 4.9,
'maximum': 7.2
}, {
'label': 'Medium/High',
'minimum': 7.3,
'maximum': 9.6
}, {
'label': 'High',
'minimum': 9.7,
'maximum': 12
}]
TREND_FLAT = 'Flat'
TREND_INCREASING = 'Increasing'
TREND_SUBSIDING = 'Subsiding'
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up IQVIA sensors based on the old way."""
pass
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up IQVIA sensors based on a config entry."""
iqvia = hass.data[DOMAIN][DATA_CLIENT][entry.entry_id]
sensor_class_mapping = {
TYPE_ALLERGY_FORECAST: ForecastSensor,
TYPE_ALLERGY_TODAY: IndexSensor,
TYPE_ALLERGY_TOMORROW: IndexSensor,
TYPE_ASTHMA_FORECAST: ForecastSensor,
TYPE_ASTHMA_TODAY: IndexSensor,
TYPE_ASTHMA_TOMORROW: IndexSensor,
TYPE_DISEASE_FORECAST: ForecastSensor,
TYPE_DISEASE_TODAY: IndexSensor,
}
sensors = []
for sensor_type in iqvia.sensor_types:
klass = sensor_class_mapping[sensor_type]
name, icon = SENSORS[sensor_type]
sensors.append(klass(iqvia, sensor_type, name, icon, iqvia.zip_code))
async_add_entities(sensors, True)
def calculate_trend(indices):
"""Calculate the "moving average" of a set of indices."""
index_range = np.arange(0, len(indices))
index_array = np.array(indices)
linear_fit = np.polyfit(index_range, index_array, 1)
slope = round(linear_fit[0], 2)
if slope > 0:
return TREND_INCREASING
if slope < 0:
return TREND_SUBSIDING
return TREND_FLAT
class ForecastSensor(IQVIAEntity):
"""Define sensor related to forecast data."""
async def async_update(self):
"""Update the sensor."""
if not self._iqvia.data:
return
data = self._iqvia.data[self._type].get('Location')
if not data or not data.get('periods'):
return
indices = [p['Index'] for p in data['periods']]
average = round(mean(indices), 1)
[rating] = [
i['label'] for i in RATING_MAPPING
if i['minimum'] <= average <= i['maximum']
]
self._attrs.update({
ATTR_CITY: data['City'].title(),
ATTR_RATING: rating,
ATTR_STATE: data['State'],
ATTR_TREND: calculate_trend(indices),
ATTR_ZIP_CODE: data['ZIP']
})
if self._type == TYPE_ALLERGY_FORECAST:
outlook = self._iqvia.data[TYPE_ALLERGY_OUTLOOK]
self._attrs[ATTR_OUTLOOK] = outlook.get('Outlook')
self._attrs[ATTR_SEASON] = outlook.get('Season')
self._state = average
class IndexSensor(IQVIAEntity):
"""Define sensor related to indices."""
async def async_update(self):
"""Update the sensor."""
if not self._iqvia.data:
return
data = {}
if self._type in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW):
data = self._iqvia.data[TYPE_ALLERGY_INDEX].get('Location')
elif self._type in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW):
data = self._iqvia.data[TYPE_ASTHMA_INDEX].get('Location')
elif self._type == TYPE_DISEASE_TODAY:
data = self._iqvia.data[TYPE_DISEASE_INDEX].get('Location')
if not data:
return
key = self._type.split('_')[-1].title()
[period] = [p for p in data['periods'] if p['Type'] == key]
[rating] = [
i['label'] for i in RATING_MAPPING
if i['minimum'] <= period['Index'] <= i['maximum']
]
self._attrs.update({
ATTR_CITY: data['City'].title(),
ATTR_RATING: rating,
ATTR_STATE: data['State'],
ATTR_ZIP_CODE: data['ZIP']
})
if self._type in (TYPE_ALLERGY_TODAY, TYPE_ALLERGY_TOMORROW):
for idx, attrs in enumerate(period['Triggers']):
index = idx + 1
self._attrs.update({
'{0}_{1}'.format(ATTR_ALLERGEN_GENUS, index):
attrs['Genus'],
'{0}_{1}'.format(ATTR_ALLERGEN_NAME, index):
attrs['Name'],
'{0}_{1}'.format(ATTR_ALLERGEN_TYPE, index):
attrs['PlantType'],
})
elif self._type in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW):
for idx, attrs in enumerate(period['Triggers']):
index = idx + 1
self._attrs.update({
'{0}_{1}'.format(ATTR_ALLERGEN_NAME, index):
attrs['Name'],
'{0}_{1}'.format(ATTR_ALLERGEN_AMOUNT, index):
attrs['PPM'],
})
elif self._type == TYPE_DISEASE_TODAY:
for attrs in period['Triggers']:
self._attrs['{0}_index'.format(
attrs['Name'].lower())] = attrs['Index']
self._state = period['Index']