diff --git a/src/panels/lovelace/cards/hui-column-card.js b/src/panels/lovelace/cards/hui-column-card.js index 6bda7f8f8d..499d4ada17 100644 --- a/src/panels/lovelace/cards/hui-column-card.js +++ b/src/panels/lovelace/cards/hui-column-card.js @@ -12,7 +12,7 @@ class HuiColumnCard extends PolymerElement { #root { display: flex; flex-direction: column; - margin-top: -4px + margin-top: -4px; margin-bottom: -8px; } #root > * { diff --git a/src/panels/lovelace/cards/hui-entity-picture-card.js b/src/panels/lovelace/cards/hui-entity-picture-card.js deleted file mode 100644 index 3fc2854e3e..0000000000 --- a/src/panels/lovelace/cards/hui-entity-picture-card.js +++ /dev/null @@ -1,144 +0,0 @@ -import { html } from '@polymer/polymer/lib/utils/html-tag.js'; -import { PolymerElement } from '@polymer/polymer/polymer-element.js'; - -import '../../../components/ha-card.js'; - -import { STATES_ON } from '../../../common/const.js'; -import computeDomain from '../../../common/entity/compute_domain.js'; -import computeStateDisplay from '../../../common/entity/compute_state_display.js'; -import computeStateName from '../../../common/entity/compute_state_name.js'; - -import LocalizeMixin from '../../../mixins/localize-mixin.js'; - -const DOMAINS_NO_STATE = ['scene', 'script', 'weblink']; - -/* - * @appliesMixin LocalizeMixin - */ -class HuiPictureCard extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - - - - - - [[_computeTitle(config.entity, hass.states)]] - [[_computeState(config.entity, hass.states)]] - - - [[_error]] - - - `; - } - - static get properties() { - return { - hass: Object, - config: { - type: Object, - observer: '_configChanged' - }, - _error: String - }; - } - - getCardSize() { - return 3; - } - - _configChanged(config) { - if (config && config.entity && config.image) { - this._error = null; - } else { - this._error = 'Error in card configuration.'; - } - } - - _computeClass(entityId, states) { - return DOMAINS_NO_STATE.includes(computeDomain(entityId)) || - STATES_ON.includes(states[entityId].state) ? '' : 'state-off'; - } - - _computeTitle(entityId, states) { - return entityId && entityId in states && computeStateName(states[entityId]); - } - - _computeState(entityId, states) { - const domain = computeDomain(entityId); - switch (domain) { - case 'scene': - return this.localize('ui.card.scene.activate'); - case 'script': - return this.localize('ui.card.script.execute'); - case 'weblink': - return 'Open'; - default: - return computeStateDisplay(this.localize, states[entityId]); - } - } - - _cardClicked() { - const entityId = this.config.entity; - const domain = computeDomain(entityId); - if (domain === 'weblink') { - window.open(this.hass.states[entityId].state); - } else { - const turnOn = !STATES_ON.includes(this.hass.states[entityId].state); - let service; - switch (domain) { - case 'lock': - service = turnOn ? 'unlock' : 'lock'; - break; - case 'cover': - service = turnOn ? 'open_cover' : 'close_cover'; - break; - default: - service = turnOn ? 'turn_on' : 'turn_off'; - } - this.hass.callService(domain, service, { entity_id: entityId }); - } - } -} - -customElements.define('hui-entity-picture-card', HuiPictureCard); diff --git a/src/panels/lovelace/cards/hui-history-graph-card.js b/src/panels/lovelace/cards/hui-history-graph-card.js index a9e9678b00..3ec600370b 100644 --- a/src/panels/lovelace/cards/hui-history-graph-card.js +++ b/src/panels/lovelace/cards/hui-history-graph-card.js @@ -2,6 +2,7 @@ import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import './hui-error-card.js'; +import '../../../components/ha-card.js'; import '../../../components/state-history-charts.js'; import '../../../data/ha-state-history-data.js'; diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.js b/src/panels/lovelace/cards/hui-picture-entity-card.js new file mode 100644 index 0000000000..f78bd6c06b --- /dev/null +++ b/src/panels/lovelace/cards/hui-picture-entity-card.js @@ -0,0 +1,165 @@ +import { html } from '@polymer/polymer/lib/utils/html-tag.js'; +import { PolymerElement } from '@polymer/polymer/polymer-element.js'; + +import './hui-error-card.js'; +import '../../../components/ha-card.js'; + +import { STATES_OFF } from '../../../common/const.js'; +import computeDomain from '../../../common/entity/compute_domain.js'; +import computeStateDisplay from '../../../common/entity/compute_state_display.js'; +import computeStateDomain from '../../../common/entity/compute_state_domain.js'; +import computeStateName from '../../../common/entity/compute_state_name.js'; +import createErrorCardConfig from '../common/create-error-card-config.js'; + +import LocalizeMixin from '../../../mixins/localize-mixin.js'; + +const OFFLINE = 'Offline'; + +/* + * @appliesMixin LocalizeMixin + */ +class HuiPictureEntityCard extends LocalizeMixin(PolymerElement) { + static get template() { + return html` + + + + + + + + + + + + + `; + } + + static get properties() { + return { + hass: { + type: Object, + observer: '_hassChanged' + }, + config: { + type: Object, + observer: '_configChanged' + }, + _error: Object + }; + } + + getCardSize() { + return 3; + } + + _configChanged(config) { + if (!config || !config.entity || (!config.image && !config.state_image)) { + const error = 'Error in card configuration.'; + this._error = createErrorCardConfig(error, config); + return; + } + this._error = null; + } + + _hassChanged(hass) { + const config = this.config; + const entityId = config && config.entity; + if (!entityId) { + return; + } + if (!(entityId in hass.states) && this._oldState === OFFLINE) { + return; + } + if (!(entityId in hass.states) || hass.states[entityId].state !== this._oldState) { + this._updateState(hass, entityId, config); + } + } + + _updateState(hass, entityId, config) { + const state = entityId in hass.states ? hass.states[entityId].state : OFFLINE; + const stateImg = config.state_image && + (config.state_image[state] || config.state_image.default); + + this.$.image.src = stateImg || config.image; + this.$.image.style.filter = stateImg || (!STATES_OFF.includes(state) && state !== OFFLINE) ? + '' : 'grayscale(100%)'; + this.$.title.innerText = config.title || (state === OFFLINE ? + entityId : computeStateName(hass.states[entityId])); + this.$.state.innerText = state === OFFLINE ? + OFFLINE : this._computeState(hass.states[entityId]); + this._oldState = state; + } + + _computeState(stateObj) { + const domain = computeStateDomain(stateObj); + switch (domain) { + case 'scene': + return this.localize('ui.card.scene.activate'); + case 'script': + return this.localize('ui.card.script.execute'); + case 'weblink': + return 'Open'; + default: + return computeStateDisplay(this.localize, stateObj); + } + } + + _cardClicked() { + const entityId = this.config && this.config.entity; + if (!(entityId in this.hass.states)) { + return; + } + + const stateDomain = computeDomain(entityId); + if (stateDomain === 'weblink') { + window.open(this.hass.states[entityId].state); + } else { + const turnOn = STATES_OFF.includes(this.hass.states[entityId].state); + let service; + switch (stateDomain) { + case 'lock': + service = turnOn ? 'unlock' : 'lock'; + break; + case 'cover': + service = turnOn ? 'open_cover' : 'close_cover'; + break; + default: + service = turnOn ? 'turn_on' : 'turn_off'; + } + const serviceDomain = stateDomain === 'group' ? 'homeassistant' : stateDomain; + this.hass.callService(serviceDomain, service, { entity_id: entityId }); + } + } +} + +customElements.define('hui-picture-entity-card', HuiPictureEntityCard); diff --git a/src/panels/lovelace/common/create-card-element.js b/src/panels/lovelace/common/create-card-element.js index d307416d39..6e18620336 100644 --- a/src/panels/lovelace/common/create-card-element.js +++ b/src/panels/lovelace/common/create-card-element.js @@ -10,8 +10,8 @@ import '../cards/hui-history-graph-card.js'; import '../cards/hui-iframe-card.js'; import '../cards/hui-markdown-card.js'; import '../cards/hui-media-control-card.js'; -import '../cards/hui-entity-picture-card.js'; import '../cards/hui-picture-elements-card'; +import '../cards/hui-picture-entity-card'; import '../cards/hui-picture-glance-card'; import '../cards/hui-plant-status-card.js'; import '../cards/hui-row-card.js'; @@ -24,7 +24,6 @@ const CARD_TYPES = [ 'column', 'entities', 'entity-filter', - 'entity-picture', 'error', 'glance', 'history-graph', @@ -32,6 +31,7 @@ const CARD_TYPES = [ 'markdown', 'media-control', 'picture-elements', + 'picture-entity', 'picture-glance', 'plant-status', 'row',