diff --git a/README.md b/README.md index 27383efbf557..49d1168d8842 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 2e61a12a5fa4..706cc5037bee 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 10396475cbdd..a96da96e2073 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 0336fba59934..168823c7b0f1 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 a2384c091535..a50ae3a994d4 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 d3867cec9a8a..c2a69c5ae7e0 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 1a56415d829f..e34bf0909136 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 628bb6fb663e..7817d39c2352 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 78361f9f37d5..eac31972a8c0 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'>" "" "" - "" + "" "" "").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(("" + write(("" "" "
CategoryStateEntity IDStateAttributesLast Changed
{}{}{}{}