Device tracker rewrite

This commit is contained in:
Paulus Schoutsen 2015-09-09 23:37:15 -07:00
parent e88fabbe6d
commit f9b17ab026
13 changed files with 351 additions and 325 deletions

View File

@ -123,6 +123,7 @@ def prepare_setup_platform(hass, config, domain, platform_name):
# Not found # Not found
if platform is None: if platform is None:
_LOGGER.error('Unable to find platform %s', platform_path)
return None return None
# Already loaded # Already loaded

View File

@ -3,48 +3,70 @@ homeassistant.components.tracker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to keep track of devices. Provides functionality to keep track of devices.
device_tracker:
platform: netgear
# Optional
# How many seconds to wait after not seeing device to consider it not home
consider_home: 180
# Seconds between each scan
interval_seconds: 12
# New found devices auto found
track_new_devices: yes
""" """
import logging
import threading
import os
import csv import csv
from datetime import timedelta from datetime import timedelta
import logging
import os
import threading
from homeassistant.helpers import validate_config from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.helpers.entity import _OVERWRITE from homeassistant.components import discovery, group
from homeassistant.config import load_yaml_config_file
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_per_platform
from homeassistant.helpers.entity import Entity
import homeassistant.util as util import homeassistant.util as util
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.helpers.event import track_utc_time_change from homeassistant.helpers.event import track_utc_time_change
from homeassistant.const import ( from homeassistant.const import (
STATE_HOME, STATE_NOT_HOME, ATTR_ENTITY_PICTURE, ATTR_FRIENDLY_NAME, ATTR_ENTITY_PICTURE, DEVICE_DEFAULT_NAME, STATE_HOME, STATE_NOT_HOME,
CONF_PLATFORM, DEVICE_DEFAULT_NAME) STATE_UNKNOWN)
from homeassistant.components import group
DOMAIN = "device_tracker" DOMAIN = "device_tracker"
DEPENDENCIES = [] DEPENDENCIES = []
SERVICE_DEVICE_TRACKER_RELOAD = "reload_devices_csv"
GROUP_NAME_ALL_DEVICES = 'all devices' GROUP_NAME_ALL_DEVICES = 'all devices'
ENTITY_ID_ALL_DEVICES = group.ENTITY_ID_FORMAT.format('all_devices') ENTITY_ID_ALL_DEVICES = group.ENTITY_ID_FORMAT.format('all_devices')
ENTITY_ID_FORMAT = DOMAIN + '.{}' ENTITY_ID_FORMAT = DOMAIN + '.{}'
# After how much time do we consider a device not home if CSV_DEVICES = "known_devices.csv"
# it does not show up on scans YAML_DEVICES = 'known_devices.yaml'
TIME_DEVICE_NOT_FOUND = timedelta(minutes=3)
# Filename to save known devices to CONF_TRACK_NEW = "track_new_devices"
KNOWN_DEVICES_FILE = "known_devices.csv" DEFAULT_CONF_TRACK_NEW = True
CONF_SECONDS = "interval_seconds" CONF_CONSIDER_HOME = 'consider_home'
DEFAULT_CONF_CONSIDER_HOME = 180 # seconds
DEFAULT_CONF_SECONDS = 12 CONF_SCAN_INTERVAL = "interval_seconds"
DEFAULT_SCAN_INTERVAL = 12
TRACK_NEW_DEVICES = "track_new_devices" CONF_AWAY_HIDE = 'hide_if_away'
DEFAULT_AWAY_HIDE = False
ATTR_LATITUDE = 'latitude'
ATTR_LONGITUDE = 'longitude'
DISCOVERY_PLATFORMS = {
discovery.SERVICE_NETGEAR: 'netgear',
}
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -56,292 +78,268 @@ def is_on(hass, entity_id=None):
def setup(hass, config): def setup(hass, config):
""" Sets up the device tracker. """ """ Setup device tracker """
yaml_path = hass.config.path(YAML_DEVICES)
csv_path = hass.config.path(CSV_DEVICES)
if os.path.isfile(csv_path) and not os.path.isfile(yaml_path) and \
convert_csv_config(csv_path, yaml_path):
os.remove(csv_path)
if not validate_config(config, {DOMAIN: [CONF_PLATFORM]}, _LOGGER): conf = config.get(DOMAIN, {})
return False consider_home = util.convert(conf.get(CONF_CONSIDER_HOME), int,
DEFAULT_CONF_CONSIDER_HOME)
track_new = util.convert(conf.get(CONF_TRACK_NEW), bool,
DEFAULT_CONF_TRACK_NEW)
tracker_type = config[DOMAIN].get(CONF_PLATFORM) devices = load_yaml_config_file(yaml_path)
tracker = DeviceTracker(hass, devices, consider_home, track_new)
tracker_implementation = \ def setup_platform(p_type, p_config, disc_info=None):
prepare_setup_platform(hass, config, DOMAIN, tracker_type) """ Setup a device tracker platform. """
platform = prepare_setup_platform(hass, config, DOMAIN, p_type)
if platform is None:
return
if tracker_implementation is None: try:
_LOGGER.error("Unknown device_tracker type specified: %s.", if hasattr(platform, 'get_scanner'):
tracker_type) scanner = platform.get_scanner(hass, {DOMAIN: p_config})
return False if scanner is None:
_LOGGER.error('Error setting up platform %s', p_type)
return
device_scanner = tracker_implementation.get_scanner(hass, config) setup_scanner_platform(hass, p_config, scanner, tracker.see)
return
if device_scanner is None: if not platform.setup_scanner(hass, p_config, tracker.see):
_LOGGER.error("Failed to initialize device scanner: %s", _LOGGER.error('Error setting up platform %s', p_type)
tracker_type) except Exception: # pylint: disable=broad-except
_LOGGER.exception('Error setting up platform %s', p_type)
return False for p_type, p_config in \
config_per_platform(config, DOMAIN, _LOGGER):
setup_platform(p_type, p_config)
seconds = util.convert(config[DOMAIN].get(CONF_SECONDS), int, def device_tracker_discovered(service, info):
DEFAULT_CONF_SECONDS) """ Called when a device tracker platform is discovered. """
setup_platform(DISCOVERY_PLATFORMS[service], {}, info)
track_new_devices = config[DOMAIN].get(TRACK_NEW_DEVICES) or False discovery.listen(hass, DISCOVERY_PLATFORMS.keys(),
_LOGGER.info("Tracking new devices: %s", track_new_devices) device_tracker_discovered)
tracker = DeviceTracker(hass, device_scanner, seconds, track_new_devices) def update_stale(event):
""" Clean up stale devices. """
tracker.update_stale()
track_utc_time_change(hass, update_stale, second=range(0, 60, 5))
# We only succeeded if we got to parse the known devices file return True
return not tracker.invalid_known_devices_file
class DeviceTracker(object): class DeviceTracker(object):
""" Class that tracks which devices are home and which are not. """ """ Track devices """
def __init__(self, hass, config, consider_home, track_new):
def __init__(self, hass, device_scanner, seconds, track_new_devices):
self.hass = hass self.hass = hass
self.devices = {}
self.device_scanner = device_scanner self.mac_to_dev = {}
self.consider_home = timedelta(seconds=consider_home)
self.track_new = track_new
self.lock = threading.Lock() self.lock = threading.Lock()
# Do we track new devices by default? # Load config
self.track_new_devices = track_new_devices for dev_id, device_dict in config.items():
dev_id = str(dev_id)
device_dict = device_dict or {}
away_hide = device_dict.get(CONF_AWAY_HIDE, False)
device = Device(
hass, self.consider_home, device_dict.get('track', False),
dev_id, device_dict.get('mac'), device_dict.get('name'),
device_dict.get('picture'), away_hide)
if device.mac:
self.mac_to_dev[device.mac] = device
self.devices[dev_id] = device
# Dictionary to keep track of known devices and devices we track # pylint: disable=too-many-arguments
self.tracked = {} def see(self, mac=None, dev_id=None, host_name=None, location_name=None,
self.untracked_devices = set() gps=None):
""" Notify device tracker that you see a device. """
with self.lock:
if mac is None and dev_id is None:
raise HomeAssistantError('Neither mac or device id passed in')
elif mac is not None:
mac = mac.upper()
device = self.mac_to_dev.get(mac)
if not device:
dev_id = util.slugify(host_name) or mac.replace(':', '')
else:
dev_id = str(dev_id)
device = self.devices.get(dev_id)
# Did we encounter an invalid known devices file if device:
self.invalid_known_devices_file = False device.seen(host_name, location_name, gps)
if device.track:
# Wrap it in a func instead of lambda so it can be identified in device.update_ha_state()
# the bus by its __name__ attribute.
def update_device_state(now):
""" Triggers update of the device states. """
self.update_devices(now)
dev_group = group.Group(
hass, GROUP_NAME_ALL_DEVICES, user_defined=False)
def reload_known_devices_service(service):
""" Reload known devices file. """
self._read_known_devices_file()
self.update_devices(dt_util.utcnow())
dev_group.update_tracked_entity_ids(self.device_entity_ids)
reload_known_devices_service(None)
if self.invalid_known_devices_file:
return return
seconds = range(0, 60, seconds) # If no device can be found, create it
device = Device(
self.hass, self.consider_home, self.track_new, dev_id, mac,
(host_name or dev_id).replace('_', ' '))
self.devices[dev_id] = device
if mac is not None:
self.mac_to_dev[mac] = device
_LOGGER.info("Device tracker interval second=%s", seconds) device.seen(host_name, location_name, gps)
track_utc_time_change(hass, update_device_state, second=seconds) if device.track:
device.update_ha_state()
hass.services.register(DOMAIN, update_config(self.hass.config.path(YAML_DEVICES), dev_id, device)
SERVICE_DEVICE_TRACKER_RELOAD,
reload_known_devices_service) def update_stale(self):
""" Update stale devices. """
with self.lock:
now = dt_util.utcnow()
for device in self.devices.values():
if device.last_update_home and device.stale(now):
device.update_ha_state(True)
class Device(Entity):
""" Tracked device. """
# pylint: disable=too-many-instance-attributes, too-many-arguments
host_name = None
location_name = None
gps = None
last_seen = None
# Track if the last update of this device was HOME
last_update_home = False
_state = STATE_UNKNOWN
def __init__(self, hass, consider_home, track, dev_id, mac, name=None,
picture=None, away_hide=False):
self.hass = hass
self.entity_id = ENTITY_ID_FORMAT.format(dev_id)
# Timedelta object how long we consider a device home if it is not
# detected anymore.
self.consider_home = consider_home
# Device ID
self.dev_id = dev_id
self.mac = mac
# If we should track this device
self.track = track
# Configured name
self.config_name = name
# Configured picture
self.config_picture = picture
self.away_hide = away_hide
@property @property
def device_entity_ids(self): def name(self):
""" Returns a set containing all device entity ids """ Returns the name of the entity. """
that are being tracked. """ return self.config_name or self.host_name or DEVICE_DEFAULT_NAME
return set(device['entity_id'] for device in self.tracked.values())
def _update_state(self, now, device, is_home): @property
""" Update the state of a device. """ def state(self):
dev_info = self.tracked[device] """ State of the device. """
return self._state
if is_home: @property
# Update last seen if at home def state_attributes(self):
dev_info['last_seen'] = now """ 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],
@property
def hidden(self):
""" If device should be hidden. """
return self.away_hide and self.state != STATE_HOME
def seen(self, host_name=None, location_name=None, gps=None):
""" Mark the device as seen. """
self.last_seen = dt_util.utcnow()
self.host_name = host_name
self.location_name = location_name
self.gps = gps
self.update()
def stale(self, now=None):
""" Return if device state is stale. """
return self.last_seen and \
(now or dt_util.utcnow()) - self.last_seen > self.consider_home
def update(self):
""" Update state of entity. """
if not self.last_seen:
return
elif self.location_name:
self._state = self.location_name
elif self.stale():
self._state = STATE_NOT_HOME
self.last_update_home = False
else: else:
# State remains at home if it has been seen in the last self._state = STATE_HOME
# TIME_DEVICE_NOT_FOUND self.last_update_home = True
is_home = now - dev_info['last_seen'] < TIME_DEVICE_NOT_FOUND
state = STATE_HOME if is_home else STATE_NOT_HOME
# overwrite properties that have been set in the config file def convert_csv_config(csv_path, yaml_path):
attr = dict(dev_info['state_attr']) """ Convert CSV config file format to YAML. """
attr.update(_OVERWRITE.get(dev_info['entity_id'], {})) used_ids = set()
with open(csv_path) as inp:
self.hass.states.set(
dev_info['entity_id'], state, attr)
def update_devices(self, now):
""" Update device states based on the found devices. """
if not self.lock.acquire(False):
return
try:
found_devices = set(dev.upper() for dev in
self.device_scanner.scan_devices())
for device in self.tracked:
is_home = device in found_devices
self._update_state(now, device, is_home)
if is_home:
found_devices.remove(device)
# Did we find any devices that we didn't know about yet?
new_devices = found_devices - self.untracked_devices
if new_devices:
if not self.track_new_devices:
self.untracked_devices.update(new_devices)
self._update_known_devices_file(new_devices)
finally:
self.lock.release()
# pylint: disable=too-many-branches
def _read_known_devices_file(self):
""" Parse and process the known devices file. """
known_dev_path = self.hass.config.path(KNOWN_DEVICES_FILE)
# Return if no known devices file exists
if not os.path.isfile(known_dev_path):
return
self.lock.acquire()
self.untracked_devices.clear()
with open(known_dev_path) as inp:
# To track which devices need an entity_id assigned
need_entity_id = []
# All devices that are still in this set after we read the CSV file
# have been removed from the file and thus need to be cleaned up.
removed_devices = set(self.tracked.keys())
try:
for row in csv.DictReader(inp): for row in csv.DictReader(inp):
device = row['device'].upper() dev_id = util.ensure_unique_string(util.slugify(row['name']),
used_ids)
used_ids.add(dev_id)
device = Device(None, None, row['track'] == '1', dev_id,
row['device'], row['name'], row['picture'])
update_config(yaml_path, dev_id, device)
return True
if row['track'] == '1':
if device in self.tracked: def update_config(path, dev_id, device):
# Device exists """ Add device to YAML config file. """
removed_devices.remove(device) with open(path, 'a') as out:
out.write('\n')
out.write('{}:\n'.format(device.dev_id))
for key, value in (('name', device.name), ('mac', device.mac),
('picture', ''),
('track', 'yes' if device.track else 'no'),
(CONF_AWAY_HIDE,
'yes' if device.away_hide else 'no')):
out.write(' {}: {}\n'.format(key, '' if value is None else value))
def setup_scanner_platform(hass, config, scanner, see):
""" Helper method to connect scanner-based platform to device tracker. """
interval = util.convert(config.get(CONF_SCAN_INTERVAL), int,
DEFAULT_SCAN_INTERVAL)
# Initial scan of each mac we also tell about host name for config
seen = set()
def device_tracker_scan(now):
""" Called when interval matches. """
for mac in scanner.scan_devices():
if mac in seen:
host_name = None
else: else:
# We found a new device host_name = scanner.get_device_name(mac)
need_entity_id.append(device) seen.add(mac)
see(mac=mac, host_name=host_name)
self._track_device(device, row['name']) track_utc_time_change(hass, device_tracker_scan, second=range(0, 60,
interval))
# Update state_attr with latest from file device_tracker_scan(None)
state_attr = {
ATTR_FRIENDLY_NAME: row['name']
}
if row['picture']:
state_attr[ATTR_ENTITY_PICTURE] = row['picture']
self.tracked[device]['state_attr'] = state_attr
else:
self.untracked_devices.add(device)
# Remove existing devices that we no longer track
for device in removed_devices:
entity_id = self.tracked[device]['entity_id']
_LOGGER.info("Removing entity %s", entity_id)
self.hass.states.remove(entity_id)
self.tracked.pop(device)
self._generate_entity_ids(need_entity_id)
if not self.tracked:
_LOGGER.warning(
"No devices to track. Please update %s.",
known_dev_path)
_LOGGER.info("Loaded devices from %s", known_dev_path)
except KeyError:
self.invalid_known_devices_file = True
_LOGGER.warning(
("Invalid known devices file: %s. "
"We won't update it with new found devices."),
known_dev_path)
finally:
self.lock.release()
def _update_known_devices_file(self, new_devices):
""" Add new devices to known devices file. """
if not self.invalid_known_devices_file:
known_dev_path = self.hass.config.path(KNOWN_DEVICES_FILE)
try:
# If file does not exist we will write the header too
is_new_file = not os.path.isfile(known_dev_path)
with open(known_dev_path, 'a') as outp:
_LOGGER.info("Found %d new devices, updating %s",
len(new_devices), known_dev_path)
writer = csv.writer(outp)
if is_new_file:
writer.writerow(("device", "name", "track", "picture"))
for device in new_devices:
# See if the device scanner knows the name
# else defaults to unknown device
name = self.device_scanner.get_device_name(device) or \
DEVICE_DEFAULT_NAME
track = 0
if self.track_new_devices:
self._track_device(device, name)
track = 1
writer.writerow((device, name, track, ""))
if self.track_new_devices:
self._generate_entity_ids(new_devices)
except IOError:
_LOGGER.exception("Error updating %s with %d new devices",
known_dev_path, len(new_devices))
def _track_device(self, device, name):
"""
Add a device to the list of tracked devices.
Does not generate the entity id yet.
"""
default_last_seen = dt_util.utcnow().replace(year=1990)
self.tracked[device] = {
'name': name,
'last_seen': default_last_seen,
'state_attr': {ATTR_FRIENDLY_NAME: name}
}
def _generate_entity_ids(self, need_entity_id):
""" Generate entity ids for a list of devices. """
# Setup entity_ids for the new devices
used_entity_ids = [info['entity_id'] for device, info
in self.tracked.items()
if device not in need_entity_id]
for device in need_entity_id:
name = self.tracked[device]['name']
entity_id = util.ensure_unique_string(
ENTITY_ID_FORMAT.format(util.slugify(name)),
used_entity_ids)
used_entity_ids.append(entity_id)
self.tracked[device]['entity_id'] = entity_id

View File

@ -0,0 +1,48 @@
"""
homeassistant.components.device_tracker.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MQTT platform for the device tracker.
device_tracker:
platform: mqtt
qos: 1
devices:
paulus_oneplus: /location/paulus
annetherese_n4: /location/annetherese
"""
import logging
from homeassistant import util
import homeassistant.components.mqtt as mqtt
DEPENDENCIES = ['mqtt']
CONF_QOS = 'qos'
CONF_DEVICES = 'devices'
DEFAULT_QOS = 0
_LOGGER = logging.getLogger(__name__)
def setup_scanner(hass, config, see):
""" Set up a MQTT tracker. """
devices = config.get(CONF_DEVICES)
qos = util.convert(config.get(CONF_QOS), int, DEFAULT_QOS)
if not isinstance(devices, dict):
_LOGGER.error('Expected %s to be a dict, found %s', CONF_DEVICES,
devices)
return False
dev_id_lookup = {}
def device_tracker_message_received(topic, payload, qos):
""" MQTT message received. """
see(dev_id=dev_id_lookup[topic], location_name=payload)
for dev_id, topic in devices.items():
dev_id_lookup[topic] = dev_id
mqtt.subscribe(hass, topic, device_tracker_message_received, qos)
return True

View File

@ -70,7 +70,6 @@ class NetgearDeviceScanner(object):
self.lock = threading.Lock() self.lock = threading.Lock()
if host is None: if host is None:
print("BIER")
self._api = pynetgear.Netgear() self._api = pynetgear.Netgear()
elif username is None: elif username is None:
self._api = pynetgear.Netgear(password, host) self._api = pynetgear.Netgear(password, host)

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """ """ DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "35ecb5457a9ff0f4142c2605b53eb843" VERSION = "8d7dfdebcbbde875470573016b005b73"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit b0b12e20e0f61df849c414c2dfbcf9923f784631 Subproject commit d069489d09e9155c44a0fdbdb3cecdab02d18b5f

View File

@ -60,6 +60,7 @@ MQTT_CLIENT = None
DEFAULT_PORT = 1883 DEFAULT_PORT = 1883
DEFAULT_KEEPALIVE = 60 DEFAULT_KEEPALIVE = 60
DEFAULT_QOS = 0
SERVICE_PUBLISH = 'publish' SERVICE_PUBLISH = 'publish'
EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED' EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED'
@ -79,17 +80,18 @@ ATTR_PAYLOAD = 'payload'
ATTR_QOS = 'qos' ATTR_QOS = 'qos'
def publish(hass, topic, payload, qos=0): def publish(hass, topic, payload, qos=None):
""" Send an MQTT message. """ """ Send an MQTT message. """
data = { data = {
ATTR_TOPIC: topic, ATTR_TOPIC: topic,
ATTR_PAYLOAD: payload, ATTR_PAYLOAD: payload,
ATTR_QOS: qos,
} }
if qos is not None:
data[ATTR_QOS] = qos
hass.services.call(DOMAIN, SERVICE_PUBLISH, data) hass.services.call(DOMAIN, SERVICE_PUBLISH, data)
def subscribe(hass, topic, callback, qos=0): def subscribe(hass, topic, callback, qos=DEFAULT_QOS):
""" Subscribe to a topic. """ """ Subscribe to a topic. """
def mqtt_topic_subscriber(event): def mqtt_topic_subscriber(event):
""" Match subscribed MQTT topic. """ """ Match subscribed MQTT topic. """
@ -141,7 +143,7 @@ def setup(hass, config):
""" Handle MQTT publish service calls. """ """ Handle MQTT publish service calls. """
msg_topic = call.data.get(ATTR_TOPIC) msg_topic = call.data.get(ATTR_TOPIC)
payload = call.data.get(ATTR_PAYLOAD) payload = call.data.get(ATTR_PAYLOAD)
qos = call.data.get(ATTR_QOS) qos = call.data.get(ATTR_QOS, DEFAULT_QOS)
if msg_topic is None or payload is None: if msg_topic is None or payload is None:
return return
MQTT_CLIENT.publish(msg_topic, payload, qos) MQTT_CLIENT.publish(msg_topic, payload, qos)

View File

@ -1,6 +1,6 @@
""" Constants used by Home Assistant components. """ """ Constants used by Home Assistant components. """
__version__ = "0.7.3dev" __version__ = "0.7.3dev0"
# Can be used to specify a catch all when registering state or event listeners. # Can be used to specify a catch all when registering state or event listeners.
MATCH_ALL = '*' MATCH_ALL = '*'
@ -40,7 +40,7 @@ STATE_ON = 'on'
STATE_OFF = 'off' STATE_OFF = 'off'
STATE_HOME = 'home' STATE_HOME = 'home'
STATE_NOT_HOME = 'not_home' STATE_NOT_HOME = 'not_home'
STATE_UNKNOWN = "unknown" STATE_UNKNOWN = 'unknown'
STATE_OPEN = 'open' STATE_OPEN = 'open'
STATE_CLOSED = 'closed' STATE_CLOSED = 'closed'
STATE_PLAYING = 'playing' STATE_PLAYING = 'playing'

View File

@ -10,8 +10,8 @@ from collections import defaultdict
from homeassistant.exceptions import NoEntitySpecifiedError from homeassistant.exceptions import NoEntitySpecifiedError
from homeassistant.const import ( from homeassistant.const import (
ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT, ATTR_HIDDEN, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_UNIT_OF_MEASUREMENT,
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, TEMP_CELCIUS, DEVICE_DEFAULT_NAME, STATE_ON, STATE_OFF, STATE_UNKNOWN, TEMP_CELCIUS,
TEMP_FAHRENHEIT) TEMP_FAHRENHEIT)
# Dict mapping entity_id to a boolean that overwrites the hidden property # Dict mapping entity_id to a boolean that overwrites the hidden property
@ -44,17 +44,17 @@ class Entity(object):
@property @property
def name(self): def name(self):
""" Returns the name of the entity. """ """ Returns the name of the entity. """
return self.get_name() return DEVICE_DEFAULT_NAME
@property @property
def state(self): def state(self):
""" Returns the state of the entity. """ """ Returns the state of the entity. """
return self.get_state() return STATE_UNKNOWN
@property @property
def state_attributes(self): def state_attributes(self):
""" Returns the state attributes. """ """ Returns the state attributes. """
return {} return None
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
@ -64,34 +64,12 @@ class Entity(object):
@property @property
def hidden(self): def hidden(self):
""" Suggestion if the entity should be hidden from UIs. """ """ Suggestion if the entity should be hidden from UIs. """
return self._hidden return False
@hidden.setter
def hidden(self, val):
""" Sets the suggestion for visibility. """
self._hidden = bool(val)
def update(self): def update(self):
""" Retrieve latest state. """ """ Retrieve latest state. """
pass pass
# DEPRECATION NOTICE:
# Device is moving from getters to properties.
# For now the new properties will call the old functions
# This will be removed in the future.
def get_name(self):
""" Returns the name of the entity if any. """
return DEVICE_DEFAULT_NAME
def get_state(self):
""" Returns state of the entity. """
return "Unknown"
def get_state_attributes(self):
""" Returns optional state attributes. """
return None
# DO NOT OVERWRITE # DO NOT OVERWRITE
# These properties and methods are either managed by Home Assistant or they # These properties and methods are either managed by Home Assistant or they
# are used to perform a very specific function. Overwriting these may # are used to perform a very specific function. Overwriting these may

View File

@ -129,13 +129,13 @@ class EntityComponent(object):
if platform is None: if platform is None:
return return
platform_name = '{}.{}'.format(self.domain, platform_type)
try: try:
platform.setup_platform( platform.setup_platform(
self.hass, platform_config, self.add_entities, discovery_info) self.hass, platform_config, self.add_entities, discovery_info)
self.hass.config.components.append(platform_name)
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
self.logger.exception( self.logger.exception(
'Error while setting up platform %s', platform_type) 'Error while setting up platform %s', platform_type)
return
platform_name = '{}.{}'.format(self.domain, platform_type)
self.hass.config.components.append(platform_name)

View File

@ -71,7 +71,7 @@ def ensure_unique_string(preferred_string, current_strings):
""" Returns a string that is not present in current_strings. """ Returns a string that is not present in current_strings.
If preferred string exists will append _2, _3, .. """ If preferred string exists will append _2, _3, .. """
test_string = preferred_string test_string = preferred_string
current_strings = list(current_strings) current_strings = set(current_strings)
tries = 1 tries = 1