diff --git a/README.md b/README.md index 25b6765..2212e98 100644 --- a/README.md +++ b/README.md @@ -39,49 +39,49 @@ resources: ## Options -| Name | Type | Requirement | Description | -| --------- | ------ | ------------ | ----------------------------------------------------------------------------------------------------- | -| type | string | **Required** | `custom:config-template-card` | -| entities | list | **Required** | List of entity strings that should be watched for updates. Templates can be used here | -| variables | list | **Optional** | List of variables, which can be templates, that can be used in your `config` and indexed using `vars` | -| card | object | **Optional** | Card configuration. (A card, row, or element configuaration must be provided) | -| row | object | **Optional** | Row configuration. (A card, row, or element configuaration must be provided) | -| element | object | **Optional** | Element configuration. (A card, row, or element configuaration must be provided) | -| card | object | **Optional** | Style configuration. (Required if you use an element) | +| Name | Type | Requirement | Description | +| --------- | ------ | ------------ | ---------------------------------------------------------------------------------------------------------------- | +| type | string | **Required** | `custom:config-template-card` | +| entities | list | **Required** | List of entity strings that should be watched for updates. Templates can be used here | +| variables | list | **Optional** | List of variables, which can be templates, that can be used in your `config` and indexed using `vars` or by name | +| card | object | **Optional** | Card configuration. (A card, row, or element configuaration must be provided) | +| row | object | **Optional** | Row configuration. (A card, row, or element configuaration must be provided) | +| element | object | **Optional** | Element configuration. (A card, row, or element configuaration must be provided) | +| card | object | **Optional** | Style configuration. (Required if you use an element) | ### Available variables for templating -| Variable | Description | -| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `this.hass` | The [hass](https://developers.home-assistant.io/docs/en/frontend_data.html) object | -| `states` | The [states](https://developers.home-assistant.io/docs/en/frontend_data.html#hassstates) object | -| `user` | The [user](https://developers.home-assistant.io/docs/en/frontend_data.html#hassuser) object | -| `vars` | Defined by `variables` configuration and accessible in your templates starting at the 0th index as your firstly defined variable to help clean up your templates | +| Variable | Description | +| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `this.hass` | The [hass](https://developers.home-assistant.io/docs/frontend/data/) object | +| `states` | The [states](https://developers.home-assistant.io/docs/frontend/data/#hassstates) object | +| `user` | The [user](https://developers.home-assistant.io/docs/frontend/data/#hassuser) object | +| `vars` | Defined by `variables` configuration and accessible in your templates to help clean them up. If `variables` in the configuration is a yaml list, then `vars` is an array starting at the 0th index as your firstly defined variable. If `variables` is an object in the configuration, then `vars` is a string-indexed map and you can also access the variables by name without using `vars` at all. | ```yaml type: 'custom:config-template-card' variables: - - states['light.bed_light'].state - - states['cover.garage_door'].state + LIGHT_STATE: states['light.bed_light'].state + GARAGE_STATE: states['cover.garage_door'].state entities: - light.bed_light - cover.garage_door - alarm_control_panel.alarm - climate.ecobee card: - type: "${vars[0] === 'on' ? 'glance' : 'entities'}" + type: "${LIGHT_STATE === 'on' ? 'glance' : 'entities'}" entities: - entity: alarm_control_panel.alarm - name: "${vars[1] === 'open' && states['alarm_control_panel.alarm'].state === 'armed_home' ? 'Close the garage!' : ''}" + name: "${GARAGE_STATE === 'open' && states['alarm_control_panel.alarm'].state === 'armed_home' ? 'Close the garage!' : ''}" - entity: binary_sensor.basement_floor_wet - entity: climate.ecobee name: "${states['climate.ecobee'].attributes.current_temperature > 22 ? 'Cozy' : 'Too Hot/Cold'}" - entity: cover.garage_door - - entity: "${vars[0] === 'on' ? 'light.bed_light' : 'climate.ecobee'}" - icon: "${vars[1] === 'open' ? 'mdi:hotel' : '' }" + - entity: "${LIGHT_STATE === 'on' ? 'light.bed_light' : 'climate.ecobee'}" + icon: "${GARAGE_STATE === 'open' ? 'mdi:hotel' : '' }" ``` -Templated entities example +## Templated entities example ```yaml type: 'custom:config-template-card' @@ -118,7 +118,7 @@ elements: Entities card example -```yaml +````yaml type: entities entities: - type: 'custom:config-template-card' @@ -132,6 +132,33 @@ entities: - entity: light.bed_light ``` +## Defining global functions in variables + +If you find yourself having to rewrite the same logic in multiple locations, you can define global methods inside Config Template Card's variables, which can be called anywhere within the scope of the card: + +```yaml +type: 'custom:config-template-card' + variables: + setTempMessage: | + temp => { + if (temp <= 19) { + return 'Quick, get a blanket!'; + } + else if (temp >= 20 && temp <= 22) { + return 'Cozy!'; + } + return 'It's getting hot in here...'; + } + currentTemp: states['climate.ecobee'].attributes.current_temperature + entities: + - climate.ecobee + card: + type: entities + entities: + - entity: climate.ecobee + name: '${ setTempMessage(currentTemp) }' +```` + ### Note: All templates must be enclosed by `${}` [Troubleshooting](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins) diff --git a/package.json b/package.json index d4c8459..9b91590 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "custom-card-helpers": "^1.6.6", "deep-clone-simple": "^1.1.1", "home-assistant-js-websocket": "^4.4.0", - "lit-element": "^2.2.1", - "lit-html": "^1.1.2" + "lit-element": "^2.4.0", + "lit-html": "^1.3.0" }, "devDependencies": { "@babel/core": "^7.6.4", @@ -47,4 +47,4 @@ "lint": "eslint src/*.ts", "rollup": "rollup -c" } -} \ No newline at end of file +} diff --git a/src/config-template-card.ts b/src/config-template-card.ts index c126ad3..7e462e5 100644 --- a/src/config-template-card.ts +++ b/src/config-template-card.ts @@ -1,7 +1,14 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { LitElement, html, customElement, property, TemplateResult, PropertyValues } from 'lit-element'; +import { + LitElement, + html, + customElement, + property, + TemplateResult, + PropertyValues, + internalProperty, +} from 'lit-element'; import deepClone from 'deep-clone-simple'; -import { HomeAssistant, LovelaceElementConfigBase } from 'custom-card-helpers'; +import { HomeAssistant } from 'custom-card-helpers'; import { ConfigTemplateConfig } from './types'; import { CARD_VERSION } from './const'; @@ -15,9 +22,9 @@ console.info( @customElement('config-template-card') export class ConfigTemplateCard extends LitElement { - @property() public hass?: HomeAssistant; - @property() private _config?: ConfigTemplateConfig; - @property() private _helpers?: any; + @property({ attribute: false }) public hass?: HomeAssistant; + @internalProperty() private _config?: ConfigTemplateConfig; + @internalProperty() private _helpers?: any; private _initialized = false; public setConfig(config: ConfigTemplateConfig): void { @@ -161,15 +168,29 @@ export class ConfigTemplateCard extends LitElement { /* eslint-disable @typescript-eslint/no-unused-vars */ const user = this.hass ? this.hass.user : undefined; const states = this.hass ? this.hass.states : undefined; - const vars: any[] = []; + let vars: any[] | { [key: string]: any }; + let varDef = ''; if (this._config) { - for (const v in this._config.variables) { - const newV = eval(this._config.variables[v]); - vars.push(newV); + if (Array.isArray(this._config.variables)) { + // if variables are an array, create vars as an array + vars = []; + for (const v in this._config.variables) { + const newV = eval(this._config.variables[v]); + vars.push(newV); + } + } else { + // if it is an object, then create a key-value map containing + // the values + vars = {}; + for (const varName in this._config.variables) { + const newV = eval(this._config.variables[varName]); + vars[varName] = newV; + // create variable definitions to be injected: + varDef = varDef + `var ${varName} = vars['${varName}'];\n`; + } } } - - return eval(template.substring(2, template.length - 1)); + return eval(varDef + template.substring(2, template.length - 1)); } } diff --git a/src/types.ts b/src/types.ts index 0324806..6db6414 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,7 +3,7 @@ import { LovelaceCardConfig, EntitiesCardEntityConfig, LovelaceElementConfigBase export interface ConfigTemplateConfig { type: string; entities: string[]; - variables?: string[]; + variables?: string[] | { [key: string]: string }; card?: LovelaceCardConfig; row?: EntitiesCardEntityConfig; element?: LovelaceElementConfigBase;