Actualización módulos de hacs

This commit is contained in:
dfcarvajal
2019-12-09 12:40:02 +00:00
parent a2367aadfe
commit a5fb833ab1
36 changed files with 2532 additions and 2654 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const path = require('path')
module.exports = {
entry: './src/main.js',
mode: 'production',
output: {
filename: 'auto-entities.js',
path: path.resolve(__dirname)
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const path = require('path');
module.exports = {
entry: './src/main.js',
mode: 'production',
output: {
filename: 'card-tools.js',
path: path.resolve(__dirname)
}
};

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const path = require('path');
module.exports = {
entry: './src/main.js',
mode: 'production',
output: {
filename: 'fold-entity-row.js',
path: path.resolve(__dirname)
}
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const path = require('path');
module.exports = {
entry: './src/main.js',
mode: 'production',
output: {
filename: 'layout-card.js',
path: path.resolve(__dirname)
}
};

View File

@@ -17,6 +17,7 @@ class MultipleEntityRow extends Polymer.Element {
}
.info {
flex: 1 0 60px;
cursor: pointer;
}
.info, .info > * {
white-space: nowrap;
@@ -36,10 +37,12 @@ class MultipleEntityRow extends Polymer.Element {
}
state-badge {
flex: 0 0 40px;
cursor: pointer;
}
.entity {
margin-right: 16px;
text-align: center;
cursor: pointer;
}
.entity span {
font-size: 10px;
@@ -50,58 +53,93 @@ class MultipleEntityRow extends Polymer.Element {
}
.state {
min-width: 45px;
text-align: end;
}
.toggle {
margin-left: 8px;
}
</style>
<state-badge state-obj="[[_config.stateObj]]" override-icon="[[_config.icon]]"></state-badge>
<div class="flex">
<state-badge state-obj="[[main.stateObj]]" override-icon="[[main.icon]]" on-click="defaultMoreInfo"></state-badge>
<div class="flex" on-click="defaultMoreInfo">
<div class="info">
[[entityName(_config)]]
[[entityName(main)]]
<div class="secondary">
<template is="dom-if" if="{{displayInfo}}">
<template is="dom-if" if="{{info}}">
[[entityName(info)]] [[entityState(info)]]
</template>
<template is="dom-if" if="{{displayLastChanged}}">
<ha-relative-time datetime="[[_config.stateObj.last_changed]]" hass="[[_hass]]"></ha-relative-time>
<template is="dom-if" if="{{showLastChanged}}">
<ha-relative-time datetime="[[main.stateObj.last_changed]]" hass="[[_hass]]"></ha-relative-time>
</template>
</div>
</div>
<template is="dom-if" if="{{displayPrimary}}">
<div class="entity" on-click="primaryMoreInfo">
<span>[[entityName(primary)]]</span>
<div>[[entityState(primary)]]</div>
<template is="dom-if" if="{{primary}}">
<div class="entity" on-click="primaryMoreInfo">
<span>[[entityName(primary)]]</span>
<div>
<template is="dom-if" if="{{primary.showToggle}}">
<ha-entity-toggle state-obj="[[primary.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</template>
<template is="dom-if" if="{{!primary.showToggle}}">[[entityState(primary)]]</template>
</div>
</template>
<template is="dom-if" if="{{displaySecondary}}">
<div class="entity" on-click="secondaryMoreInfo">
<span>[[entityName(secondary)]]</span>
<div>[[entityState(secondary)]]</div>
</div>
</template>
<template is="dom-if" if="{{displayValue}}">
<div class="state">
[[entityState(_config)]]
</div>
</template>
<template is="dom-if" if="{{displayToggle}}">
<div class="toggle">
<ha-entity-toggle state-obj="[[_config.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
<template is="dom-if" if="{{secondary}}">
<div class="entity" on-click="secondaryMoreInfo">
<span>[[entityName(secondary)]]</span>
<div>
<template is="dom-if" if="{{secondary.showToggle}}">
<ha-entity-toggle state-obj="[[secondary.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</template>
<template is="dom-if" if="{{!secondary.showToggle}}">[[entityState(secondary)]]</template>
</div>
</div>
</template>
<template is="dom-if" if="{{tertiary}}">
<div class="entity" on-click="tertiaryMoreInfo">
<span>[[entityName(tertiary)]]</span>
<div>
<template is="dom-if" if="{{tertiary.showToggle}}">
<ha-entity-toggle state-obj="[[tertiary.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</template>
<template is="dom-if" if="{{!tertiary.showToggle}}">[[entityState(tertiary)]]</template>
</div>
</div>
</template>
<template is="dom-if" if="{{!main.hide_state}}">
<div class="state entity">
<template is="dom-if" if="{{showMainHeader}}">
<span>[[_config.name_state]]</span>
</template>
<template is="dom-if" if="{{main.showToggle}}">
<div class="toggle">
<ha-entity-toggle state-obj="[[main.stateObj]]" hass="[[_hass]]"></ha-entity-toggle>
</div>
</template>
<template is="dom-if" if="{{!main.showToggle}}">
<div>[[entityState(main)]]</div>
</template>
</div>
</template>
</div>`;
}
defaultMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.main.entity);
}
primaryMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this._config.primary.entity)
this.fireEvent(this.primary.entity);
}
secondaryMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this._config.secondary.entity)
this.fireEvent(this.secondary.entity);
}
tertiaryMoreInfo(e) {
e.stopPropagation();
this.fireEvent(this.tertiary.entity);
}
entityName(data) {
@@ -111,7 +149,7 @@ class MultipleEntityRow extends Polymer.Element {
entityState(data) {
if (!data || !data.stateObj) return this._hass.localize('state.default.unavailable');
return data.attribute
? data.stateObj.attributes[data.attribute]
? (data.attribute in data.stateObj.attributes)
? `${data.stateObj.attributes[data.attribute]} ${data.unit ? data.unit : ''}`
: this._hass.localize('state.default.unavailable')
: this.computeStateValue(data.stateObj, data.unit);
@@ -134,8 +172,8 @@ class MultipleEntityRow extends Polymer.Element {
if (!display) {
display = this._hass.localize(`state.${domain}.default.${stateObj.state}`);
}
} else if ((unit || stateObj.attributes.unit_of_measurement) && !["unknown", "unavailable"].includes(stateObj.state)) {
display = `${stateObj.state} ${stateObj.attributes.unit_of_measurement}`;
} else if (unit !== false && (unit || stateObj.attributes.unit_of_measurement) && !["unknown", "unavailable"].includes(stateObj.state)) {
display = `${stateObj.state} ${unit || stateObj.attributes.unit_of_measurement}`;
} else if (domain === "zwave") {
display = ["initializing", "dead"].includes(stateObj.state)
? this._hass.localize(`state.zwave.query_stage.${stateObj.state}`, 'query_stage', stateObj.attributes.query_stage)
@@ -154,14 +192,13 @@ class MultipleEntityRow extends Polymer.Element {
if (!config.entity) throw new Error('Please define an entity.');
if (config.primary && !config.primary.entity) throw new Error('Please define a primary entity.');
if (config.secondary && !config.secondary.entity) throw new Error('Please define a secondary entity.');
if (config.tertiary && !config.tertiary.entity) throw new Error('Please define a tertiary entity.');
if (config.info && !config.info.entity) throw new Error('Please define an info entity.');
this.showMainHeader = config.name_state;
this.showLastChanged = config.secondary_info === 'last-changed' && !config.info;
this._config = config;
this.displayToggle = config.toggle === true;
this.displayValue = !this.displayToggle && !config.hide_state;
this.displayPrimary = config.primary && config.primary.entity;
this.displaySecondary = config.secondary && config.secondary.entity;
this.displayInfo = config.info && config.info.entity;
this.displayLastChanged = !this.displayInfo && config.secondary_info === 'last-changed';
}
set hass(hass) {
@@ -170,24 +207,27 @@ class MultipleEntityRow extends Polymer.Element {
if (hass && this._config) {
const stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
if (stateObj) {
this._config.stateObj = stateObj;
this.primary = Object.assign({}, this._config.primary, {
stateObj: this.displayPrimary && this._config.primary.entity in hass.states ?
hass.states[this._config.primary.entity] : null
});
this.secondary = Object.assign({}, this._config.secondary, {
stateObj: this.displaySecondary && this._config.secondary.entity in hass.states ?
hass.states[this._config.secondary.entity] : null
});
this.info = Object.assign({}, this._config.info, {
stateObj: this.displayInfo && this._config.info.entity in hass.states ?
hass.states[this._config.info.entity] : null
});
this.main = this.initEntity(this._config);
this.primary = this.initEntity(this._config.primary);
this.secondary = this.initEntity(this._config.secondary);
this.tertiary = this.initEntity(this._config.tertiary);
this.info = this.initEntity(this._config.info);
}
}
}
initEntity(config) {
const stateObj = config && config.entity && this._hass.states[config.entity];
return stateObj ? Object.assign({}, config, {
stateObj: stateObj,
showToggle: this.validateToggle(config, stateObj),
}) : null;
}
validateToggle(config, stateObj) {
return config && config.toggle === true && stateObj && (stateObj.state === "on" || stateObj.state === "off");
}
fireEvent(entity, options = {}) {
const event = new Event('hass-more-info', {
bubbles: options.bubbles || true,

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const path = require('path');
module.exports = {
entry: './src/main.js',
mode: 'production',
output: {
filename: 'slider-entity-row.js',
path: path.resolve(__dirname)
}
};

View File

@@ -55,16 +55,16 @@ class XiaomiVacuumCard extends Polymer.Element {
</template>
<div class="content grid" style="[[contentStyle]]" on-click="moreInfo">
<div class="grid-content grid-left">
<div>[[_config.labels.status]]: [[stateObj.attributes.status]]</div>
<div>[[_config.labels.battery]]: [[stateObj.attributes.battery_level]] %</div>
<div>[[_config.labels.mode]]: [[stateObj.attributes.fan_speed]]</div>
<div>[[getValue('status')]]</div>
<div>[[getValue('battery', ' %')]]</div>
<div>[[getValue('mode')]]</div>
</div>
<template is="dom-if" if="{{showDetails}}">
<div class="grid-content grid-right" >
<div>[[_config.labels.main_brush]]: [[stateObj.attributes.main_brush_left]] [[_config.labels.hours]]</div>
<div>[[_config.labels.side_brush]]: [[stateObj.attributes.side_brush_left]] [[_config.labels.hours]]</div>
<div>[[_config.labels.filter]]: [[stateObj.attributes.filter_left]] [[_config.labels.hours]]</div>
<div>[[_config.labels.sensor]]: [[stateObj.attributes.sensor_dirty_left]] [[_config.labels.hours]]</div>
<div>[[computeValue('main_brush')]]</div>
<div>[[computeValue('side_brush')]]</div>
<div>[[computeValue('filter')]]</div>
<div>[[computeValue('sensor')]]</div>
</div>
</template>
</div>
@@ -165,11 +165,32 @@ class XiaomiVacuumCard extends Polymer.Element {
return: true,
};
const attributes = {
status: 'status',
battery: 'battery_level',
mode: 'fan_speed',
main_brush: 'main_brush_left',
side_brush: 'side_brush_left',
filter: 'filter_left',
sensor: 'sensor_dirty_left',
};
const vendors = {
xiaomi: {
image: '/local/img/vacuum.png',
details: true,
},
valetudo: {
image: '/local/img/vacuum.png',
details: true,
attributes: {
status: 'state',
main_brush: 'mainBrush',
side_brush: 'sideBrush',
filter: 'filter',
sensor: 'sensor',
},
},
ecovacs: {
image: '/local/img/vacuum_ecovacs.png',
details: false,
@@ -182,6 +203,21 @@ class XiaomiVacuumCard extends Polymer.Element {
pause: 'stop',
stop: 'turn_off',
},
},
deebot: {
image: '/local/img/vacuum_ecovacs.png',
details: true,
service: {
start: 'turn_on',
pause: 'stop',
stop: 'turn_off',
},
attributes: {
main_brush: 'component_main_brush',
side_brush: 'component_side_brush',
filter: 'component_filter',
},
computeValue: v => Math.round(Number(v) / 100),
}
};
@@ -196,8 +232,25 @@ class XiaomiVacuumCard extends Polymer.Element {
config.service = Object.assign({}, services, vendor.service);
config.buttons = Object.assign({}, buttons, vendor.buttons, config.buttons);
config.attributes = Object.assign({}, attributes, vendor.attributes, config.attributes);
config.labels = Object.assign({}, labels, config.labels);
this.getValue = (field, unit = '') => {
const value = (this.stateObj && config.attributes[field] in this.stateObj.attributes)
? this.stateObj.attributes[config.attributes[field]] + unit
: (this._hass ? this._hass.localize('state.default.unavailable') : 'Unavailable');
return `${config.labels[field]}: ${value}`;
};
this.computeValue = field => {
if (this.stateObj && config.attributes[field] in this.stateObj.attributes) {
const value = this.stateObj.attributes[config.attributes[field]];
return `${config.labels[field]}: ${vendor.computeValue ? vendor.computeValue(value) : value} ${config.labels.hours}`;
} else {
return `${config.labels[field]}: - `;
}
};
this.contentText = `color: ${config.image !== false ? 'white; text-shadow: 0 0 10px black;' : 'var(--primary-text-color)'}`;
this.contentStyle = `padding: ${this.showButtons ? '16px 16px 4px' : '16px'}; ${this.contentText}`;
this.backgroundImage = config.image !== false ? `background-image: url('${config.image || vendor.image}')` : '';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,122 +0,0 @@
class MonsterCard extends HTMLElement {
_getEntities(hass, filters) {
function _filterEntityId(stateObj, pattern) {
if (pattern.indexOf('*') === -1) {
return stateObj.entity_id === pattern;
}
const regEx = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`, 'i');
return stateObj.entity_id.search(regEx) === 0;
}
function _filterName(stateObj, pattern) {
let compareEntity = stateObj.attributes.title ? stateObj.attributes.title : stateObj.attributes.friendly_name;
if (!compareEntity) compareEntity = stateObj.entity_id;
if (pattern.indexOf('*') === -1) {
return compareEntity === pattern;
}
const regEx = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`, 'i');
return compareEntity.search(regEx) === 0;
}
// Allows '< 300' in b
function _complexCompare(a, b) {
const _compare = {
'>': (x, y) => x > y,
'<': (x, y) => x < y,
'<=': (x, y) => x <= y,
'>=': (x, y) => x >= y,
'=': (x, y) => x === y,
};
let operator = '=';
let y = b;
let x = a;
if (!isNaN(a) && typeof (b) == 'string'
&& b.split(" ").length > 1) {
[operator, y] = b.split(' ', 2);
x = parseFloat(a);
}
return _compare[operator](x, y);
}
const entities = new Map();
filters.forEach((filter) => {
const filters = [];
if (filter.domain) {
filters.push(stateObj => stateObj.entity_id.split('.', 1)[0] === filter.domain);
}
if (filter.attributes) {
Object.keys(filter.attributes).forEach(key => {
filters.push(stateObj => _complexCompare(stateObj.attributes[key], filter.attributes[key]));
});
}
if (filter.entity_id) {
filters.push(stateObj => _filterEntityId(stateObj, filter.entity_id));
}
if (filter.name) {
filters.push(stateObj => _filterName(stateObj, filter.name));
}
if (filter.state) {
filters.push(stateObj => _complexCompare(stateObj.state, filter.state));
}
const options = filter.options ? filter.options : {}
Object.keys(hass.states).sort().forEach(key => {
if (filters.every(filterFunc => filterFunc(hass.states[key]))) {
entities.set(hass.states[key].entity_id, Object.assign({ "entity": hass.states[key].entity_id }, options));
}
});
});
return Array.from(entities.values());
}
setConfig(config) {
if (!config.filter.include || !Array.isArray(config.filter.include)) {
throw new Error('Please define filters');
}
if (this.lastChild) this.removeChild(this.lastChild);
const cardConfig = Object.assign({}, config);
if (!cardConfig.card) cardConfig.card = {};
if (config.card.entities) delete config.card.entities;
if (!cardConfig.card.type) cardConfig.card.type = 'entities';
const element = document.createElement(`hui-${cardConfig.card.type}-card`);
this.appendChild(element);
this._config = cardConfig;
}
set hass(hass) {
const config = this._config;
let entities = this._getEntities(hass, config.filter.include);
if (config.filter.exclude) {
const excludeEntities = this._getEntities(hass, config.filter.exclude).map(entity => entity.entity);
entities = entities.filter(entity => !excludeEntities.includes(entity.entity));
}
if (entities.length === 0 && config.show_empty === false) {
this.style.display = 'none';
} else {
if (config.when && (hass.states[config.when.entity].state == config.when.state) || !config.when) {
this.style.display = 'block';
} else {
this.style.display = 'none';
}
}
if (!config.card.entities || config.card.entities.length !== entities.length ||
!config.card.entities.every((value, index) => value.entity === entities[index].entity)) {
config.card.entities = entities;
this.lastChild.setConfig(config.card);
}
this.lastChild.hass = hass;
}
getCardSize() {
return 'getCardSize' in this.lastChild ? this.lastChild.getCardSize() : 1;
}
}
customElements.define('monster-card', MonsterCard);

View File

@@ -10,24 +10,16 @@ class VerticalStackInCard extends HTMLElement {
throw new Error('Card config incorrect');
}
this.style.boxShadow = "var(--ha-card-box-shadow, 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2))";
this.style.borderRadius = "var(--ha-card-border-radius, 2px)";
this.style.background = "var(--paper-card-background-color)";
this.style.display = "block";
const root = this.shadowRoot;
while (root.hasChildNodes()) {
root.removeChild(root.lastChild);
const shadow = this.shadowRoot;
while (shadow.hasChildNodes()) {
shadow.removeChild(shadow.lastChild);
}
const card = document.createElement("ha-card");
const cardContent = document.createElement("div");
card.header = config.title;
this._refCards = [];
if (config.title) {
const title = document.createElement("div");
title.className = "header";
title.style = "font-family: var(--paper-font-headline_-_font-family); -webkit-font-smoothing: var(--paper-font-headline_-_-webkit-font-smoothing); font-size: var(--paper-font-headline_-_font-size); font-weight: var(--paper-font-headline_-_font-weight); letter-spacing: var(--paper-font-headline_-_letter-spacing); line-height: var(--paper-font-headline_-_line-height);text-rendering: var(--paper-font-common-expensive-kerning_-_text-rendering);opacity: var(--dark-primary-opacity);padding: 24px 16px 0px 16px";
title.innerHTML = '<div class="name">' + config.title + '</div>';
root.appendChild(title);
}
const _createThing = (tag, config) => {
const element = document.createElement(tag);
@@ -84,7 +76,7 @@ class VerticalStackInCard extends HTMLElement {
if (customElements.get(tag)) {
const element = _createThing(tag, item);
root.appendChild(element);
cardContent.appendChild(element);
this._refCards.push(element);
} else {
// If element doesn't exist (yet) create an error
@@ -104,10 +96,12 @@ class VerticalStackInCard extends HTMLElement {
_fireEvent("ll-rebuild", {}, element);
});
root.appendChild(element);
cardContent.appendChild(element);
this._refCards.push(element);
}
});
card.appendChild(cardContent);
shadow.appendChild(card);
}
set hass(hass) {
@@ -148,11 +142,17 @@ class VerticalStackInCard extends HTMLElement {
this._card(searchEles[i]);
}
} else {
element.shadowRoot.querySelector('ha-card').style.boxShadow = 'none';
let ele = element.shadowRoot.querySelector('ha-card')
ele.style.boxShadow = 'none';
ele.style.background = 'transparent';
ele.style.borderRadius = '0';
}
} else {
if (typeof element.querySelector === 'function' && element.querySelector('ha-card')) {
element.querySelector('ha-card').style.boxShadow = 'none';
let ele = element.querySelector('ha-card')
ele.style.boxShadow = 'none';
ele.style.background = 'transparent';
ele.style.borderRadius = '0';
}
let searchEles = element.childNodes;
for (let i = 0; i < searchEles.length; i++) {