From a147a189ca1112402c6412170533e9ca8fc5a1c5 Mon Sep 17 00:00:00 2001 From: michaeldavie Date: Sat, 13 Jul 2019 12:14:29 -0400 Subject: [PATCH] Update Environment Canada platforms (#24884) * Add support for French * Move labels to env_canada * Bump env_canada to 0.0.17, change update frequency to 1 minute * Update requirements_all.txt * Set entity IDs separate from labels * Flake error * Remove monitored conditions * Use next hourly forecast for missing conditions * Switch sensors to unique_id * Flake error * Requested changes * Simplify setting location parameters --- .../components/environment_canada/camera.py | 10 +- .../environment_canada/manifest.json | 2 +- .../components/environment_canada/sensor.py | 136 ++++++++---------- .../components/environment_canada/weather.py | 49 ++++--- requirements_all.txt | 2 +- 5 files changed, 89 insertions(+), 110 deletions(-) diff --git a/homeassistant/components/environment_canada/camera.py b/homeassistant/components/environment_canada/camera.py index 18a88129e1d..7a42c770841 100755 --- a/homeassistant/components/environment_canada/camera.py +++ b/homeassistant/components/environment_canada/camera.py @@ -45,14 +45,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if config.get(CONF_STATION): radar_object = ECRadar(station_id=config[CONF_STATION], precip_type=config.get(CONF_PRECIP_TYPE)) - elif config.get(CONF_LATITUDE) and config.get(CONF_LONGITUDE): - radar_object = ECRadar(coordinates=(config[CONF_LATITUDE], - config[CONF_LONGITUDE]), - precip_type=config.get(CONF_PRECIP_TYPE)) else: - radar_object = ECRadar(coordinates=(hass.config.latitude, - hass.config.longitude), - precip_type=config.get(CONF_PRECIP_TYPE)) + lat = config.get(CONF_LATITUDE, hass.config.latitude) + lon = config.get(CONF_LONGITUDE, hass.config.longitude) + radar_object = ECRadar(coordinates=(lat, lon)) add_devices([ECCamera(radar_object, config.get(CONF_NAME))], True) diff --git a/homeassistant/components/environment_canada/manifest.json b/homeassistant/components/environment_canada/manifest.json index ea809238499..42c419ba015 100644 --- a/homeassistant/components/environment_canada/manifest.json +++ b/homeassistant/components/environment_canada/manifest.json @@ -3,7 +3,7 @@ "name": "Environment Canada", "documentation": "https://www.home-assistant.io/components/environment_canada", "requirements": [ - "env_canada==0.0.10" + "env_canada==0.0.18" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/environment_canada/sensor.py b/homeassistant/components/environment_canada/sensor.py index c0b78cd4f35..9bfb205f4e5 100755 --- a/homeassistant/components/environment_canada/sensor.py +++ b/homeassistant/components/environment_canada/sensor.py @@ -4,7 +4,7 @@ Support for the Environment Canada weather service. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.environment_canada/ """ -import datetime +from datetime import datetime, timedelta import logging import re @@ -12,11 +12,10 @@ import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( - CONF_MONITORED_CONDITIONS, TEMP_CELSIUS, CONF_NAME, CONF_LATITUDE, - CONF_LONGITUDE, ATTR_ATTRIBUTION, ATTR_LOCATION, ATTR_HIDDEN) + TEMP_CELSIUS, CONF_LATITUDE, CONF_LONGITUDE, ATTR_ATTRIBUTION, + ATTR_LOCATION) from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -import homeassistant.util.dt as dt import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -28,43 +27,9 @@ ATTR_TIME = 'alert time' CONF_ATTRIBUTION = "Data provided by Environment Canada" CONF_STATION = 'station' +CONF_LANGUAGE = 'language' -MIN_TIME_BETWEEN_UPDATES = datetime.timedelta(minutes=10) - -SENSOR_TYPES = { - 'temperature': {'name': 'Temperature', - 'unit': TEMP_CELSIUS}, - 'dewpoint': {'name': 'Dew Point', - 'unit': TEMP_CELSIUS}, - 'wind_chill': {'name': 'Wind Chill', - 'unit': TEMP_CELSIUS}, - 'humidex': {'name': 'Humidex', - 'unit': TEMP_CELSIUS}, - 'pressure': {'name': 'Pressure', - 'unit': 'kPa'}, - 'tendency': {'name': 'Tendency'}, - 'humidity': {'name': 'Humidity', - 'unit': '%'}, - 'visibility': {'name': 'Visibility', - 'unit': 'km'}, - 'condition': {'name': 'Condition'}, - 'wind_speed': {'name': 'Wind Speed', - 'unit': 'km/h'}, - 'wind_gust': {'name': 'Wind Gust', - 'unit': 'km/h'}, - 'wind_dir': {'name': 'Wind Direction'}, - 'high_temp': {'name': 'High Temperature', - 'unit': TEMP_CELSIUS}, - 'low_temp': {'name': 'Low Temperature', - 'unit': TEMP_CELSIUS}, - 'pop': {'name': 'Chance of Precip.', - 'unit': '%'}, - 'warnings': {'name': 'Warnings'}, - 'watches': {'name': 'Watches'}, - 'advisories': {'name': 'Advisories'}, - 'statements': {'name': 'Statements'}, - 'endings': {'name': 'Ended'} -} +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) def validate_station(station): @@ -77,52 +42,58 @@ def validate_station(station): PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)): - vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), - vol.Optional(CONF_NAME): cv.string, + vol.Required(CONF_LANGUAGE, default='english'): + vol.In(['english', 'french']), vol.Optional(CONF_STATION): validate_station, vol.Inclusive(CONF_LATITUDE, 'latlon'): cv.latitude, vol.Inclusive(CONF_LONGITUDE, 'latlon'): cv.longitude, }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Environment Canada sensor.""" from env_canada import ECData if config.get(CONF_STATION): - ec_data = ECData(station_id=config[CONF_STATION]) - elif config.get(CONF_LATITUDE) and config.get(CONF_LONGITUDE): - ec_data = ECData(coordinates=(config[CONF_LATITUDE], - config[CONF_LONGITUDE])) + ec_data = ECData(station_id=config[CONF_STATION], + language=config.get(CONF_LANGUAGE)) else: - ec_data = ECData(coordinates=(hass.config.latitude, - hass.config.longitude)) + lat = config.get(CONF_LATITUDE, hass.config.latitude) + lon = config.get(CONF_LONGITUDE, hass.config.longitude) + ec_data = ECData(coordinates=(lat, lon), + language=config.get(CONF_LANGUAGE)) - add_devices([ECSensor(sensor_type, ec_data, config.get(CONF_NAME)) - for sensor_type in config[CONF_MONITORED_CONDITIONS]], - True) + sensor_list = list(ec_data.conditions.keys()) + list(ec_data.alerts.keys()) + sensor_list.remove('icon_code') + add_entities([ECSensor(sensor_type, + ec_data) + for sensor_type in sensor_list], + True) class ECSensor(Entity): """Implementation of an Environment Canada sensor.""" - def __init__(self, sensor_type, ec_data, platform_name): + def __init__(self, sensor_type, ec_data): """Initialize the sensor.""" self.sensor_type = sensor_type self.ec_data = ec_data - self.platform_name = platform_name + + self._unique_id = None + self._name = None self._state = None self._attr = None + self._unit = None + + @property + def unique_id(self) -> str: + """Return the unique ID of the sensor.""" + return self._unique_id @property def name(self): """Return the name of the sensor.""" - if self.platform_name is None: - return SENSOR_TYPES[self.sensor_type]['name'] - - return ' '.join([self.platform_name, - SENSOR_TYPES[self.sensor_type]['name']]) + return self._name @property def state(self): @@ -137,7 +108,7 @@ class ECSensor(Entity): @property def unit_of_measurement(self): """Return the units of measurement.""" - return SENSOR_TYPES[self.sensor_type].get('unit') + return self._unit @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): @@ -145,34 +116,43 @@ class ECSensor(Entity): self.ec_data.update() self.ec_data.conditions.update(self.ec_data.alerts) - self._attr = {} + conditions = self.ec_data.conditions + metadata = self.ec_data.metadata + sensor_data = conditions.get(self.sensor_type) - sensor_data = self.ec_data.conditions.get(self.sensor_type) - if isinstance(sensor_data, list): + self._unique_id = '{}-{}'.format(metadata['location'], + self.sensor_type) + self._attr = {} + self._name = sensor_data.get('label') + value = sensor_data.get('value') + + if isinstance(value, list): self._state = ' | '.join([str(s.get('title')) - for s in sensor_data]) + for s in value]) self._attr.update({ ATTR_DETAIL: ' | '.join([str(s.get('detail')) - for s in sensor_data]), + for s in value]), ATTR_TIME: ' | '.join([str(s.get('date')) - for s in sensor_data]) + for s in value]) }) else: - self._state = sensor_data + self._state = value - timestamp = self.ec_data.conditions.get('timestamp') - if timestamp: - updated_utc = datetime.datetime.strptime(timestamp, '%Y%m%d%H%M%S') - updated_local = dt.as_local(updated_utc).isoformat() + if sensor_data.get('unit') == 'C': + self._unit = TEMP_CELSIUS else: - updated_local = None + self._unit = sensor_data.get('unit') - hidden = bool(self._state is None or self._state == '') + timestamp = metadata.get('timestamp') + if timestamp: + updated_utc = datetime.strptime(timestamp, + '%Y%m%d%H%M%S').isoformat() + else: + updated_utc = None self._attr.update({ ATTR_ATTRIBUTION: CONF_ATTRIBUTION, - ATTR_UPDATED: updated_local, - ATTR_LOCATION: self.ec_data.conditions.get('location'), - ATTR_STATION: self.ec_data.conditions.get('station'), - ATTR_HIDDEN: hidden + ATTR_UPDATED: updated_utc, + ATTR_LOCATION: metadata.get('location'), + ATTR_STATION: metadata.get('station'), }) diff --git a/homeassistant/components/environment_canada/weather.py b/homeassistant/components/environment_canada/weather.py index 0589a23445e..0be659138fb 100644 --- a/homeassistant/components/environment_canada/weather.py +++ b/homeassistant/components/environment_canada/weather.py @@ -67,12 +67,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Environment Canada weather.""" if config.get(CONF_STATION): ec_data = ECData(station_id=config[CONF_STATION]) - elif config.get(CONF_LATITUDE) and config.get(CONF_LONGITUDE): - ec_data = ECData(coordinates=(config[CONF_LATITUDE], - config[CONF_LONGITUDE])) else: - ec_data = ECData(coordinates=(hass.config.latitude, - hass.config.longitude)) + lat = config.get(CONF_LATITUDE, hass.config.latitude) + lon = config.get(CONF_LONGITUDE, hass.config.longitude) + ec_data = ECData(coordinates=(lat, lon)) add_devices([ECWeather(ec_data, config)]) @@ -96,13 +94,15 @@ class ECWeather(WeatherEntity): """Return the name of the weather entity.""" if self.platform_name: return self.platform_name - return self.ec_data.conditions['location'] + return self.ec_data.metadata.get('location') @property def temperature(self): """Return the temperature.""" - if self.ec_data.conditions.get('temperature'): - return float(self.ec_data.conditions['temperature']) + if self.ec_data.conditions.get('temperature').get('value'): + return float(self.ec_data.conditions['temperature']['value']) + if self.ec_data.hourly_forecasts[0].get('temperature'): + return float(self.ec_data.hourly_forecasts[0]['temperature']) return None @property @@ -113,48 +113,51 @@ class ECWeather(WeatherEntity): @property def humidity(self): """Return the humidity.""" - if self.ec_data.conditions.get('humidity'): - return float(self.ec_data.conditions['humidity']) + if self.ec_data.conditions.get('humidity').get('value'): + return float(self.ec_data.conditions['humidity']['value']) return None @property def wind_speed(self): """Return the wind speed.""" - if self.ec_data.conditions.get('wind_speed'): - return float(self.ec_data.conditions['wind_speed']) + if self.ec_data.conditions.get('wind_speed').get('value'): + return float(self.ec_data.conditions['wind_speed']['value']) return None @property def wind_bearing(self): """Return the wind bearing.""" - if self.ec_data.conditions.get('wind_bearing'): - return float(self.ec_data.conditions['wind_bearing']) + if self.ec_data.conditions.get('wind_bearing').get('value'): + return float(self.ec_data.conditions['wind_bearing']['value']) return None @property def pressure(self): """Return the pressure.""" - if self.ec_data.conditions.get('pressure'): - return 10 * float(self.ec_data.conditions['pressure']) + if self.ec_data.conditions.get('pressure').get('value'): + return 10 * float(self.ec_data.conditions['pressure']['value']) return None @property def visibility(self): """Return the visibility.""" - if self.ec_data.conditions.get('visibility'): - return float(self.ec_data.conditions['visibility']) + if self.ec_data.conditions.get('visibility').get('value'): + return float(self.ec_data.conditions['visibility']['value']) return None @property def condition(self): """Return the weather condition.""" - icon_code = self.ec_data.conditions.get('icon_code') + icon_code = None + + if self.ec_data.conditions.get('icon_code').get('value'): + icon_code = self.ec_data.conditions['icon_code']['value'] + elif self.ec_data.hourly_forecasts[0].get('icon_code'): + icon_code = self.ec_data.hourly_forecasts[0]['icon_code'] + if icon_code: return icon_code_to_condition(int(icon_code)) - condition = self.ec_data.conditions.get('condition') - if condition: - return condition - return 'Condition not observed' + return '' @property def forecast(self): diff --git a/requirements_all.txt b/requirements_all.txt index 40c8a63d1a2..78b86b0819b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -430,7 +430,7 @@ enocean==0.50 enturclient==0.2.0 # homeassistant.components.environment_canada -env_canada==0.0.10 +env_canada==0.0.18 # homeassistant.components.envirophat # envirophat==0.0.6