mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
DeviceTracker can now reload tracked devices without restart
This commit is contained in:
parent
f07622e0d7
commit
05e68c3e1e
@ -239,6 +239,19 @@ class StateMachine(object):
|
||||
""" List of categories which states are being tracked. """
|
||||
return self.states.keys()
|
||||
|
||||
def remove_category(self, category):
|
||||
""" Removes a category from the state machine.
|
||||
|
||||
Returns boolean to indicate if a category was removed. """
|
||||
try:
|
||||
del self.states[category]
|
||||
|
||||
return True
|
||||
|
||||
except KeyError:
|
||||
# if category does not exist
|
||||
return False
|
||||
|
||||
def set_state(self, category, new_state, attributes=None):
|
||||
""" Set the state of a category, add category if it does not exist.
|
||||
|
||||
@ -271,12 +284,14 @@ class StateMachine(object):
|
||||
def get_state(self, category):
|
||||
""" Returns a dict (state,last_changed, attributes) describing
|
||||
the state of the specified category. """
|
||||
if category not in self.states:
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
# Make a copy so people won't accidently mutate the state
|
||||
return dict(self.states[category])
|
||||
|
||||
except KeyError:
|
||||
# If category does not exist
|
||||
return None
|
||||
|
||||
def is_state(self, category, state):
|
||||
""" Returns True if category exists and is specified state. """
|
||||
cur_state = self.get_state(category)
|
||||
|
@ -19,6 +19,8 @@ import requests
|
||||
|
||||
import homeassistant as ha
|
||||
|
||||
EVENT_DEVICE_TRACKER_RELOAD = "device_tracker.reload_devices_csv"
|
||||
|
||||
STATE_CATEGORY_SUN = "weather.sun"
|
||||
STATE_ATTRIBUTE_NEXT_SUN_RISING = "next_rising"
|
||||
STATE_ATTRIBUTE_NEXT_SUN_SETTING = "next_setting"
|
||||
@ -109,74 +111,23 @@ class DeviceTracker(object):
|
||||
# Did we encounter a valid known devices file
|
||||
self.invalid_known_devices_file = False
|
||||
|
||||
# Read known devices if file exists
|
||||
if os.path.isfile(KNOWN_DEVICES_FILE):
|
||||
with open(KNOWN_DEVICES_FILE) as inp:
|
||||
default_last_seen = datetime(1990, 1, 1)
|
||||
|
||||
# Temp variable to keep track of which categories we use
|
||||
# so we can ensure we have unique categories.
|
||||
used_categories = []
|
||||
|
||||
try:
|
||||
for row in csv.DictReader(inp):
|
||||
device = row['device']
|
||||
|
||||
row['track'] = True if row['track'] == '1' else False
|
||||
|
||||
# If we track this device setup tracking variables
|
||||
if row['track']:
|
||||
row['last_seen'] = default_last_seen
|
||||
|
||||
# Make sure that each device is mapped
|
||||
# to a unique category name
|
||||
name = row['name']
|
||||
|
||||
if not name:
|
||||
name = "unnamed_device"
|
||||
|
||||
tries = 0
|
||||
suffix = ""
|
||||
while True:
|
||||
tries += 1
|
||||
|
||||
if tries > 1:
|
||||
suffix = "_{}".format(tries)
|
||||
|
||||
category = STATE_CATEGORY_DEVICE_FORMAT.format(
|
||||
name + suffix)
|
||||
|
||||
if category not in used_categories:
|
||||
break
|
||||
|
||||
row['category'] = category
|
||||
used_categories.append(category)
|
||||
|
||||
self.known_devices[device] = row
|
||||
|
||||
except KeyError:
|
||||
self.invalid_known_devices_file = False
|
||||
self.logger.warning((
|
||||
"Invalid {} found. "
|
||||
"We won't update it with new found devices.").
|
||||
format(KNOWN_DEVICES_FILE))
|
||||
|
||||
if len(self.device_state_categories) == 0:
|
||||
self.logger.warning(
|
||||
"No devices to track. Please update {}.".format(
|
||||
KNOWN_DEVICES_FILE))
|
||||
self._read_known_devices_file()
|
||||
|
||||
ha.track_time_change(eventbus,
|
||||
lambda time:
|
||||
self.update_devices(
|
||||
device_scanner.scan_devices()))
|
||||
|
||||
eventbus.listen(EVENT_DEVICE_TRACKER_RELOAD,
|
||||
lambda event: self._read_known_devices_file())
|
||||
|
||||
@property
|
||||
def device_state_categories(self):
|
||||
""" Returns a list containing all categories
|
||||
""" Returns a set containing all categories
|
||||
that are maintained for devices. """
|
||||
return [self.known_devices[device]['category'] for device
|
||||
in self.known_devices if self.known_devices[device]['track']]
|
||||
return set([self.known_devices[device]['category'] for device
|
||||
in self.known_devices
|
||||
if self.known_devices[device]['track']])
|
||||
|
||||
def update_devices(self, found_devices):
|
||||
""" Update device states based on the found devices. """
|
||||
@ -261,6 +212,92 @@ class DeviceTracker(object):
|
||||
|
||||
self.lock.release()
|
||||
|
||||
def _read_known_devices_file(self):
|
||||
""" Parse and process the known devices file. """
|
||||
|
||||
# Read known devices if file exists
|
||||
if os.path.isfile(KNOWN_DEVICES_FILE):
|
||||
self.lock.acquire()
|
||||
|
||||
known_devices = {}
|
||||
|
||||
with open(KNOWN_DEVICES_FILE) as inp:
|
||||
default_last_seen = datetime(1990, 1, 1)
|
||||
|
||||
# Temp variable to keep track of which categories we use
|
||||
# so we can ensure we have unique categories.
|
||||
used_categories = []
|
||||
|
||||
try:
|
||||
for row in csv.DictReader(inp):
|
||||
device = row['device']
|
||||
|
||||
row['track'] = True if row['track'] == '1' else False
|
||||
|
||||
# If we track this device setup tracking variables
|
||||
if row['track']:
|
||||
row['last_seen'] = default_last_seen
|
||||
|
||||
# Make sure that each device is mapped
|
||||
# to a unique category name
|
||||
name = row['name']
|
||||
|
||||
if not name:
|
||||
name = "unnamed_device"
|
||||
|
||||
tries = 0
|
||||
suffix = ""
|
||||
while True:
|
||||
tries += 1
|
||||
|
||||
if tries > 1:
|
||||
suffix = "_{}".format(tries)
|
||||
|
||||
category = STATE_CATEGORY_DEVICE_FORMAT.format(
|
||||
name + suffix)
|
||||
|
||||
if category not in used_categories:
|
||||
break
|
||||
|
||||
row['category'] = category
|
||||
used_categories.append(category)
|
||||
|
||||
known_devices[device] = row
|
||||
|
||||
if len(known_devices) == 0:
|
||||
self.logger.warning(
|
||||
"No devices to track. Please update {}.".format(
|
||||
KNOWN_DEVICES_FILE))
|
||||
|
||||
# Remove categories that are no longer maintained
|
||||
new_categories = set([known_devices[device]['category']
|
||||
for device in known_devices
|
||||
if known_devices[device]['track']])
|
||||
|
||||
for category in \
|
||||
self.device_state_categories - new_categories:
|
||||
|
||||
print "Removing ", category
|
||||
self.statemachine.remove_category(category)
|
||||
|
||||
# File parsed, warnings given if necessary
|
||||
# categories cleaned up, make it available
|
||||
self.known_devices = known_devices
|
||||
|
||||
self.logger.info(
|
||||
"DeviceTracker:Loaded devices from {}".format(
|
||||
KNOWN_DEVICES_FILE))
|
||||
|
||||
except KeyError:
|
||||
self.invalid_known_devices_file = True
|
||||
self.logger.warning((
|
||||
"Invalid {} found. "
|
||||
"We won't update it with new found devices.").
|
||||
format(KNOWN_DEVICES_FILE))
|
||||
|
||||
finally:
|
||||
self.lock.release()
|
||||
|
||||
|
||||
class TomatoDeviceScanner(object):
|
||||
""" This class queries a wireless router running Tomato firmware
|
||||
|
Loading…
x
Reference in New Issue
Block a user