def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Pollen sensor.""" name = config.get(CONF_NAME) sensors = config.get(CONF_SENSORS) state_as_string = config.get(CONF_STATE_AS_STRING) method = 'GET' payload = '' auth = '' verify_ssl = DEFAULT_VERIFY_SSL headers = {} rest = RestData(method, _ENDPOINT, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: _LOGGER.error("Unable to fetch data from Pollenkollen") return False devices = [] for sensor in sensors: if 'days_to_track' in sensor: for day in range(int(sensor['days_to_track'])): for allergen in sensor['allergens']: devices.append( PollenkollSensor(rest, name, sensor, allergen, state_as_string, day)) else: for allergen in sensor['allergens']: devices.append( PollenkollSensor(rest, name, sensor, allergen, state_as_string)) add_devices(devices, True)
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the PVOutput sensor.""" name = config.get(CONF_NAME) sensors = config.get('sensors') method = 'GET' payload = '' auth = '' verify_ssl = DEFAULT_VERIFY_SSL headers = {} rest = RestData(method, _ENDPOINT, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: _LOGGER.error("Unable to fetch data from Pollenkollen") return False for sensor in sensors: if 'days_to_track' in sensor: i = 0 while i <= sensor['days_to_track']: for allergen in sensor['allergens']: add_devices([PollenkollSensor(rest, name, sensor, allergen, i)], True) i += 1 else: for allergen in sensor['allergens']: add_devices([PollenkollSensor(rest, name, sensor, allergen, 0)], True)
def __init__(self, hass, config, add_sensors_callback): self._hass = hass self._sensors = {} self._add_sensors_callback = add_sensors_callback verify_ssl = True self._url = config.get(CONF_URL) self._rest = RestData('GET', self._url, '', '', '', verify_ssl) # query the latest data from Pool Math soup = self._fetch_latest_data() if soup is None: raise PlatformNotReady self._name = config.get(CONF_NAME) if self._name == None: self._name = DEFAULT_NAME # extract the pool name, if defined h1_span = soup.select('h1') if h1_span and h1_span[0]: pool_name = h1_span[0].string if pool_name != None: self._name = f"{pool_name} {DEFAULT_NAME}" LOG.info(f"Creating Pool Math sensors for '{self._name}'") self._update_from_log_entries(soup)
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Web scrape sensor.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) method = 'GET' payload = None headers = config.get(CONF_HEADERS) verify_ssl = config.get(CONF_VERIFY_SSL) select = config.get(CONF_SELECT) attr = config.get(CONF_ATTR) index = config.get(CONF_INDEX) unit = config.get(CONF_UNIT_OF_MEASUREMENT) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) value_template = config.get(CONF_VALUE_TEMPLATE) if value_template is not None: value_template.hass = hass if username and password: if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION: auth = HTTPDigestAuth(username, password) else: auth = HTTPBasicAuth(username, password) else: auth = None rest = RestData(method, resource, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: raise PlatformNotReady add_entities([ ScrapeSensor(rest, name, select, attr, index, value_template, unit)], True)
class MoonPhaseHereAPI(object): """Get the latest data and update the states.""" def __init__(self, app_id, app_code, zipcode): """Initialize the data object.""" from homeassistant.components.rest.sensor import RestData resource = "{}app_id={}&app_code={}&zipcode={}".format( _ENDPOINT, app_id, app_code, zipcode) self._rest = RestData('GET', resource, None, None, None, False) self.data = None self.available = True self.update() @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Get the latest data from Here.""" try: self._rest.update() self.data = json.loads(self._rest.data) self._last_updated = dt_util.now().isoformat() _LOGGER.debug("Moon sensor updated") self.available = True except TypeError: _LOGGER.debug("Unable to fetch data from Here") self.available = False
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Doomsday Clock sensor.""" name = config.get(CONF_NAME) resource = CONF_RESOURCE method = 'GET' selector = CONF_SELECTOR payload = headers = auth = None verify_ssl = False unit_of_measurement = config.get(CONF_UNIT_OF_MEASUREMENT) icon = config.get(CONF_ICON) value_template = config.get(CONF_VALUE_TEMPLATE) if value_template is not None: value_template.hass = hass rest = RestData(method, resource, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: _LOGGER.error("Unable to fetch URL: %s", resource) return False add_entities([ DoomsdayClockSensor(rest, name, selector, unit_of_measurement, icon, value_template) ], True)
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Web scrape sensor.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) method = "GET" payload = None headers = config.get(CONF_HEADERS) verify_ssl = config.get(CONF_VERIFY_SSL) select = config.get(CONF_SELECT) attr = config.get(CONF_ATTR) index = config.get(CONF_INDEX) unit = config.get(CONF_UNIT_OF_MEASUREMENT) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) value_template = config.get(CONF_VALUE_TEMPLATE) if value_template is not None: value_template.hass = hass if username and password: if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION: auth = HTTPDigestAuth(username, password) else: auth = HTTPBasicAuth(username, password) else: auth = None rest = RestData(method, resource, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: raise PlatformNotReady add_entities( [ScrapeSensor(rest, name, select, attr, index, value_template, unit)], True)
def __init__(self, api_key): """Initialize the data object.""" from homeassistant.components.rest.sensor import RestData resource = "{}{}".format(_ENDPOINT, api_key) self._rest = RestData('GET', resource, None, None, None, False) self.data = None self.available = True self._rest.async_update()
def __init__(self, app_id, app_code, zipcode): """Initialize the data object.""" from homeassistant.components.rest.sensor import RestData resource = "{}app_id={}&app_code={}&zipcode={}".format( _ENDPOINT, app_id, app_code, zipcode) self._rest = RestData('GET', resource, None, None, None, False) self.data = None self.available = True self.update()
def __init__(self, partregion_ids): """Initialize the data object.""" resource = "https://opendata.dwd.de/climate_environment/health/alerts/s31fg.json" self._rest = RestData('GET', resource, None, None, None, True) self._partregion_ids = partregion_ids self.last_update = None self.sensordata = {} self.api_id_to_descr = {} self.available = False self.update()
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensor.""" district_name = config.get(CONF_DISTRICT_NAME) rest = RestData(DEFAULT_METHOD, URL, None, None, None, DEFAULT_VERIFY_SSL) rest.update() if rest.data is None: raise PlatformNotReady # Must update the sensor now (including fetching the rest resource) to # ensure it's updating its state. add_entities([NswFireServiceFireDangerSensor(hass, rest, district_name)], True)
def __init__(self, region_name): """Initialize the data object.""" resource = "https://www.dwd.de/DWD/warnungen/warnapp_landkreise/json/warnings.json?jsonp=loadWarnings" # a User-Agent is necessary for this rest api endpoint (#29496) headers = {"User-Agent": HA_USER_AGENT} self._rest = RestData("GET", resource, None, headers, None, True) self.region_name = region_name self.region_id = None self.region_state = None self.data = None self.available = True self.update()
def __init__(self, region_name): """Initialize the data object.""" resource = "{}{}{}?{}".format( 'https://', 'www.dwd.de', '/DWD/warnungen/warnapp_landkreise/json/warnings.json', 'jsonp=loadWarnings') self._rest = RestData('GET', resource, None, None, None, True) self.region_name = region_name self.region_id = None self.region_state = None self.data = None self.available = True self.update()
def setup_rest(self, endpoint, variables=None): payload = auth = headers = None verify_ssl = False method = 'GET' return RestData(method, endpoint.format(variables), auth, headers, payload, verify_ssl)
def __init__(self, api_key, user_id): """Initialize the data object.""" self.user_id = user_id self.available = True resource = "https://api.flatastic-app.com/index.php/api/chores" headers = { "Accept": "application/json, text/plain, */*", "X-Api-Key": api_key, "X-Api-Version": "2.0.0", } self._rest = RestData("GET", resource, None, headers, None, True) self.data = { "chore": None, "time_remaining": None, } self.user_chores = []
async def async_setup_scanner(hass, config, async_see, discovery_info=None): """Validate the configuration and return a Traccar scanner.""" method = 'GET' username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) json_attrs = config.get(CONF_JSON_ATTRS) force_update = config.get(CONF_FORCE_UPDATE) headers = None payload = None if username and password: if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION: auth = HTTPDigestAuth(username, password) else: auth = HTTPBasicAuth(username, password) else: auth = None rest = RestData(method, config.get(CONF_RESOURCE), auth, headers, payload, config.get(CONF_VERIFY_SSL)) scanner = RestDeviceTracker(hass, rest, async_see, config.get(CONF_NAME), config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL), config.get(CONF_DEVICE), config.get(CONF_JSON_ATTRS), config.get(CONF_FORCE_UPDATE)) return await scanner.async_init()
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensor.""" ip_address = config[CONF_IP_ADDRESS] password = config[CONF_PASSWORD] auth = HTTPBasicAuth(DEFAULT_USERNAME, password) url = URL_TEMPLATE.format(ip_address) rest = RestData(DEFAULT_METHOD, url, auth, None, None, False) rest.update() if rest.data is None: raise PlatformNotReady # Must update the sensor now (including fetching the rest resource) to # ensure it's updating its state. add_entities([NetgearCm500vModemConnectionStatus( hass, rest, ip_address)], True)
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PVOutput sensor.""" name = config.get(CONF_NAME) api_key = config.get(CONF_API_KEY) system_id = config.get(CONF_SYSTEM_ID) method = "GET" payload = auth = None verify_ssl = DEFAULT_VERIFY_SSL headers = {"X-Pvoutput-Apikey": api_key, "X-Pvoutput-SystemId": system_id} rest = RestData(method, _ENDPOINT, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: _LOGGER.error("Unable to fetch data from PVOutput") return False add_entities([PvoutputSensor(rest, name)], True)
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Pollen sensor.""" name = config.get(CONF_NAME) sensors = config.get(CONF_SENSORS) method = 'GET' payload = '' auth = '' verify_ssl = DEFAULT_VERIFY_SSL headers = {} rest = RestData(method, _ENDPOINT, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: _LOGGER.error("Unable to fetch data from Pollenkollen") return False for item in sensors: add_devices([PollenkollSensor(rest, name, item)], True)
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PVOutput sensor.""" name = config.get(CONF_NAME) api_key = config.get(CONF_API_KEY) system_id = config.get(CONF_SYSTEM_ID) method = 'GET' payload = auth = None verify_ssl = DEFAULT_VERIFY_SSL headers = { 'X-Pvoutput-Apikey': api_key, 'X-Pvoutput-SystemId': system_id, } rest = RestData(method, _ENDPOINT, auth, headers, payload, verify_ssl) rest.update() if rest.data is None: _LOGGER.error("Unable to fetch data from PVOutput") return False add_entities([PvoutputSensor(rest, name)], True)
class SectorPerfAPI(object): """Get the latest data and update the states.""" def __init__(self, api_key): """Initialize the data object.""" from homeassistant.components.rest.sensor import RestData resource = "{}{}".format(_ENDPOINT, api_key) self._rest = RestData('GET', resource, None, None, None, False) self.data = None self.available = True self._rest.async_update() @Throttle(MIN_TIME_BETWEEN_UPDATES) async def async_update(self): """Get the latest data from Alphavantage.""" try: await self._rest.async_update() self.data = json.loads(self._rest.data) self.available = True except TypeError: _LOGGER.error("Unable to fetch data from Alphavantage") self.available = False
class FlatasticAPI: """Get the latest data from Flatastic API.""" def __init__(self, api_key, user_id): """Initialize the data object.""" self.user_id = user_id self.available = True resource = "https://api.flatastic-app.com/index.php/api/chores" headers = { "Accept": "application/json, text/plain, */*", "X-Api-Key": api_key, "X-Api-Version": "2.0.0", } self._rest = RestData("GET", resource, None, headers, None, True) self.data = { "chore": None, "time_remaining": None, } self.user_chores = [] @Throttle(SCAN_INTERVAL) def update(self): """Get the latest data from Flatastic.""" try: self._rest.update() self.chores = json.loads(self._rest.data) # sort chores by their due date self.chores.sort(key=lambda chore: chore["timeLeftNext"]) for chore in self.chores: if chore.get("currentUser") == self.user_id: # self.user_chores.append(chore) self.data["chore"] = chore.get("title") self.data["time_remaining"] = int(chore.get("timeLeftNext") / 86400) break # self.data["chore"] = data.get("temperature") / 10 # self.data["time"] = datetime.fromtimestamp(timestamp / 1000).isoformat() except TypeError: _LOGGER.error("Unable to fetch data from Flatastic API") self.available = False
def __init__(self, region_name): """Initialize the data object.""" resource = "{}{}{}?{}".format( 'https://', 'www.dwd.de', '/DWD/warnungen/warnapp_landkreise/json/warnings.json', 'jsonp=loadWarnings' ) self._rest = RestData('GET', resource, None, None, None, True) self.region_name = region_name self.region_id = None self.region_state = None self.data = None self.available = True self.update()
async def add_sensors(hass, config, async_add_devices, api_key, fetch_interval, number_of_sensors, unit_of_measurement, name, update_name, location, max_journeys, time_offset, filter, discovery_info=None): method = 'GET' payload = '' auth = None verify_ssl = DEFAULT_VERIFY_SSL headers = {} params = {} timeout = 5000 time = None resource = _ENDPOINT + '&key=' + api_key + '&id=' + str( location) + '&maxJourneys=' + str(max_journeys) sensors = [] helpers = [] helper = 'helper_' + name base_resource = resource if time_offset: time = dateparser.parse("in " + str(time_offset) + " minutes") resource = resource + '&time=' + time.strftime( "%H:%M") + '&date=' + time.strftime('%Y-%m-%d') rest = RestData(hass, method, resource, auth, headers, params, payload, verify_ssl, timeout) helpers.append( helperEntity(rest, helper, fetch_interval, time_offset, base_resource, filter)) async_add_devices(helpers, True) for i in range(0, number_of_sensors): entityName = name + '_' + str(i) sensors.append( entityRepresentation(hass, helper, entityName, i, number_of_sensors, unit_of_measurement, update_name, time_offset)) async_add_devices(sensors, True)
class DwdWeatherWarningsAPI: """Get the latest data and update the states.""" def __init__(self, region_name): """Initialize the data object.""" resource = "{}{}{}?{}".format( 'https://', 'www.dwd.de', '/DWD/warnungen/warnapp_landkreise/json/warnings.json', 'jsonp=loadWarnings') self._rest = RestData('GET', resource, None, None, None, True) self.region_name = region_name self.region_id = None self.region_state = None self.data = None self.available = True self.update() @Throttle(SCAN_INTERVAL) def update(self): """Get the latest data from the DWD-Weather-Warnings.""" try: self._rest.update() json_string = self._rest.data[24:len(self._rest.data) - 2] json_obj = json.loads(json_string) data = {'time': json_obj['time']} for mykey, myvalue in { 'current': 'warnings', 'advance': 'vorabInformation' }.items(): _LOGGER.debug("Found %d %s global DWD warnings", len(json_obj[myvalue]), mykey) data['{}_warning_level'.format(mykey)] = 0 my_warnings = [] if self.region_id is not None: # get a specific region_id if self.region_id in json_obj[myvalue]: my_warnings = json_obj[myvalue][self.region_id] else: # loop through all items to find warnings, region_id # and region_state for region_name for key in json_obj[myvalue]: my_region = json_obj[myvalue][key][0]['regionName'] if my_region != self.region_name: continue my_warnings = json_obj[myvalue][key] my_state = json_obj[myvalue][key][0]['stateShort'] self.region_id = key self.region_state = my_state break # Get max warning level maxlevel = data['{}_warning_level'.format(mykey)] for event in my_warnings: if event['level'] >= maxlevel: data['{}_warning_level'.format(mykey)] = event['level'] data['{}_warning_count'.format(mykey)] = len(my_warnings) data['{}_warnings'.format(mykey)] = my_warnings _LOGGER.debug("Found %d %s local DWD warnings", len(my_warnings), mykey) self.data = data self.available = True except TypeError: _LOGGER.error("Unable to fetch data from DWD-Weather-Warnings") self.available = False
class DwdWeatherWarningsAPI: """Get the latest data and update the states.""" def __init__(self, region_name): """Initialize the data object.""" resource = "{}{}{}?{}".format( 'https://', 'www.dwd.de', '/DWD/warnungen/warnapp_landkreise/json/warnings.json', 'jsonp=loadWarnings' ) self._rest = RestData('GET', resource, None, None, None, True) self.region_name = region_name self.region_id = None self.region_state = None self.data = None self.available = True self.update() @Throttle(SCAN_INTERVAL) def update(self): """Get the latest data from the DWD-Weather-Warnings.""" try: self._rest.update() json_string = self._rest.data[24:len(self._rest.data) - 2] json_obj = json.loads(json_string) data = {'time': json_obj['time']} for mykey, myvalue in { 'current': 'warnings', 'advance': 'vorabInformation' }.items(): _LOGGER.debug("Found %d %s global DWD warnings", len(json_obj[myvalue]), mykey) data['{}_warning_level'.format(mykey)] = 0 my_warnings = [] if self.region_id is not None: # get a specific region_id if self.region_id in json_obj[myvalue]: my_warnings = json_obj[myvalue][self.region_id] else: # loop through all items to find warnings, region_id # and region_state for region_name for key in json_obj[myvalue]: my_region = json_obj[myvalue][key][0]['regionName'] if my_region != self.region_name: continue my_warnings = json_obj[myvalue][key] my_state = json_obj[myvalue][key][0]['stateShort'] self.region_id = key self.region_state = my_state break # Get max warning level maxlevel = data['{}_warning_level'.format(mykey)] for event in my_warnings: if event['level'] >= maxlevel: data['{}_warning_level'.format(mykey)] = event['level'] data['{}_warning_count'.format(mykey)] = len(my_warnings) data['{}_warnings'.format(mykey)] = my_warnings _LOGGER.debug("Found %d %s local DWD warnings", len(my_warnings), mykey) self.data = data self.available = True except TypeError: _LOGGER.error("Unable to fetch data from DWD-Weather-Warnings") self.available = False
class DwdWeatherWarningsAPI: """Get the latest data and update the states.""" def __init__(self, region_name): """Initialize the data object.""" resource = "https://www.dwd.de/DWD/warnungen/warnapp_landkreise/json/warnings.json?jsonp=loadWarnings" # a User-Agent is necessary for this rest api endpoint (#29496) headers = {"User-Agent": HA_USER_AGENT} self._rest = RestData("GET", resource, None, headers, None, True) self.region_name = region_name self.region_id = None self.region_state = None self.data = None self.available = True self.update() @Throttle(SCAN_INTERVAL) def update(self): """Get the latest data from the DWD-Weather-Warnings.""" try: self._rest.update() json_string = self._rest.data[24:len(self._rest.data) - 2] json_obj = json.loads(json_string) data = {"time": json_obj["time"]} for mykey, myvalue in { "current": "warnings", "advance": "vorabInformation", }.items(): _LOGGER.debug("Found %d %s global DWD warnings", len(json_obj[myvalue]), mykey) data[f"{mykey}_warning_level"] = 0 my_warnings = [] if self.region_id is not None: # get a specific region_id if self.region_id in json_obj[myvalue]: my_warnings = json_obj[myvalue][self.region_id] else: # loop through all items to find warnings, region_id # and region_state for region_name for key in json_obj[myvalue]: my_region = json_obj[myvalue][key][0]["regionName"] if my_region != self.region_name: continue my_warnings = json_obj[myvalue][key] my_state = json_obj[myvalue][key][0]["stateShort"] self.region_id = key self.region_state = my_state break # Get max warning level maxlevel = data[f"{mykey}_warning_level"] for event in my_warnings: if event["level"] >= maxlevel: data[f"{mykey}_warning_level"] = event["level"] data[f"{mykey}_warning_count"] = len(my_warnings) data[f"{mykey}_warnings"] = my_warnings _LOGGER.debug("Found %d %s local DWD warnings", len(my_warnings), mykey) self.data = data self.available = True except TypeError: _LOGGER.error("Unable to fetch data from DWD-Weather-Warnings") self.available = False
class PoolMathClient(): def __init__(self, hass, config, add_sensors_callback): self._hass = hass self._sensors = {} self._add_sensors_callback = add_sensors_callback verify_ssl = True self._url = config.get(CONF_URL) self._rest = RestData('GET', self._url, '', '', '', verify_ssl) # query the latest data from Pool Math soup = self._fetch_latest_data() if soup is None: raise PlatformNotReady self._name = config.get(CONF_NAME) if self._name == None: self._name = DEFAULT_NAME # extract the pool name, if defined h1_span = soup.select('h1') if h1_span and h1_span[0]: pool_name = h1_span[0].string if pool_name != None: self._name = f"{pool_name} {DEFAULT_NAME}" LOG.info(f"Creating Pool Math sensors for '{self._name}'") self._update_from_log_entries(soup) def _fetch_latest_data(self): """Fetch the latest log entries from the Pool Math service""" self._rest.update() result = self._rest.data if result is None: LOG.warn(f"Failed updating Pool Math data from {self._url}") return None soup = BeautifulSoup(result, 'html.parser') #LOG.debug("Raw data from %s: %s", self._url, soup) return soup def update(self): soup = self._fetch_latest_data() if not soup: return None return self._update_from_log_entries(soup) def get_sensor(self, sensor_type): sensor = self._sensors.get(sensor_type, None) if sensor: return sensor config = POOL_MATH_SENSOR_SETTINGS.get(sensor_type, None) if config is None: LOG.warning( f"Unknown Pool Math sensor '{sensor_type}' discovered at {self._url}" ) return None name = self._name + ' ' + config['name'] sensor = UpdatableSensor(self._hass, name, config) self._sensors[sensor_type] = sensor # register sensor with Home Assistant self._add_sensors_callback([sensor], True) return sensor def _update_from_log_entries(self, poolmath_soup): updated_sensors = {} latest_timestamp = None # Read back through all log entries and update any changed sensor states (since a given # log entry may only have a subset of sensor states) log_entries = poolmath_soup.find_all('div', class_='testLogCard') for log_entry in log_entries: log_fields = log_entry.select('.chiclet') LOG.debug("Pool Math log fields=%s", log_fields) if not latest_timestamp: # capture the timestamp for the most recent Pool Math log entry latest_timestamp = log_entry.find('time', class_='timestamp timereal') # FIXME: improve parsing to be more robust to Pool Math changes for entry in log_fields: sensor_type = entry.contents[3].text.lower() if not sensor_type in updated_sensors: state = entry.contents[1].text sensor = self.get_sensor(sensor_type) if sensor: timestamp = log_entry.find( 'time', class_='timestamp timereal').text if sensor.state != state: LOG.info( f"Pool Math returned updated {sensor_type}={state} (timestamp={timestamp})" ) sensor.inject_state(state, timestamp) updated_sensors[sensor_type] = sensor # record the most recent log entry's timestamp as the service's last updated timestamp self._timestamp = latest_timestamp return latest_timestamp @property def sensor_names(self): return self._sensors.keys() @property def latest_log_timestamp(self): return self._timestamp
class DwdPollenAPI: """ Get the latest data and update the states. Format of map sensordata: sensordata[<region_id>]['region_name'] sensordata[<region_id>]['partregion_name'] sensordata[<region_id>]['pollendata'][<pollen_name>]['today'|'today_mapped'|'tomorrow'|'tomorrow_mapped'|'dayafter_tomorrow'|'dayafter_tomorrow_mapped'] """ def __init__(self, partregion_ids): """Initialize the data object.""" resource = "https://opendata.dwd.de/climate_environment/health/alerts/s31fg.json" self._rest = RestData('GET', resource, None, None, None, True) self._partregion_ids = partregion_ids self.last_update = None self.sensordata = {} self.api_id_to_descr = {} self.available = False self.update() @Throttle(SCAN_INTERVAL) def update(self): """Get the latest pollen_name data from DWD open data site.""" try: # Update DWD weather data by calling rest service self._rest.update() # Retrieve REST data from correspionding object rest_api_result = json.loads(self._rest.data) self.last_update = datetime.strptime(rest_api_result[REST_API_KEY_LAST_UPDATE], '%Y-%m-%d %H:%M Uhr') self.generate_api_id_to_descr_map(rest_api_result) # Iterate over all supplied partregions for partregion_data in rest_api_result[REST_API_KEY_CONTENT]: current_partregion_id = partregion_data[REST_API_KEY_PARTREGION_ID] if current_partregion_id == -1: current_partregion_id = partregion_data[REST_API_KEY_REGION_ID] # Is the current partregion_id included in the ones we should parse? if current_partregion_id in self._partregion_ids: self.sensordata[current_partregion_id] = {} self.sensordata[current_partregion_id][SENSORDATA_REGION_NAME] = partregion_data[ REST_API_KEY_REGION_NAME] self.sensordata[current_partregion_id][SENSORDATA_PARTREGION_NAME] = partregion_data[ REST_API_KEY_PARTREGION_NAME] self.sensordata[current_partregion_id]['data'] = {} self.calculateit(current_partregion_id, partregion_data[REST_API_KEY_POLLEN], 'today', self.last_update.date()) self.calculateit(current_partregion_id, partregion_data[REST_API_KEY_POLLEN], 'tomorrow', self.last_update.date() + timedelta(days=1)) self.calculateit(current_partregion_id, partregion_data[REST_API_KEY_POLLEN], 'dayafter_to', self.last_update.date() + timedelta(days=2)) self.available = True except TypeError: _LOGGER.error("Unable to fetch pollen_name data from DWD opendata server") self.available = False def calculateit(self, current_partregion_id, pollendata, day, pollen_date): """ Format: { "41": { "region_name": "<region name>", "partregion_name": "<partregion name>", "data": { "<pollen_date1>": { "pollendata": { "<polle1>": { "id": "<api ID>", "descr": "<api description of api ID>", "value": "<sensor value>" }, "<polle2>": { "id": "<api ID>", "descr": "<api description of api ID>", "value": "<sensor value>" } [...] }, "stats": { "min": <minimum value>, "max": <maximum value>, "avg": <average value> } }, [...] } } } """ minimum = None # minimum = 6 maximum = None # maximum = 0 total_count = None # total_count = 0 total_sum = None # total_sum = 0 self.sensordata[current_partregion_id]['data'][pollen_date] = {} self.sensordata[current_partregion_id]['data'][pollen_date][SENSORDATA_POLLENDATA] = {} for pollen_name in pollendata: retrieved_pollendata = pollendata[pollen_name] internal_pollen_id = str(pollen_name).lower() self.sensordata[current_partregion_id]['data'][pollen_date][SENSORDATA_POLLENDATA][internal_pollen_id] = {} pollen_amount_api_id = retrieved_pollendata[day] pollen_amount_descr = self.api_id_to_descr[pollen_amount_api_id] pollen_amount_value = API_TO_HOMEASSISTANT_MAP[pollen_amount_api_id] self.sensordata[current_partregion_id]['data'][pollen_date][SENSORDATA_POLLENDATA][internal_pollen_id][ 'id'] = pollen_amount_api_id self.sensordata[current_partregion_id]['data'][pollen_date][SENSORDATA_POLLENDATA][internal_pollen_id][ 'descr'] = pollen_amount_descr self.sensordata[current_partregion_id]['data'][pollen_date][SENSORDATA_POLLENDATA][internal_pollen_id][ 'value'] = pollen_amount_value if pollen_amount_value is not None: minimum = pollen_amount_value if minimum is None else min(minimum, pollen_amount_value) maximum = pollen_amount_value if maximum is None else max(maximum, pollen_amount_value) total_count = 1 if total_count is None else total_count + 1 total_sum = pollen_amount_value if total_sum is None else total_sum + pollen_amount_value _LOGGER.debug("Successfully retrieved pollen_name data for %s (ID %d).", self.sensordata[current_partregion_id][SENSORDATA_PARTREGION_NAME], current_partregion_id) self.sensordata[current_partregion_id]['data'][pollen_date]['stats'] = {} self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_MIN] = {} self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_MIN]['value'] = minimum minimum_api_id = HOMEASSISTANT_TO_API_MAP[minimum] self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_MIN]['descr'] = self.api_id_to_descr[minimum_api_id] self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_MAX] = {} self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_MAX]['value'] = maximum maximum_api_id = HOMEASSISTANT_TO_API_MAP[maximum] self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_MAX]['descr'] = self.api_id_to_descr[maximum_api_id] if total_count is None or total_sum is None or total_count <= 0: average = None else: average = total_sum / total_count self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_AVG] = {} self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_AVG]['value'] = average average_api_id = None if average is None else HOMEASSISTANT_TO_API_MAP[round(average, 0)] self.sensordata[current_partregion_id]['data'][pollen_date]['stats'][STAT_AVG]['descr'] = None if average_api_id is None else self.api_id_to_descr[average_api_id] def generate_api_id_to_descr_map(self, json_obj): legend_map = json_obj['legend'] for key, value in legend_map.items(): if not key.endswith('_desc'): self.api_id_to_descr[value] = legend_map["%s_desc" % key] self.api_id_to_descr['-1'] = 'n/a' def get_adjusted_day(self, day): today = datetime.now().date() last_update_day = self.last_update.date() offset = (today - last_update_day).days return DAY_ADJUSTMENTS[day][offset] def get_descr_for_value(self, value): if not value: return None api_id = HOMEASSISTANT_TO_API_MAP[value] if api_id in self.api_id_to_descr: return self.api_id_to_descr[api_id] else: return None