Add template support

This commit is contained in:
Thomas Lovén 2020-01-09 22:03:50 +01:00
parent f4d1b54579
commit 906869a37c
3 changed files with 79 additions and 13 deletions

View File

@ -25,6 +25,7 @@ entities:
- <entity>
- <entity>
filter:
template: <template>
include:
- <filter>
- <filter>
@ -42,14 +43,15 @@ sort: <sort_method>
- `card:` **Required.** The card to display. Specify this as you would specify any normal lovelace card, but ommit the `entities:` parameter.
- `entities:` Any entities added here will be added to the card before any filters are applied.
- `filter:`
- `include:` **Required.** A list of filters specifying which entities to add to the card
- `template:` A jinja2 template evaluating to a whitespace- or comma-separated list of entity ids to include
- `include:` A list of filters specifying which entities to add to the card
- `exclude:` A list of filters specifying which entities to remove from the card
- `show_empty:` Whether to display the card if it has no entities. Default: `true`.
- `unique:` Whether to remove duplicate values after filtering and sorting. Default: `false`.
- `sort:` How to sort the entities of the card. Default: `none`. See [Sorting entities for details](#sorting-entities)
### Filters
The two filter sections `include` and `exclude` each takes a list of filters.
The two main filter sections `include` and `exclude` each takes a list of filters.
Filters have the following options, and will match any entity fulfilling **ALL** options:
@ -70,11 +72,17 @@ Special options:
- `not:` Specifies a filter that entities must *not* match.
- `sort:` Specifies a method to sort entities matched by *this filter only*.
### Template filter
The filter section `template` takes a jinja2 template which evaluates to a list of comma- or whitespace separated `entity_id`s which are included.
> Note: Due to how the templating engine of Home Assistant works, this may or may not be as useful as it sounds. See note at templating example below.
## How it works
`auto-entities` creates a list of entities by:
1. Including every entitiy given in `entities:` (this allow nesting of `auto-entities`if you'd want to do that for some reason...)
2. Include all entities that matches **ALL** options of **ANY** filter in the `filter.include` section. The same entity may be included several times by different filters.
3. Remove all entities that matches **ALL** options on **ANY** filter in the `filter.exclude` section.
2. Include every entity listed in a `filter.template` evaluation
3. Include all entities that matches **ALL** options of **ANY** filter in the `filter.include` section. The same entity may be included several times by different filters.
4. Remove all entities that matches **ALL** options on **ANY** filter in the `filter.exclude` section.
It then creates a card based on the configuration given in `card:`, and fills in `entities:` of that card with the entities from above.
@ -296,5 +304,42 @@ filter:
entity_id: this.entity_id
```
Example using templates:
```yaml
type: custom:auto-entities
card:
type: entities
filter:
template: |
{% for light in states.light %}
{% if light.state == "on" %}
{{ light.entity_id}},
{% endif %}
{% endfor %}
```
> Note: templates won't update automatically on state changes unless they contain the literal entity id of the entity whose state changes.
> I.e. the example above will not update when a light is turned on or off, unless the view is reloaded.
>
> This is a limitation of the Home Assistant template engine, and nothing I can do anything about. There are, however two mitigations you could make.
>
> One is to redefine the template, e.g.:
> ```yaml
> template: |
> {%if is_state('light.bed_light','on')%}light.bed_light{%endif%}
> {%if is_state('light.kitchen_lights','on')%}light.kitchen_lights{%endif%}
> {%if is_state('light.ceiling_lights','on')%}light.ceiling_lights{%endif%}
> ```
>
> The other option is to add a list of entities to monitor:
> ```yaml
> filter:
> template: |
> ...etc...
> entity_ids:
> - light.bed_light
> - light.kitchen_lights
> - light.ceiling_lights
> ```
---
<a href="https://www.buymeacoffee.com/uqD6KHCdJ" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/white_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,7 @@ import { getData } from "card-tools/src/devices";
import { fireEvent } from "card-tools/src/event";
import { createCard } from "card-tools/src/lovelace-element";
import { hass } from "card-tools/src/hass";
import {subscribeRenderTemplate} from "card-tools/src/templates";
class AutoEntities extends LitElement {
@ -28,6 +29,19 @@ class AutoEntities extends LitElement {
this._config = config;
this.hass = this.hass;
}
if(config.filter && config.filter.template) {
this.template = "";
if(String(config.filter.template).includes("{%") || String(config.filter.template).includes("{{")) {
subscribeRenderTemplate(null, (res) => {
this.template = res;
this._getEntities();
}, {
template: config.filter.template,
variables: {config},
entity_ids: config.filter.entity_ids,
});
}
}
// Reevaluate all filters once areas have been loaded
getData().then(() => this._getEntities());
@ -35,21 +49,28 @@ class AutoEntities extends LitElement {
_getEntities()
{
const format_entities = (e) => {
if(!e) return null;
if(typeof(e) === "string")
return {entity: e.trim()}
return e;
}
let entities = [];
// Start with any entities added by the `entities` parameter
if(this._config.entities)
entities = entities.concat(this._config.entities)
.map((e) => {
if(typeof(e) === "string")
return {entity: e};
return e;
});
entities = entities.concat(this._config.entities.map(format_entities));
if(!this.hass || !this._config.filter) return entities;
if(this.template) {
entities = entities.concat(this.template.split(/[\s,]+/).map(format_entities));
}
entities = entities.filter(Boolean);
if(this._config.filter.include) {
const all_entities = Object.keys(this.hass.states)
.map((e) => new Object({entity: e}));
const all_entities = Object.keys(this.hass.states).map(format_entities);
for(const f of this._config.filter.include) {
if(f.type !== undefined) {