-
-
Notifications
You must be signed in to change notification settings - Fork 37.6k
Added DWD WarnApp Sensor #8657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Added DWD WarnApp Sensor #8657
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
1af723f
Added DWD WarnApp Sensor
runningman84 7cb7924
Fixed some idents and spaces
runningman84 17cc1a7
Removed unused imports
runningman84 7b3e84c
Removed comment
runningman84 a85e8d5
Some fixes
runningman84 d9da925
Added throttle
runningman84 d2f6676
Renamed sensor to dwd weather warnings
runningman84 df60b1a
Renamed test file
runningman84 deb31e7
shorten lines
runningman84 5c270a4
shorten lines
runningman84 7426e3e
Implemented changes requested by fabaff
runningman84 43cc842
added ATTRIBUTION
runningman84 8a510f7
move ATTRIBUTION to existing method
runningman84 339b097
fixed lint tests
runningman84 8095761
Fix linter issues
runningman84 0e0a9e9
Fix linter issues
runningman84 70d0195
Fix linter
runningman84 0940766
Fixed linter
runningman84 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
243 changes: 243 additions & 0 deletions
243
homeassistant/components/sensor/dwd_weather_warnings.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,243 @@ | ||
| """ | ||
| Support for getting statistical data from a DWD Weather Warnings. | ||
|
|
||
| For more details about this platform, please refer to the documentation at | ||
| https://home-assistant.io/components/sensor.dwd_weather_warnings/ | ||
|
|
||
| Data is fetched from DWD: | ||
| https://rcccm.dwd.de/DE/wetter/warnungen_aktuell/objekt_einbindung/objekteinbindung.html | ||
|
|
||
| Warnungen vor extremem Unwetter (Stufe 4) | ||
| Unwetterwarnungen (Stufe 3) | ||
| Warnungen vor markantem Wetter (Stufe 2) | ||
| Wetterwarnungen (Stufe 1) | ||
| """ | ||
| import logging | ||
| import json | ||
| from datetime import timedelta | ||
|
|
||
| import voluptuous as vol | ||
|
|
||
| import homeassistant.helpers.config_validation as cv | ||
| from homeassistant.helpers.entity import Entity | ||
| from homeassistant.components.sensor import PLATFORM_SCHEMA | ||
| from homeassistant.const import ( | ||
| ATTR_ATTRIBUTION, CONF_NAME, CONF_MONITORED_CONDITIONS) | ||
| from homeassistant.util import Throttle | ||
| import homeassistant.util.dt as dt_util | ||
| from homeassistant.components.sensor.rest import RestData | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| ATTRIBUTION = "Data provided by DWD" | ||
|
|
||
| DEFAULT_NAME = 'DWD-Weather-Warnings' | ||
|
|
||
| CONF_REGION_NAME = 'region_name' | ||
|
|
||
| SCAN_INTERVAL = timedelta(minutes=15) | ||
|
|
||
| MONITORED_CONDITIONS = { | ||
| 'current_warning_level': ['Current Warning Level', | ||
| None, 'mdi:close-octagon-outline'], | ||
| 'advance_warning_level': ['Advance Warning Level', | ||
| None, 'mdi:close-octagon-outline'], | ||
| } | ||
|
|
||
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
| vol.Optional(CONF_REGION_NAME): cv.string, | ||
| vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, | ||
| vol.Optional(CONF_MONITORED_CONDITIONS, default=MONITORED_CONDITIONS): | ||
| vol.All(cv.ensure_list, [vol.In(MONITORED_CONDITIONS)]), | ||
| }) | ||
|
|
||
|
|
||
| def setup_platform(hass, config, add_devices, discovery_info=None): | ||
| """Set up the DWD-Weather-Warnings sensor.""" | ||
| name = config.get(CONF_NAME) | ||
| region_name = config.get(CONF_REGION_NAME) | ||
|
|
||
| api = DwdWeatherWarningsAPI(region_name) | ||
|
|
||
| sensors = [DwdWeatherWarningsSensor(api, name, condition) | ||
| for condition in config[CONF_MONITORED_CONDITIONS]] | ||
|
|
||
| add_devices(sensors, True) | ||
|
|
||
|
|
||
| class DwdWeatherWarningsSensor(Entity): | ||
| """Representation of a DWD-Weather-Warnings sensor.""" | ||
|
|
||
| def __init__(self, api, name, variable): | ||
| """Initialize a DWD-Weather-Warnings sensor.""" | ||
| self._api = api | ||
| self._name = name | ||
| self._var_id = variable | ||
|
|
||
| variable_info = MONITORED_CONDITIONS[variable] | ||
| self._var_name = variable_info[0] | ||
| self._var_units = variable_info[1] | ||
| self._var_icon = variable_info[2] | ||
|
|
||
| @property | ||
| def name(self): | ||
| """Return the name of the sensor.""" | ||
| return "{} {}".format(self._name, self._var_name) | ||
|
|
||
| @property | ||
| def icon(self): | ||
| """Icon to use in the frontend, if any.""" | ||
| return self._var_icon | ||
|
|
||
| @property | ||
| def unit_of_measurement(self): | ||
| """Return the unit the value is expressed in.""" | ||
| return self._var_units | ||
|
|
||
| # pylint: disable=no-member | ||
| @property | ||
| def state(self): | ||
| """Return the state of the device.""" | ||
| try: | ||
| return round(self._api.data[self._var_id], 2) | ||
| except TypeError: | ||
| return self._api.data[self._var_id] | ||
|
|
||
| # pylint: disable=no-member | ||
| @property | ||
| def device_state_attributes(self): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please add an attribution?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean? |
||
| """Return the state attributes of the DWD-Weather-Warnings.""" | ||
| data = { | ||
| ATTR_ATTRIBUTION: ATTRIBUTION, | ||
| 'region_name': self._api.region_name | ||
| } | ||
|
|
||
| if self._api.region_id is not None: | ||
| data['region_id'] = self._api.region_id | ||
|
|
||
| if self._api.region_state is not None: | ||
| data['region_state'] = self._api.region_state | ||
|
|
||
| if self._api.data['time'] is not None: | ||
| data['last_update'] = dt_util.as_local( | ||
| dt_util.utc_from_timestamp(self._api.data['time'] / 1000)) | ||
|
|
||
| if self._var_id == 'current_warning_level': | ||
| prefix = 'current' | ||
| elif self._var_id == 'advance_warning_level': | ||
| prefix = 'advance' | ||
| else: | ||
| raise Exception('Unknown warning type') | ||
|
|
||
| data['warning_count'] = self._api.data[prefix + '_warning_count'] | ||
| i = 0 | ||
| for event in self._api.data[prefix + '_warnings']: | ||
| i = i + 1 | ||
|
|
||
| data['warning_{}_name'.format(i)] = event['event'] | ||
| data['warning_{}_level'.format(i)] = event['level'] | ||
| data['warning_{}_type'.format(i)] = event['type'] | ||
| if len(event['headline']) > 0: | ||
| data['warning_{}_headline'.format(i)] = event['headline'] | ||
| if len(event['description']) > 0: | ||
| data['warning_{}_description'.format(i)] = event['description'] | ||
| if len(event['instruction']) > 0: | ||
| data['warning_{}_instruction'.format(i)] = event['instruction'] | ||
|
|
||
| if event['start'] is not None: | ||
| data['warning_{}_start'.format(i)] = dt_util.as_local( | ||
| dt_util.utc_from_timestamp(event['start'] / 1000)) | ||
|
|
||
| if event['end'] is not None: | ||
| data['warning_{}_end'.format(i)] = dt_util.as_local( | ||
| dt_util.utc_from_timestamp(event['end'] / 1000)) | ||
|
|
||
| return data | ||
|
|
||
| @property | ||
| def available(self): | ||
| """Could the device be accessed during the last update call.""" | ||
| return self._api.available | ||
|
|
||
| def update(self): | ||
| """Get the latest data from the DWD-Weather-Warnings API.""" | ||
| self._api.update() | ||
|
|
||
|
|
||
| class DwdWeatherWarningsAPI(object): | ||
| """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 | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
redefinition of unused 'device_state_attributes' from line 96