core/homeassistant/components/flunearyou/sensor.py

210 lines
6.5 KiB
Python

"""Support for user- and CDC-based flu info sensors from Flu Near You."""
from homeassistant.const import (
ATTR_ATTRIBUTION,
ATTR_STATE,
CONF_LATITUDE,
CONF_LONGITUDE,
)
from homeassistant.core import callback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import CATEGORY_CDC_REPORT, CATEGORY_USER_REPORT, DATA_COORDINATOR, DOMAIN
ATTR_CITY = "city"
ATTR_REPORTED_DATE = "reported_date"
ATTR_REPORTED_LATITUDE = "reported_latitude"
ATTR_REPORTED_LONGITUDE = "reported_longitude"
ATTR_STATE_REPORTS_LAST_WEEK = "state_reports_last_week"
ATTR_STATE_REPORTS_THIS_WEEK = "state_reports_this_week"
ATTR_ZIP_CODE = "zip_code"
DEFAULT_ATTRIBUTION = "Data provided by Flu Near You"
SENSOR_TYPE_CDC_LEVEL = "level"
SENSOR_TYPE_CDC_LEVEL2 = "level2"
SENSOR_TYPE_USER_CHICK = "chick"
SENSOR_TYPE_USER_DENGUE = "dengue"
SENSOR_TYPE_USER_FLU = "flu"
SENSOR_TYPE_USER_LEPTO = "lepto"
SENSOR_TYPE_USER_NO_SYMPTOMS = "none"
SENSOR_TYPE_USER_SYMPTOMS = "symptoms"
SENSOR_TYPE_USER_TOTAL = "total"
CDC_SENSORS = [
(SENSOR_TYPE_CDC_LEVEL, "CDC Level", "mdi:biohazard", None),
(SENSOR_TYPE_CDC_LEVEL2, "CDC Level 2", "mdi:biohazard", None),
]
USER_SENSORS = [
(SENSOR_TYPE_USER_CHICK, "Avian Flu Symptoms", "mdi:alert", "reports"),
(SENSOR_TYPE_USER_DENGUE, "Dengue Fever Symptoms", "mdi:alert", "reports"),
(SENSOR_TYPE_USER_FLU, "Flu Symptoms", "mdi:alert", "reports"),
(SENSOR_TYPE_USER_LEPTO, "Leptospirosis Symptoms", "mdi:alert", "reports"),
(SENSOR_TYPE_USER_NO_SYMPTOMS, "No Symptoms", "mdi:alert", "reports"),
(SENSOR_TYPE_USER_SYMPTOMS, "Flu-like Symptoms", "mdi:alert", "reports"),
(SENSOR_TYPE_USER_TOTAL, "Total Symptoms", "mdi:alert", "reports"),
]
EXTENDED_SENSOR_TYPE_MAPPING = {
SENSOR_TYPE_USER_FLU: "ili",
SENSOR_TYPE_USER_NO_SYMPTOMS: "no_symptoms",
SENSOR_TYPE_USER_TOTAL: "total_surveys",
}
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Flu Near You sensors based on a config entry."""
coordinators = hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id]
sensors = []
for (sensor_type, name, icon, unit) in CDC_SENSORS:
sensors.append(
CdcSensor(
coordinators[CATEGORY_CDC_REPORT],
config_entry,
sensor_type,
name,
icon,
unit,
)
)
for (sensor_type, name, icon, unit) in USER_SENSORS:
sensors.append(
UserSensor(
coordinators[CATEGORY_USER_REPORT],
config_entry,
sensor_type,
name,
icon,
unit,
)
)
async_add_entities(sensors)
class FluNearYouSensor(CoordinatorEntity):
"""Define a base Flu Near You sensor."""
def __init__(self, coordinator, config_entry, sensor_type, name, icon, unit):
"""Initialize the sensor."""
super().__init__(coordinator)
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._config_entry = config_entry
self._icon = icon
self._name = name
self._sensor_type = sensor_type
self._state = None
self._unit = unit
@property
def extra_state_attributes(self):
"""Return the device state attributes."""
return self._attrs
@property
def icon(self):
"""Return the icon."""
return self._icon
@property
def name(self):
"""Return the name."""
return self._name
@property
def state(self):
"""Return the state."""
return self._state
@property
def unique_id(self):
"""Return a unique, Home Assistant friendly identifier for this entity."""
return (
f"{self._config_entry.data[CONF_LATITUDE]},"
f"{self._config_entry.data[CONF_LONGITUDE]}_{self._sensor_type}"
)
@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self.update_from_latest_data()
self.async_write_ha_state()
async def async_added_to_hass(self):
"""Register callbacks."""
await super().async_added_to_hass()
self.update_from_latest_data()
@callback
def update_from_latest_data(self):
"""Update the sensor."""
raise NotImplementedError
class CdcSensor(FluNearYouSensor):
"""Define a sensor for CDC reports."""
@callback
def update_from_latest_data(self):
"""Update the sensor."""
self._attrs.update(
{
ATTR_REPORTED_DATE: self.coordinator.data["week_date"],
ATTR_STATE: self.coordinator.data["name"],
}
)
self._state = self.coordinator.data[self._sensor_type]
class UserSensor(FluNearYouSensor):
"""Define a sensor for user reports."""
@callback
def update_from_latest_data(self):
"""Update the sensor."""
self._attrs.update(
{
ATTR_CITY: self.coordinator.data["local"]["city"].split("(")[0],
ATTR_REPORTED_LATITUDE: self.coordinator.data["local"]["latitude"],
ATTR_REPORTED_LONGITUDE: self.coordinator.data["local"]["longitude"],
ATTR_STATE: self.coordinator.data["state"]["name"],
ATTR_ZIP_CODE: self.coordinator.data["local"]["zip"],
}
)
if self._sensor_type in self.coordinator.data["state"]["data"]:
states_key = self._sensor_type
elif self._sensor_type in EXTENDED_SENSOR_TYPE_MAPPING:
states_key = EXTENDED_SENSOR_TYPE_MAPPING[self._sensor_type]
self._attrs[ATTR_STATE_REPORTS_THIS_WEEK] = self.coordinator.data["state"][
"data"
][states_key]
self._attrs[ATTR_STATE_REPORTS_LAST_WEEK] = self.coordinator.data["state"][
"last_week_data"
][states_key]
if self._sensor_type == SENSOR_TYPE_USER_TOTAL:
self._state = sum(
v
for k, v in self.coordinator.data["local"].items()
if k
in (
SENSOR_TYPE_USER_CHICK,
SENSOR_TYPE_USER_DENGUE,
SENSOR_TYPE_USER_FLU,
SENSOR_TYPE_USER_LEPTO,
SENSOR_TYPE_USER_SYMPTOMS,
)
)
else:
self._state = self.coordinator.data["local"][self._sensor_type]