-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve script and template sensor (#23)
* Completed plots will be recalculated to the lowest consumption in the list as base value (1) * Added README for script and sensor * Updated README for macro with some additional information * Created separate files with script and sensor to make it easier to import them in your configuration
- Loading branch information
Showing
5 changed files
with
232 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Why this package? | ||
|
||
The macro supports providing weight factors in case your device doesn't have a stable energy usage pattern. With this script and template sensor you can plot the weight factors needed for the macro. | ||
|
||
# How to install this | ||
|
||
You need both the script and the template sensor. The script sends events which are used to store the data in the sensor. You can put it in your configuration as a package, or place the script in your scripts.yaml, and the template sensor in your configuration.yaml. | ||
The [script.yaml](./script.yaml) can be placed in `script.yaml` directly, and [sensor.yaml](./sensor.yaml) in your `configuration.yaml`. In case you already have definded `template:` in `configuration.yaml` make sure to place it under that key, and remove the `template:` line from my code. | ||
|
||
# How to use it | ||
|
||
Start the script in either an automation, or manually from developer tools > services | ||
You need to provide some details as script variables: | ||
|variable|mandatory|type|default|example|description| | ||
|---|---|---|---|---|---| | ||
|description|no|string|`"unknown"`|`"washing machine"`|Description which will be used as key to for which device the data is plotted| | ||
|sensor|yes|string|`none`|`"sensor.wasmachine_energy"`|The energy sensor used to track the usage of the device| | ||
|no_weight_points|no|integer|`4`|`2`|The number of weight points per hour| | ||
|stop_entity|yes|string|`none`|`sensor.washing_machine`|An entity which is used to define when the script should stop sending data. This can be provided by the device, but can also be a input_boolean or binary_sensor which is eg toggled based on the power usage of the device| | ||
|stop_state|yes|string|`none`|`"off"`|The state the `stop_entity` should be on to stop the script| | ||
|
||
Example of the total script service call (using `script.turn_on` in this case) | ||
```yaml | ||
service: script.turn_on | ||
target: | ||
entity_id: script.plot_energy_usage | ||
data: | ||
variables: | ||
description: Washing Machine Cotton 1400rpm | ||
sensor: sensor.washing_machine_energy | ||
no_weight_points: 6 | ||
stop_entity: binary_sensor.washing_machine_power_usage | ||
stop_state: "off" | ||
``` | ||
# Important to know | ||
* If Home Assistants restarts during the process or the script is stopped because of another reason, it won't be restarted. You'll have to start the process again. | ||
* Plots with the same `description` will be overwritten | ||
* There is a limited number of bytes which is allowed in an attribute. If you store too many plots, you could lose the data | ||
|
||
# How to use the plot in the macro | ||
Use the following in developer tools > template to get the data from the sensor. Copy paste that somewhere (or store it in an input_text) to use it later. | ||
```jinja | ||
{{ state_attr('sensor.energy_plots', 'energy_plots')['Your Description'].data }} | ||
``` | ||
As long as the data is still in the sensor, you can directly refer to it. | ||
```jinja | ||
{% set w = state_attr('sensor.energy_plots', 'energy_plots')['Your Description'].data %} | ||
{% set wp = state_attr('sensor.energy_plots', 'energy_plots')['Your Description'].no_weight_points %} | ||
{{ cheapest_energy_hours('sensor.nordpool_kwh_nl_eur', no_weight_points=wp, weight=w }} | ||
``` | ||
|
||
If you store the data in an input_text, or otherwise in a string instead of a list, you need to apply `| from_json` to convert it to a list again | ||
```jinja | ||
{% set w = states('input_text.energy_plot') | from_json %} | ||
{{ cheapest_energy_hours('sensor.nordpool_kwh_nl_eur', no_weight_points=4, weight=w }} | ||
``` | ||
|
||
# How to remove a plot from the sensor | ||
In developer tools > events, you can send an event to remove a plot. The event type should be `update_energy_plot` | ||
As event_data you need to send the description of the data you want to remove, and `status: remove` | ||
```yaml | ||
description: Washing Machine Cotton 1400rpm | ||
status: remove | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
plot_energy_usage: | ||
alias: "00 - Plot energy usage" | ||
icon: mdi:brightness-percent | ||
mode: parallel | ||
max: 20 | ||
max_exceeded: silent | ||
fields: | ||
sensor: | ||
description: "Select energy sensor" | ||
name: Energy Sensor | ||
example: sensor.dishwasher_energy | ||
required: true | ||
selector: | ||
entity: | ||
domain: sensor | ||
device_class: energy | ||
description: | ||
description: "Description for the plot" | ||
name: Description | ||
example: 120 | ||
required: true | ||
selector: | ||
text: | ||
no_weight_points: | ||
description: "Number of weight points/hour" | ||
name: Weight points | ||
default: 1 | ||
example: 3 | ||
required: true | ||
selector: | ||
number: | ||
min: 0 | ||
max: 12 | ||
step: 1 | ||
mode: slider | ||
stop_entity: | ||
description: "Entity to use to stop the plot" | ||
example: input_boolean.dishwasher_off | ||
required: true | ||
selector: | ||
entity: | ||
stop_state: | ||
description: "State the entity should have to stop the plot" | ||
example: "off" | ||
required: true | ||
selector: | ||
text: | ||
sequence: | ||
- variables: | ||
not_defined: > | ||
{{ [ | ||
'energy sensor' if sensor is not defined or not sensor else none, | ||
'stop entity' if stop_entity is not defined or not stop_entity else none, | ||
'stop state' if stop_state is not defined else none | ||
] | reject('none') | list | ||
}} | ||
- if: "{{ not_defined | count > 0 }}" | ||
then: | ||
- stop: > | ||
{{ not_defined | join(', ') }} {{ 'is' if not_defined | count == 1 else 'are'}} not defined, script has stopped | ||
error: true | ||
- variables: | ||
description: "{{ description | default('unknown') }}" | ||
no_weight_points: "{{ no_weight_points | default(4) | int(4) }}" | ||
- repeat: | ||
until: | ||
- condition: template | ||
value_template: "{{ is_state(stop_entity, stop_state) }}" | ||
sequence: | ||
- variables: | ||
sensor_state: "{{ states(sensor) | float('na') }}" | ||
- if: "{{ not sensor_state | is_number }}" | ||
then: | ||
- stop: "Received non numeric state, script has stopped" | ||
error: true | ||
- event: update_energy_plot | ||
event_data: | ||
description: "{{ description }}" | ||
status: "{{ 'first' if repeat.first else 'ongoing' }}" | ||
state: "{{ sensor_state }}" | ||
no_weight_points: "{{ no_weight_points }}" | ||
- delay: | ||
minutes: "{{ 60 / no_weight_points }}" | ||
- event: update_energy_plot | ||
event_data: | ||
description: "{{ description }}" | ||
no_weight_points: "{{ no_weight_points }}" | ||
status: complete |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
template: | ||
- trigger: | ||
- platform: event | ||
event_type: update_energy_plot | ||
sensor: | ||
- unique_id: 36c9491c-2e16-4fc3-bc9f-a6ada5fc88b7 | ||
name: Energy plots | ||
state: OK | ||
attributes: | ||
energy_plots: > | ||
{%- set c = this.attributes.get('energy_plots', {}) -%} | ||
{%- if trigger.event.data is defined -%} | ||
{%- set d = trigger.event.data.description | default('unknown') -%} | ||
{%- set s = trigger.event.data.state | default(0) -%} | ||
{%- set st = trigger.event.data.status | default('unknown') -%} | ||
{%- set wp = trigger.event.data.no_weight_points | default(none) %} | ||
{%- if st == 'remove' -%} | ||
{{ dict(c.items() | rejectattr('0', 'eq', d)) }} | ||
{%- else -%} | ||
{%- if st == 'first' -%} | ||
{%- set p = {d: dict(data=[], state=s, no_weight_points=wp, complete=false)} -%} | ||
{%- elif st == 'complete' -%} | ||
{%- set data = c.get(d, {}).get('data', []) -%} | ||
{%- set no_zero = data | select() | list -%} | ||
{%- set factor = 1 / no_zero | min if no_zero else 0 -%} | ||
{%- set data = data | map('multiply', factor) | map('round', 3) | list -%} | ||
{%- set p = {d: dict(data=data, no_weight_points=wp, complete=true)} -%} | ||
{%- elif st == 'ongoing' -%} | ||
{%- set data = c.get(d, {}).get('data', []) -%} | ||
{%- set u = s - c.get(d, {}).get('state', 0) -%} | ||
{%- set data = data + [u | round(3)] -%} | ||
{%- set p = {d: dict(data=data, state=s, no_weight_points=wp, complete=false)} -%} | ||
{%- else -%} | ||
{%- set p = {} -%} | ||
{%- endif -%} | ||
{{ dict(c, **p) }} | ||
{%- endif -%} | ||
{%- else -%} | ||
{{ c }} | ||
{%- endif -%} |