""" homeassistant.components.history ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Provide pre-made queries on top of the recorder component. """ import re from datetime import datetime, timedelta from itertools import groupby import homeassistant.components.recorder as recorder DOMAIN = 'history' DEPENDENCIES = ['recorder', 'http'] def last_5_states(entity_id): """ Return the last 5 states for entity_id. """ entity_id = entity_id.lower() query = """ SELECT * FROM states WHERE entity_id=? AND last_changed=last_updated ORDER BY last_changed DESC LIMIT 0, 5 """ return recorder.query_states(query, (entity_id, )) def state_changes_during_period(start_time, end_time=None, entity_id=None): """ Return states changes during period start_time - end_time. Currently does _not_ include how the states where at exactly start_time. """ where = "last_changed=last_updated AND last_changed > ? " data = [start_time] if end_time is not None: where += "AND last_changed < ? " data.append(end_time) if entity_id is not None: where += "AND entity_id = ? " data.append(entity_id.lower()) query = ("SELECT * FROM states WHERE {} " "ORDER BY entity_id, last_changed ASC").format(where) states = recorder.query_states(query, data) result = [] for entity_id, group in groupby(states, lambda state: state.entity_id): # Query the state of the entity ID before `start_time` so the returned # set will cover everything between `start_time` and `end_time`. old_state = list(recorder.query_states( "SELECT * FROM states WHERE entity_id = ? AND last_changed <= ? " "AND last_changed=last_updated ORDER BY last_changed DESC " "LIMIT 0, 1", (entity_id, start_time))) if old_state: old_state[0].last_changed = start_time result.append(old_state + list(group)) return result def setup(hass, config): """ Setup history hooks. """ hass.http.register_path( 'GET', re.compile( r'/api/history/entity/(?P[a-zA-Z\._0-9]+)/' r'recent_states'), _api_last_5_states) hass.http.register_path( 'GET', re.compile(r'/api/history/period'), _api_history_period) return True # pylint: disable=invalid-name def _api_last_5_states(handler, path_match, data): """ Return the last 5 states for an entity id as JSON. """ entity_id = path_match.group('entity_id') handler.write_json(list(last_5_states(entity_id))) def _api_history_period(handler, path_match, data): """ Return history over a period of time. """ # 1 day for now.. start_time = datetime.now() - timedelta(seconds=86400) entity_id = data.get('filter_entity_id') handler.write_json( state_changes_during_period(start_time, entity_id=entity_id))