mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-21 08:16:36 +00:00
Remove last ES6
This commit is contained in:
parent
57f40725d9
commit
43940d067a
@ -16,13 +16,11 @@
|
|||||||
"frontend_html": "script/vulcanize.js",
|
"frontend_html": "script/vulcanize.js",
|
||||||
"frontend_prod": "npm run js_prod && npm run frontend_html",
|
"frontend_prod": "npm run js_prod && npm run frontend_html",
|
||||||
"frontend_demo": "npm run js_demo && npm run frontend_html",
|
"frontend_demo": "npm run js_demo && npm run frontend_html",
|
||||||
"ru_all": "npm run ru_core | npm run ru_ui | npm run ru_demo",
|
"ru_all": "npm run ru_core | npm run ru_demo",
|
||||||
"ru_core": "rollup --config rollup/core.js",
|
"ru_core": "rollup --config rollup/core.js",
|
||||||
"ru_ui": "rollup --config rollup/ui.js",
|
|
||||||
"ru_demo": "rollup --config rollup/demo.js",
|
"ru_demo": "rollup --config rollup/demo.js",
|
||||||
"watch_ru_all": "npm run watch_ru_core | npm run watch_ru_ui | npm run watch_ru_demo",
|
"watch_ru_all": "npm run watch_ru_core | npm run watch_ru_demo",
|
||||||
"watch_ru_core": "rollup --config rollup/core.js --watch",
|
"watch_ru_core": "rollup --config rollup/core.js --watch",
|
||||||
"watch_ru_ui": "rollup --config rollup/ui.js --watch",
|
|
||||||
"watch_ru_demo": "rollup --config rollup/demo.js --watch",
|
"watch_ru_demo": "rollup --config rollup/demo.js --watch",
|
||||||
"test": "eslint src panels --ext html"
|
"test": "eslint src panels --ext html"
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import config from './base-config';
|
import config from './base-config';
|
||||||
|
|
||||||
export default Object.assign({}, config, {
|
export default Object.assign({}, config, {
|
||||||
entry: 'src/entry-points/app-core.js',
|
entry: 'src/app-core.js',
|
||||||
targets: [
|
targets: [
|
||||||
{ dest: 'build/core.js', format: 'iife' },
|
{ dest: 'build/core.js', format: 'iife' },
|
||||||
],
|
],
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import config from './base-config';
|
|
||||||
|
|
||||||
export default Object.assign({}, config, {
|
|
||||||
entry: 'src/entry-points/home-assistant-main.js',
|
|
||||||
targets: [
|
|
||||||
{ dest: 'build-temp/ui.js', format: 'iife' },
|
|
||||||
],
|
|
||||||
});
|
|
@ -1,4 +1,4 @@
|
|||||||
import HomeAssistant from '../../home-assistant-js/src/index';
|
import HomeAssistant from '../home-assistant-js/src/index';
|
||||||
|
|
||||||
const hass = new HomeAssistant();
|
const hass = new HomeAssistant();
|
||||||
|
|
@ -1 +1,220 @@
|
|||||||
<link rel="import" href="../../bower_components/polymer/polymer.html">
|
<link rel="import" href="../../bower_components/polymer/polymer.html">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function range(start, end) {
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
for (let i = start; i < end; i++) {
|
||||||
|
result.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveParseFloat(value) {
|
||||||
|
var parsed = parseFloat(value);
|
||||||
|
return !isNaN(parsed) && isFinite(parsed) ? parsed : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Polymer({
|
||||||
|
is: 'state-history-chart-line',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'dataChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
unit: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
isSingleDevice: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
isAttached: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
observer: 'dataChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
chartEngine: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function () {
|
||||||
|
this.style.display = 'block';
|
||||||
|
},
|
||||||
|
|
||||||
|
attached: function () {
|
||||||
|
this.isAttached = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
dataChanged: function () {
|
||||||
|
this.drawChart();
|
||||||
|
},
|
||||||
|
|
||||||
|
drawChart: function () {
|
||||||
|
var unit = this.unit;
|
||||||
|
var deviceStates = this.data;
|
||||||
|
var options;
|
||||||
|
var startTime;
|
||||||
|
var endTime;
|
||||||
|
var dataTables;
|
||||||
|
var finalDataTable;
|
||||||
|
|
||||||
|
if (!this.isAttached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.chartEngine) {
|
||||||
|
this.chartEngine = new window.google.visualization.LineChart(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceStates.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = {
|
||||||
|
legend: { position: 'top' },
|
||||||
|
interpolateNulls: true,
|
||||||
|
titlePosition: 'none',
|
||||||
|
vAxes: {
|
||||||
|
// Adds units to the left hand side of the graph
|
||||||
|
0: { title: unit },
|
||||||
|
},
|
||||||
|
hAxis: {
|
||||||
|
format: 'H:mm',
|
||||||
|
},
|
||||||
|
chartArea: { left: '60', width: '95%' },
|
||||||
|
explorer: {
|
||||||
|
actions: ['dragToZoom', 'rightClickToReset', 'dragToPan'],
|
||||||
|
keepInBounds: true,
|
||||||
|
axis: 'horizontal',
|
||||||
|
maxZoomIn: 0.1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.isSingleDevice) {
|
||||||
|
options.legend.position = 'none';
|
||||||
|
options.vAxes[0].title = null;
|
||||||
|
options.chartArea.left = 40;
|
||||||
|
options.chartArea.height = '80%';
|
||||||
|
options.chartArea.top = 5;
|
||||||
|
options.enableInteractivity = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime = new Date(Math.min.apply(null, deviceStates.map(function (states) {
|
||||||
|
return states[0].lastChangedAsDate;
|
||||||
|
})));
|
||||||
|
|
||||||
|
endTime = new Date(startTime);
|
||||||
|
endTime.setDate(endTime.getDate() + 1);
|
||||||
|
if (endTime > new Date()) {
|
||||||
|
endTime = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
dataTables = deviceStates.map(function (states) {
|
||||||
|
var last = states[states.length - 1];
|
||||||
|
var domain = last.domain;
|
||||||
|
var name = last.entityDisplay;
|
||||||
|
var data = [];
|
||||||
|
var dataTable = new window.google.visualization.DataTable();
|
||||||
|
// array containing [time, value1, value2, etc]
|
||||||
|
var prevValues;
|
||||||
|
var hasTargetRange;
|
||||||
|
var processState;
|
||||||
|
var noInterpolations;
|
||||||
|
dataTable.addColumn({ type: 'datetime', id: 'Time' });
|
||||||
|
|
||||||
|
function pushData(values, noInterpolationValues) {
|
||||||
|
if (prevValues && noInterpolationValues) {
|
||||||
|
// if we have to prevent interpolation, we add an old value for each
|
||||||
|
// value that should not be interpolated at the same time that our new
|
||||||
|
// line will be published.
|
||||||
|
data.push([values[0]].concat(prevValues.slice(1).map(
|
||||||
|
function (val, index) {
|
||||||
|
return noInterpolationValues[index] ? val : null;
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
data.push(values);
|
||||||
|
prevValues = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain === 'thermostat') {
|
||||||
|
// We differentiate between thermostats that have a target temperature
|
||||||
|
// range versus ones that have just a target temperature
|
||||||
|
hasTargetRange = states.reduce(
|
||||||
|
(cum, cur) => cum || cur.attributes.target_temp_high !== cur.attributes.target_temp_low,
|
||||||
|
false);
|
||||||
|
|
||||||
|
dataTable.addColumn('number', `${name} current temperature`);
|
||||||
|
|
||||||
|
if (hasTargetRange) {
|
||||||
|
dataTable.addColumn('number', `${name} target temperature high`);
|
||||||
|
dataTable.addColumn('number', `${name} target temperature low`);
|
||||||
|
|
||||||
|
noInterpolations = [false, true, true];
|
||||||
|
|
||||||
|
processState = function (state) {
|
||||||
|
var curTemp = saveParseFloat(state.attributes.current_temperature);
|
||||||
|
var targetHigh = saveParseFloat(state.attributes.target_temp_high);
|
||||||
|
var targetLow = saveParseFloat(state.attributes.target_temp_low);
|
||||||
|
pushData([state.lastUpdatedAsDate, curTemp, targetHigh, targetLow], noInterpolations);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
dataTable.addColumn('number', `${name} target temperature`);
|
||||||
|
|
||||||
|
noInterpolations = [false, true];
|
||||||
|
|
||||||
|
processState = function (state) {
|
||||||
|
var curTemp = saveParseFloat(state.attributes.current_temperature);
|
||||||
|
var target = saveParseFloat(state.attributes.temperature);
|
||||||
|
pushData([state.lastUpdatedAsDate, curTemp, target], noInterpolations);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
states.forEach(processState);
|
||||||
|
} else {
|
||||||
|
dataTable.addColumn('number', name);
|
||||||
|
|
||||||
|
// Only disable interpolation for sensors
|
||||||
|
noInterpolations = domain !== 'sensor' && [true];
|
||||||
|
|
||||||
|
states.forEach(function (state) {
|
||||||
|
var value = saveParseFloat(state.state);
|
||||||
|
pushData([state.lastChangedAsDate, value], noInterpolations);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an entry for final values
|
||||||
|
pushData([endTime].concat(prevValues.slice(1)), false);
|
||||||
|
|
||||||
|
dataTable.addRows(data);
|
||||||
|
return dataTable;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dataTables.length === 1) {
|
||||||
|
finalDataTable = dataTables[0];
|
||||||
|
} else {
|
||||||
|
finalDataTable = dataTables.slice(1).reduce(
|
||||||
|
function (tot, cur) {
|
||||||
|
return window.google.visualization.data.join(
|
||||||
|
tot, cur, 'full', [[0, 0]],
|
||||||
|
range(1, tot.getNumberOfColumns()),
|
||||||
|
range(1, cur.getNumberOfColumns()));
|
||||||
|
},
|
||||||
|
dataTables[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chartEngine.draw(finalDataTable, options);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
|
@ -1,206 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
function range(start, end) {
|
|
||||||
const result = [];
|
|
||||||
|
|
||||||
for (let i = start; i < end; i++) {
|
|
||||||
result.push(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveParseFloat(value) {
|
|
||||||
const parsed = parseFloat(value);
|
|
||||||
return !isNaN(parsed) && isFinite(parsed) ? parsed : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'state-history-chart-line',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'dataChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
unit: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
|
|
||||||
isSingleDevice: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
isAttached: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
observer: 'dataChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
chartEngine: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.style.display = 'block';
|
|
||||||
},
|
|
||||||
|
|
||||||
attached() {
|
|
||||||
this.isAttached = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
dataChanged() {
|
|
||||||
this.drawChart();
|
|
||||||
},
|
|
||||||
|
|
||||||
drawChart() {
|
|
||||||
if (!this.isAttached) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.chartEngine) {
|
|
||||||
this.chartEngine = new window.google.visualization.LineChart(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const unit = this.unit;
|
|
||||||
const deviceStates = this.data;
|
|
||||||
|
|
||||||
if (deviceStates.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
legend: { position: 'top' },
|
|
||||||
interpolateNulls: true,
|
|
||||||
titlePosition: 'none',
|
|
||||||
vAxes: {
|
|
||||||
// Adds units to the left hand side of the graph
|
|
||||||
0: { title: unit },
|
|
||||||
},
|
|
||||||
hAxis: {
|
|
||||||
format: 'H:mm',
|
|
||||||
},
|
|
||||||
chartArea: { left: '60', width: '95%' },
|
|
||||||
explorer: {
|
|
||||||
actions: ['dragToZoom', 'rightClickToReset', 'dragToPan'],
|
|
||||||
keepInBounds: true,
|
|
||||||
axis: 'horizontal',
|
|
||||||
maxZoomIn: 0.1,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.isSingleDevice) {
|
|
||||||
options.legend.position = 'none';
|
|
||||||
options.vAxes[0].title = null;
|
|
||||||
options.chartArea.left = 40;
|
|
||||||
options.chartArea.height = '80%';
|
|
||||||
options.chartArea.top = 5;
|
|
||||||
options.enableInteractivity = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const startTime = new Date(Math.min.apply(
|
|
||||||
null, deviceStates.map(states => states[0].lastChangedAsDate)));
|
|
||||||
|
|
||||||
let endTime = new Date(startTime);
|
|
||||||
endTime.setDate(endTime.getDate() + 1);
|
|
||||||
if (endTime > new Date()) {
|
|
||||||
endTime = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataTables = deviceStates.map(states => {
|
|
||||||
const last = states[states.length - 1];
|
|
||||||
const domain = last.domain;
|
|
||||||
const name = last.entityDisplay;
|
|
||||||
const dataTable = new window.google.visualization.DataTable();
|
|
||||||
dataTable.addColumn({ type: 'datetime', id: 'Time' });
|
|
||||||
const data = [];
|
|
||||||
|
|
||||||
// array containing [time, value1, value2, etc]
|
|
||||||
let prevValues;
|
|
||||||
function pushData(values, noInterpolations) {
|
|
||||||
if (prevValues && noInterpolations) {
|
|
||||||
// if we have to prevent interpolation, we add an old value for each
|
|
||||||
// value that should not be interpolated at the same time that our new
|
|
||||||
// line will be published.
|
|
||||||
data.push([values[0]].concat(prevValues.slice(1).map(
|
|
||||||
(val, index) => (noInterpolations[index] ? val : null))));
|
|
||||||
}
|
|
||||||
data.push(values);
|
|
||||||
prevValues = values;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (domain === 'thermostat') {
|
|
||||||
// We differentiate between thermostats that have a target temperature
|
|
||||||
// range versus ones that have just a target temperature
|
|
||||||
const hasTargetRange = states.reduce(
|
|
||||||
(cum, cur) => cum || cur.attributes.target_temp_high !== cur.attributes.target_temp_low,
|
|
||||||
false);
|
|
||||||
|
|
||||||
dataTable.addColumn('number', `${name} current temperature`);
|
|
||||||
|
|
||||||
let processState;
|
|
||||||
|
|
||||||
if (hasTargetRange) {
|
|
||||||
dataTable.addColumn('number', `${name} target temperature high`);
|
|
||||||
dataTable.addColumn('number', `${name} target temperature low`);
|
|
||||||
|
|
||||||
const noInterpolations = [false, true, true];
|
|
||||||
|
|
||||||
processState = state => {
|
|
||||||
const curTemp = saveParseFloat(state.attributes.current_temperature);
|
|
||||||
const targetHigh = saveParseFloat(state.attributes.target_temp_high);
|
|
||||||
const targetLow = saveParseFloat(state.attributes.target_temp_low);
|
|
||||||
pushData([state.lastUpdatedAsDate, curTemp, targetHigh, targetLow], noInterpolations);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
dataTable.addColumn('number', `${name} target temperature`);
|
|
||||||
|
|
||||||
const noInterpolations = [false, true];
|
|
||||||
|
|
||||||
processState = state => {
|
|
||||||
const curTemp = saveParseFloat(state.attributes.current_temperature);
|
|
||||||
const target = saveParseFloat(state.attributes.temperature);
|
|
||||||
pushData([state.lastUpdatedAsDate, curTemp, target], noInterpolations);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
states.forEach(processState);
|
|
||||||
} else {
|
|
||||||
dataTable.addColumn('number', name);
|
|
||||||
|
|
||||||
// Only disable interpolation for sensors
|
|
||||||
const noInterpolation = domain !== 'sensor' && [true];
|
|
||||||
|
|
||||||
states.forEach(state => {
|
|
||||||
const value = saveParseFloat(state.state);
|
|
||||||
pushData([state.lastChangedAsDate, value], noInterpolation);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an entry for final values
|
|
||||||
pushData([endTime].concat(prevValues.slice(1)), false);
|
|
||||||
|
|
||||||
dataTable.addRows(data);
|
|
||||||
return dataTable;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let finalDataTable;
|
|
||||||
|
|
||||||
if (dataTables.length === 1) {
|
|
||||||
finalDataTable = dataTables[0];
|
|
||||||
} else {
|
|
||||||
finalDataTable = dataTables.slice(1).reduce(
|
|
||||||
(tot, cur) => window.google.visualization.data.join(
|
|
||||||
tot, cur, 'full', [[0, 0]],
|
|
||||||
range(1, tot.getNumberOfColumns()),
|
|
||||||
range(1, cur.getNumberOfColumns())),
|
|
||||||
dataTables[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.chartEngine.draw(finalDataTable, options);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,10 +1,122 @@
|
|||||||
<link rel="import" href="../../bower_components/polymer/polymer.html">
|
<link rel="import" href="../../bower_components/polymer/polymer.html">
|
||||||
|
|
||||||
<dom-module is='state-history-chart-timeline'>
|
<script>
|
||||||
<style>
|
Polymer({
|
||||||
:host {
|
is: 'state-history-chart-timeline',
|
||||||
display: block;
|
|
||||||
|
properties: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'dataChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
isAttached: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
observer: 'dataChanged',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function () {
|
||||||
|
this.style.display = 'block';
|
||||||
|
},
|
||||||
|
|
||||||
|
attached: function () {
|
||||||
|
this.isAttached = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
dataChanged: function () {
|
||||||
|
this.drawChart();
|
||||||
|
},
|
||||||
|
|
||||||
|
drawChart: function () {
|
||||||
|
var root = Polymer.dom(this);
|
||||||
|
var stateHistory = this.data;
|
||||||
|
var chart;
|
||||||
|
var dataTable;
|
||||||
|
var startTime;
|
||||||
|
var endTime;
|
||||||
|
var numTimelines;
|
||||||
|
|
||||||
|
if (!this.isAttached) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
<template></template>
|
while (root.node.lastChild) {
|
||||||
</dom-module>
|
root.node.removeChild(root.node.lastChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateHistory || stateHistory.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chart = new window.google.visualization.Timeline(this);
|
||||||
|
dataTable = new window.google.visualization.DataTable();
|
||||||
|
|
||||||
|
dataTable.addColumn({ type: 'string', id: 'Entity' });
|
||||||
|
dataTable.addColumn({ type: 'string', id: 'State' });
|
||||||
|
dataTable.addColumn({ type: 'date', id: 'Start' });
|
||||||
|
dataTable.addColumn({ type: 'date', id: 'End' });
|
||||||
|
|
||||||
|
function addRow(entityDisplay, stateStr, start, end) {
|
||||||
|
var stateDisplay = stateStr.replace(/_/g, ' ');
|
||||||
|
dataTable.addRow([entityDisplay, stateDisplay, start, end]);
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime = new Date(
|
||||||
|
stateHistory.reduce(
|
||||||
|
function (minTime, stateInfo) {
|
||||||
|
return Math.min(minTime, stateInfo[0].lastChangedAsDate);
|
||||||
|
}, new Date()));
|
||||||
|
|
||||||
|
// end time is Math.min(curTime, start time + 1 day)
|
||||||
|
endTime = new Date(startTime);
|
||||||
|
endTime.setDate(endTime.getDate() + 1);
|
||||||
|
if (endTime > new Date()) {
|
||||||
|
endTime = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
numTimelines = 0;
|
||||||
|
// stateHistory is a list of lists of sorted state objects
|
||||||
|
stateHistory.forEach(function (stateInfo) {
|
||||||
|
var entityDisplay;
|
||||||
|
var newLastChanged;
|
||||||
|
var prevState = null;
|
||||||
|
var prevLastChanged = null;
|
||||||
|
|
||||||
|
if (stateInfo.length === 0) return;
|
||||||
|
|
||||||
|
entityDisplay = stateInfo[0].entityDisplay;
|
||||||
|
|
||||||
|
stateInfo.forEach(function (state) {
|
||||||
|
if (prevState !== null && state.state !== prevState) {
|
||||||
|
newLastChanged = state.lastChangedAsDate;
|
||||||
|
|
||||||
|
addRow(entityDisplay, prevState, prevLastChanged, newLastChanged);
|
||||||
|
|
||||||
|
prevState = state.state;
|
||||||
|
prevLastChanged = newLastChanged;
|
||||||
|
} else if (prevState === null) {
|
||||||
|
prevState = state.state;
|
||||||
|
prevLastChanged = state.lastChangedAsDate;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addRow(entityDisplay, prevState, prevLastChanged, endTime);
|
||||||
|
numTimelines++;
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.draw(dataTable, {
|
||||||
|
height: 55 + (numTimelines * 42),
|
||||||
|
|
||||||
|
timeline: {
|
||||||
|
showRowLabels: stateHistory.length > 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
hAxis: {
|
||||||
|
format: 'H:mm',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'state-history-chart-timeline',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'dataChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
isAttached: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
observer: 'dataChanged',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
attached() {
|
|
||||||
this.isAttached = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
dataChanged() {
|
|
||||||
this.drawChart();
|
|
||||||
},
|
|
||||||
|
|
||||||
drawChart() {
|
|
||||||
if (!this.isAttached) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const root = Polymer.dom(this);
|
|
||||||
const stateHistory = this.data;
|
|
||||||
|
|
||||||
while (root.node.lastChild) {
|
|
||||||
root.node.removeChild(root.node.lastChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stateHistory || stateHistory.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const chart = new window.google.visualization.Timeline(this);
|
|
||||||
const dataTable = new window.google.visualization.DataTable();
|
|
||||||
|
|
||||||
dataTable.addColumn({ type: 'string', id: 'Entity' });
|
|
||||||
dataTable.addColumn({ type: 'string', id: 'State' });
|
|
||||||
dataTable.addColumn({ type: 'date', id: 'Start' });
|
|
||||||
dataTable.addColumn({ type: 'date', id: 'End' });
|
|
||||||
|
|
||||||
function addRow(entityDisplay, stateStr, start, end) {
|
|
||||||
const stateDisplay = stateStr.replace(/_/g, ' ');
|
|
||||||
dataTable.addRow([entityDisplay, stateDisplay, start, end]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const startTime = new Date(
|
|
||||||
stateHistory.reduce((minTime, stateInfo) => Math.min(
|
|
||||||
minTime, stateInfo[0].lastChangedAsDate), new Date())
|
|
||||||
);
|
|
||||||
|
|
||||||
// end time is Math.min(curTime, start time + 1 day)
|
|
||||||
let endTime = new Date(startTime);
|
|
||||||
endTime.setDate(endTime.getDate() + 1);
|
|
||||||
if (endTime > new Date()) {
|
|
||||||
endTime = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
let numTimelines = 0;
|
|
||||||
// stateHistory is a list of lists of sorted state objects
|
|
||||||
stateHistory.forEach((stateInfo) => {
|
|
||||||
if (stateInfo.length === 0) return;
|
|
||||||
|
|
||||||
const entityDisplay = stateInfo[0].entityDisplay;
|
|
||||||
/* eslint-disable prefer-const */
|
|
||||||
let newLastChanged;
|
|
||||||
/* eslint-enable prefer-const */
|
|
||||||
let prevState = null;
|
|
||||||
let prevLastChanged = null;
|
|
||||||
|
|
||||||
stateInfo.forEach((state) => {
|
|
||||||
if (prevState !== null && state.state !== prevState) {
|
|
||||||
newLastChanged = state.lastChangedAsDate;
|
|
||||||
|
|
||||||
addRow(entityDisplay, prevState, prevLastChanged, newLastChanged);
|
|
||||||
|
|
||||||
prevState = state.state;
|
|
||||||
prevLastChanged = newLastChanged;
|
|
||||||
} else if (prevState === null) {
|
|
||||||
prevState = state.state;
|
|
||||||
prevLastChanged = state.lastChangedAsDate;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addRow(entityDisplay, prevState, prevLastChanged, endTime);
|
|
||||||
numTimelines++;
|
|
||||||
});
|
|
||||||
|
|
||||||
chart.draw(dataTable, {
|
|
||||||
height: 55 + (numTimelines * 42),
|
|
||||||
|
|
||||||
timeline: {
|
|
||||||
showRowLabels: stateHistory.length > 1,
|
|
||||||
},
|
|
||||||
|
|
||||||
hAxis: {
|
|
||||||
format: 'H:mm',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@ -25,7 +25,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<google-legacy-loader on-api-load="googleApiLoaded"></google-legacy-loader>
|
<google-legacy-loader on-api-load="googleApiLoaded"></google-legacy-loader>
|
||||||
|
|
||||||
<div hidden$="{{!isLoading}}" class='loading-container'>
|
<div hidden$="[[!isLoading]]" class='loading-container'>
|
||||||
<loading-box>Updating history data</loading-box>
|
<loading-box>Updating history data</loading-box>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -40,10 +40,116 @@
|
|||||||
</state-history-chart-timeline>
|
</state-history-chart-timeline>
|
||||||
|
|
||||||
<template is='dom-repeat' items='[[groupedStateHistory.line]]'>
|
<template is='dom-repeat' items='[[groupedStateHistory.line]]'>
|
||||||
<state-history-chart-line unit='[[extractUnit(item)]]'
|
<state-history-chart-line
|
||||||
data='[[extractData(item)]]' is-single-device='[[isSingleDevice]]'>
|
unit='[[item.unit]]'
|
||||||
|
data='[[item.data]]'
|
||||||
|
is-single-device='[[isSingleDevice]]'>
|
||||||
</state-history-chart-line>
|
</state-history-chart-line>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'state-history-charts',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
stateHistory: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
isLoadingData: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
apiLoaded: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
isLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
computed: 'computeIsLoading(isLoadingData, apiLoaded)',
|
||||||
|
},
|
||||||
|
|
||||||
|
groupedStateHistory: {
|
||||||
|
type: Object,
|
||||||
|
computed: 'computeGroupedStateHistory(isLoading, stateHistory)',
|
||||||
|
},
|
||||||
|
|
||||||
|
isSingleDevice: {
|
||||||
|
type: Boolean,
|
||||||
|
computed: 'computeIsSingleDevice(stateHistory)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computeIsSingleDevice: function (stateHistory) {
|
||||||
|
return stateHistory && stateHistory.size === 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeGroupedStateHistory: function (isLoading, stateHistory) {
|
||||||
|
var lineChartDevices = {};
|
||||||
|
var timelineDevices = [];
|
||||||
|
var unitStates;
|
||||||
|
|
||||||
|
if (isLoading || !stateHistory) {
|
||||||
|
return { line: [], timeline: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
stateHistory.forEach(function (stateInfo) {
|
||||||
|
var stateWithUnit;
|
||||||
|
var unit;
|
||||||
|
|
||||||
|
if (!stateInfo || stateInfo.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stateWithUnit = stateInfo.find(
|
||||||
|
(state) => 'unit_of_measurement' in state.attributes);
|
||||||
|
|
||||||
|
unit = stateWithUnit ?
|
||||||
|
stateWithUnit.attributes.unit_of_measurement : false;
|
||||||
|
|
||||||
|
if (!unit) {
|
||||||
|
timelineDevices.push(stateInfo.toArray());
|
||||||
|
} else if (unit in lineChartDevices) {
|
||||||
|
lineChartDevices[unit].push(stateInfo.toArray());
|
||||||
|
} else {
|
||||||
|
lineChartDevices[unit] = [stateInfo.toArray()];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
timelineDevices = timelineDevices.length > 0 && timelineDevices;
|
||||||
|
|
||||||
|
unitStates = Object.keys(lineChartDevices).map(
|
||||||
|
function (unit) {
|
||||||
|
return { unit: unit, data: lineChartDevices[unit] };
|
||||||
|
});
|
||||||
|
|
||||||
|
return { line: unitStates, timeline: timelineDevices };
|
||||||
|
},
|
||||||
|
|
||||||
|
googleApiLoaded: function () {
|
||||||
|
window.google.load('visualization', '1', {
|
||||||
|
packages: ['timeline', 'corechart'],
|
||||||
|
callback: function () {
|
||||||
|
this.apiLoaded = true;
|
||||||
|
}.bind(this),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContentClasses: function (isLoading) {
|
||||||
|
return isLoading ? 'loading' : '';
|
||||||
|
},
|
||||||
|
|
||||||
|
computeIsLoading: function (isLoadingData, apiLoaded) {
|
||||||
|
return isLoadingData || !apiLoaded;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeIsEmpty: function (stateHistory) {
|
||||||
|
return stateHistory && stateHistory.size === 0;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
import './state-history-chart-timeline';
|
|
||||||
import './state-history-chart-line';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'state-history-charts',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
stateHistory: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
isLoadingData: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
apiLoaded: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
isLoading: {
|
|
||||||
type: Boolean,
|
|
||||||
computed: 'computeIsLoading(isLoadingData, apiLoaded)',
|
|
||||||
},
|
|
||||||
|
|
||||||
groupedStateHistory: {
|
|
||||||
type: Object,
|
|
||||||
computed: 'computeGroupedStateHistory(isLoading, stateHistory)',
|
|
||||||
},
|
|
||||||
|
|
||||||
isSingleDevice: {
|
|
||||||
type: Boolean,
|
|
||||||
computed: 'computeIsSingleDevice(stateHistory)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
computeIsSingleDevice(stateHistory) {
|
|
||||||
return stateHistory && stateHistory.size === 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeGroupedStateHistory(isLoading, stateHistory) {
|
|
||||||
if (isLoading || !stateHistory) {
|
|
||||||
return { line: [], timeline: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
const lineChartDevices = {};
|
|
||||||
let timelineDevices = [];
|
|
||||||
|
|
||||||
stateHistory.forEach((stateInfo) => {
|
|
||||||
if (!stateInfo || stateInfo.size === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stateWithUnit = stateInfo.find(
|
|
||||||
(state) => 'unit_of_measurement' in state.attributes);
|
|
||||||
|
|
||||||
const unit = stateWithUnit ?
|
|
||||||
stateWithUnit.attributes.unit_of_measurement : false;
|
|
||||||
|
|
||||||
if (!unit) {
|
|
||||||
timelineDevices.push(stateInfo.toArray());
|
|
||||||
} else if (unit in lineChartDevices) {
|
|
||||||
lineChartDevices[unit].push(stateInfo.toArray());
|
|
||||||
} else {
|
|
||||||
lineChartDevices[unit] = [stateInfo.toArray()];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
timelineDevices = timelineDevices.length > 0 && timelineDevices;
|
|
||||||
|
|
||||||
const unitStates = Object.keys(lineChartDevices).map(
|
|
||||||
(unit) => [unit, lineChartDevices[unit]]);
|
|
||||||
|
|
||||||
return { line: unitStates, timeline: timelineDevices };
|
|
||||||
},
|
|
||||||
|
|
||||||
googleApiLoaded() {
|
|
||||||
window.google.load('visualization', '1', {
|
|
||||||
packages: ['timeline', 'corechart'],
|
|
||||||
callback: () => { this.apiLoaded = true; },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
computeContentClasses(isLoading) {
|
|
||||||
return isLoading ? 'loading' : '';
|
|
||||||
},
|
|
||||||
|
|
||||||
computeIsLoading(isLoadingData, apiLoaded) {
|
|
||||||
return isLoadingData || !apiLoaded;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeIsEmpty(stateHistory) {
|
|
||||||
return stateHistory && stateHistory.size === 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
extractUnit(arr) {
|
|
||||||
return arr[0];
|
|
||||||
},
|
|
||||||
|
|
||||||
extractData(arr) {
|
|
||||||
return arr[1];
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,3 +0,0 @@
|
|||||||
// components that still require update
|
|
||||||
import '../components/state-history-charts';
|
|
||||||
import '../more-infos/more-info-content';
|
|
@ -10,7 +10,7 @@
|
|||||||
<link rel='import' href='./util/hass-util.html'>
|
<link rel='import' href='./util/hass-util.html'>
|
||||||
<link rel='import' href='./util/hass-behavior.html'>
|
<link rel='import' href='./util/hass-behavior.html'>
|
||||||
<link rel='import' href='./layouts/login-form.html'>
|
<link rel='import' href='./layouts/login-form.html'>
|
||||||
<link rel='import' href='./entry-points/home-assistant-main.html'>
|
<link rel='import' href='./layouts/home-assistant-main.html'>
|
||||||
<link rel='import' href='./resources/home-assistant-style.html'>
|
<link rel='import' href='./resources/home-assistant-style.html'>
|
||||||
<link rel='import' href='./resources/panel-imports.html'>
|
<link rel='import' href='./resources/panel-imports.html'>
|
||||||
|
|
||||||
@ -103,5 +103,3 @@ Polymer({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src='../build-temp/ui.js'></script>
|
|
||||||
|
@ -7,63 +7,63 @@
|
|||||||
<link rel="import" href="../components/ha-view-tabs.html">
|
<link rel="import" href="../components/ha-view-tabs.html">
|
||||||
|
|
||||||
<dom-module id="partial-cards">
|
<dom-module id="partial-cards">
|
||||||
<style is="custom-style" include="iron-flex iron-positioning"></style>
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
-ms-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-scroll-header-panel {
|
|
||||||
--paper-scroll-header-panel-container: {
|
|
||||||
background-color: #E5E5E5;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-scroll-header-panel[has-views] paper-toolbar {
|
|
||||||
height: 104px;
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-toolbar:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
bottom: -5px;
|
|
||||||
width: 100%;
|
|
||||||
height: 5px;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);
|
|
||||||
will-change: opacity;
|
|
||||||
transition: opacity 0.4s;
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-scroll-header-panel.raised paper-toolbar:after {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-icon {
|
|
||||||
margin-right: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu > .title {
|
|
||||||
line-height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu > .title > span {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.views {
|
|
||||||
padding-left: 12px;
|
|
||||||
--paper-tabs-selection-bar-color: #FFF;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<style is="custom-style" include="iron-flex iron-positioning"></style>
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-scroll-header-panel {
|
||||||
|
--paper-scroll-header-panel-container: {
|
||||||
|
background-color: #E5E5E5;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-scroll-header-panel[has-views] paper-toolbar {
|
||||||
|
height: 104px;
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-toolbar:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: -5px;
|
||||||
|
width: 100%;
|
||||||
|
height: 5px;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);
|
||||||
|
will-change: opacity;
|
||||||
|
transition: opacity 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
paper-scroll-header-panel.raised paper-toolbar:after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu > .title {
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu > .title > span {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.views {
|
||||||
|
padding-left: 12px;
|
||||||
|
--paper-tabs-selection-bar-color: #FFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<paper-scroll-header-panel id='panel'
|
<paper-scroll-header-panel id='panel'
|
||||||
condenses keep-condensed-header class='fit' has-views$='[[hasViews]]'
|
condenses keep-condensed-header class='fit' has-views$='[[hasViews]]'
|
||||||
header-height="[[computeHeaderHeight(hasViews, narrow)]]"
|
header-height="[[computeHeaderHeight(hasViews, narrow)]]"
|
||||||
|
@ -16,3 +16,104 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-alarm_control_panel',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
enteredCode: {
|
||||||
|
type: String,
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
disarmButtonVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
armHomeButtonVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
armAwayButtonVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
codeInputVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
codeInputEnabled: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
codeFormat: {
|
||||||
|
type: String,
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
codeValid: {
|
||||||
|
type: Boolean,
|
||||||
|
computed: 'validateCode(enteredCode, codeFormat)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
validateCode: function (code, format) {
|
||||||
|
var re = new RegExp(format);
|
||||||
|
if (format === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return re.test(code);
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObjChanged: function (newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.codeFormat = newVal.attributes.code_format;
|
||||||
|
this.codeInputVisible = this.codeFormat !== null;
|
||||||
|
this.codeInputEnabled = (
|
||||||
|
newVal.state === 'armed_home' ||
|
||||||
|
newVal.state === 'armed_away' ||
|
||||||
|
newVal.state === 'disarmed' ||
|
||||||
|
newVal.state === 'pending' ||
|
||||||
|
newVal.state === 'triggered');
|
||||||
|
this.disarmButtonVisible = (
|
||||||
|
newVal.state === 'armed_home' ||
|
||||||
|
newVal.state === 'armed_away' ||
|
||||||
|
newVal.state === 'pending' ||
|
||||||
|
newVal.state === 'triggered');
|
||||||
|
this.armHomeButtonVisible = newVal.state === 'disarmed';
|
||||||
|
this.armAwayButtonVisible = newVal.state === 'disarmed';
|
||||||
|
}
|
||||||
|
this.async(function () {
|
||||||
|
this.fire('iron-resize');
|
||||||
|
}.bind(this), 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDisarmTap: function () {
|
||||||
|
this.callService('alarm_disarm', { code: this.enteredCode });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleHomeTap: function () {
|
||||||
|
this.callService('alarm_arm_home', { code: this.enteredCode });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleAwayTap: function () {
|
||||||
|
this.callService('alarm_arm_away', { code: this.enteredCode });
|
||||||
|
},
|
||||||
|
|
||||||
|
callService: function (service, data) {
|
||||||
|
var serviceData = data || {};
|
||||||
|
serviceData.entity_id = this.stateObj.entityId;
|
||||||
|
this.hass.serviceActions.callService('alarm_control_panel', service, serviceData)
|
||||||
|
.then(function () {
|
||||||
|
this.enteredCode = '';
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-alarm_control_panel',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
enteredCode: {
|
|
||||||
type: String,
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
disarmButtonVisible: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
armHomeButtonVisible: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
armAwayButtonVisible: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
codeInputVisible: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
codeInputEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
codeFormat: {
|
|
||||||
type: String,
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
codeValid: {
|
|
||||||
type: Boolean,
|
|
||||||
computed: 'validateCode(enteredCode, codeFormat)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
validateCode(code, format) {
|
|
||||||
const re = new RegExp(format);
|
|
||||||
if (format === null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return re.test(code);
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(newVal) {
|
|
||||||
if (newVal) {
|
|
||||||
this.codeFormat = newVal.attributes.code_format;
|
|
||||||
this.codeInputVisible = this.codeFormat !== null;
|
|
||||||
this.codeInputEnabled = (
|
|
||||||
newVal.state === 'armed_home' ||
|
|
||||||
newVal.state === 'armed_away' ||
|
|
||||||
newVal.state === 'disarmed' ||
|
|
||||||
newVal.state === 'pending' ||
|
|
||||||
newVal.state === 'triggered');
|
|
||||||
this.disarmButtonVisible = (
|
|
||||||
newVal.state === 'armed_home' ||
|
|
||||||
newVal.state === 'armed_away' ||
|
|
||||||
newVal.state === 'pending' ||
|
|
||||||
newVal.state === 'triggered');
|
|
||||||
this.armHomeButtonVisible = newVal.state === 'disarmed';
|
|
||||||
this.armAwayButtonVisible = newVal.state === 'disarmed';
|
|
||||||
}
|
|
||||||
this.async(() => this.fire('iron-resize'), 500);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDisarmTap() {
|
|
||||||
this.callService('alarm_disarm', { code: this.enteredCode });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleHomeTap() {
|
|
||||||
this.callService('alarm_arm_home', { code: this.enteredCode });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleAwayTap() {
|
|
||||||
this.callService('alarm_arm_away', { code: this.enteredCode });
|
|
||||||
},
|
|
||||||
|
|
||||||
callService(service, data) {
|
|
||||||
const serviceData = data || {};
|
|
||||||
serviceData.entity_id = this.stateObj.entityId;
|
|
||||||
this.hass.serviceActions.callService('alarm_control_panel', service, serviceData)
|
|
||||||
.then(() => { this.enteredCode = ''; });
|
|
||||||
},
|
|
||||||
});
|
|
@ -4,38 +4,48 @@
|
|||||||
<link rel='import' href='../components/loading-box.html'>
|
<link rel='import' href='../components/loading-box.html'>
|
||||||
|
|
||||||
<dom-module id='more-info-configurator'>
|
<dom-module id='more-info-configurator'>
|
||||||
<style is="custom-style" include="iron-flex"></style>
|
|
||||||
<style>
|
|
||||||
p {
|
|
||||||
margin: 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p > img {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.error {
|
|
||||||
color: #C62828;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.submit {
|
|
||||||
text-align: center;
|
|
||||||
height: 41px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<template>
|
<template>
|
||||||
|
<style is="custom-style" include="iron-flex"></style>
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p > img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.error {
|
||||||
|
color: #C62828;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.submit {
|
||||||
|
text-align: center;
|
||||||
|
height: 41px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<div class='layout vertical'>
|
<div class='layout vertical'>
|
||||||
<template is='dom-if' if='[[isConfigurable]]'>
|
<template is='dom-if' if='[[isConfigurable]]'>
|
||||||
|
|
||||||
<p hidden$='[[!stateObj.attributes.description]]'>[[stateObj.attributes.description]]
|
<p hidden$='[[!stateObj.attributes.description]]'>
|
||||||
<a hidden$='[[!stateObj.attributes.link_url]]' href='[[stateObj.attributes.link_url]]' target='_blank'>[[stateObj.attributes.link_name]]</a>
|
[[stateObj.attributes.description]]
|
||||||
|
<a
|
||||||
|
hidden$='[[!stateObj.attributes.link_url]]'
|
||||||
|
href='[[stateObj.attributes.link_url]]'
|
||||||
|
target='_blank'
|
||||||
|
>
|
||||||
|
[[stateObj.attributes.link_name]]
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class='error' hidden$='[[!stateObj.attributes.errors]]'>[[stateObj.attributes.errors]]</p>
|
<p class='error' hidden$='[[!stateObj.attributes.errors]]'>
|
||||||
|
[[stateObj.attributes.errors]]
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class='center' hidden$='[[!stateObj.attributes.description_image]]'>
|
<p class='center' hidden$='[[!stateObj.attributes.description_image]]'>
|
||||||
<img src='[[stateObj.attributes.description_image]]' />
|
<img src='[[stateObj.attributes.description_image]]' />
|
||||||
@ -43,14 +53,19 @@
|
|||||||
|
|
||||||
<template is='dom-repeat' items='[[stateObj.attributes.fields]]'>
|
<template is='dom-repeat' items='[[stateObj.attributes.fields]]'>
|
||||||
<paper-input-container id='paper-input-fields-{{item.id}}'>
|
<paper-input-container id='paper-input-fields-{{item.id}}'>
|
||||||
<label>{{item.name}}</label>
|
<label>[[item.name]]</label>
|
||||||
<input is="iron-input" type="{{item.type}}" id='{{item.id}}' on-change="fieldChanged"/>
|
<input is="iron-input" type="[[item.type]]" id='[[item.id]]' on-change="fieldChanged"/>
|
||||||
</paper-input-container>
|
</paper-input-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<p class='submit'>
|
<p class='submit'>
|
||||||
<paper-button raised on-tap='submitClicked'
|
<paper-button
|
||||||
hidden$='[[isConfiguring]]'>[[submitCaption]]</paper-button>
|
raised
|
||||||
|
on-tap='submitClicked'
|
||||||
|
hidden$='[[isConfiguring]]'
|
||||||
|
>
|
||||||
|
[[submitCaption]]
|
||||||
|
</paper-button>
|
||||||
|
|
||||||
<loading-box hidden$='[[!isConfiguring]]'>Configuring</loading-box>
|
<loading-box hidden$='[[!isConfiguring]]'>Configuring</loading-box>
|
||||||
</p>
|
</p>
|
||||||
@ -59,3 +74,83 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-configurator',
|
||||||
|
|
||||||
|
behaviors: [window.hassBehavior],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
action: {
|
||||||
|
type: String,
|
||||||
|
value: 'display',
|
||||||
|
},
|
||||||
|
|
||||||
|
isStreaming: {
|
||||||
|
type: Boolean,
|
||||||
|
bindNuclear: function (hass) {
|
||||||
|
return hass.streamGetters.isStreamingEvents;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
isConfigurable: {
|
||||||
|
type: Boolean,
|
||||||
|
computed: 'computeIsConfigurable(stateObj)',
|
||||||
|
},
|
||||||
|
|
||||||
|
isConfiguring: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
submitCaption: {
|
||||||
|
type: String,
|
||||||
|
computed: 'computeSubmitCaption(stateObj)',
|
||||||
|
},
|
||||||
|
|
||||||
|
fieldInput: {
|
||||||
|
type: Object, value: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computeIsConfigurable: function (stateObj) {
|
||||||
|
return stateObj.state === 'configure';
|
||||||
|
},
|
||||||
|
|
||||||
|
computeSubmitCaption: function (stateObj) {
|
||||||
|
return stateObj.attributes.submit_caption || 'Set configuration';
|
||||||
|
},
|
||||||
|
|
||||||
|
fieldChanged: function (ev) {
|
||||||
|
var el = ev.target;
|
||||||
|
this.fieldInput[el.id] = el.value;
|
||||||
|
},
|
||||||
|
|
||||||
|
submitClicked: function () {
|
||||||
|
var data = {
|
||||||
|
configure_id: this.stateObj.attributes.configure_id,
|
||||||
|
fields: this.fieldInput,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isConfiguring = true;
|
||||||
|
|
||||||
|
this.hass.serviceActions.callService('configurator', 'configure', data).then(
|
||||||
|
function () {
|
||||||
|
this.isConfiguring = false;
|
||||||
|
|
||||||
|
if (!this.isStreaming) {
|
||||||
|
this.hass.syncActions.fetchAll();
|
||||||
|
}
|
||||||
|
}.bind(this),
|
||||||
|
function () {
|
||||||
|
this.isConfiguring = false;
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-configurator',
|
|
||||||
|
|
||||||
behaviors: [window.hassBehavior],
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
action: {
|
|
||||||
type: String,
|
|
||||||
value: 'display',
|
|
||||||
},
|
|
||||||
|
|
||||||
isStreaming: {
|
|
||||||
type: Boolean,
|
|
||||||
bindNuclear: hass => hass.streamGetters.isStreamingEvents,
|
|
||||||
},
|
|
||||||
|
|
||||||
isConfigurable: {
|
|
||||||
type: Boolean,
|
|
||||||
computed: 'computeIsConfigurable(stateObj)',
|
|
||||||
},
|
|
||||||
|
|
||||||
isConfiguring: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
submitCaption: {
|
|
||||||
type: String,
|
|
||||||
computed: 'computeSubmitCaption(stateObj)',
|
|
||||||
},
|
|
||||||
|
|
||||||
fieldInput: {
|
|
||||||
type: Object, value: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
computeIsConfigurable(stateObj) {
|
|
||||||
return stateObj.state === 'configure';
|
|
||||||
},
|
|
||||||
|
|
||||||
computeSubmitCaption(stateObj) {
|
|
||||||
return stateObj.attributes.submit_caption || 'Set configuration';
|
|
||||||
},
|
|
||||||
|
|
||||||
fieldChanged(ev) {
|
|
||||||
const el = ev.target;
|
|
||||||
this.fieldInput[el.id] = el.value;
|
|
||||||
},
|
|
||||||
|
|
||||||
submitClicked() {
|
|
||||||
this.isConfiguring = true;
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
configure_id: this.stateObj.attributes.configure_id,
|
|
||||||
fields: this.fieldInput,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hass.serviceActions.callService('configurator', 'configure', data).then(
|
|
||||||
() => {
|
|
||||||
this.isConfiguring = false;
|
|
||||||
|
|
||||||
if (!this.isStreaming) {
|
|
||||||
this.hass.syncActions.fetchAll();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.isConfiguring = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -21,3 +21,28 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-content',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObjChanged: function (stateObj) {
|
||||||
|
if (!stateObj) return;
|
||||||
|
|
||||||
|
window.hassUtil.dynamicContentUpdater(
|
||||||
|
this, 'MORE-INFO-' + window.hassUtil.stateMoreInfoType(stateObj).toUpperCase(),
|
||||||
|
{ hass: this.hass, stateObj: stateObj });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
import './more-info-group';
|
|
||||||
import './more-info-sun';
|
|
||||||
import './more-info-configurator';
|
|
||||||
import './more-info-thermostat';
|
|
||||||
import './more-info-script';
|
|
||||||
import './more-info-light';
|
|
||||||
import './more-info-media_player';
|
|
||||||
import './more-info-updater';
|
|
||||||
import './more-info-alarm_control_panel';
|
|
||||||
import './more-info-lock';
|
|
||||||
import './more-info-hvac';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-content',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(stateObj) {
|
|
||||||
if (!stateObj) return;
|
|
||||||
|
|
||||||
window.hassUtil.dynamicContentUpdater(
|
|
||||||
this, `MORE-INFO-${window.hassUtil.stateMoreInfoType(stateObj).toUpperCase()}`,
|
|
||||||
{ hass: this.hass, stateObj });
|
|
||||||
},
|
|
||||||
});
|
|
@ -22,3 +22,77 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-group',
|
||||||
|
|
||||||
|
behaviors: [window.hassBehavior],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
states: {
|
||||||
|
type: Array,
|
||||||
|
bindNuclear: hass => [
|
||||||
|
hass.moreInfoGetters.currentEntity,
|
||||||
|
hass.entityGetters.entityMap,
|
||||||
|
(currentEntity, entities) => {
|
||||||
|
// weird bug??
|
||||||
|
if (!currentEntity) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return currentEntity.attributes.entity_id.map(
|
||||||
|
entities.get.bind(entities));
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
observers: [
|
||||||
|
'statesChanged(stateObj, states)',
|
||||||
|
],
|
||||||
|
|
||||||
|
statesChanged: function (stateObj, states) {
|
||||||
|
var groupDomainStateObj = false;
|
||||||
|
var baseStateObj;
|
||||||
|
var i;
|
||||||
|
var state;
|
||||||
|
var el;
|
||||||
|
|
||||||
|
if (states && states.length > 0) {
|
||||||
|
baseStateObj = states[0];
|
||||||
|
|
||||||
|
groupDomainStateObj = baseStateObj.set('entityId', stateObj.entityId).set(
|
||||||
|
'attributes', Object.assign({}, baseStateObj.attributes));
|
||||||
|
|
||||||
|
for (i = 0; i < states.length; i++) {
|
||||||
|
state = states[i];
|
||||||
|
if (state && state.domain) {
|
||||||
|
if (groupDomainStateObj.domain !== state.domain) {
|
||||||
|
groupDomainStateObj = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!groupDomainStateObj) {
|
||||||
|
el = Polymer.dom(this.$.groupedControlDetails);
|
||||||
|
if (el.lastChild) {
|
||||||
|
el.removeChild(el.lastChild);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.hassUtil.dynamicContentUpdater(
|
||||||
|
this.$.groupedControlDetails,
|
||||||
|
'MORE-INFO-' + window.hassUtil.stateMoreInfoType(groupDomainStateObj).toUpperCase(),
|
||||||
|
{ stateObj: groupDomainStateObj });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-group',
|
|
||||||
|
|
||||||
behaviors: [window.hassBehavior],
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
states: {
|
|
||||||
type: Array,
|
|
||||||
bindNuclear: hass => [
|
|
||||||
hass.moreInfoGetters.currentEntity,
|
|
||||||
hass.entityGetters.entityMap,
|
|
||||||
(currentEntity, entities) => {
|
|
||||||
// weird bug??
|
|
||||||
if (!currentEntity) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return currentEntity.attributes.entity_id.map(
|
|
||||||
entities.get.bind(entities));
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
observers: [
|
|
||||||
'statesChanged(stateObj, states)',
|
|
||||||
],
|
|
||||||
|
|
||||||
statesChanged(stateObj, states) {
|
|
||||||
let groupDomainStateObj = false;
|
|
||||||
|
|
||||||
if (states && states.length > 0) {
|
|
||||||
const baseStateObj = states[0];
|
|
||||||
|
|
||||||
groupDomainStateObj = baseStateObj.set('entityId', stateObj.entityId).set(
|
|
||||||
'attributes', Object.assign({}, baseStateObj.attributes));
|
|
||||||
|
|
||||||
for (let i = 0; i < states.length; i++) {
|
|
||||||
const s = states[i];
|
|
||||||
if (s && s.domain) {
|
|
||||||
if (groupDomainStateObj.domain !== s.domain) {
|
|
||||||
groupDomainStateObj = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!groupDomainStateObj) {
|
|
||||||
const el = Polymer.dom(this.$.groupedControlDetails);
|
|
||||||
if (el.lastChild) {
|
|
||||||
el.removeChild(el.lastChild);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
window.hassUtil.dynamicContentUpdater(
|
|
||||||
this.$.groupedControlDetails,
|
|
||||||
`MORE-INFO-${window.hassUtil.stateMoreInfoType(groupDomainStateObj).toUpperCase()}`,
|
|
||||||
{ stateObj: groupDomainStateObj });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
@ -129,3 +129,165 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-hvac',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
operationIndex: {
|
||||||
|
type: Number,
|
||||||
|
value: -1,
|
||||||
|
observer: 'handleOperationmodeChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
fanIndex: {
|
||||||
|
type: Number,
|
||||||
|
value: -1,
|
||||||
|
observer: 'handleFanmodeChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
swingIndex: {
|
||||||
|
type: Number,
|
||||||
|
value: -1,
|
||||||
|
observer: 'handleSwingmodeChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
awayToggleChecked: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
auxToggleChecked: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObjChanged: function (newVal) {
|
||||||
|
this.awayToggleChecked = newVal.attributes.away_mode === 'on';
|
||||||
|
this.auxheatToggleChecked = newVal.attributes.aux_heat === 'on';
|
||||||
|
|
||||||
|
if (newVal.attributes.fan_list) {
|
||||||
|
this.fanIndex = newVal.attributes.fan_list.indexOf(
|
||||||
|
newVal.attributes.fan_mode);
|
||||||
|
} else {
|
||||||
|
this.fanIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newVal.attributes.operation_list) {
|
||||||
|
this.operationIndex = newVal.attributes.operation_list.indexOf(
|
||||||
|
newVal.attributes.operation_mode);
|
||||||
|
} else {
|
||||||
|
this.operationIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newVal.attributes.swing_list) {
|
||||||
|
this.swingIndex = newVal.attributes.swing_list.indexOf(
|
||||||
|
newVal.attributes.swing_mode);
|
||||||
|
} else {
|
||||||
|
this.swingIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.async(function () {
|
||||||
|
this.fire('iron-resize');
|
||||||
|
}.bind(this), 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeClassNames: function (stateObj) {
|
||||||
|
return 'more-info-hvac' + window.hassUtil.attributeClassNames(
|
||||||
|
stateObj,
|
||||||
|
['away_mode', 'aux_heat', 'temperature', 'humidity', 'operation_list',
|
||||||
|
'fan_list', 'swing_list']
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
targetTemperatureSliderChanged: function (ev) {
|
||||||
|
var temperature = ev.target.value;
|
||||||
|
|
||||||
|
if (temperature === this.stateObj.attributes.temperature) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_temperature', { temperature });
|
||||||
|
},
|
||||||
|
|
||||||
|
targetHumiditySliderChanged: function (ev) {
|
||||||
|
var humidity = ev.target.value;
|
||||||
|
|
||||||
|
if (humidity === this.stateObj.attributes.humidity) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_humidity', { humidity });
|
||||||
|
},
|
||||||
|
|
||||||
|
awayToggleChanged: function (ev) {
|
||||||
|
var oldVal = this.stateObj.attributes.away_mode === 'on';
|
||||||
|
var newVal = ev.target.checked;
|
||||||
|
|
||||||
|
if (oldVal === newVal) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_away_mode', { away_mode: newVal });
|
||||||
|
},
|
||||||
|
|
||||||
|
auxToggleChanged: function (ev) {
|
||||||
|
var oldVal = this.stateObj.attributes.aux_heat === 'on';
|
||||||
|
var newVal = ev.target.checked;
|
||||||
|
|
||||||
|
if (oldVal === newVal) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_aux_heat', { aux_heat: newVal });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleFanmodeChanged: function (fanIndex) {
|
||||||
|
var fanInput;
|
||||||
|
// Selected Option will transition to '' before transitioning to new value
|
||||||
|
if (fanIndex === '' || fanIndex === -1) return;
|
||||||
|
|
||||||
|
fanInput = this.stateObj.attributes.fan_list[fanIndex];
|
||||||
|
if (fanInput === this.stateObj.attributes.fan_mode) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_fan_mode', { fan_mode: fanInput });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOperationmodeChanged: function (operationIndex) {
|
||||||
|
var operationInput;
|
||||||
|
// Selected Option will transition to '' before transitioning to new value
|
||||||
|
if (operationIndex === '' || operationIndex === -1) return;
|
||||||
|
|
||||||
|
operationInput = this.stateObj.attributes.operation_list[operationIndex];
|
||||||
|
if (operationInput === this.stateObj.attributes.operation_mode) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_operation_mode', { operation_mode: operationInput });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSwingmodeChanged: function (swingIndex) {
|
||||||
|
var swingInput;
|
||||||
|
// Selected Option will transition to '' before transitioning to new value
|
||||||
|
if (swingIndex === '' || swingIndex === -1) return;
|
||||||
|
|
||||||
|
swingInput = this.stateObj.attributes.swing_list[swingIndex];
|
||||||
|
if (swingInput === this.stateObj.attributes.swing_mode) return;
|
||||||
|
|
||||||
|
this.callServiceHelper('set_swing_mode', { swing_mode: swingInput });
|
||||||
|
},
|
||||||
|
|
||||||
|
callServiceHelper: function (service, data) {
|
||||||
|
// We call stateChanged after a successful call to re-sync the inputs
|
||||||
|
// with the state. It will be out of sync if our service call did not
|
||||||
|
// result in the entity to be turned on. Since the state is not changing,
|
||||||
|
// the resync is not called automatic.
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
data.entity_id = this.stateObj.entityId;
|
||||||
|
/* eslint-enable no-param-reassign */
|
||||||
|
this.hass.serviceActions.callService('hvac', service, data)
|
||||||
|
.then(function () {
|
||||||
|
this.stateObjChanged(this.stateObj);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,160 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
const ATTRIBUTE_CLASSES = [
|
|
||||||
'away_mode',
|
|
||||||
'aux_heat',
|
|
||||||
'temperature',
|
|
||||||
'humidity',
|
|
||||||
'operation_list',
|
|
||||||
'fan_list',
|
|
||||||
'swing_list',
|
|
||||||
];
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-hvac',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
operationIndex: {
|
|
||||||
type: Number,
|
|
||||||
value: -1,
|
|
||||||
observer: 'handleOperationmodeChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
fanIndex: {
|
|
||||||
type: Number,
|
|
||||||
value: -1,
|
|
||||||
observer: 'handleFanmodeChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
swingIndex: {
|
|
||||||
type: Number,
|
|
||||||
value: -1,
|
|
||||||
observer: 'handleSwingmodeChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
awayToggleChecked: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
|
|
||||||
auxToggleChecked: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(newVal) {
|
|
||||||
this.awayToggleChecked = newVal.attributes.away_mode === 'on';
|
|
||||||
this.auxheatToggleChecked = newVal.attributes.aux_heat === 'on';
|
|
||||||
|
|
||||||
if (newVal.attributes.fan_list) {
|
|
||||||
this.fanIndex = newVal.attributes.fan_list.indexOf(
|
|
||||||
newVal.attributes.fan_mode);
|
|
||||||
} else {
|
|
||||||
this.fanIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newVal.attributes.operation_list) {
|
|
||||||
this.operationIndex = newVal.attributes.operation_list.indexOf(
|
|
||||||
newVal.attributes.operation_mode);
|
|
||||||
} else {
|
|
||||||
this.operationIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newVal.attributes.swing_list) {
|
|
||||||
this.swingIndex = newVal.attributes.swing_list.indexOf(
|
|
||||||
newVal.attributes.swing_mode);
|
|
||||||
} else {
|
|
||||||
this.swingIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.async(() => this.fire('iron-resize'), 500);
|
|
||||||
},
|
|
||||||
|
|
||||||
computeClassNames(stateObj) {
|
|
||||||
return `more-info-hvac ${window.hassUtil.attributeClassNames(stateObj, ATTRIBUTE_CLASSES)}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
targetTemperatureSliderChanged(ev) {
|
|
||||||
const temperature = ev.target.value;
|
|
||||||
|
|
||||||
if (temperature === this.stateObj.attributes.temperature) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_temperature', { temperature });
|
|
||||||
},
|
|
||||||
|
|
||||||
targetHumiditySliderChanged(ev) {
|
|
||||||
const humidity = ev.target.value;
|
|
||||||
|
|
||||||
if (humidity === this.stateObj.attributes.humidity) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_humidity', { humidity });
|
|
||||||
},
|
|
||||||
|
|
||||||
awayToggleChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.away_mode === 'on';
|
|
||||||
const newVal = ev.target.checked;
|
|
||||||
|
|
||||||
if (oldVal === newVal) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_away_mode', { away_mode: newVal });
|
|
||||||
},
|
|
||||||
|
|
||||||
auxToggleChanged(ev) {
|
|
||||||
const oldVal = this.stateObj.attributes.aux_heat === 'on';
|
|
||||||
const newVal = ev.target.checked;
|
|
||||||
|
|
||||||
if (oldVal === newVal) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_aux_heat', { aux_heat: newVal });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleFanmodeChanged(fanIndex) {
|
|
||||||
// Selected Option will transition to '' before transitioning to new value
|
|
||||||
if (fanIndex === '' || fanIndex === -1) return;
|
|
||||||
|
|
||||||
const fanInput = this.stateObj.attributes.fan_list[fanIndex];
|
|
||||||
if (fanInput === this.stateObj.attributes.fan_mode) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_fan_mode', { fan_mode: fanInput });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleOperationmodeChanged(operationIndex) {
|
|
||||||
// Selected Option will transition to '' before transitioning to new value
|
|
||||||
if (operationIndex === '' || operationIndex === -1) return;
|
|
||||||
|
|
||||||
const operationInput = this.stateObj.attributes.operation_list[operationIndex];
|
|
||||||
if (operationInput === this.stateObj.attributes.operation_mode) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_operation_mode', { operation_mode: operationInput });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSwingmodeChanged(swingIndex) {
|
|
||||||
// Selected Option will transition to '' before transitioning to new value
|
|
||||||
if (swingIndex === '' || swingIndex === -1) return;
|
|
||||||
|
|
||||||
const swingInput = this.stateObj.attributes.swing_list[swingIndex];
|
|
||||||
if (swingInput === this.stateObj.attributes.swing_mode) return;
|
|
||||||
|
|
||||||
this.callServiceHelper('set_swing_mode', { swing_mode: swingInput });
|
|
||||||
},
|
|
||||||
|
|
||||||
callServiceHelper(service, data) {
|
|
||||||
// We call stateChanged after a successful call to re-sync the inputs
|
|
||||||
// with the state. It will be out of sync if our service call did not
|
|
||||||
// result in the entity to be turned on. Since the state is not changing,
|
|
||||||
// the resync is not called automatic.
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
data.entity_id = this.stateObj.entityId;
|
|
||||||
/* eslint-enable no-param-reassign */
|
|
||||||
this.hass.serviceActions.callService('hvac', service, data)
|
|
||||||
.then(() => this.stateObjChanged(this.stateObj));
|
|
||||||
},
|
|
||||||
});
|
|
@ -54,3 +54,104 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-light',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
brightnessSliderValue: {
|
||||||
|
type: Number,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
ctSliderValue: {
|
||||||
|
type: Number,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObjChanged: function (newVal) {
|
||||||
|
if (newVal && newVal.state === 'on') {
|
||||||
|
this.brightnessSliderValue = newVal.attributes.brightness;
|
||||||
|
this.ctSliderValue = newVal.attributes.color_temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.async(function () {
|
||||||
|
this.fire('iron-resize');
|
||||||
|
}.bind(this), 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeClassNames: function (stateObj) {
|
||||||
|
return window.hassUtil.attributeClassNames(
|
||||||
|
stateObj, ['brightness', 'rgb_color', 'color_temp']);
|
||||||
|
},
|
||||||
|
|
||||||
|
brightnessSliderChanged: function (ev) {
|
||||||
|
var bri = parseInt(ev.target.value, 10);
|
||||||
|
|
||||||
|
if (isNaN(bri)) return;
|
||||||
|
|
||||||
|
if (bri === 0) {
|
||||||
|
this.hass.serviceActions.callTurnOff(this.stateObj.entityId);
|
||||||
|
} else {
|
||||||
|
this.hass.serviceActions.callService('light', 'turn_on', {
|
||||||
|
entity_id: this.stateObj.entityId,
|
||||||
|
brightness: bri,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ctSliderChanged: function (ev) {
|
||||||
|
var ct = parseInt(ev.target.value, 10);
|
||||||
|
|
||||||
|
if (isNaN(ct)) return;
|
||||||
|
|
||||||
|
this.hass.serviceActions.callService('light', 'turn_on', {
|
||||||
|
entity_id: this.stateObj.entityId,
|
||||||
|
color_temp: ct,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceChangeColor: function (hass, entityId, color) {
|
||||||
|
hass.serviceActions.callService('light', 'turn_on', {
|
||||||
|
entity_id: entityId,
|
||||||
|
rgb_color: [color.r, color.g, color.b],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a new color has been picked. We will not respond to every
|
||||||
|
* color pick event but have a pause between requests.
|
||||||
|
*/
|
||||||
|
colorPicked: function (ev) {
|
||||||
|
if (this.skipColorPicked) {
|
||||||
|
this.colorChanged = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.color = ev.detail.rgb;
|
||||||
|
|
||||||
|
this.serviceChangeColor(this.hass, this.stateObj.entityId, this.color);
|
||||||
|
|
||||||
|
this.colorChanged = false;
|
||||||
|
this.skipColorPicked = true;
|
||||||
|
|
||||||
|
this.colorDebounce = setTimeout(function () {
|
||||||
|
if (this.colorChanged) {
|
||||||
|
this.serviceChangeColor(this.hass, this.stateObj.entityId, this.color);
|
||||||
|
}
|
||||||
|
this.skipColorPicked = false;
|
||||||
|
}.bind(this), 500);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
const ATTRIBUTE_CLASSES = ['brightness', 'rgb_color', 'color_temp'];
|
|
||||||
|
|
||||||
function pickColor(hass, entityId, color) {
|
|
||||||
hass.serviceActions.callService('light', 'turn_on', {
|
|
||||||
entity_id: entityId,
|
|
||||||
rgb_color: [color.r, color.g, color.b],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-light',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
brightnessSliderValue: {
|
|
||||||
type: Number,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
ctSliderValue: {
|
|
||||||
type: Number,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(newVal) {
|
|
||||||
if (newVal && newVal.state === 'on') {
|
|
||||||
this.brightnessSliderValue = newVal.attributes.brightness;
|
|
||||||
this.ctSliderValue = newVal.attributes.color_temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.async(() => this.fire('iron-resize'), 500);
|
|
||||||
},
|
|
||||||
|
|
||||||
computeClassNames(stateObj) {
|
|
||||||
return window.hassUtil.attributeClassNames(stateObj, ATTRIBUTE_CLASSES);
|
|
||||||
},
|
|
||||||
|
|
||||||
brightnessSliderChanged(ev) {
|
|
||||||
const bri = parseInt(ev.target.value, 10);
|
|
||||||
|
|
||||||
if (isNaN(bri)) return;
|
|
||||||
|
|
||||||
if (bri === 0) {
|
|
||||||
this.hass.serviceActions.callTurnOff(this.stateObj.entityId);
|
|
||||||
} else {
|
|
||||||
this.hass.serviceActions.callService('light', 'turn_on', {
|
|
||||||
entity_id: this.stateObj.entityId,
|
|
||||||
brightness: bri,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ctSliderChanged(ev) {
|
|
||||||
const ct = parseInt(ev.target.value, 10);
|
|
||||||
|
|
||||||
if (isNaN(ct)) return;
|
|
||||||
|
|
||||||
this.hass.serviceActions.callService('light', 'turn_on', {
|
|
||||||
entity_id: this.stateObj.entityId,
|
|
||||||
color_temp: ct,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a new color has been picked. We will not respond to every
|
|
||||||
* color pick event but have a pause between requests.
|
|
||||||
*/
|
|
||||||
colorPicked(ev) {
|
|
||||||
if (this.skipColorPicked) {
|
|
||||||
this.colorChanged = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.color = ev.detail.rgb;
|
|
||||||
|
|
||||||
pickColor(this.hass, this.stateObj.entityId, this.color);
|
|
||||||
|
|
||||||
this.colorChanged = false;
|
|
||||||
this.skipColorPicked = true;
|
|
||||||
|
|
||||||
this.colorDebounce = setTimeout(() => {
|
|
||||||
if (this.colorChanged) {
|
|
||||||
pickColor(this.hass, this.stateObj.entityId, this.color);
|
|
||||||
}
|
|
||||||
this.skipColorPicked = false;
|
|
||||||
}, 500);
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
@ -17,3 +17,46 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-lock',
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
enteredCode: {
|
||||||
|
type: String,
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
handleUnlockTap: function () {
|
||||||
|
this.callService('unlock', { code: this.enteredCode });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleLockTap: function () {
|
||||||
|
this.callService('lock', { code: this.enteredCode });
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObjChanged: function (newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.isLocked = newVal.state === 'locked';
|
||||||
|
}
|
||||||
|
this.async(function () {
|
||||||
|
this.fire('iron-resize');
|
||||||
|
}.bind(this), 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
callService: function (service, data) {
|
||||||
|
var serviceData = data || {};
|
||||||
|
serviceData.entity_id = this.stateObj.entityId;
|
||||||
|
this.hass.serviceActions.callService('lock', service, serviceData);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-lock',
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
enteredCode: {
|
|
||||||
type: String,
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
handleUnlockTap() {
|
|
||||||
this.callService('unlock', { code: this.enteredCode });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleLockTap() {
|
|
||||||
this.callService('lock', { code: this.enteredCode });
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(newVal) {
|
|
||||||
if (newVal) {
|
|
||||||
this.isLocked = newVal.state === 'locked';
|
|
||||||
}
|
|
||||||
this.async(() => this.fire('iron-resize'), 500);
|
|
||||||
},
|
|
||||||
|
|
||||||
callService(service, data) {
|
|
||||||
const serviceData = data || {};
|
|
||||||
serviceData.entity_id = this.stateObj.entityId;
|
|
||||||
this.hass.serviceActions.callService('lock', service, serviceData);
|
|
||||||
},
|
|
||||||
});
|
|
@ -86,3 +86,245 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-media_player',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
isOff: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
isPlaying: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
isMuted: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
source: {
|
||||||
|
type: String,
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
sourceIndex: {
|
||||||
|
type: Number,
|
||||||
|
value: 0,
|
||||||
|
observer: 'handleSourceChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
volumeSliderValue: {
|
||||||
|
type: Number,
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsPause: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsVolumeSet: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsVolumeMute: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsPreviousTrack: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsNextTrack: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsTurnOn: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsTurnOff: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsVolumeButtons: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsSelectSource: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
hasMediaControl: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
HAS_MEDIA_STATES: ['playing', 'paused', 'unknown'],
|
||||||
|
|
||||||
|
stateObjChanged: function (newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.isOff = newVal.state === 'off';
|
||||||
|
this.isPlaying = newVal.state === 'playing';
|
||||||
|
this.hasMediaControl = this.HAS_MEDIA_STATES.indexOf(newVal.state) !== -1;
|
||||||
|
this.volumeSliderValue = newVal.attributes.volume_level * 100;
|
||||||
|
this.isMuted = newVal.attributes.is_volume_muted;
|
||||||
|
this.source = newVal.attributes.source;
|
||||||
|
this.supportsPause = (newVal.attributes.supported_media_commands & 1) !== 0;
|
||||||
|
this.supportsVolumeSet = (newVal.attributes.supported_media_commands & 4) !== 0;
|
||||||
|
this.supportsVolumeMute = (newVal.attributes.supported_media_commands & 8) !== 0;
|
||||||
|
this.supportsPreviousTrack = (newVal.attributes.supported_media_commands & 16) !== 0;
|
||||||
|
this.supportsNextTrack = (newVal.attributes.supported_media_commands & 32) !== 0;
|
||||||
|
this.supportsTurnOn = (newVal.attributes.supported_media_commands & 128) !== 0;
|
||||||
|
this.supportsTurnOff = (newVal.attributes.supported_media_commands & 256) !== 0;
|
||||||
|
this.supportsVolumeButtons = (newVal.attributes.supported_media_commands & 1024) !== 0;
|
||||||
|
this.supportsSelectSource = (newVal.attributes.supported_media_commands & 2048) !== 0;
|
||||||
|
|
||||||
|
if (newVal.attributes.source_list !== undefined) {
|
||||||
|
this.sourceIndex = newVal.attributes.source_list.indexOf(this.source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.async(function () {
|
||||||
|
this.fire('iron-resize');
|
||||||
|
}.bind(this), 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeClassNames: function (stateObj) {
|
||||||
|
return window.hassUtil.attributeClassNames(stateObj, ['volume_level']);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeIsOff: function (stateObj) {
|
||||||
|
return stateObj.state === 'off';
|
||||||
|
},
|
||||||
|
|
||||||
|
computeMuteVolumeIcon: function (isMuted) {
|
||||||
|
return isMuted ? 'mdi:volume-off' : 'mdi:volume-high';
|
||||||
|
},
|
||||||
|
|
||||||
|
computeHideVolumeButtons: function (isOff, supportsVolumeButtons) {
|
||||||
|
return !supportsVolumeButtons || isOff;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeShowPlaybackControls: function (isOff, hasMedia) {
|
||||||
|
return !isOff && hasMedia;
|
||||||
|
},
|
||||||
|
|
||||||
|
computePlaybackControlIcon: function () {
|
||||||
|
if (this.isPlaying) {
|
||||||
|
return this.supportsPause ? 'mdi:pause' : 'mdi:stop';
|
||||||
|
}
|
||||||
|
return 'mdi:play';
|
||||||
|
},
|
||||||
|
|
||||||
|
computeHidePowerButton: function (isOff, supportsTurnOn, supportsTurnOff) {
|
||||||
|
return isOff ? !supportsTurnOn : !supportsTurnOff;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeHideSelectSource: function (isOff, supportsSelectSource) {
|
||||||
|
return !isOff && supportsSelectSource;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeSelectedSource: function (stateObj) {
|
||||||
|
return stateObj.attributes.source_list.indexOf(stateObj.attributes.source);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleTogglePower: function () {
|
||||||
|
this.callService(this.isOff ? 'turn_on' : 'turn_off');
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePrevious: function () {
|
||||||
|
this.callService('media_previous_track');
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePlaybackControl: function () {
|
||||||
|
this.callService('media_play_pause');
|
||||||
|
},
|
||||||
|
|
||||||
|
handleNext: function () {
|
||||||
|
this.callService('media_next_track');
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSourceChanged: function (sourceIndex) {
|
||||||
|
var sourceInput;
|
||||||
|
// Selected Option will transition to '' before transitioning to new value
|
||||||
|
if (!this.stateObj
|
||||||
|
|| this.stateObj.attributes.source_list === undefined
|
||||||
|
|| sourceIndex < 0
|
||||||
|
|| sourceIndex >= this.stateObj.attributes.source_list.length
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceInput = this.stateObj.attributes.source_list[sourceIndex];
|
||||||
|
|
||||||
|
if (sourceInput === this.stateObj.attributes.source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.callService('select_source', { source: sourceInput });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleVolumeTap: function () {
|
||||||
|
if (!this.supportsVolumeMute) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.callService('volume_mute', { is_volume_muted: !this.isMuted });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleVolumeUp: function () {
|
||||||
|
var obj = this.$.volumeUp;
|
||||||
|
this.handleVolumeWorker('volume_up', obj, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleVolumeDown: function () {
|
||||||
|
var obj = this.$.volumeDown;
|
||||||
|
this.handleVolumeWorker('volume_down', obj, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleVolumeWorker: function (service, obj, force) {
|
||||||
|
if (force || (obj !== undefined && obj.pointerDown)) {
|
||||||
|
this.callService(service);
|
||||||
|
this.async(function () {
|
||||||
|
this.handleVolumeWorker(service, obj, false);
|
||||||
|
}.bind(this), 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
volumeSliderChanged: function (ev) {
|
||||||
|
var volPercentage = parseFloat(ev.target.value);
|
||||||
|
var vol = volPercentage > 0 ? volPercentage / 100 : 0;
|
||||||
|
this.callService('volume_set', { volume_level: vol });
|
||||||
|
},
|
||||||
|
|
||||||
|
callService: function (service, data) {
|
||||||
|
var serviceData = data || {};
|
||||||
|
serviceData.entity_id = this.stateObj.entityId;
|
||||||
|
this.hass.serviceActions.callService('media_player', service, serviceData);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,237 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
const ATTRIBUTE_CLASSES = ['volume_level'];
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-media_player',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
isOff: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
isPlaying: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
isMuted: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
source: {
|
|
||||||
type: String,
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
sourceIndex: {
|
|
||||||
type: Number,
|
|
||||||
value: 0,
|
|
||||||
observer: 'handleSourceChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
volumeSliderValue: {
|
|
||||||
type: Number,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsPause: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsVolumeSet: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsVolumeMute: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsPreviousTrack: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsNextTrack: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsTurnOn: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsTurnOff: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsVolumeButtons: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
supportsSelectSource: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
hasMediaControl: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(newVal) {
|
|
||||||
if (newVal) {
|
|
||||||
const hasMediaStates = ['playing', 'paused', 'unknown'];
|
|
||||||
|
|
||||||
this.isOff = newVal.state === 'off';
|
|
||||||
this.isPlaying = newVal.state === 'playing';
|
|
||||||
this.hasMediaControl = hasMediaStates.indexOf(newVal.state) !== -1;
|
|
||||||
this.volumeSliderValue = newVal.attributes.volume_level * 100;
|
|
||||||
this.isMuted = newVal.attributes.is_volume_muted;
|
|
||||||
this.source = newVal.attributes.source;
|
|
||||||
this.supportsPause = (newVal.attributes.supported_media_commands & 1) !== 0;
|
|
||||||
this.supportsVolumeSet = (newVal.attributes.supported_media_commands & 4) !== 0;
|
|
||||||
this.supportsVolumeMute = (newVal.attributes.supported_media_commands & 8) !== 0;
|
|
||||||
this.supportsPreviousTrack = (newVal.attributes.supported_media_commands & 16) !== 0;
|
|
||||||
this.supportsNextTrack = (newVal.attributes.supported_media_commands & 32) !== 0;
|
|
||||||
this.supportsTurnOn = (newVal.attributes.supported_media_commands & 128) !== 0;
|
|
||||||
this.supportsTurnOff = (newVal.attributes.supported_media_commands & 256) !== 0;
|
|
||||||
this.supportsVolumeButtons = (newVal.attributes.supported_media_commands & 1024) !== 0;
|
|
||||||
this.supportsSelectSource = (newVal.attributes.supported_media_commands & 2048) !== 0;
|
|
||||||
|
|
||||||
if (newVal.attributes.source_list !== undefined) {
|
|
||||||
this.sourceIndex = newVal.attributes.source_list.indexOf(this.source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.async(() => this.fire('iron-resize'), 500);
|
|
||||||
},
|
|
||||||
|
|
||||||
computeClassNames(stateObj) {
|
|
||||||
return window.hassUtil.attributeClassNames(stateObj, ATTRIBUTE_CLASSES);
|
|
||||||
},
|
|
||||||
|
|
||||||
computeIsOff(stateObj) {
|
|
||||||
return stateObj.state === 'off';
|
|
||||||
},
|
|
||||||
|
|
||||||
computeMuteVolumeIcon(isMuted) {
|
|
||||||
return isMuted ? 'mdi:volume-off' : 'mdi:volume-high';
|
|
||||||
},
|
|
||||||
|
|
||||||
computeHideVolumeButtons(isOff, supportsVolumeButtons) {
|
|
||||||
return !supportsVolumeButtons || isOff;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeShowPlaybackControls(isOff, hasMedia) {
|
|
||||||
return !isOff && hasMedia;
|
|
||||||
},
|
|
||||||
|
|
||||||
computePlaybackControlIcon() {
|
|
||||||
if (this.isPlaying) {
|
|
||||||
return this.supportsPause ? 'mdi:pause' : 'mdi:stop';
|
|
||||||
}
|
|
||||||
return 'mdi:play';
|
|
||||||
},
|
|
||||||
|
|
||||||
computeHidePowerButton(isOff, supportsTurnOn, supportsTurnOff) {
|
|
||||||
return isOff ? !supportsTurnOn : !supportsTurnOff;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeHideSelectSource(isOff, supportsSelectSource) {
|
|
||||||
return !isOff && supportsSelectSource;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeSelectedSource(stateObj) {
|
|
||||||
return stateObj.attributes.source_list.indexOf(stateObj.attributes.source);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleTogglePower() {
|
|
||||||
this.callService(this.isOff ? 'turn_on' : 'turn_off');
|
|
||||||
},
|
|
||||||
|
|
||||||
handlePrevious() {
|
|
||||||
this.callService('media_previous_track');
|
|
||||||
},
|
|
||||||
|
|
||||||
handlePlaybackControl() {
|
|
||||||
this.callService('media_play_pause');
|
|
||||||
},
|
|
||||||
|
|
||||||
handleNext() {
|
|
||||||
this.callService('media_next_track');
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSourceChanged(sourceIndex) {
|
|
||||||
// Selected Option will transition to '' before transitioning to new value
|
|
||||||
if (!this.stateObj
|
|
||||||
|| this.stateObj.attributes.source_list === undefined
|
|
||||||
|| sourceIndex < 0
|
|
||||||
|| sourceIndex >= this.stateObj.attributes.source_list.length
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sourceInput = this.stateObj.attributes.source_list[sourceIndex];
|
|
||||||
if (sourceInput === this.stateObj.attributes.source) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.callService('select_source', { source: sourceInput });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVolumeTap() {
|
|
||||||
if (!this.supportsVolumeMute) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.callService('volume_mute', { is_volume_muted: !this.isMuted });
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVolumeUp() {
|
|
||||||
const obj = this.$.volumeUp;
|
|
||||||
this.handleVolumeWorker('volume_up', obj, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVolumeDown() {
|
|
||||||
const obj = this.$.volumeDown;
|
|
||||||
this.handleVolumeWorker('volume_down', obj, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleVolumeWorker(service, obj, force) {
|
|
||||||
if (force || (obj !== undefined && obj.pointerDown)) {
|
|
||||||
this.callService(service);
|
|
||||||
this.async(() => this.handleVolumeWorker(service, obj, false), 500);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
volumeSliderChanged(ev) {
|
|
||||||
const volPercentage = parseFloat(ev.target.value);
|
|
||||||
const vol = volPercentage > 0 ? volPercentage / 100 : 0;
|
|
||||||
this.callService('volume_set', { volume_level: vol });
|
|
||||||
},
|
|
||||||
|
|
||||||
callService(service, data) {
|
|
||||||
const serviceData = data || {};
|
|
||||||
serviceData.entity_id = this.stateObj.entityId;
|
|
||||||
this.hass.serviceActions.callService('media_player', service, serviceData);
|
|
||||||
},
|
|
||||||
});
|
|
@ -11,3 +11,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-script',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-script',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -20,3 +20,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-sun',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
risingDate: {
|
||||||
|
type: Object,
|
||||||
|
computed: 'computeRising(stateObj)',
|
||||||
|
},
|
||||||
|
|
||||||
|
settingDate: {
|
||||||
|
type: Object,
|
||||||
|
computed: 'computeSetting(stateObj)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computeRising: function (stateObj) {
|
||||||
|
return new Date(stateObj.attributes.next_rising);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeSetting: function (stateObj) {
|
||||||
|
return new Date(stateObj.attributes.next_setting);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeOrder: function (risingDate, settingDate) {
|
||||||
|
return risingDate > settingDate ? ['set', 'ris'] : ['ris', 'set'];
|
||||||
|
},
|
||||||
|
|
||||||
|
itemCaption: function (type) {
|
||||||
|
return type === 'ris' ? 'Rising ' : 'Setting ';
|
||||||
|
},
|
||||||
|
|
||||||
|
itemDate: function (type) {
|
||||||
|
return type === 'ris' ? this.risingDate : this.settingDate;
|
||||||
|
},
|
||||||
|
|
||||||
|
itemValue: function (type) {
|
||||||
|
return window.hassUtil.formatTime(this.itemDate(type));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-sun',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
risingDate: {
|
|
||||||
type: Object,
|
|
||||||
computed: 'computeRising(stateObj)',
|
|
||||||
},
|
|
||||||
|
|
||||||
settingDate: {
|
|
||||||
type: Object,
|
|
||||||
computed: 'computeSetting(stateObj)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
computeRising(stateObj) {
|
|
||||||
return new Date(stateObj.attributes.next_rising);
|
|
||||||
},
|
|
||||||
|
|
||||||
computeSetting(stateObj) {
|
|
||||||
return new Date(stateObj.attributes.next_setting);
|
|
||||||
},
|
|
||||||
|
|
||||||
computeOrder(risingDate, settingDate) {
|
|
||||||
return risingDate > settingDate ? ['set', 'ris'] : ['ris', 'set'];
|
|
||||||
},
|
|
||||||
|
|
||||||
itemCaption(type) {
|
|
||||||
return type === 'ris' ? 'Rising ' : 'Setting ';
|
|
||||||
},
|
|
||||||
|
|
||||||
itemDate(type) {
|
|
||||||
return type === 'ris' ? this.risingDate : this.settingDate;
|
|
||||||
},
|
|
||||||
|
|
||||||
itemValue(type) {
|
|
||||||
return window.hassUtil.formatTime(this.itemDate(type));
|
|
||||||
},
|
|
||||||
});
|
|
@ -39,3 +39,77 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-thermostat',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
hass: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
observer: 'stateObjChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
tempMin: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
|
||||||
|
tempMax: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
|
||||||
|
targetTemperatureSliderValue: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
|
||||||
|
awayToggleChecked: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
stateObjChanged: function (newVal) {
|
||||||
|
this.targetTemperatureSliderValue = newVal.attributes.temperature;
|
||||||
|
this.awayToggleChecked = newVal.attributes.away_mode === 'on';
|
||||||
|
|
||||||
|
this.tempMin = newVal.attributes.min_temp;
|
||||||
|
this.tempMax = newVal.attributes.max_temp;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeClassNames: function (stateObj) {
|
||||||
|
return window.hassUtil.attributeClassNames(stateObj, ['away_mode']);
|
||||||
|
},
|
||||||
|
|
||||||
|
targetTemperatureSliderChanged: function (ev) {
|
||||||
|
this.hass.serviceActions.callService('thermostat', 'set_temperature', {
|
||||||
|
entity_id: this.stateObj.entityId,
|
||||||
|
temperature: ev.target.value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleChanged: function (ev) {
|
||||||
|
const newVal = ev.target.checked;
|
||||||
|
|
||||||
|
if (newVal && this.stateObj.attributes.away_mode === 'off') {
|
||||||
|
this.service_set_away(true);
|
||||||
|
} else if (!newVal && this.stateObj.attributes.away_mode === 'on') {
|
||||||
|
this.service_set_away(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
service_set_away: function (awayMode) {
|
||||||
|
// We call stateChanged after a successful call to re-sync the toggle
|
||||||
|
// with the state. It will be out of sync if our service call did not
|
||||||
|
// result in the entity to be turned on. Since the state is not changing,
|
||||||
|
// the resync is not called automatic.
|
||||||
|
this.hass.serviceActions.callService(
|
||||||
|
'thermostat', 'set_away_mode',
|
||||||
|
{ away_mode: awayMode, entity_id: this.stateObj.entityId })
|
||||||
|
|
||||||
|
.then(function () { this.stateObjChanged(this.stateObj); }.bind(this));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
const ATTRIBUTE_CLASSES = ['away_mode'];
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-thermostat',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObj: {
|
|
||||||
type: Object,
|
|
||||||
observer: 'stateObjChanged',
|
|
||||||
},
|
|
||||||
|
|
||||||
tempMin: {
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
|
|
||||||
tempMax: {
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
|
|
||||||
targetTemperatureSliderValue: {
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
|
|
||||||
awayToggleChecked: {
|
|
||||||
type: Boolean,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
stateObjChanged(newVal) {
|
|
||||||
this.targetTemperatureSliderValue = newVal.attributes.temperature;
|
|
||||||
this.awayToggleChecked = newVal.attributes.away_mode === 'on';
|
|
||||||
|
|
||||||
this.tempMin = newVal.attributes.min_temp;
|
|
||||||
this.tempMax = newVal.attributes.max_temp;
|
|
||||||
},
|
|
||||||
|
|
||||||
computeClassNames(stateObj) {
|
|
||||||
return window.hassUtil.attributeClassNames(stateObj, ATTRIBUTE_CLASSES);
|
|
||||||
},
|
|
||||||
|
|
||||||
targetTemperatureSliderChanged(ev) {
|
|
||||||
this.hass.serviceActions.callService('thermostat', 'set_temperature', {
|
|
||||||
entity_id: this.stateObj.entityId,
|
|
||||||
temperature: ev.target.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleChanged(ev) {
|
|
||||||
const newVal = ev.target.checked;
|
|
||||||
|
|
||||||
if (newVal && this.stateObj.attributes.away_mode === 'off') {
|
|
||||||
this.service_set_away(true);
|
|
||||||
} else if (!newVal && this.stateObj.attributes.away_mode === 'on') {
|
|
||||||
this.service_set_away(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
service_set_away(awayMode) {
|
|
||||||
// We call stateChanged after a successful call to re-sync the toggle
|
|
||||||
// with the state. It will be out of sync if our service call did not
|
|
||||||
// result in the entity to be turned on. Since the state is not changing,
|
|
||||||
// the resync is not called automatic.
|
|
||||||
this.hass.serviceActions.callService(
|
|
||||||
'thermostat', 'set_away_mode',
|
|
||||||
{ away_mode: awayMode, entity_id: this.stateObj.entityId })
|
|
||||||
|
|
||||||
.then(() => this.stateObjChanged(this.stateObj));
|
|
||||||
},
|
|
||||||
});
|
|
@ -15,3 +15,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'more-info-updater',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import Polymer from '../polymer';
|
|
||||||
|
|
||||||
export default new Polymer({
|
|
||||||
is: 'more-info-updater',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
},
|
|
||||||
});
|
|
Loading…
x
Reference in New Issue
Block a user