diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 615554ae56f..2915f37dd21 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -15,7 +15,6 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.components import bloomsky from homeassistant.const import ( - ATTR_ENTITY_PICTURE, HTTP_NOT_FOUND, ATTR_ENTITY_ID, ) @@ -132,6 +131,11 @@ class Camera(Entity): """No need to poll cameras.""" return False + @property + def entity_picture(self): + """Return a link to the camera feed as entity picture.""" + return ENTITY_IMAGE_URL.format(self.entity_id) + @property # pylint: disable=no-self-use def is_recording(self): @@ -195,9 +199,7 @@ class Camera(Entity): @property def state_attributes(self): """Camera state attributes.""" - attr = { - ATTR_ENTITY_PICTURE: ENTITY_IMAGE_URL.format(self.entity_id), - } + attr = {} if self.model: attr['model_name'] = self.model diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index c5b4ccd1c16..8c3fd62a0f8 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -25,7 +25,7 @@ import homeassistant.util.dt as dt_util from homeassistant.helpers.event import track_utc_time_change from homeassistant.const import ( - ATTR_ENTITY_PICTURE, ATTR_GPS_ACCURACY, ATTR_LATITUDE, ATTR_LONGITUDE, + ATTR_GPS_ACCURACY, ATTR_LATITUDE, ATTR_LONGITUDE, DEVICE_DEFAULT_NAME, STATE_HOME, STATE_NOT_HOME) DOMAIN = "device_tracker" @@ -297,14 +297,16 @@ class Device(Entity): """ State of the device. """ return self._state + @property + def entity_picture(self): + """Picture of the device.""" + return self.config_picture + @property def state_attributes(self): """ Device state attributes. """ attr = {} - if self.config_picture: - attr[ATTR_ENTITY_PICTURE] = self.config_picture - if self.gps: attr[ATTR_LATITUDE] = self.gps[0] attr[ATTR_LONGITUDE] = self.gps[1] diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index d0f3015fb74..32bf57108f7 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -15,7 +15,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.const import ( STATE_OFF, STATE_UNKNOWN, STATE_PLAYING, STATE_IDLE, - ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, SERVICE_TURN_OFF, SERVICE_TURN_ON, + ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_SET, SERVICE_VOLUME_MUTE, SERVICE_TOGGLE, SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE, @@ -525,6 +525,11 @@ class MediaPlayerDevice(Entity): else: self.media_play() + @property + def entity_picture(self): + """Return image of the media playing.""" + return None if self.state == STATE_OFF else self.media_image_url + @property def state_attributes(self): """ Return the state attributes. """ @@ -538,7 +543,4 @@ class MediaPlayerDevice(Entity): in ATTR_TO_PROPERTY if getattr(self, attr) is not None } - if self.media_image_url: - state_attr[ATTR_ENTITY_PICTURE] = self.media_image_url - return state_attr diff --git a/homeassistant/components/sensor/steam_online.py b/homeassistant/components/sensor/steam_online.py index 6b740d0639b..5e12cb338c8 100644 --- a/homeassistant/components/sensor/steam_online.py +++ b/homeassistant/components/sensor/steam_online.py @@ -7,7 +7,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.steam_online/ """ from homeassistant.helpers.entity import Entity -from homeassistant.const import (ATTR_ENTITY_PICTURE, CONF_API_KEY) +from homeassistant.const import CONF_API_KEY ICON = 'mdi:steam' @@ -62,11 +62,9 @@ class SteamSensor(Entity): }.get(self._profile.status, 'Offline') @property - def device_state_attributes(self): - """ Returns the state attributes. """ - return { - ATTR_ENTITY_PICTURE: self._profile.avatar_medium - } + def entity_picture(self): + """Avatar of the account.""" + return self._profile.avatar_medium @property def icon(self): diff --git a/homeassistant/components/sensor/twitch.py b/homeassistant/components/sensor/twitch.py index db81c55b6a9..abe257cadd8 100644 --- a/homeassistant/components/sensor/twitch.py +++ b/homeassistant/components/sensor/twitch.py @@ -4,7 +4,6 @@ Support for the Twitch stream status. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.twitch/ """ -from homeassistant.const import ATTR_ENTITY_PICTURE from homeassistant.helpers.entity import Entity STATE_STREAMING = 'streaming' @@ -51,6 +50,11 @@ class TwitchSensor(Entity): """State of the sensor.""" return self._state + @property + def entity_picture(self): + """Preview of current game.""" + return self._preview + # pylint: disable=no-member def update(self): """Update device state.""" @@ -62,6 +66,7 @@ class TwitchSensor(Entity): self._preview = stream.get('preview').get('small') self._state = STATE_STREAMING else: + self._preview = None self._state = STATE_OFFLINE @property @@ -71,7 +76,6 @@ class TwitchSensor(Entity): return { ATTR_GAME: self._game, ATTR_TITLE: self._title, - ATTR_ENTITY_PICTURE: self._preview } @property diff --git a/homeassistant/components/sensor/yr.py b/homeassistant/components/sensor/yr.py index 6bb460b1373..907c0bed049 100644 --- a/homeassistant/components/sensor/yr.py +++ b/homeassistant/components/sensor/yr.py @@ -8,8 +8,7 @@ import logging import requests -from homeassistant.const import ( - ATTR_ENTITY_PICTURE, CONF_LATITUDE, CONF_LONGITUDE) +from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE from homeassistant.helpers.entity import Entity from homeassistant.util import dt as dt_util from homeassistant.util import location @@ -97,20 +96,21 @@ class YrSensor(Entity): """Returns the state of the device.""" return self._state + @property + def entity_picture(self): + """Weather symbol if type is symbol.""" + if self.type != 'symbol': + return None + return "http://api.met.no/weatherapi/weathericon/1.1/" \ + "?symbol={0};content_type=image/png".format(self._state) + @property def device_state_attributes(self): """Returns state attributes. """ - data = { + return { 'about': "Weather forecast from yr.no, delivered by the" " Norwegian Meteorological Institute and the NRK" } - if self.type == 'symbol': - symbol_nr = self._state - data[ATTR_ENTITY_PICTURE] = \ - "http://api.met.no/weatherapi/weathericon/1.1/" \ - "?symbol={0};content_type=image/png".format(symbol_nr) - - return data @property def unit_of_measurement(self): diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index afe5bc80291..d7d37135cb2 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -10,7 +10,8 @@ from collections import defaultdict from homeassistant.const import ( ATTR_ASSUMED_STATE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, DEVICE_DEFAULT_NAME, STATE_OFF, STATE_ON, - STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELCIUS, TEMP_FAHRENHEIT) + STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELCIUS, TEMP_FAHRENHEIT, + ATTR_ENTITY_PICTURE) from homeassistant.exceptions import NoEntitySpecifiedError from homeassistant.util import ensure_unique_string, slugify @@ -105,6 +106,11 @@ class Entity(object): """Return the icon to use in the frontend, if any.""" return None + @property + def entity_picture(self): + """Return the entity picture to use in the frontend, if any.""" + return None + @property def hidden(self): """Return True if the entity should be hidden from UIs.""" @@ -157,25 +163,18 @@ class Entity(object): if device_attr is not None: attr.update(device_attr) - if ATTR_UNIT_OF_MEASUREMENT not in attr and \ - self.unit_of_measurement is not None: - attr[ATTR_UNIT_OF_MEASUREMENT] = str(self.unit_of_measurement) + self._attr_setter('unit_of_measurement', str, ATTR_UNIT_OF_MEASUREMENT, + attr) if not self.available: state = STATE_UNAVAILABLE attr = {} - if self.name is not None: - attr[ATTR_FRIENDLY_NAME] = str(self.name) - - if self.icon is not None: - attr[ATTR_ICON] = str(self.icon) - - if self.hidden: - attr[ATTR_HIDDEN] = bool(self.hidden) - - if self.assumed_state: - attr[ATTR_ASSUMED_STATE] = bool(self.assumed_state) + self._attr_setter('name', str, ATTR_FRIENDLY_NAME, attr) + self._attr_setter('icon', str, ATTR_ICON, attr) + self._attr_setter('entity_picture', str, ATTR_ENTITY_PICTURE, attr) + self._attr_setter('hidden', bool, ATTR_HIDDEN, attr) + self._attr_setter('assumed_state', bool, ATTR_ASSUMED_STATE, attr) # overwrite properties that have been set in the config file attr.update(_OVERWRITE.get(self.entity_id, {})) @@ -195,6 +194,21 @@ class Entity(object): return self.hass.states.set(self.entity_id, state, attr) + def _attr_setter(self, name, typ, attr, attrs): + """Helper method to populate attributes based on properties.""" + if attr in attrs: + return + + value = getattr(self, name) + + if not value: + return + + try: + attrs[attr] = typ(value) + except (TypeError, ValueError): + pass + def __eq__(self, other): return (isinstance(other, Entity) and other.unique_id == self.unique_id)