From 8a14f46595b0f80f1eacc7500e70f4941a0aa913 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 14 Jun 2015 22:56:55 -0700 Subject: [PATCH] Add support to logbook component to browse days --- homeassistant/components/logbook.py | 31 +++++--- .../sensor/swiss_public_transport.py | 2 +- homeassistant/components/sensor/time_date.py | 6 +- homeassistant/util/dt.py | 71 ++++++++++++------- 4 files changed, 72 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/logbook.py b/homeassistant/components/logbook.py index cad31d41cab..d876e9002c8 100644 --- a/homeassistant/components/logbook.py +++ b/homeassistant/components/logbook.py @@ -4,12 +4,14 @@ homeassistant.components.logbook Parses events and generates a human log. """ +from datetime import timedelta from itertools import groupby +import re from homeassistant import State, DOMAIN as HA_DOMAIN from homeassistant.const import ( EVENT_STATE_CHANGED, STATE_HOME, STATE_ON, STATE_OFF, - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, HTTP_BAD_REQUEST) import homeassistant.util.dt as dt_util import homeassistant.components.recorder as recorder import homeassistant.components.sun as sun @@ -17,12 +19,10 @@ import homeassistant.components.sun as sun DOMAIN = "logbook" DEPENDENCIES = ['recorder', 'http'] -URL_LOGBOOK = '/api/logbook' +URL_LOGBOOK = re.compile(r'/api/logbook(?:/(?P\d{4}-\d{2}-\d{2})|)') -QUERY_EVENTS_AFTER = "SELECT * FROM events WHERE time_fired > ?" QUERY_EVENTS_BETWEEN = """ SELECT * FROM events WHERE time_fired > ? AND time_fired < ? - ORDER BY time_fired """ GROUP_BY_MINUTES = 15 @@ -37,11 +37,26 @@ def setup(hass, config): def _handle_get_logbook(handler, path_match, data): """ Return logbook entries. """ - start_today = dt_util.now().replace(hour=0, minute=0, second=0) + date_str = path_match.group('date') - handler.write_json(humanify( - recorder.query_events( - QUERY_EVENTS_AFTER, (dt_util.as_utc(start_today),)))) + if date_str: + start_date = dt_util.date_str_to_date(date_str) + + if start_date is None: + handler.write_json_message("Error parsing JSON", HTTP_BAD_REQUEST) + return + + start_day = dt_util.start_of_local_day(start_date) + else: + start_day = dt_util.start_of_local_day() + + end_day = start_day + timedelta(days=1) + + events = recorder.query_events( + QUERY_EVENTS_BETWEEN, + (dt_util.as_utc(start_day), dt_util.as_utc(end_day))) + + handler.write_json(humanify(events)) class Entry(object): diff --git a/homeassistant/components/sensor/swiss_public_transport.py b/homeassistant/components/sensor/swiss_public_transport.py index a9eda2754bd..bd2d336d8ed 100644 --- a/homeassistant/components/sensor/swiss_public_transport.py +++ b/homeassistant/components/sensor/swiss_public_transport.py @@ -122,7 +122,7 @@ class PublicTransportData(object): try: return [ - dt_util.datetime_to_short_time_str( + dt_util.datetime_to_time_str( dt_util.as_local(dt_util.utc_from_timestamp( item['from']['departureTimestamp'])) ) diff --git a/homeassistant/components/sensor/time_date.py b/homeassistant/components/sensor/time_date.py index cd35e8343ba..c77910ddcc9 100644 --- a/homeassistant/components/sensor/time_date.py +++ b/homeassistant/components/sensor/time_date.py @@ -89,9 +89,9 @@ class TimeDateSensor(Entity): """ Gets the latest data and updates the states. """ time_date = dt_util.utcnow() - time = dt_util.datetime_to_short_time_str(dt_util.as_local(time_date)) - time_utc = dt_util.datetime_to_short_time_str(time_date) - date = dt_util.datetime_to_short_date_str(dt_util.as_local(time_date)) + time = dt_util.datetime_to_time_str(dt_util.as_local(time_date)) + time_utc = dt_util.datetime_to_time_str(time_date) + date = dt_util.datetime_to_date_str(dt_util.as_local(time_date)) # Calculate the beat (Swatch Internet Time) time without date. hours, minutes, seconds = time_date.strftime('%H:%M:%S').split(':') diff --git a/homeassistant/util/dt.py b/homeassistant/util/dt.py index fbe00c85527..d8fecf20db8 100644 --- a/homeassistant/util/dt.py +++ b/homeassistant/util/dt.py @@ -9,9 +9,9 @@ import datetime as dt import pytz -DATE_STR_FORMAT = "%H:%M:%S %d-%m-%Y" -DATE_SHORT_STR_FORMAT = "%Y-%m-%d" -TIME_SHORT_STR_FORMAT = "%H:%M" +DATETIME_STR_FORMAT = "%H:%M:%S %d-%m-%Y" +DATE_STR_FORMAT = "%Y-%m-%d" +TIME_STR_FORMAT = "%H:%M" UTC = DEFAULT_TIME_ZONE = pytz.utc @@ -34,7 +34,7 @@ def get_time_zone(time_zone_str): def utcnow(): """ Get now in UTC time. """ - return dt.datetime.now(pytz.utc) + return dt.datetime.now(UTC) def now(time_zone=None): @@ -45,12 +45,12 @@ def now(time_zone=None): def as_utc(dattim): """ Return a datetime as UTC time. Assumes datetime without tzinfo to be in the DEFAULT_TIME_ZONE. """ - if dattim.tzinfo == pytz.utc: + if dattim.tzinfo == UTC: return dattim elif dattim.tzinfo is None: dattim = dattim.replace(tzinfo=DEFAULT_TIME_ZONE) - return dattim.astimezone(pytz.utc) + return dattim.astimezone(UTC) def as_local(dattim): @@ -58,17 +58,28 @@ def as_local(dattim): if dattim.tzinfo == DEFAULT_TIME_ZONE: return dattim elif dattim.tzinfo is None: - dattim = dattim.replace(tzinfo=pytz.utc) + dattim = dattim.replace(tzinfo=UTC) return dattim.astimezone(DEFAULT_TIME_ZONE) def utc_from_timestamp(timestamp): """ Returns a UTC time from a timestamp. """ - return dt.datetime.utcfromtimestamp(timestamp).replace(tzinfo=pytz.utc) + return dt.datetime.utcfromtimestamp(timestamp).replace(tzinfo=UTC) -def datetime_to_local_str(dattim, time_zone=None): +def start_of_local_day(dt_or_d=None): + """ Return local datetime object of start of day from date or datetime. """ + if dt_or_d is None: + dt_or_d = now().date() + elif isinstance(dt_or_d, dt.datetime): + dt_or_d = dt_or_d.date() + + return dt.datetime.combine(dt_or_d, dt.time()).replace( + tzinfo=DEFAULT_TIME_ZONE) + + +def datetime_to_local_str(dattim): """ Converts datetime to specified time_zone and returns a string. """ return datetime_to_str(as_local(dattim)) @@ -76,27 +87,27 @@ def datetime_to_local_str(dattim, time_zone=None): def datetime_to_str(dattim): """ Converts datetime to a string format. + @rtype : str + """ + return dattim.strftime(DATETIME_STR_FORMAT) + + +def datetime_to_time_str(dattim): + """ Converts datetime to a string containing only the time. + + @rtype : str + """ + return dattim.strftime(TIME_STR_FORMAT) + + +def datetime_to_date_str(dattim): + """ Converts datetime to a string containing only the date. + @rtype : str """ return dattim.strftime(DATE_STR_FORMAT) -def datetime_to_short_time_str(dattim): - """ Converts datetime to a string format as short time. - - @rtype : str - """ - return dattim.strftime(TIME_SHORT_STR_FORMAT) - - -def datetime_to_short_date_str(dattim): - """ Converts datetime to a string format as short date. - - @rtype : str - """ - return dattim.strftime(DATE_SHORT_STR_FORMAT) - - def str_to_datetime(dt_str): """ Converts a string to a UTC datetime object. @@ -104,7 +115,15 @@ def str_to_datetime(dt_str): """ try: return dt.datetime.strptime( - dt_str, DATE_STR_FORMAT).replace(tzinfo=pytz.utc) + dt_str, DATETIME_STR_FORMAT).replace(tzinfo=pytz.utc) + except ValueError: # If dt_str did not match our format + return None + + +def date_str_to_date(dt_str): + """ Converts a date string to a date object. """ + try: + return dt.datetime.strptime(dt_str, DATE_STR_FORMAT).date() except ValueError: # If dt_str did not match our format return None