diff --git a/README.md b/README.md
index 27383efbf55..49d1168d884 100644
--- a/README.md
+++ b/README.md
@@ -62,11 +62,11 @@ Other status codes that can occur are:
The api supports the following actions:
**/api/states - GET**
-Returns a list of categories for which a state is available
+Returns a list of entity ids for which a state is available
```json
{
- "categories": [
+ "entity_ids": [
"Paulus_Nexus_4",
"weather.sun",
"all_devices"
@@ -103,8 +103,8 @@ Returns a dict with as keys the domain and as value a list of published services
}
```
-**/api/states/<category>** - GET
-Returns the current state from a category
+**/api/states/<entity_id>** - GET
+Returns the current state from an entity
```json
{
@@ -112,14 +112,14 @@ Returns the current state from a category
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
- "category": "weather.sun",
+ "entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
```
-**/api/states/<category>** - POST
-Updates the current state of a category. Returns status code 201 if successful with location header of updated resource and the new state in the body.
+**/api/states/<entity_id>** - POST
+Updates the current state of an entity. Returns status code 201 if successful with location header of updated resource and the new state in the body.
parameter: new_state - string
optional parameter: attributes - JSON encoded object
@@ -129,7 +129,7 @@ optional parameter: attributes - JSON encoded object
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
- "category": "weather.sun",
+ "entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
diff --git a/homeassistant/__init__.py b/homeassistant/__init__.py
index 2e61a12a5fa..706cc5037be 100644
--- a/homeassistant/__init__.py
+++ b/homeassistant/__init__.py
@@ -3,13 +3,13 @@ homeassistant
~~~~~~~~~~~~~
Home Assistant is a Home Automation framework for observing the state
-of objects and react to changes.
+of entities and react to changes.
"""
import time
import logging
import threading
-from collections import defaultdict, namedtuple
+from collections import namedtuple
import datetime as dt
import homeassistant.util as util
@@ -78,33 +78,33 @@ def _matcher(subject, pattern):
return MATCH_ALL == pattern or subject in pattern
-def split_state_category(category):
- """ Splits a state category into domain, object_id. """
- return category.split(".", 1)
+def split_entity_id(entity_id):
+ """ Splits a state entity_id into domain, object_id. """
+ return entity_id.split(".", 1)
-def filter_categories(categories, domain_filter=None, strip_domain=False):
- """ Filter a list of categories based on domain. Setting strip_domain
+def filter_entity_ids(entity_ids, domain_filter=None, strip_domain=False):
+ """ Filter a list of entities based on domain. Setting strip_domain
will only return the object_ids. """
return [
- split_state_category(cat)[1] if strip_domain else cat
- for cat in categories if
- not domain_filter or cat.startswith(domain_filter)
+ split_entity_id(entity_id)[1] if strip_domain else entity_id
+ for entity_id in entity_ids if
+ not domain_filter or entity_id.startswith(domain_filter)
]
-def track_state_change(bus, category, action, from_state=None, to_state=None):
+def track_state_change(bus, entity_id, action, from_state=None, to_state=None):
""" Helper method to track specific state changes. """
from_state = _process_match_param(from_state)
to_state = _process_match_param(to_state)
def listener(event):
""" State change listener that listens for specific state changes. """
- if category == event.data['category'] and \
+ if entity_id == event.data['entity_id'] and \
_matcher(event.data['old_state'].state, from_state) and \
_matcher(event.data['new_state'].state, to_state):
- action(event.data['category'],
+ action(event.data['entity_id'],
event.data['old_state'],
event.data['new_state'])
@@ -304,7 +304,11 @@ class State(object):
else:
self.last_changed = last_changed
- def to_json_dict(self, category=None):
+ def copy(self):
+ """ Creates a copy of itself. """
+ return State(self.state, dict(self.attributes), self.last_changed)
+
+ def to_json_dict(self, entity_id=None):
""" Converts State to a dict to be used within JSON.
Ensures: state == State.from_json_dict(state.to_json_dict()) """
@@ -312,15 +316,11 @@ class State(object):
'attributes': self.attributes,
'last_changed': util.datetime_to_str(self.last_changed)}
- if category:
- json_dict['category'] = category
+ if entity_id:
+ json_dict['entity_id'] = entity_id
return json_dict
- def copy(self):
- """ Creates a copy of itself. """
- return State(self.state, dict(self.attributes), self.last_changed)
-
@staticmethod
def from_json_dict(json_dict):
""" Static method to create a state from a dict.
@@ -345,75 +345,75 @@ class State(object):
class StateMachine(object):
- """ Helper class that tracks the state of different categories. """
+ """ Helper class that tracks the state of different entities. """
def __init__(self, bus):
- self.states = dict()
+ self.states = {}
self.bus = bus
self.lock = threading.Lock()
@property
- def categories(self):
- """ List of categories which states are being tracked. """
+ def entity_ids(self):
+ """ List of entitie ids that are being tracked. """
with self.lock:
return self.states.keys()
- def remove_category(self, category):
- """ Removes a category from the state machine.
+ def remove_entity(self, entity_id):
+ """ Removes a entity from the state machine.
- Returns boolean to indicate if a category was removed. """
+ Returns boolean to indicate if a entity was removed. """
with self.lock:
try:
- del self.states[category]
+ del self.states[entity_id]
return True
except KeyError:
- # if category does not exist
+ # if entity 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.
+ def set_state(self, entity_id, new_state, attributes=None):
+ """ Set the state of an entity, add entity if it does not exist.
Attributes is an optional dict to specify attributes of this state. """
attributes = attributes or {}
with self.lock:
- # Add category if it does not exist
- if category not in self.states:
- self.states[category] = State(new_state, attributes)
+ # Add entity if it does not exist
+ if entity_id not in self.states:
+ self.states[entity_id] = State(new_state, attributes)
# Change state and fire listeners
else:
- old_state = self.states[category]
+ old_state = self.states[entity_id]
if old_state.state != new_state or \
old_state.attributes != attributes:
- self.states[category] = State(new_state, attributes)
+ self.states[entity_id] = State(new_state, attributes)
self.bus.fire_event(EVENT_STATE_CHANGED,
- {'category': category,
+ {'entity_id': entity_id,
'old_state': old_state,
- 'new_state': self.states[category]})
+ 'new_state': self.states[entity_id]})
- def get_state(self, category):
+ def get_state(self, entity_id):
""" Returns a dict (state, last_changed, attributes) describing
- the state of the specified category. """
+ the state of the specified entity. """
with self.lock:
try:
# Make a copy so people won't mutate the state
- return self.states[category].copy()
+ return self.states[entity_id].copy()
except KeyError:
- # If category does not exist
+ # If entity does not exist
return None
- def is_state(self, category, state):
- """ Returns True if category exists and is specified state. """
+ def is_state(self, entity_id, state):
+ """ Returns True if entity exists and is specified state. """
try:
- return self.get_state(category).state == state
+ return self.get_state(entity_id).state == state
except AttributeError:
# get_state returned None
return False
@@ -438,8 +438,10 @@ class Timer(threading.Thread):
last_fired_on_second = -1
+ calc_now = dt.datetime.now
+
while True:
- now = dt.datetime.now()
+ now = calc_now()
# First check checks if we are not on a second matching the
# timer interval. Second check checks if we did not already fire
@@ -457,7 +459,7 @@ class Timer(threading.Thread):
time.sleep(slp_seconds)
- now = dt.datetime.now()
+ now = calc_now()
last_fired_on_second = now.second
diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py
index 10396475cbd..a96da96e207 100644
--- a/homeassistant/bootstrap.py
+++ b/homeassistant/bootstrap.py
@@ -138,10 +138,10 @@ def from_config_file(config_path):
# Init groups
if has_section("groups"):
- for name, categories in config.items("groups"):
+ for name, entity_ids in config.items("groups"):
add_status("Group - {}".format(name),
group.setup(bus, statemachine, name,
- categories.split(",")))
+ entity_ids.split(",")))
# Light trigger
if light_control:
diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py
index 0336fba5993..168823c7b0f 100644
--- a/homeassistant/components/__init__.py
+++ b/homeassistant/components/__init__.py
@@ -8,7 +8,7 @@ Component design guidelines:
Each component defines a constant DOMAIN that is equal to its filename.
-Each component that tracks states should create state category names in the
+Each component that tracks states should create state entity names in the
format ".".
Each component should publish services only under its own domain.
diff --git a/homeassistant/components/chromecast.py b/homeassistant/components/chromecast.py
index a2384c09153..a50ae3a994d 100644
--- a/homeassistant/components/chromecast.py
+++ b/homeassistant/components/chromecast.py
@@ -16,7 +16,7 @@ DOMAIN = "chromecast"
SERVICE_YOUTUBE_VIDEO = "play_youtube_video"
-STATE_CATEGORY_FORMAT = DOMAIN + '.{}'
+ENTITY_ID_FORMAT = DOMAIN + '.{}'
STATE_NO_APP = "none"
ATTR_FRIENDLY_NAME = "friendly_name"
@@ -29,15 +29,15 @@ def turn_off(statemachine, cc_id=None):
""" Exits any running app on the specified ChromeCast and shows
idle screen. Will quit all ChromeCasts if nothing specified. """
- cats = [STATE_CATEGORY_FORMAT.format(cc_id)] if cc_id \
- else ha.filter_categories(statemachine.categories, DOMAIN)
+ entity_ids = [ENTITY_ID_FORMAT.format(cc_id)] if cc_id \
+ else ha.filter_entity_ids(statemachine.entity_ids, DOMAIN)
- for cat in cats:
- state = statemachine.get_state(cat)
+ for entity_id in entity_ids:
+ state = statemachine.get_state(entity_id)
- if state and \
- state.state != STATE_NO_APP or \
- state.state != pychromecast.APP_ID_HOME:
+ if (state and
+ (state.state != STATE_NO_APP or
+ state.state != pychromecast.APP_ID_HOME)):
pychromecast.quit_app(state.attributes[ATTR_HOST])
@@ -53,7 +53,7 @@ def setup(bus, statemachine, host):
logger.error("Could not find Chromecast")
return False
- category = STATE_CATEGORY_FORMAT.format(util.slugify(
+ entity = ENTITY_ID_FORMAT.format(util.slugify(
device.friendly_name))
bus.register_service(DOMAIN, ha.SERVICE_TURN_OFF,
@@ -80,7 +80,7 @@ def setup(bus, statemachine, host):
status = pychromecast.get_app_status(host)
if status:
- statemachine.set_state(category, status.name,
+ statemachine.set_state(entity, status.name,
{ATTR_FRIENDLY_NAME:
pychromecast.get_friendly_name(
status.name),
@@ -88,7 +88,7 @@ def setup(bus, statemachine, host):
ATTR_STATE: status.state,
ATTR_OPTIONS: status.options})
else:
- statemachine.set_state(category, STATE_NO_APP, {ATTR_HOST: host})
+ statemachine.set_state(entity, STATE_NO_APP, {ATTR_HOST: host})
ha.track_time_change(bus, update_chromecast_state)
diff --git a/homeassistant/components/device_sun_light_trigger.py b/homeassistant/components/device_sun_light_trigger.py
index d3867cec9a8..c2a69c5ae7e 100644
--- a/homeassistant/components/device_sun_light_trigger.py
+++ b/homeassistant/components/device_sun_light_trigger.py
@@ -22,20 +22,20 @@ def setup(bus, statemachine, light_group=None):
logger = logging.getLogger(__name__)
- device_state_categories = ha.filter_categories(statemachine.categories,
- device_tracker.DOMAIN)
+ device_entity_ids = ha.filter_entity_ids(statemachine.entity_ids,
+ device_tracker.DOMAIN)
- if not device_state_categories:
+ if not device_entity_ids:
logger.error("LightTrigger:No devices found to track")
return False
if not light_group:
- light_group = light.STATE_GROUP_NAME_ALL_LIGHTS
+ light_group = light.GROUP_NAME_ALL_LIGHTS
# Get the light IDs from the specified group
- light_ids = ha.filter_categories(
- group.get_categories(statemachine, light_group), light.DOMAIN, True)
+ light_ids = ha.filter_entity_ids(
+ group.get_entity_ids(statemachine, light_group), light.DOMAIN, True)
if not light_ids:
logger.error("LightTrigger:No lights found to turn on ")
@@ -48,7 +48,7 @@ def setup(bus, statemachine, light_group=None):
len(light_ids))
# pylint: disable=unused-argument
- def handle_sun_rising(category, old_state, new_state):
+ def handle_sun_rising(entity, old_state, new_state):
"""The moment sun sets we want to have all the lights on.
We will schedule to have each light start after one another
and slowly transition in."""
@@ -76,7 +76,7 @@ def setup(bus, statemachine, light_group=None):
# Track every time sun rises so we can schedule a time-based
# pre-sun set event
- ha.track_state_change(bus, sun.STATE_CATEGORY, handle_sun_rising,
+ ha.track_state_change(bus, sun.ENTITY_ID, handle_sun_rising,
sun.STATE_BELOW_HORIZON, sun.STATE_ABOVE_HORIZON)
# If the sun is already above horizon
@@ -84,14 +84,14 @@ def setup(bus, statemachine, light_group=None):
if sun.is_up(statemachine):
handle_sun_rising(None, None, None)
- def handle_device_state_change(category, old_state, new_state):
+ def handle_device_state_change(entity, old_state, new_state):
""" Function to handle tracked device state changes. """
lights_are_on = group.is_on(statemachine, light_group)
light_needed = not (lights_are_on or sun.is_up(statemachine))
# Specific device came home ?
- if (category != device_tracker.STATE_CATEGORY_ALL_DEVICES and
+ if (entity != device_tracker.ENTITY_ID_ALL_DEVICES and
new_state.state == ha.STATE_HOME):
# These variables are needed for the elif check
@@ -103,7 +103,7 @@ def setup(bus, statemachine, light_group=None):
logger.info(
"Home coming event for {}. Turning lights on".
- format(category))
+ format(entity))
for light_id in light_ids:
light.turn_on(bus, light_id)
@@ -127,7 +127,7 @@ def setup(bus, statemachine, light_group=None):
break
# Did all devices leave the house?
- elif (category == device_tracker.STATE_CATEGORY_ALL_DEVICES and
+ elif (entity == device_tracker.ENTITY_ID_ALL_DEVICES and
new_state.state == ha.STATE_NOT_HOME and lights_are_on):
logger.info(
@@ -136,12 +136,12 @@ def setup(bus, statemachine, light_group=None):
general.shutdown_devices(bus, statemachine)
# Track home coming of each seperate device
- for category in device_state_categories:
- ha.track_state_change(bus, category, handle_device_state_change,
+ for entity in device_entity_ids:
+ ha.track_state_change(bus, entity, handle_device_state_change,
ha.STATE_NOT_HOME, ha.STATE_HOME)
# Track when all devices are gone to shut down lights
- ha.track_state_change(bus, device_tracker.STATE_CATEGORY_ALL_DEVICES,
+ ha.track_state_change(bus, device_tracker.ENTITY_ID_ALL_DEVICES,
handle_device_state_change, ha.STATE_HOME,
ha.STATE_NOT_HOME)
diff --git a/homeassistant/components/device_tracker.py b/homeassistant/components/device_tracker.py
index 1a56415d829..e34bf090913 100644
--- a/homeassistant/components/device_tracker.py
+++ b/homeassistant/components/device_tracker.py
@@ -24,11 +24,11 @@ DOMAIN = "device_tracker"
SERVICE_DEVICE_TRACKER_RELOAD = "reload_devices_csv"
-STATE_GROUP_NAME_ALL_DEVICES = 'all_tracked_devices'
-STATE_CATEGORY_ALL_DEVICES = group.STATE_CATEGORY_FORMAT.format(
- STATE_GROUP_NAME_ALL_DEVICES)
+GROUP_NAME_ALL_DEVICES = 'all_tracked_devices'
+ENTITY_ID_ALL_DEVICES = group.ENTITY_ID_FORMAT.format(
+ GROUP_NAME_ALL_DEVICES)
-STATE_CATEGORY_FORMAT = DOMAIN + '.{}'
+ENTITY_ID_FORMAT = DOMAIN + '.{}'
# After how much time do we consider a device not home if
# it does not show up on scans
@@ -43,10 +43,10 @@ KNOWN_DEVICES_FILE = "known_devices.csv"
def is_home(statemachine, device_id=None):
""" Returns if any or specified device is home. """
- category = STATE_CATEGORY_FORMAT.format(device_id) if device_id \
- else STATE_CATEGORY_ALL_DEVICES
+ entity = ENTITY_ID_FORMAT.format(device_id) if device_id \
+ else ENTITY_ID_ALL_DEVICES
- return statemachine.is_state(category, ha.STATE_HOME)
+ return statemachine.is_state(entity, ha.STATE_HOME)
# pylint: disable=too-many-instance-attributes
@@ -83,14 +83,14 @@ class DeviceTracker(object):
self.update_devices(device_scanner.scan_devices())
- group.setup(bus, statemachine, STATE_GROUP_NAME_ALL_DEVICES,
- list(self.device_state_categories))
+ group.setup(bus, statemachine, GROUP_NAME_ALL_DEVICES,
+ list(self.device_entity_ids))
@property
- def device_state_categories(self):
- """ Returns a set containing all categories
- that are maintained for devices. """
- return set([self.known_devices[device]['category'] for device
+ def device_entity_ids(self):
+ """ Returns a set containing all device entity ids
+ that are being tracked. """
+ return set([self.known_devices[device]['entity_id'] for device
in self.known_devices
if self.known_devices[device]['track']])
@@ -111,7 +111,7 @@ class DeviceTracker(object):
self.known_devices[device]['last_seen'] = now
self.statemachine.set_state(
- self.known_devices[device]['category'], ha.STATE_HOME)
+ self.known_devices[device]['entity_id'], ha.STATE_HOME)
# For all devices we did not find, set state to NH
# But only if they have been gone for longer then the error time span
@@ -122,7 +122,7 @@ class DeviceTracker(object):
self.error_scanning):
self.statemachine.set_state(
- self.known_devices[device]['category'],
+ self.known_devices[device]['entity_id'],
ha.STATE_NOT_HOME)
# If we come along any unknown devices we will write them to the
@@ -180,9 +180,9 @@ class DeviceTracker(object):
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 = []
+ # Temp variable to keep track of which entity ids we use
+ # so we can ensure we have unique entity ids.
+ used_entity_ids = []
try:
for row in csv.DictReader(inp):
@@ -195,23 +195,23 @@ class DeviceTracker(object):
row['last_seen'] = default_last_seen
# Make sure that each device is mapped
- # to a unique category name
+ # to a unique entity_id name
name = util.slugify(row['name']) if row['name'] \
else "unnamed_device"
- category = STATE_CATEGORY_FORMAT.format(name)
+ entity_id = ENTITY_ID_FORMAT.format(name)
tries = 1
- while category in used_categories:
+ while entity_id in used_entity_ids:
tries += 1
suffix = "_{}".format(tries)
- category = STATE_CATEGORY_FORMAT.format(
+ entity_id = ENTITY_ID_FORMAT.format(
name + suffix)
- row['category'] = category
- used_categories.append(category)
+ row['entity_id'] = entity_id
+ used_entity_ids.append(entity_id)
known_devices[device] = row
@@ -220,21 +220,21 @@ class DeviceTracker(object):
"No devices to track. Please update {}.".format(
KNOWN_DEVICES_FILE))
- # Remove categories that are no longer maintained
- new_categories = set([known_devices[device]['category']
+ # Remove entities that are no longer maintained
+ new_entity_ids = set([known_devices[device]['entity_id']
for device in known_devices
if known_devices[device]['track']])
- for category in \
- self.device_state_categories - new_categories:
+ for entity_id in \
+ self.device_entity_ids - new_entity_ids:
self.logger.info(
- "DeviceTracker:Removing category {}".format(
- category))
- self.statemachine.remove_category(category)
+ "DeviceTracker:Removing entity {}".format(
+ entity_id))
+ self.statemachine.remove_entity(entity_id)
# File parsed, warnings given if necessary
- # categories cleaned up, make it available
+ # entities cleaned up, make it available
self.known_devices = known_devices
self.logger.info(
diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py
index 628bb6fb663..7817d39c235 100644
--- a/homeassistant/components/group.py
+++ b/homeassistant/components/group.py
@@ -11,9 +11,9 @@ import homeassistant as ha
DOMAIN = "group"
-STATE_CATEGORY_FORMAT = DOMAIN + ".{}"
+ENTITY_ID_FORMAT = DOMAIN + ".{}"
-STATE_ATTR_CATEGORIES = "categories"
+STATE_ATTR_ENTITY_IDS = "entity_ids"
_GROUP_TYPES = {
"on_off": (ha.STATE_ON, ha.STATE_OFF),
@@ -46,29 +46,32 @@ def is_on(statemachine, group):
return False
-def get_categories(statemachine, group):
- """ Get the categories that make up this group. """
- state = statemachine.get_state(group)
-
- return state.attributes[STATE_ATTR_CATEGORIES] if state else []
+def get_entity_ids(statemachine, group):
+ """ Get the entity ids that make up this group. """
+ try:
+ return statemachine.get_state(group).attributes[STATE_ATTR_ENTITY_IDS]
+ except (AttributeError, KeyError):
+ # AttributeError if state did not exist
+ # KeyError if key did not exist in attributes
+ return []
# pylint: disable=too-many-branches
-def setup(bus, statemachine, name, categories):
+def setup(bus, statemachine, name, entity_ids):
""" Sets up a group state that is the combined state of
several states. Supports ON/OFF and DEVICE_HOME/DEVICE_NOT_HOME. """
logger = logging.getLogger(__name__)
- # Loop over the given categories to:
+ # Loop over the given entities to:
# - determine which group type this is (on_off, device_home)
# - if all states exist and have valid states
# - retrieve the current state of the group
errors = []
group_type, group_on, group_off, group_state = None, None, None, None
- for cat in categories:
- state = statemachine.get_state(cat)
+ for entity_id in entity_ids:
+ state = statemachine.get_state(entity_id)
# Try to determine group type if we didn't yet
if not group_type and state:
@@ -85,15 +88,15 @@ def setup(bus, statemachine, name, categories):
break
- # Check if category exists
+ # Check if entity exists
if not state:
- errors.append("Category {} does not exist".format(cat))
+ errors.append("Entity {} does not exist".format(entity_id))
- # Check if category is valid state
+ # Check if entity is valid state
elif state.state != group_off and state.state != group_on:
errors.append("State of {} is {} (expected: {}, {})".format(
- cat, state.state, group_off, group_on))
+ entity_id, state.state, group_off, group_on))
# Keep track of the group state to init later on
elif group_state == group_off and state.state == group_on:
@@ -105,15 +108,15 @@ def setup(bus, statemachine, name, categories):
return False
- group_cat = STATE_CATEGORY_FORMAT.format(name)
- state_attr = {STATE_ATTR_CATEGORIES: categories}
+ group_entity_id = ENTITY_ID_FORMAT.format(name)
+ state_attr = {STATE_ATTR_ENTITY_IDS: entity_ids}
# pylint: disable=unused-argument
- def _update_group_state(category, old_state, new_state):
+ def _update_group_state(entity_id, old_state, new_state):
""" Updates the group state based on a state change by a tracked
- category. """
+ entity. """
- cur_group_state = statemachine.get_state(group_cat).state
+ cur_group_state = statemachine.get_state(group_entity_id).state
# if cur_group_state = OFF and new_state = ON: set ON
# if cur_group_state = ON and new_state = OFF: research
@@ -121,18 +124,18 @@ def setup(bus, statemachine, name, categories):
if cur_group_state == group_off and new_state.state == group_on:
- statemachine.set_state(group_cat, group_on, state_attr)
+ statemachine.set_state(group_entity_id, group_on, state_attr)
elif cur_group_state == group_on and new_state.state == group_off:
# Check if any of the other states is still on
- if not any([statemachine.is_state(cat, group_on)
- for cat in categories if cat != category]):
- statemachine.set_state(group_cat, group_off, state_attr)
+ if not any([statemachine.is_state(ent_id, group_on)
+ for ent_id in entity_ids if entity_id != ent_id]):
+ statemachine.set_state(group_entity_id, group_off, state_attr)
- for cat in categories:
- ha.track_state_change(bus, cat, _update_group_state)
+ for entity_id in entity_ids:
+ ha.track_state_change(bus, entity_id, _update_group_state)
- statemachine.set_state(group_cat, group_state, state_attr)
+ statemachine.set_state(group_entity_id, group_state, state_attr)
return True
diff --git a/homeassistant/components/httpinterface/__init__.py b/homeassistant/components/httpinterface/__init__.py
index 78361f9f37d..eac31972a8c 100644
--- a/homeassistant/components/httpinterface/__init__.py
+++ b/homeassistant/components/httpinterface/__init__.py
@@ -18,31 +18,31 @@ Other status codes that can occur are:
The api supports the following actions:
/api/states - GET
-Returns a list of categories for which a state is available
+Returns a list of entities for which a state is available
Example result:
{
- "categories": [
+ "entity_ids": [
"Paulus_Nexus_4",
"weather.sun",
"all_devices"
]
}
-/api/states/ - GET
-Returns the current state from a category
+/api/states/ - GET
+Returns the current state from an entity
Example result:
{
"attributes": {
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
- "category": "weather.sun",
+ "entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
-/api/states/ - POST
-Updates the current state of a category. Returns status code 201 if successful
+/api/states/ - POST
+Updates the current state of an entity. Returns status code 201 if successful
with location header of updated resource and as body the new state.
parameter: new_state - string
optional parameter: attributes - JSON encoded object
@@ -52,7 +52,7 @@ Example result:
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
- "category": "weather.sun",
+ "entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
@@ -94,7 +94,7 @@ URL_CHANGE_STATE = "/change_state"
URL_FIRE_EVENT = "/fire_event"
URL_API_STATES = "/api/states"
-URL_API_STATES_CATEGORY = "/api/states/{}"
+URL_API_STATES_ENTITY = "/api/states/{}"
URL_API_EVENTS = "/api/events"
URL_API_EVENTS_EVENT = "/api/events/{}"
URL_API_SERVICES = "/api/services"
@@ -150,10 +150,10 @@ class RequestHandler(BaseHTTPRequestHandler):
# /states
('GET', '/api/states', '_handle_get_api_states'),
('GET',
- re.compile(r'/api/states/(?P[a-zA-Z\._0-9]+)'),
- '_handle_get_api_states_category'),
+ re.compile(r'/api/states/(?P[a-zA-Z\._0-9]+)'),
+ '_handle_get_api_states_entity'),
('POST',
- re.compile(r'/api/states/(?P[a-zA-Z\._0-9]+)'),
+ re.compile(r'/api/states/(?P[a-zA-Z\._0-9]+)'),
'_handle_change_state'),
# /events
@@ -317,8 +317,6 @@ class RequestHandler(BaseHTTPRequestHandler):
self.server.flash_message = None
# Describe state machine:
- categories = []
-
write(("
"
"
"
"
"
@@ -328,17 +326,15 @@ class RequestHandler(BaseHTTPRequestHandler):
"class='form-change-state'>"
""
"
"
- "
Category
State
"
+ "
Entity ID
State
"
"
Attributes
Last Changed
"
"
").format(self.server.api_password))
- for category in \
- sorted(self.server.statemachine.categories,
+ for entity_id in \
+ sorted(self.server.statemachine.entity_ids,
key=lambda key: key.lower()):
- categories.append(category)
-
- state = self.server.statemachine.get_state(category)
+ state = self.server.statemachine.get_state(entity_id)
attributes = " ".join(
["{}: {}".format(attr, state.attributes[attr])
@@ -347,14 +343,14 @@ class RequestHandler(BaseHTTPRequestHandler):
write(("
"
"
{}
{}
{}
{}
"
"
").format(
- category,
+ entity_id,
state.state,
attributes,
util.datetime_to_str(state.last_changed)))
# Change state form
- write(("