mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
History: Add support to fetch specific days
This commit is contained in:
parent
d34ecd1c25
commit
f26ac070d5
@ -1,2 +1,2 @@
|
||||
""" DO NOT MODIFY. Auto-generated by build_frontend script """
|
||||
VERSION = "9472014df7b663c70bf33bb456bd8245"
|
||||
VERSION = "a6643dc82e02ec14b6c1b662f1aab661"
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,5 +1,14 @@
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
|
||||
<dom-module is='state-history-chart-timeline'>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<template></template>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
Polymer({
|
||||
@ -18,10 +27,6 @@
|
||||
},
|
||||
},
|
||||
|
||||
created: function() {
|
||||
this.style.display = 'block';
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this.isAttached = true;
|
||||
},
|
||||
@ -45,7 +50,7 @@
|
||||
if (!stateHistory || stateHistory.length === 0) {
|
||||
return;
|
||||
}
|
||||
// debugger;
|
||||
|
||||
var chart = new google.visualization.Timeline(this);
|
||||
var dataTable = new google.visualization.DataTable();
|
||||
|
||||
@ -59,15 +64,6 @@
|
||||
dataTable.addRow([entityDisplay, stateStr, start, end]);
|
||||
};
|
||||
|
||||
// people can pass in history of 1 entityId or a collection.
|
||||
// var stateHistory;
|
||||
// if (_.isArray(data[0])) {
|
||||
// stateHistory = data;
|
||||
// } else {
|
||||
// stateHistory = [data];
|
||||
// isSingleDevice = true;
|
||||
// }
|
||||
|
||||
var numTimelines = 0;
|
||||
// stateHistory is a list of lists of sorted state objects
|
||||
stateHistory.forEach(function(stateInfo) {
|
||||
@ -90,17 +86,17 @@
|
||||
}
|
||||
});
|
||||
|
||||
addRow(entityDisplay, prevState, prevLastChanged, new Date());
|
||||
// end time is start time + 1 day
|
||||
var endTime = new Date(stateInfo[0].lastChangedAsDate);
|
||||
endTime.setDate(endTime.getDate()+1);
|
||||
|
||||
addRow(entityDisplay, prevState, prevLastChanged, endTime);
|
||||
numTimelines++;
|
||||
}.bind(this));
|
||||
|
||||
chart.draw(dataTable, {
|
||||
height: 55 + numTimelines * 42,
|
||||
|
||||
// interactive properties require CSS, the JS api puts it on the document
|
||||
// instead of inside our Shadow DOM.
|
||||
enableInteractivity: false,
|
||||
|
||||
timeline: {
|
||||
showRowLabels: stateHistory.length > 1
|
||||
},
|
||||
|
@ -16,29 +16,34 @@
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
height: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<google-legacy-loader on-api-load="googleApiLoaded"></google-legacy-loader>
|
||||
|
||||
<div hidden$="{{!isLoading}}" class='loading-container'>
|
||||
<loading-box>Loading history data</loading-box>
|
||||
<loading-box>Updating history data</loading-box>
|
||||
</div>
|
||||
|
||||
<template is='dom-if' if='[[!isLoading]]'>
|
||||
<template is='dom-if' if='[[groupedStateHistory.timeline]]'>
|
||||
<state-history-chart-timeline data='[[groupedStateHistory.timeline]]'
|
||||
is-single-device='[[isSingleDevice]]'>
|
||||
</state-history-chart-timeline>
|
||||
<div class$='[[computeContentClasses(isLoading)]]'>
|
||||
<template is='dom-if' if='[[computeIsEmpty(stateHistory)]]'>
|
||||
No state history found.
|
||||
</template>
|
||||
|
||||
<template is='dom-if' if='[[groupedStateHistory.line]]'>
|
||||
<template is='dom-repeat' items='[[groupedStateHistory.line]]'>
|
||||
<state-history-chart-line unit='[[extractUnit(item)]]'
|
||||
data='[[extractData(item)]]' is-single-device='[[isSingleDevice]]'>
|
||||
</state-history-chart-line>
|
||||
</template>
|
||||
<state-history-chart-timeline data='[[groupedStateHistory.timeline]]'
|
||||
is-single-device='[[isSingleDevice]]'>
|
||||
</state-history-chart-timeline>
|
||||
|
||||
<template is='dom-repeat' items='[[groupedStateHistory.line]]'>
|
||||
<state-history-chart-line unit='[[extractUnit(item)]]'
|
||||
data='[[extractData(item)]]' is-single-device='[[isSingleDevice]]'>
|
||||
</state-history-chart-line>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</dom-module>
|
||||
|
||||
@ -69,7 +74,7 @@
|
||||
|
||||
groupedStateHistory: {
|
||||
type: Object,
|
||||
computed: 'computeGroupedStateHistory(stateHistory)',
|
||||
computed: 'computeGroupedStateHistory(isLoading, stateHistory)',
|
||||
},
|
||||
|
||||
isSingleDevice: {
|
||||
@ -82,11 +87,11 @@
|
||||
return stateHistory && stateHistory.length == 1;
|
||||
},
|
||||
|
||||
computeGroupedStateHistory: function(stateHistory) {
|
||||
computeGroupedStateHistory: function(isLoading, stateHistory) {
|
||||
var lineChartDevices = {};
|
||||
var timelineDevices = [];
|
||||
|
||||
if (!stateHistory) {
|
||||
if (isLoading || !stateHistory) {
|
||||
return {line: unitStates, timeline: timelineDevices};
|
||||
}
|
||||
|
||||
@ -129,10 +134,18 @@
|
||||
});
|
||||
},
|
||||
|
||||
computeContentClasses: function(isLoading) {
|
||||
return isLoading ? 'loading' : '';
|
||||
},
|
||||
|
||||
computeIsLoading: function(isLoadingData, apiLoaded) {
|
||||
return isLoadingData || !apiLoaded;
|
||||
},
|
||||
|
||||
computeIsEmpty: function(stateHistory) {
|
||||
return stateHistory && stateHistory.length === 0;
|
||||
},
|
||||
|
||||
extractUnit: function(arr) {
|
||||
return arr[0];
|
||||
},
|
||||
|
@ -134,7 +134,7 @@
|
||||
this.stateStoreChanged();
|
||||
this.stateHistoryStoreChanged();
|
||||
|
||||
if (this.hasHistoryComponent && stateHistoryStore.isStale(entityId)) {
|
||||
if (this.hasHistoryComponent && stateHistoryStore.shouldFetchEntity(entityId)) {
|
||||
this.isLoadingHistoryData = true;
|
||||
stateHistoryActions.fetch(entityId);
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit cec99925399b1c8e8cea15bbbba5d873522ccbd6
|
||||
Subproject commit 48cbca40dda47dba296e764fc4c9157652dbbbf1
|
@ -1,5 +1,6 @@
|
||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
<link rel="import" href="../bower_components/paper-input/paper-input.html">
|
||||
|
||||
<link rel="import" href="./partial-base.html">
|
||||
|
||||
@ -14,6 +15,14 @@
|
||||
.content.wide {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
paper-input {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.narrow paper-input {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<partial-base narrow="[[narrow]]">
|
||||
@ -23,6 +32,9 @@
|
||||
on-click="handleRefreshClick"></paper-icon-button>
|
||||
|
||||
<div class$="[[computeContentClasses(narrow)]]">
|
||||
<paper-input label='Showing entries for' on-click='handleShowDatePicker'
|
||||
value='[[computeDateCaption(selectedDate)]]'></paper-input>
|
||||
|
||||
<state-history-charts state-history="[[stateHistory]]"
|
||||
is-loading-data="[[isLoadingData]]"></state-history-charts>
|
||||
</div>
|
||||
@ -32,6 +44,12 @@
|
||||
<script>
|
||||
(function() {
|
||||
var stateHistoryActions = window.hass.stateHistoryActions;
|
||||
var stateHistoryStore = window.hass.stateHistoryStore;
|
||||
var uiActions = window.hass.uiActions;
|
||||
|
||||
function date_to_str(date) {
|
||||
return date.getFullYear() + '-' + (date.getMonth()+1) + '-' + date.getDate();
|
||||
}
|
||||
|
||||
Polymer({
|
||||
is: 'partial-history',
|
||||
@ -51,23 +69,42 @@
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
selectedDate: {
|
||||
type: String,
|
||||
value: null,
|
||||
observer: 'fetchIfNeeded',
|
||||
},
|
||||
},
|
||||
|
||||
stateHistoryStoreChanged: function(stateHistoryStore) {
|
||||
if (stateHistoryStore.isStale()) {
|
||||
this.isLoadingData = true;
|
||||
stateHistoryActions.fetchAll();
|
||||
}
|
||||
else {
|
||||
this.isLoadingData = false;
|
||||
}
|
||||
stateHistoryStoreChanged: function() {
|
||||
this.isLoadingData = this.fetchIfNeeded();
|
||||
this.stateHistory = this.isLoadingData ?
|
||||
[] : stateHistoryStore.all(this.selectedDate);
|
||||
},
|
||||
|
||||
this.stateHistory = stateHistoryStore.all;
|
||||
computeDateCaption: function(selectedDate) {
|
||||
return selectedDate || 'today';
|
||||
},
|
||||
|
||||
fetchIfNeeded: function() {
|
||||
if (stateHistoryStore.shouldFetch(this.selectedDate)) {
|
||||
this.isLoadingData = true;
|
||||
stateHistoryActions.fetchAll(this.selectedDate);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
handleRefreshClick: function() {
|
||||
this.isLoadingData = true;
|
||||
stateHistoryActions.fetchAll();
|
||||
stateHistoryActions.fetchAll(this.selectedDate);
|
||||
},
|
||||
|
||||
handleShowDatePicker: function() {
|
||||
uiActions.showDatePicker(function(selectedDate) {
|
||||
this.selectedDate = date_to_str(selectedDate);
|
||||
}.bind(this), this.selectedDate);
|
||||
},
|
||||
|
||||
computeContentClasses: function(narrow) {
|
||||
|
@ -13,6 +13,10 @@
|
||||
.selected-date-container {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
paper-input {
|
||||
max-width: 200px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<partial-base narrow="[[narrow]]">
|
||||
|
@ -9,12 +9,16 @@ from datetime import timedelta
|
||||
from itertools import groupby
|
||||
from collections import defaultdict
|
||||
|
||||
import homeassistant.util.dt as date_util
|
||||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.components.recorder as recorder
|
||||
from homeassistant.const import HTTP_BAD_REQUEST
|
||||
|
||||
DOMAIN = 'history'
|
||||
DEPENDENCIES = ['recorder', 'http']
|
||||
|
||||
URL_HISTORY_PERIOD = re.compile(
|
||||
r'/api/history/period(?:/(?P<date>\d{4}-\d{1,2}-\d{1,2})|)')
|
||||
|
||||
|
||||
def last_5_states(entity_id):
|
||||
""" Return the last 5 states for entity_id. """
|
||||
@ -111,8 +115,7 @@ def setup(hass, config):
|
||||
r'recent_states'),
|
||||
_api_last_5_states)
|
||||
|
||||
hass.http.register_path(
|
||||
'GET', re.compile(r'/api/history/period'), _api_history_period)
|
||||
hass.http.register_path('GET', URL_HISTORY_PERIOD, _api_history_period)
|
||||
|
||||
return True
|
||||
|
||||
@ -128,10 +131,25 @@ def _api_last_5_states(handler, path_match, data):
|
||||
|
||||
def _api_history_period(handler, path_match, data):
|
||||
""" Return history over a period of time. """
|
||||
# 1 day for now..
|
||||
start_time = date_util.utcnow() - timedelta(seconds=86400)
|
||||
date_str = path_match.group('date')
|
||||
one_day = timedelta(seconds=86400)
|
||||
|
||||
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_time = dt_util.as_utc(dt_util.start_of_local_day(start_date))
|
||||
else:
|
||||
start_time = dt_util.utcnow() - one_day
|
||||
|
||||
end_time = start_time + one_day
|
||||
|
||||
print("Fetchign", start_time, end_time)
|
||||
|
||||
entity_id = data.get('filter_entity_id')
|
||||
|
||||
handler.write_json(
|
||||
state_changes_during_period(start_time, entity_id=entity_id).values())
|
||||
state_changes_during_period(start_time, end_time, entity_id).values())
|
||||
|
Loading…
x
Reference in New Issue
Block a user