mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-20 15:56:35 +00:00
Remove last ES6
This commit is contained in:
parent
57f40725d9
commit
43940d067a
@ -16,13 +16,11 @@
|
||||
"frontend_html": "script/vulcanize.js",
|
||||
"frontend_prod": "npm run js_prod && 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_ui": "rollup --config rollup/ui.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_ui": "rollup --config rollup/ui.js --watch",
|
||||
"watch_ru_demo": "rollup --config rollup/demo.js --watch",
|
||||
"test": "eslint src panels --ext html"
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
import config from './base-config';
|
||||
|
||||
export default Object.assign({}, config, {
|
||||
entry: 'src/entry-points/app-core.js',
|
||||
entry: 'src/app-core.js',
|
||||
targets: [
|
||||
{ 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();
|
||||
|
@ -1 +1,220 @@
|
||||
<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">
|
||||
|
||||
<dom-module is='state-history-chart-timeline'>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'state-history-chart-timeline',
|
||||
|
||||
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>
|
||||
</dom-module>
|
||||
|
||||
while (root.node.lastChild) {
|
||||
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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@ -40,10 +40,116 @@
|
||||
</state-history-chart-timeline>
|
||||
|
||||
<template is='dom-repeat' items='[[groupedStateHistory.line]]'>
|
||||
<state-history-chart-line unit='[[extractUnit(item)]]'
|
||||
data='[[extractData(item)]]' is-single-device='[[isSingleDevice]]'>
|
||||
<state-history-chart-line
|
||||
unit='[[item.unit]]'
|
||||
data='[[item.data]]'
|
||||
is-single-device='[[isSingleDevice]]'>
|
||||
</state-history-chart-line>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</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-behavior.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/panel-imports.html'>
|
||||
|
||||
@ -103,5 +103,3 @@ Polymer({
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src='../build-temp/ui.js'></script>
|
||||
|
@ -7,63 +7,63 @@
|
||||
<link rel="import" href="../components/ha-view-tabs.html">
|
||||
|
||||
<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>
|
||||
<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'
|
||||
condenses keep-condensed-header class='fit' has-views$='[[hasViews]]'
|
||||
header-height="[[computeHeaderHeight(hasViews, narrow)]]"
|
||||
|
@ -16,3 +16,104 @@
|
||||
</div>
|
||||
</template>
|
||||
</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'>
|
||||
|
||||
<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>
|
||||
<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'>
|
||||
<template is='dom-if' if='[[isConfigurable]]'>
|
||||
|
||||
<p hidden$='[[!stateObj.attributes.description]]'>[[stateObj.attributes.description]]
|
||||
<a hidden$='[[!stateObj.attributes.link_url]]' href='[[stateObj.attributes.link_url]]' target='_blank'>[[stateObj.attributes.link_name]]</a>
|
||||
<p hidden$='[[!stateObj.attributes.description]]'>
|
||||
[[stateObj.attributes.description]]
|
||||
<a
|
||||
hidden$='[[!stateObj.attributes.link_url]]'
|
||||
href='[[stateObj.attributes.link_url]]'
|
||||
target='_blank'
|
||||
>
|
||||
[[stateObj.attributes.link_name]]
|
||||
</a>
|
||||
</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]]'>
|
||||
<img src='[[stateObj.attributes.description_image]]' />
|
||||
@ -43,14 +53,19 @@
|
||||
|
||||
<template is='dom-repeat' items='[[stateObj.attributes.fields]]'>
|
||||
<paper-input-container id='paper-input-fields-{{item.id}}'>
|
||||
<label>{{item.name}}</label>
|
||||
<input is="iron-input" type="{{item.type}}" id='{{item.id}}' on-change="fieldChanged"/>
|
||||
<label>[[item.name]]</label>
|
||||
<input is="iron-input" type="[[item.type]]" id='[[item.id]]' on-change="fieldChanged"/>
|
||||
</paper-input-container>
|
||||
</template>
|
||||
|
||||
<p class='submit'>
|
||||
<paper-button raised on-tap='submitClicked'
|
||||
hidden$='[[isConfiguring]]'>[[submitCaption]]</paper-button>
|
||||
<paper-button
|
||||
raised
|
||||
on-tap='submitClicked'
|
||||
hidden$='[[isConfiguring]]'
|
||||
>
|
||||
[[submitCaption]]
|
||||
</paper-button>
|
||||
|
||||
<loading-box hidden$='[[!isConfiguring]]'>Configuring</loading-box>
|
||||
</p>
|
||||
@ -59,3 +74,83 @@
|
||||
</div>
|
||||
</template>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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>
|
||||
</template>
|
||||
</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