mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-15 21:36:36 +00:00
Merge remote-tracking branch 'balloob/master'
This commit is contained in:
commit
97d4514dc6
12
.babelrc
12
.babelrc
@ -1,10 +1,6 @@
|
||||
{
|
||||
"stage": 1,
|
||||
"highlightCode": true,
|
||||
"optional": ["es7.objectRestSpread", "es7.classProperties"],
|
||||
"env": {
|
||||
"production": {
|
||||
"optional": ["optimisation"]
|
||||
}
|
||||
}
|
||||
"presets": ["es2015"],
|
||||
"plugins": ["transform-object-rest-spread", "transform-export-extensions",
|
||||
"transform-class-properties", "babel-plugin-default-import-checker"],
|
||||
"highlightCode": true
|
||||
}
|
||||
|
@ -8,10 +8,11 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"polymer": "Polymer/polymer#^1.2",
|
||||
"polymer": "Polymer/polymer#~1.2.3",
|
||||
"pikaday": "1.4",
|
||||
"leaflet-map": "1.1.0",
|
||||
"iron-elements": "PolymerElements/iron-elements#~1.0.4",
|
||||
"paper-elements": "PolymerElements/paper-elements#~1.0.6"
|
||||
"iron-elements": "PolymerElements/iron-elements#~1.0.7",
|
||||
"paper-elements": "PolymerElements/paper-elements#~1.0.7",
|
||||
"google-apis": "GoogleWebComponents/google-apis#~1.1.3"
|
||||
}
|
||||
}
|
||||
|
19
package.json
19
package.json
@ -20,19 +20,24 @@
|
||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"home-assistant-js": "git+https://github.com/balloob/home-assistant-js.git#2877f375e76c85505de34af6b752478664570c23",
|
||||
"home-assistant-js": "git+https://github.com/balloob/home-assistant-js.git#b35fb90c94c1dfbb45c9691e9789f0b84b949d94",
|
||||
"lodash": "^3.10.1",
|
||||
"moment": "^2.10.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^5.8.29",
|
||||
"babel-eslint": "^4.1.5",
|
||||
"babel-loader": "^5.3.2",
|
||||
"babel-core": "^6.3",
|
||||
"babel-eslint": "^5.0.0-beta6",
|
||||
"babel-loader": "^6.2",
|
||||
"babel-plugin-default-import-checker": "^1.0.8",
|
||||
"babel-plugin-transform-class-properties": "^6.3.13",
|
||||
"babel-plugin-transform-export-extensions": "^6.3.13",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.3.13",
|
||||
"babel-preset-es2015": "^6.0.0",
|
||||
"bower": "^1.6.5",
|
||||
"eslint": "^1.9",
|
||||
"eslint-config-airbnb": "^1.0.0",
|
||||
"eslint": "^1.10.3",
|
||||
"eslint-config-airbnb": "^0.1.0",
|
||||
"html-minifier": "^1.0.0",
|
||||
"vulcanize": "^1.14.0",
|
||||
"webpack": "^1.12.2"
|
||||
"webpack": "^1.12"
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
import Polymer from '../polymer';
|
||||
import { moreInfoActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
import canToggle from '../util/can-toggle';
|
||||
|
||||
require('../components/ha-card');
|
||||
require('../components/entity/ha-entity-toggle');
|
||||
require('../state-summary/state-card-content');
|
||||
|
||||
const { moreInfoActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-domain-card',
|
||||
|
||||
@ -36,7 +38,7 @@ export default new Polymer({
|
||||
},
|
||||
|
||||
showGroupToggle(groupEntity, states) {
|
||||
if (!groupEntity || groupEntity.state !== 'on' && groupEntity.state !== 'off') {
|
||||
if (!groupEntity || !states || groupEntity.state !== 'on' && groupEntity.state !== 'off') {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
<li><a href='https://home-assistant.io/components/' target='_blank'>
|
||||
Available components
|
||||
</a></li>
|
||||
<li><a href='https://home-assistant.io/getting-started/troubleshooting-configuration/'>Troubleshooting your configuration</a></li>
|
||||
<li><a href='https://home-assistant.io/getting-started/troubleshooting-configuration/' target='_blank'>Troubleshooting your configuration</a></li>
|
||||
<li><a href='https://home-assistant.io/help/' target='_blank'>
|
||||
Getting help
|
||||
</a></li>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { entityGetters } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
const { entityGetters } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'entity-list',
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
import Polymer from '../../polymer';
|
||||
import {
|
||||
import hass from '../../util/home-assistant-js-instance';
|
||||
|
||||
require('../../components/ha-label-badge');
|
||||
|
||||
const {
|
||||
reactor,
|
||||
entityGetters,
|
||||
moreInfoActions,
|
||||
} from '../../util/home-assistant-js-instance';
|
||||
|
||||
require('../../components/ha-label-badge');
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-entity-marker',
|
||||
|
@ -5,7 +5,7 @@
|
||||
<style>
|
||||
paper-toggle-button {
|
||||
cursor: pointer;
|
||||
margin-right: -14px;
|
||||
--paper-toggle-button-label-spacing: 0;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { serviceActions } from '../../util/home-assistant-js-instance';
|
||||
import hass from '../../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../../polymer';
|
||||
|
||||
const { serviceActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-entity-toggle',
|
||||
|
||||
@ -23,11 +25,12 @@ export default new Polymer({
|
||||
|
||||
toggleChanged(ev) {
|
||||
const newVal = ev.target.checked;
|
||||
const curVal = this._checkToggle(this.stateObj);
|
||||
|
||||
if (newVal && this.stateObj.state === 'off') {
|
||||
this.turn_on();
|
||||
} else if (!newVal && this.stateObj.state !== 'off') {
|
||||
this.turn_off();
|
||||
if (newVal && !curVal) {
|
||||
this._call_service(true);
|
||||
} else if (!newVal && curVal) {
|
||||
this._call_service(false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -49,23 +52,27 @@ export default new Polymer({
|
||||
this.toggleChecked = newState;
|
||||
},
|
||||
|
||||
turn_on() {
|
||||
// We call updateToggle 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.
|
||||
serviceActions.callTurnOn(this.stateObj.entityId).then(() => this.forceStateChange());
|
||||
},
|
||||
|
||||
turn_off() {
|
||||
// We call updateToggle 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.
|
||||
serviceActions.callTurnOff(this.stateObj.entityId).then(() => this.forceStateChange());
|
||||
},
|
||||
|
||||
_checkToggle(stateObj) {
|
||||
return stateObj && stateObj.state !== 'off';
|
||||
return stateObj && stateObj.state !== 'off' && stateObj.state !== 'unlocked';
|
||||
},
|
||||
|
||||
// We call updateToggle 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.
|
||||
_call_service(turnOn) {
|
||||
let domain;
|
||||
let service;
|
||||
|
||||
if (this.stateObj.domain === 'lock') {
|
||||
domain = 'lock';
|
||||
service = turnOn ? 'lock' : 'unlock';
|
||||
} else {
|
||||
domain = 'homeassistant';
|
||||
service = turnOn ? 'turn_on' : 'turn_off';
|
||||
}
|
||||
|
||||
serviceActions.callService(domain, service, {entity_id: this.stateObj.entityId})
|
||||
.then(() => this.forceStateChange());
|
||||
},
|
||||
});
|
||||
|
@ -1,13 +1,15 @@
|
||||
import Polymer from '../../polymer';
|
||||
import {
|
||||
moreInfoActions,
|
||||
serviceActions,
|
||||
} from '../../util/home-assistant-js-instance';
|
||||
import hass from '../../util/home-assistant-js-instance';
|
||||
import domainIcon from '../../util/domain-icon';
|
||||
import canToggle from '../../util/can-toggle';
|
||||
|
||||
require('../../components/ha-label-badge');
|
||||
|
||||
const {
|
||||
moreInfoActions,
|
||||
serviceActions,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-state-label-badge',
|
||||
|
||||
@ -41,6 +43,7 @@ export default new Polymer({
|
||||
switch (state.domain) {
|
||||
case 'scene':
|
||||
return 'green';
|
||||
case 'binary_sensor':
|
||||
case 'script':
|
||||
return state.state === 'on' ? 'blue' : 'grey';
|
||||
case 'updater':
|
||||
@ -52,6 +55,7 @@ export default new Polymer({
|
||||
|
||||
computeValue(state) {
|
||||
switch (state.domain) {
|
||||
case 'binary_sensor':
|
||||
case 'device_tracker':
|
||||
case 'updater':
|
||||
case 'sun':
|
||||
@ -77,13 +81,13 @@ export default new Polymer({
|
||||
return 'mdi:home-variant';
|
||||
}
|
||||
// state == 'disarmed'
|
||||
return 'mdi:lock-open';
|
||||
return domainIcon(state.domain, state.state);
|
||||
case 'binary_sensor':
|
||||
case 'device_tracker':
|
||||
case 'scene':
|
||||
case 'updater':
|
||||
case 'script':
|
||||
return domainIcon(state.domain, state.state);
|
||||
case 'updater':
|
||||
return domainIcon(state.domain);
|
||||
case 'sun':
|
||||
return state.state === 'above_horizon' ?
|
||||
domainIcon(state.domain) : 'mdi:brightness-3';
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { eventGetters } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
const { eventGetters } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'events-list',
|
||||
|
||||
|
@ -7,35 +7,21 @@
|
||||
*/
|
||||
import Polymer from '../polymer';
|
||||
|
||||
/**
|
||||
* given red, green, blue values, return the equivalent hexidecimal value
|
||||
* base source: http://stackoverflow.com/a/5624139
|
||||
*/
|
||||
function componentToHex(comp) {
|
||||
const hex = comp.toString(16);
|
||||
return hex.length === 1 ? '0' + hex : hex;
|
||||
}
|
||||
|
||||
function rgbToHex(color) {
|
||||
return '#' + componentToHex(color.r) + componentToHex(color.g) +
|
||||
componentToHex(color.b);
|
||||
}
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-color-picker',
|
||||
|
||||
properties: {
|
||||
width: {
|
||||
type: Number,
|
||||
value: 300,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
value: 300,
|
||||
},
|
||||
color: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
width: {
|
||||
type: Number,
|
||||
},
|
||||
|
||||
height: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
|
||||
listeners: {
|
||||
@ -64,56 +50,45 @@ export default new Polymer({
|
||||
},
|
||||
|
||||
onTouchMove(ev) {
|
||||
const touch = ev.touches[0];
|
||||
this.onColorSelect(ev, {x: touch.clientX, y: touch.clientY});
|
||||
if (!this.mouseMoveIsThrottled) {
|
||||
return;
|
||||
}
|
||||
this.mouseMoveIsThrottled = false;
|
||||
this.processColorSelect(ev.touches[0]);
|
||||
this.async(() => this.mouseMoveIsThrottled = true, 100);
|
||||
},
|
||||
|
||||
onMouseMove(ev) {
|
||||
ev.preventDefault();
|
||||
if (this.mouseMoveIsThrottled) {
|
||||
this.mouseMoveIsThrottled = false;
|
||||
this.onColorSelect(ev);
|
||||
this.async(() => this.mouseMoveIsThrottled = true, 100);
|
||||
if (!this.mouseMoveIsThrottled) {
|
||||
return;
|
||||
}
|
||||
this.mouseMoveIsThrottled = false;
|
||||
this.processColorSelect(ev);
|
||||
this.async(() => this.mouseMoveIsThrottled = true, 100);
|
||||
},
|
||||
|
||||
onColorSelect(ev, coords) {
|
||||
if (this.context) {
|
||||
const colorCoords = coords || this.relativeMouseCoordinates(ev);
|
||||
const data = this.context.getImageData(colorCoords.x, colorCoords.y, 1, 1).data;
|
||||
processColorSelect(ev) {
|
||||
const rect = this.canvas.getBoundingClientRect();
|
||||
|
||||
this.setColor({r: data[0], g: data[1], b: data[2]});
|
||||
// boundary check because people can move off-canvas.
|
||||
if (ev.clientX < rect.left || ev.clientX >= rect.left + rect.width ||
|
||||
ev.clientY < rect.top || ev.clientY >= rect.top + rect.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onColorSelect(ev.clientX - rect.left, ev.clientY - rect.top);
|
||||
},
|
||||
|
||||
onColorSelect(x, y) {
|
||||
const data = this.context.getImageData(x, y, 1, 1).data;
|
||||
|
||||
this.setColor({r: data[0], g: data[1], b: data[2]});
|
||||
},
|
||||
|
||||
setColor(rgb) {
|
||||
// save calculated color
|
||||
this.color = {hex: rgbToHex(rgb), rgb: rgb};
|
||||
this.color = rgb;
|
||||
|
||||
this.fire('colorselected', {
|
||||
rgb: this.color.rgb,
|
||||
hex: this.color.hex,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* given a mouse click event, return x,y coordinates relative to the clicked target
|
||||
* @returns object with x, y values
|
||||
*/
|
||||
relativeMouseCoordinates(ev) {
|
||||
let xCoord = 0;
|
||||
let yCoord = 0;
|
||||
|
||||
if (this.canvas) {
|
||||
const rect = this.canvas.getBoundingClientRect();
|
||||
xCoord = ev.clientX - rect.left;
|
||||
yCoord = ev.clientY - rect.top;
|
||||
}
|
||||
|
||||
return {
|
||||
x: xCoord,
|
||||
y: yCoord,
|
||||
};
|
||||
this.fire('colorselected', {rgb: this.color});
|
||||
},
|
||||
|
||||
ready() {
|
||||
@ -122,25 +97,34 @@ export default new Polymer({
|
||||
this.canvas = this.children[0];
|
||||
this.context = this.canvas.getContext('2d');
|
||||
|
||||
const colorGradient = this.context.createLinearGradient(0, 0, this.width, 0);
|
||||
colorGradient.addColorStop(0, 'rgb(255,0,0)');
|
||||
colorGradient.addColorStop(0.16, 'rgb(255,0,255)');
|
||||
colorGradient.addColorStop(0.32, 'rgb(0,0,255)');
|
||||
colorGradient.addColorStop(0.48, 'rgb(0,255,255)');
|
||||
colorGradient.addColorStop(0.64, 'rgb(0,255,0)');
|
||||
colorGradient.addColorStop(0.80, 'rgb(255,255,0)');
|
||||
colorGradient.addColorStop(1, 'rgb(255,0,0)');
|
||||
this.context.fillStyle = colorGradient;
|
||||
this.context.fillRect(0, 0, this.width, this.height);
|
||||
this.debounce('drawGradient', () => {
|
||||
const style = getComputedStyle(this);
|
||||
const width = parseInt(style.width, 10);
|
||||
const height = parseInt(style.height, 10);
|
||||
|
||||
const bwGradient = this.context.createLinearGradient(0, 0, 0, this.height);
|
||||
bwGradient.addColorStop(0, 'rgba(255,255,255,1)');
|
||||
bwGradient.addColorStop(0.5, 'rgba(255,255,255,0)');
|
||||
bwGradient.addColorStop(0.5, 'rgba(0,0,0,0)');
|
||||
bwGradient.addColorStop(1, 'rgba(0,0,0,1)');
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.context.fillStyle = bwGradient;
|
||||
this.context.fillRect(0, 0, this.width, this.height);
|
||||
const colorGradient = this.context.createLinearGradient(0, 0, width, 0);
|
||||
colorGradient.addColorStop(0, 'rgb(255,0,0)');
|
||||
colorGradient.addColorStop(0.16, 'rgb(255,0,255)');
|
||||
colorGradient.addColorStop(0.32, 'rgb(0,0,255)');
|
||||
colorGradient.addColorStop(0.48, 'rgb(0,255,255)');
|
||||
colorGradient.addColorStop(0.64, 'rgb(0,255,0)');
|
||||
colorGradient.addColorStop(0.80, 'rgb(255,255,0)');
|
||||
colorGradient.addColorStop(1, 'rgb(255,0,0)');
|
||||
this.context.fillStyle = colorGradient;
|
||||
this.context.fillRect(0, 0, width, height);
|
||||
|
||||
const bwGradient = this.context.createLinearGradient(0, 0, 0, height);
|
||||
bwGradient.addColorStop(0, 'rgba(255,255,255,1)');
|
||||
bwGradient.addColorStop(0.5, 'rgba(255,255,255,0)');
|
||||
bwGradient.addColorStop(0.5, 'rgba(0,0,0,0)');
|
||||
bwGradient.addColorStop(1, 'rgba(0,0,0,1)');
|
||||
|
||||
this.context.fillStyle = bwGradient;
|
||||
this.context.fillRect(0, 0, width, height);
|
||||
}, 100);
|
||||
},
|
||||
|
||||
});
|
||||
|
@ -113,6 +113,9 @@
|
||||
<paper-icon-button
|
||||
icon='mdi:nfc' data-panel='devEvent'
|
||||
on-click='handleDevClick'></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon='mdi:file-xml' data-panel='devTemplate'
|
||||
on-click='handleDevClick'></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon='mdi:information-outline' data-panel='devInfo'
|
||||
on-click='handleDevClick'></paper-icon-button>
|
||||
|
@ -1,15 +1,17 @@
|
||||
import {
|
||||
configGetters,
|
||||
navigationGetters,
|
||||
authActions,
|
||||
navigationActions,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('./stream-status');
|
||||
|
||||
const {
|
||||
configGetters,
|
||||
navigationGetters,
|
||||
authActions,
|
||||
navigationActions,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-sidebar',
|
||||
|
||||
|
@ -25,12 +25,30 @@
|
||||
|
||||
.column {
|
||||
max-width: 500px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.zone-card {
|
||||
margin-left: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
:host {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.zone-card {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 599px) {
|
||||
.column {
|
||||
max-width: 600px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<template>
|
||||
|
@ -1,11 +1,12 @@
|
||||
import Polymer from '../polymer';
|
||||
import { util } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
require('.//ha-demo-badge');
|
||||
require('../cards/ha-badges-card');
|
||||
require('../cards/ha-domain-card');
|
||||
require('../cards/ha-introduction-card');
|
||||
|
||||
const { util } = hass;
|
||||
const PRIORITY = {
|
||||
configurator: -20,
|
||||
group: -10,
|
||||
@ -16,10 +17,9 @@ const PRIORITY = {
|
||||
alarm_control_panel: 3,
|
||||
camera: 4,
|
||||
sensor: 5,
|
||||
scene: 6,
|
||||
script: 7,
|
||||
thermostat: 40,
|
||||
media_player: 50,
|
||||
binary_sensor: 6,
|
||||
scene: 7,
|
||||
script: 8,
|
||||
};
|
||||
|
||||
function getPriority(domain) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { moreInfoActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
@ -6,6 +6,8 @@ require('./domain-icon');
|
||||
require('./display-time');
|
||||
require('./relative-ha-datetime');
|
||||
|
||||
const { moreInfoActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'logbook-entry',
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import moment from 'moment';
|
||||
import { util } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
import Polymer from '../polymer';
|
||||
|
||||
const UPDATE_INTERVAL = 60000; // 60 seconds
|
||||
|
||||
const { parseDateTime } = util;
|
||||
const { util: { parseDateTime } } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'relative-ha-datetime',
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { serviceGetters } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('./domain-icon');
|
||||
|
||||
const { serviceGetters } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'services-list',
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { streamGetters, streamActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
const { streamGetters, streamActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'stream-status',
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
import {
|
||||
voiceActions,
|
||||
voiceGetters,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
const {
|
||||
voiceActions,
|
||||
voiceGetters,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'ha-voice-command-dialog',
|
||||
|
||||
|
@ -1,10 +1,4 @@
|
||||
import {
|
||||
configGetters,
|
||||
entityHistoryGetters,
|
||||
entityHistoryActions,
|
||||
moreInfoGetters,
|
||||
moreInfoActions,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
@ -13,6 +7,14 @@ require('../state-summary/state-card-content');
|
||||
require('../components/state-history-charts');
|
||||
require('../more-infos/more-info-content');
|
||||
|
||||
const {
|
||||
configGetters,
|
||||
entityHistoryGetters,
|
||||
entityHistoryActions,
|
||||
moreInfoGetters,
|
||||
moreInfoActions,
|
||||
} = hass;
|
||||
|
||||
// if you don't want the history component to show add the domain to this array
|
||||
const DOMAINS_WITH_NO_HISTORY = ['camera', 'configurator', 'scene'];
|
||||
|
||||
@ -73,13 +75,6 @@ export default new Polymer({
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
_boundOnBackdropTap: {
|
||||
type: Function,
|
||||
value: function bindBackdropTap() {
|
||||
return this._onBackdropTap.bind(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
@ -121,18 +116,10 @@ export default new Polymer({
|
||||
|
||||
dialogOpenChanged(newVal) {
|
||||
if (newVal) {
|
||||
this.$.dialog.backdropElement.addEventListener('click',
|
||||
this._boundOnBackdropTap);
|
||||
this.async(() => this._delayedDialogOpen = true, 10);
|
||||
} else if (!newVal && this.stateObj) {
|
||||
moreInfoActions.deselectEntity();
|
||||
this._delayedDialogOpen = false;
|
||||
}
|
||||
},
|
||||
|
||||
_onBackdropTap() {
|
||||
this.$.dialog.backdropElement.removeEventListener('click',
|
||||
this._boundOnBackdropTap);
|
||||
this.dialogOpen = false;
|
||||
},
|
||||
});
|
||||
|
@ -1,12 +1,6 @@
|
||||
import Polymer from './polymer';
|
||||
|
||||
import {
|
||||
localStoragePreferences,
|
||||
navigationActions,
|
||||
reactor,
|
||||
startLocalStoragePreferencesSync,
|
||||
syncGetters,
|
||||
} from './util/home-assistant-js-instance';
|
||||
import hass from './util/home-assistant-js-instance';
|
||||
|
||||
import nuclearObserver from './util/bound-nuclear-behavior';
|
||||
import validateAuth from './util/validate-auth';
|
||||
@ -14,6 +8,14 @@ import validateAuth from './util/validate-auth';
|
||||
require('./layouts/login-form');
|
||||
require('./layouts/home-assistant-main');
|
||||
|
||||
const {
|
||||
localStoragePreferences,
|
||||
navigationActions,
|
||||
reactor,
|
||||
startLocalStoragePreferencesSync,
|
||||
syncGetters,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'home-assistant',
|
||||
|
||||
@ -54,9 +56,16 @@ export default new Polymer({
|
||||
},
|
||||
|
||||
loadIcons() {
|
||||
// If the import fails, we'll try to import again, must be a server glitch
|
||||
// Since HTML imports only resolve once, we import another url.
|
||||
const success = () => this.iconsLoaded = true;
|
||||
this.importHref(`/static/mdi-${this.icons}.html`,
|
||||
() => this.iconsLoaded = true,
|
||||
() => this.loadIcons());
|
||||
success,
|
||||
() => this.importHref(`/static/mdi.html`, success, success));
|
||||
},
|
||||
|
||||
created() {
|
||||
this.registerServiceWorker();
|
||||
},
|
||||
|
||||
ready() {
|
||||
@ -72,10 +81,14 @@ export default new Polymer({
|
||||
|
||||
startLocalStoragePreferencesSync();
|
||||
|
||||
// remove the HTML init message
|
||||
const initMsg = document.getElementById('init');
|
||||
initMsg.parentElement.removeChild(initMsg);
|
||||
|
||||
this.loadIcons();
|
||||
},
|
||||
|
||||
registerServiceWorker() {
|
||||
if (!('serviceWorker' in navigator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.serviceWorker.register('./service_worker.js');
|
||||
},
|
||||
});
|
||||
|
@ -8,6 +8,7 @@
|
||||
<link rel='import' href='../layouts/partial-dev-call-service.html'>
|
||||
<link rel='import' href='../layouts/partial-dev-fire-event.html'>
|
||||
<link rel='import' href='../layouts/partial-dev-set-state.html'>
|
||||
<link rel='import' href='../layouts/partial-dev-template.html'>
|
||||
<link rel='import' href='../layouts/partial-dev-info.html'>
|
||||
<link rel='import' href='../managers/notification-manager.html'>
|
||||
<link rel="import" href="../dialogs/more-info-dialog.html">
|
||||
@ -50,6 +51,9 @@
|
||||
<template is='dom-if' if='[[isSelectedDevState]]'>
|
||||
<partial-dev-set-state main narrow='[[narrow]]' show-menu='[[showSidebar]]'></partial-dev-set-state>
|
||||
</template>
|
||||
<template is='dom-if' if='[[isSelectedDevTemplate]]'>
|
||||
<partial-dev-template main narrow='[[narrow]]' show-menu='[[showSidebar]]'></partial-dev-template>
|
||||
</template>
|
||||
<template is='dom-if' if='[[isSelectedDevInfo]]'>
|
||||
<partial-dev-info main narrow='[[narrow]]' show-menu='[[showSidebar]]'></partial-dev-info>
|
||||
</template>
|
||||
|
@ -1,12 +1,8 @@
|
||||
import Polymer from '../polymer';
|
||||
import {
|
||||
navigationActions,
|
||||
navigationGetters,
|
||||
startUrlSync,
|
||||
stopUrlSync,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
import removeInitMsg from '../util/remove-init-message';
|
||||
|
||||
require('../components/ha-sidebar');
|
||||
require('../layouts/partial-zone');
|
||||
@ -16,11 +12,19 @@ require('../layouts/partial-map');
|
||||
require('../layouts/partial-dev-call-service');
|
||||
require('../layouts/partial-dev-fire-event');
|
||||
require('../layouts/partial-dev-set-state');
|
||||
require('../layouts/partial-dev-template');
|
||||
require('../layouts/partial-dev-info');
|
||||
require('../managers/notification-manager');
|
||||
require('../dialogs/more-info-dialog');
|
||||
require('../dialogs/ha-voice-command-dialog');
|
||||
|
||||
const {
|
||||
navigationActions,
|
||||
navigationGetters,
|
||||
startUrlSync,
|
||||
stopUrlSync,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'home-assistant-main',
|
||||
|
||||
@ -68,6 +72,11 @@ export default new Polymer({
|
||||
bindNuclear: navigationGetters.isActivePane('devState'),
|
||||
},
|
||||
|
||||
isSelectedDevTemplate: {
|
||||
type: Boolean,
|
||||
bindNuclear: navigationGetters.isActivePane('devTemplate'),
|
||||
},
|
||||
|
||||
isSelectedDevService: {
|
||||
type: Boolean,
|
||||
bindNuclear: navigationGetters.isActivePane('devService'),
|
||||
@ -111,6 +120,7 @@ export default new Polymer({
|
||||
},
|
||||
|
||||
attached() {
|
||||
removeInitMsg();
|
||||
startUrlSync();
|
||||
},
|
||||
|
||||
|
@ -51,7 +51,7 @@
|
||||
|
||||
<template>
|
||||
<div class="layout vertical center center-center fit">
|
||||
<img src="/static/splash.png" height="230" />
|
||||
<img src="/static/favicon-192x192.png" height="192" />
|
||||
<a href="#" id="hideKeyboardOnFocus"></a>
|
||||
<div class='interact'>
|
||||
<div id='loginform' hidden$="[[showLoading]]">
|
||||
|
@ -1,9 +1,12 @@
|
||||
import Polymer from '../polymer';
|
||||
|
||||
import { authGetters } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
import validateAuth from '../util/validate-auth';
|
||||
import removeInitMsg from '../util/remove-init-message';
|
||||
|
||||
const { authGetters } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'login-form',
|
||||
@ -52,6 +55,10 @@ export default new Polymer({
|
||||
'validatingChanged(isValidating, isInvalid)',
|
||||
],
|
||||
|
||||
attached() {
|
||||
removeInitMsg();
|
||||
},
|
||||
|
||||
computeShowSpinner(forceShowLoading, isValidating) {
|
||||
return forceShowLoading || isValidating;
|
||||
},
|
||||
|
@ -1,14 +1,16 @@
|
||||
import {
|
||||
reactor,
|
||||
serviceActions,
|
||||
serviceGetters,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
require('./partial-base');
|
||||
require('../components/services-list');
|
||||
|
||||
const {
|
||||
reactor,
|
||||
serviceActions,
|
||||
serviceGetters,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-dev-call-service',
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { eventActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
require('./partial-base');
|
||||
require('../components/events-list');
|
||||
|
||||
const { eventActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-dev-fire-event',
|
||||
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
<link rel="import" href="./partial-base.html">
|
||||
|
||||
<link rel="import" href="../components/services-list.html">
|
||||
|
||||
<dom-module id="partial-dev-info">
|
||||
<style>
|
||||
.content {
|
||||
@ -56,7 +54,8 @@
|
||||
<div class='content fit'>
|
||||
<div class='about'>
|
||||
<p class='version'>
|
||||
<a href='https://home-assistant.io'><img src="/static/splash.png" height="230" /></a><br />
|
||||
<a href='https://home-assistant.io'><img src="/static/favicon-192x192.png" height="192" /></a><br />
|
||||
Home Assistant<br />
|
||||
[[hassVersion]]
|
||||
</p>
|
||||
<p class='develop'>
|
||||
|
@ -1,13 +1,15 @@
|
||||
import {
|
||||
configGetters,
|
||||
errorLogActions,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('./partial-base');
|
||||
|
||||
const {
|
||||
configGetters,
|
||||
errorLogActions,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-dev-info',
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { reactor, entityGetters, entityActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
require('./partial-base');
|
||||
require('../components/entity-list');
|
||||
|
||||
const { reactor, entityGetters, entityActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-dev-set-state',
|
||||
|
||||
|
71
src/layouts/partial-dev-template.html
Normal file
71
src/layouts/partial-dev-template.html
Normal file
@ -0,0 +1,71 @@
|
||||
<link rel="import" href="../../bower_components/polymer/polymer.html">
|
||||
|
||||
<link rel="import" href="../../bower_components/paper-input/paper-textarea.html">
|
||||
<link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html">
|
||||
|
||||
<link rel="import" href="./partial-base.html">
|
||||
|
||||
<link rel="import" href="../components/services-list.html">
|
||||
|
||||
<dom-module id="partial-dev-template">
|
||||
<style>
|
||||
.content {
|
||||
margin-top: 64px;
|
||||
padding: 16px;
|
||||
background-color: white;
|
||||
-ms-user-select: initial;
|
||||
-webkit-user-select: initial;
|
||||
-moz-user-select: initial;
|
||||
}
|
||||
|
||||
.edit-pane {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.horizontal .edit-pane {
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.render-pane {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.render-spinner {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.rendered {
|
||||
clear: both;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.rendered.error {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<partial-base narrow="[[narrow]]" show-menu='[[showMenu]]'>
|
||||
<span header-title>Template Editor</span>
|
||||
|
||||
<div class$='[[computeFormClasses(narrow)]]'>
|
||||
<div class='edit-pane'>
|
||||
<p>
|
||||
Templates are rendered using the Jinja2 template engine with some Home Assistant specific extensions.
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href='http://jinja.pocoo.org/docs/dev/templates/' target='_blank'>Jinja2 tempate documentation</a></li>
|
||||
<li><a href='https://home-assistant.io/getting-started/templating/' target='_blank'>Home Assistant template extensions</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<paper-textarea label="Template" value='{{template}}'></paper-textarea>
|
||||
</div>
|
||||
<div class='render-pane'>
|
||||
<paper-spinner class='render-spinner' active='[[rendering]]'></paper-spinner>
|
||||
<pre class$='[[computeRenderedClasses(error)]]'>[[processed]]</pre>
|
||||
</div>
|
||||
</div>
|
||||
</partial-base>
|
||||
</template>
|
||||
</dom-module>
|
94
src/layouts/partial-dev-template.js
Normal file
94
src/layouts/partial-dev-template.js
Normal file
@ -0,0 +1,94 @@
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('./partial-base');
|
||||
|
||||
const {
|
||||
templateActions,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-dev-template',
|
||||
|
||||
behaviors: [nuclearObserver],
|
||||
|
||||
properties: {
|
||||
narrow: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
showMenu: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
error: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
rendering: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
template: {
|
||||
type: String,
|
||||
value: '{%- if is_state("device_tracker.paulus", "home") and \n' +
|
||||
' is_state("device_tracker.anne_therese", "home") -%}\n' +
|
||||
'\n' +
|
||||
' You are both home, you silly\n' +
|
||||
'\n' +
|
||||
'{%- else -%}\n' +
|
||||
'\n' +
|
||||
' Anne Therese is at {{ states("device_tracker.anne_therese") }} and ' +
|
||||
'Paulus is at {{ states("device_tracker.paulus") }}\n' +
|
||||
'\n' +
|
||||
'{%- endif %}\n' +
|
||||
'\n' +
|
||||
'For loop example:\n' +
|
||||
'\n' +
|
||||
'{% for state in states.sensor -%}\n' +
|
||||
' {%- if loop.first %}The {% elif loop.last %} and the {% else %}, the {% endif -%}\n' +
|
||||
' {{ state.name | lower }} is {{state.state}} {{- state.attributes.unit_of_measurement}}\n' +
|
||||
'{%- endfor -%}.',
|
||||
observer: 'templateChanged',
|
||||
},
|
||||
|
||||
processed: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
|
||||
computeFormClasses(narrow) {
|
||||
return 'content fit layout ' + (narrow ? 'vertical' : 'horizontal');
|
||||
},
|
||||
|
||||
computeRenderedClasses(error) {
|
||||
return error ? 'error rendered' : 'rendered';
|
||||
},
|
||||
|
||||
templateChanged() {
|
||||
if (this.error) {
|
||||
this.error = false;
|
||||
}
|
||||
this.debounce('render-template', this.renderTemplate, 500);
|
||||
},
|
||||
|
||||
renderTemplate() {
|
||||
this.rendering = true;
|
||||
|
||||
templateActions.render(this.template).then(processed => {
|
||||
this.processed = processed;
|
||||
this.rendering = false;
|
||||
}, error => {
|
||||
this.processed = error.message;
|
||||
this.error = true;
|
||||
this.rendering = false;
|
||||
});
|
||||
},
|
||||
});
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
entityHistoryGetters,
|
||||
entityHistoryActions,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
@ -9,6 +6,11 @@ import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
require('./partial-base');
|
||||
require('../components/state-history-charts');
|
||||
|
||||
const {
|
||||
entityHistoryGetters,
|
||||
entityHistoryActions,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-history',
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { logbookGetters, logbookActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
@ -7,6 +7,8 @@ require('./partial-base');
|
||||
require('../components/ha-logbook');
|
||||
require('../components/loading-box');
|
||||
|
||||
const { logbookGetters, logbookActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-logbook',
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
import {
|
||||
configGetters,
|
||||
entityGetters,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('../components/entity/ha-entity-marker');
|
||||
|
||||
const {
|
||||
configGetters,
|
||||
entityGetters,
|
||||
} = hass;
|
||||
|
||||
window.L.Icon.Default.imagePath = '/static/images/leaflet';
|
||||
|
||||
export default new Polymer({
|
||||
|
@ -31,7 +31,7 @@
|
||||
on-click="handleListenClick"></paper-icon-button>
|
||||
</paper-toolbar>
|
||||
|
||||
<div class='content fit'>
|
||||
<div class='fit'>
|
||||
<ha-zone-cards
|
||||
show-introduction='[[computeShowIntroduction(introductionLoaded, states)]]'
|
||||
states='[[states]]' columns='[[columns]]'></ha-zone-cards>
|
||||
|
@ -1,4 +1,12 @@
|
||||
import {
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('./partial-base');
|
||||
require('../components/ha-zone-cards');
|
||||
|
||||
const {
|
||||
configGetters,
|
||||
entityGetters,
|
||||
voiceGetters,
|
||||
@ -6,13 +14,7 @@ import {
|
||||
syncGetters,
|
||||
syncActions,
|
||||
voiceActions,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('./partial-base');
|
||||
require('../components/ha-zone-cards');
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'partial-zone',
|
||||
@ -67,6 +69,7 @@ export default new Polymer({
|
||||
|
||||
columns: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
|
||||
@ -74,7 +77,7 @@ export default new Polymer({
|
||||
this.windowChange = this.windowChange.bind(this);
|
||||
const sizes = [];
|
||||
for (let col = 0; col < 5; col++) {
|
||||
sizes.push(278 + col * 278);
|
||||
sizes.push(300 + col * 300);
|
||||
}
|
||||
this.mqls = sizes.map(width => {
|
||||
const mql = window.matchMedia(`(min-width: ${width}px)`);
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { notificationGetters } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
const { notificationGetters } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'notification-manager',
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { serviceActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
const { serviceActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'more-info-alarm_control_panel',
|
||||
handleDisarmTap() {
|
||||
|
@ -1,14 +1,16 @@
|
||||
import {
|
||||
streamGetters,
|
||||
syncActions,
|
||||
serviceActions,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('../components/loading-box');
|
||||
|
||||
const {
|
||||
streamGetters,
|
||||
syncActions,
|
||||
serviceActions,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'more-info-configurator',
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Polymer from '../polymer';
|
||||
|
||||
const FILTER_KEYS = ['entity_picture', 'friendly_name', 'unit_of_measurement'];
|
||||
const FILTER_KEYS = ['entity_picture', 'friendly_name', 'icon', 'unit_of_measurement'];
|
||||
|
||||
export default new Polymer({
|
||||
is: 'more-info-default',
|
||||
|
@ -1,13 +1,15 @@
|
||||
import {
|
||||
entityGetters,
|
||||
moreInfoGetters,
|
||||
} from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import nuclearObserver from '../util/bound-nuclear-behavior';
|
||||
|
||||
require('../state-summary/state-card-content');
|
||||
|
||||
const {
|
||||
entityGetters,
|
||||
moreInfoGetters,
|
||||
} = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'more-info-group',
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
|
||||
ha-color-picker {
|
||||
display: block;
|
||||
width: 350px;
|
||||
max-width: 350px;
|
||||
height: 200px;
|
||||
margin: 0 auto;
|
||||
|
||||
max-height: 0px;
|
||||
@ -52,7 +53,7 @@
|
||||
</paper-slider>
|
||||
</div>
|
||||
|
||||
<ha-color-picker on-colorselected='colorPicked' width='350' height='200'>
|
||||
<ha-color-picker on-colorselected='colorPicked'>
|
||||
</ha-color-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,12 +1,20 @@
|
||||
import { serviceActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import attributeClassNames from '../util/attribute-class-names';
|
||||
|
||||
require('../components/ha-color-picker');
|
||||
|
||||
const { serviceActions } = hass;
|
||||
const ATTRIBUTE_CLASSES = ['brightness', 'rgb_color', 'color_temp'];
|
||||
|
||||
function pickColor(entityId, color) {
|
||||
serviceActions.callService('light', 'turn_on', {
|
||||
entity_id: entityId,
|
||||
rgb_color: [color.r, color.g, color.b],
|
||||
});
|
||||
}
|
||||
|
||||
export default new Polymer({
|
||||
is: 'more-info-light',
|
||||
|
||||
@ -66,13 +74,29 @@ export default new Polymer({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
const color = ev.detail.rgb;
|
||||
if (this.skipColorPicked) {
|
||||
this.colorChanged = true;
|
||||
return;
|
||||
}
|
||||
|
||||
serviceActions.callService('light', 'turn_on', {
|
||||
entity_id: this.stateObj.entityId,
|
||||
rgb_color: [color.r, color.g, color.b],
|
||||
});
|
||||
this.color = ev.detail.rgb;
|
||||
|
||||
pickColor(this.stateObj.entityId, this.color);
|
||||
|
||||
this.colorChanged = false;
|
||||
this.skipColorPicked = true;
|
||||
|
||||
this.colorDebounce = setTimeout(() => {
|
||||
if (this.colorChanged) {
|
||||
pickColor(this.stateObj.entityId, this.color);
|
||||
}
|
||||
this.skipColorPicked = false;
|
||||
}, 500);
|
||||
},
|
||||
|
||||
});
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { serviceActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import attributeClassNames from '../util/attribute-class-names';
|
||||
|
||||
const { serviceActions } = hass;
|
||||
const ATTRIBUTE_CLASSES = ['volume_level'];
|
||||
|
||||
export default new Polymer({
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Polymer from '../polymer';
|
||||
import { util } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import formatTime from '../util/format-time';
|
||||
|
||||
const { parseDateTime } = util;
|
||||
const { util: { parseDateTime } } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'more-info-sun',
|
||||
|
@ -22,7 +22,7 @@
|
||||
<div>
|
||||
<div>Target Temperature</div>
|
||||
<paper-slider
|
||||
min='[[tempMin]]' max='[[tempMax]]'
|
||||
min='[[tempMin]]' max='[[tempMax]]' step='0.5'
|
||||
value='[[targetTemperatureSliderValue]]' pin
|
||||
on-change='targetTemperatureSliderChanged'>
|
||||
</paper-slider>
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { serviceActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
import attributeClassNames from '../util/attribute-class-names';
|
||||
|
||||
const { serviceActions } = hass;
|
||||
const ATTRIBUTE_CLASSES = ['away_mode'];
|
||||
|
||||
export default new Polymer({
|
||||
@ -44,13 +45,9 @@ export default new Polymer({
|
||||
},
|
||||
|
||||
targetTemperatureSliderChanged(ev) {
|
||||
const temp = parseInt(ev.target.value, 10);
|
||||
|
||||
if (isNaN(temp)) return;
|
||||
|
||||
serviceActions.callService('thermostat', 'set_temperature', {
|
||||
entity_id: this.stateObj.entityId,
|
||||
temperature: temp,
|
||||
temperature: ev.target.value,
|
||||
});
|
||||
},
|
||||
|
||||
|
65
src/service-worker/index.js
Normal file
65
src/service-worker/index.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* eslint-disable no-console */
|
||||
const CACHE = '0.10';
|
||||
const INDEX_CACHE_URL = '/';
|
||||
const INDEX_ROUTES = ['/', '/logbook', '/history', '/map', '/devService', '/devState',
|
||||
'/devEvent', '/devInfo', '/states'];
|
||||
const CACHE_URLS = [
|
||||
'/static/favicon-192x192.png',
|
||||
];
|
||||
|
||||
if (__DEV__) {
|
||||
console.log('Service Worker initialized.');
|
||||
}
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
if (__DEV__) {
|
||||
console.log('Service Worker installed.');
|
||||
}
|
||||
|
||||
event.waitUntil(
|
||||
caches.open(CACHE).then(cache => cache.addAll(CACHE_URLS.concat(INDEX_CACHE_URL)))
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
if (__DEV__) {
|
||||
console.log('Service Worker activated.');
|
||||
// Force refresh service worker
|
||||
event.waitUntil(global.clients.claim());
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('message', event => {
|
||||
if (__DEV__) {
|
||||
console.log('Message received', event.data);
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
const path = event.request.url.substr(event.request.url.indexOf('/', 8));
|
||||
|
||||
// TODO: do not cache requests to 3rd party hosts (or remove those calls)
|
||||
|
||||
if (CACHE_URLS.includes(path)) {
|
||||
event.respondWith(
|
||||
caches.open(CACHE).then(cache => cache.match(event.request))
|
||||
);
|
||||
}
|
||||
|
||||
if (!INDEX_ROUTES.includes(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.open(CACHE).then(cache => {
|
||||
return cache.match(INDEX_CACHE_URL).then(cachedResponse => {
|
||||
const networkFetch = fetch(event.request).then(response => {
|
||||
cache.put(INDEX_CACHE_URL, response.clone());
|
||||
return response;
|
||||
});
|
||||
|
||||
return cachedResponse || networkFetch;
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
@ -6,3 +6,4 @@
|
||||
<link rel="import" href="state-card-configurator.html">
|
||||
<link rel="import" href="state-card-scene.html">
|
||||
<link rel="import" href="state-card-media_player.html">
|
||||
<link rel="import" href="state-card-rollershutter.html">
|
||||
|
@ -8,6 +8,7 @@ require('./state-card-thermostat');
|
||||
require('./state-card-configurator');
|
||||
require('./state-card-scene');
|
||||
require('./state-card-media_player');
|
||||
require('./state-card-rollershutter');
|
||||
|
||||
export default new Polymer({
|
||||
is: 'state-card-content',
|
||||
|
@ -15,15 +15,18 @@
|
||||
}
|
||||
|
||||
.main-text {
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-transform: capitalize;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-transform: capitalize;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.secondary-text {
|
||||
color: var(--secondary-text-color);
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
|
31
src/state-summary/state-card-rollershutter.html
Normal file
31
src/state-summary/state-card-rollershutter.html
Normal file
@ -0,0 +1,31 @@
|
||||
<link rel="import" href="../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
|
||||
<link rel="import" href="../components/state-info.html">
|
||||
|
||||
<dom-module id="state-card-rollershutter">
|
||||
<style>
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.state {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
width: 127px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<template>
|
||||
<div class='horizontal justified layout'>
|
||||
<state-info state-obj="[[stateObj]]"></state-info>
|
||||
<div class='state'>
|
||||
<paper-icon-button icon="mdi:arrow-up" on-tap='onMoveUpTap'
|
||||
disabled='[[computeIsFullyClosed(stateObj)]]'></paper-icon-button>
|
||||
<paper-icon-button icon="mdi:stop" on-tap='onStopTap'></paper-icon-button>
|
||||
<paper-icon-button icon="mdi:arrow-down" on-tap='onMoveDownTap'
|
||||
disabled='[[computeIsFullyOpen(stateObj)]]'></paper-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</dom-module>
|
40
src/state-summary/state-card-rollershutter.js
Normal file
40
src/state-summary/state-card-rollershutter.js
Normal file
@ -0,0 +1,40 @@
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
require('../components/state-info');
|
||||
|
||||
const { serviceActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'state-card-rollershutter',
|
||||
|
||||
properties: {
|
||||
stateObj: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
|
||||
computeIsFullyOpen(stateObj) {
|
||||
return stateObj.attributes.current_position === 100;
|
||||
},
|
||||
|
||||
computeIsFullyClosed(stateObj) {
|
||||
return stateObj.attributes.current_position === 0;
|
||||
},
|
||||
|
||||
onMoveUpTap() {
|
||||
serviceActions.callService('rollershutter', 'move_up',
|
||||
{entity_id: this.stateObj.entityId});
|
||||
},
|
||||
|
||||
onMoveDownTap() {
|
||||
serviceActions.callService('rollershutter', 'move_down',
|
||||
{entity_id: this.stateObj.entityId});
|
||||
},
|
||||
|
||||
onStopTap() {
|
||||
serviceActions.callService('rollershutter', 'stop',
|
||||
{entity_id: this.stateObj.entityId});
|
||||
},
|
||||
});
|
@ -1,8 +1,10 @@
|
||||
import Polymer from '../polymer';
|
||||
import { serviceActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
require('../components/state-info.js');
|
||||
|
||||
const { serviceActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'state-card-scene',
|
||||
|
||||
|
@ -11,15 +11,22 @@
|
||||
.state {
|
||||
margin-left: 16px;
|
||||
text-align: right;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.target {
|
||||
text-transform: capitalize;
|
||||
font-weight: 400;
|
||||
text-transform: capitalize;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.current {
|
||||
color: var(--secondary-text-color);
|
||||
color: var(--secondary-text-color);
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { moreInfoActions } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
import Polymer from '../polymer';
|
||||
|
||||
require('./state-card-content');
|
||||
|
||||
const { moreInfoActions } = hass;
|
||||
|
||||
export default new Polymer({
|
||||
is: 'state-card',
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { reactor } from '../util/home-assistant-js-instance';
|
||||
import hass from './home-assistant-js-instance';
|
||||
|
||||
import nuclearObserver from './nuclear-behavior';
|
||||
|
||||
export default nuclearObserver(reactor);
|
||||
export default nuclearObserver(hass.reactor);
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {
|
||||
import hass from './home-assistant-js-instance';
|
||||
|
||||
const {
|
||||
reactor,
|
||||
serviceGetters,
|
||||
} from './home-assistant-js-instance';
|
||||
} = hass;
|
||||
|
||||
// Return boolean if entity can be toggled.
|
||||
export default function canToggle(entityId) {
|
||||
|
@ -3,7 +3,10 @@ import defaultIcon from './default-icon';
|
||||
export default function domainIcon(domain, state) {
|
||||
switch (domain) {
|
||||
case 'alarm_control_panel':
|
||||
return state && state === 'disarmed' ? 'mdi:lock-open' : 'mdi:lock';
|
||||
return state && state === 'disarmed' ? 'mdi:bell-outline' : 'mdi:bell';
|
||||
|
||||
case 'binary_sensor':
|
||||
return state && state === 'off' ? 'mdi:radiobox-blank' : 'mdi:checkbox-marked-circle';
|
||||
|
||||
case 'camera':
|
||||
return 'mdi:video';
|
||||
@ -26,6 +29,9 @@ export default function domainIcon(domain, state) {
|
||||
case 'light':
|
||||
return 'mdi:lightbulb';
|
||||
|
||||
case 'lock':
|
||||
return state && state === 'unlocked' ? 'mdi:lock-open' : 'mdi:lock';
|
||||
|
||||
case 'media_player':
|
||||
let icon = 'mdi:cast';
|
||||
if (state && state !== 'off' && state !== 'idle') {
|
||||
@ -40,14 +46,8 @@ export default function domainIcon(domain, state) {
|
||||
case 'updater':
|
||||
return 'mdi:cloud-upload';
|
||||
|
||||
case 'sun':
|
||||
return 'mdi:white-balance-sunny';
|
||||
|
||||
case 'switch':
|
||||
return 'mdi:flash';
|
||||
|
||||
case 'simple_alarm':
|
||||
return 'mdi:bell';
|
||||
case 'rollershutter':
|
||||
return state && state === 'open' ? 'mdi:window-open' : 'mdi:window-closed';
|
||||
|
||||
case 'scene':
|
||||
return 'mdi:google-pages';
|
||||
@ -58,6 +58,15 @@ export default function domainIcon(domain, state) {
|
||||
case 'sensor':
|
||||
return 'mdi:eye';
|
||||
|
||||
case 'simple_alarm':
|
||||
return 'mdi:bell';
|
||||
|
||||
case 'sun':
|
||||
return 'mdi:white-balance-sunny';
|
||||
|
||||
case 'switch':
|
||||
return 'mdi:flash';
|
||||
|
||||
case 'thermostat':
|
||||
return 'mdi:nest-thermostat';
|
||||
|
||||
|
7
src/util/remove-init-message.js
Normal file
7
src/util/remove-init-message.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default function removeInitMessage() {
|
||||
// remove the HTML init message
|
||||
const initMsg = document.getElementById('ha-init-skeleton');
|
||||
if (initMsg) {
|
||||
initMsg.parentElement.removeChild(initMsg);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import canToggle from './can-toggle';
|
||||
|
||||
const DOMAINS_WITH_CARD = [
|
||||
'thermostat', 'configurator', 'scene', 'media_player'];
|
||||
'thermostat', 'configurator', 'scene', 'media_player', 'rollershutter'];
|
||||
|
||||
export default function stateCardType(state) {
|
||||
if (DOMAINS_WITH_CARD.indexOf(state.domain) !== -1) {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import defaultIcon from './default-icon';
|
||||
import domainIcon from './domain-icon.js';
|
||||
import {
|
||||
util,
|
||||
} from './home-assistant-js-instance';
|
||||
import hass from './home-assistant-js-instance';
|
||||
|
||||
const { util: { temperatureUnits } } = hass;
|
||||
|
||||
export default function stateIcon(state) {
|
||||
if (!state) {
|
||||
@ -15,8 +14,8 @@ export default function stateIcon(state) {
|
||||
const unit = state.attributes.unit_of_measurement;
|
||||
|
||||
if (unit && state.domain === 'sensor') {
|
||||
if (unit === util.temperatureUnits.UNIT_TEMP_C ||
|
||||
unit === util.temperatureUnits.UNIT_TEMP_F) {
|
||||
if (unit === temperatureUnits.UNIT_TEMP_C ||
|
||||
unit === temperatureUnits.UNIT_TEMP_F) {
|
||||
return 'mdi:thermometer';
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { authActions, localStoragePreferences } from '../util/home-assistant-js-instance';
|
||||
import hass from '../util/home-assistant-js-instance';
|
||||
|
||||
const { authActions, localStoragePreferences } = hass;
|
||||
|
||||
export default function(authToken, rememberAuth) {
|
||||
authActions.validate(authToken, {
|
||||
|
@ -1,5 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var webpack = require("webpack");
|
||||
|
||||
var definePlugin = new webpack.DefinePlugin({
|
||||
@ -8,22 +7,28 @@ var definePlugin = new webpack.DefinePlugin({
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
entry: "./src/home-assistant.js",
|
||||
entry: {
|
||||
_app_compiled: './src/home-assistant.js',
|
||||
service_worker: './src/service-worker/index.js',
|
||||
},
|
||||
output: {
|
||||
path: 'build',
|
||||
filename: "_app_compiled.js"
|
||||
path: 'build',
|
||||
filename: '[name].js',
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
loader: 'babel-loader',
|
||||
test: /.js$/,
|
||||
exclude: /node_modules\/(^home-assistant-js)/
|
||||
}
|
||||
]
|
||||
include: [
|
||||
path.resolve(__dirname, 'src'),
|
||||
path.resolve(__dirname, 'node_modules/home-assistant-js/src'),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
definePlugin,
|
||||
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /no-other-locales-for-now/)
|
||||
]
|
||||
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /no-other-locales-for-now/),
|
||||
],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user