Skip to content

Commit

Permalink
Merge branch 'main' into minor_whitespace
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFes authored Oct 5, 2023
2 parents c9044be + 8e71635 commit cc28e61
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 49 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ In case `hours` is provided, this will overrule the calculated number of hours,

|name|type|default|example|description|
|---|---|---|---|---|
|`no_weight_points`|integer|`1`|`4`|The most important hour in your hour range. Eg if hour device uses most energy in the 2nd hour, you can set this to `2` to give more weight to that energy price|
|`no_weight_points`|integer|`1`|`4`|The number of weight points per hour, eg set to `4` if each weight point represents 15 minutes. This should match with the datapoints per hour, meaning the number of minutes each list item in the sensor represents (normally 60, for dynamic prices per hour) shoudl be divisable by the number of minutes per weight point. So with hourly data you can use `4` or `12` but not `7`|
|`weight`|list|`none`|`[25, 1, 4, 0]`|The list with weight factors to be used for the calculation|
|`program`|string|none|`"Dryer Clothes"`| Description of data used in the energy plot sensor. Adds automatically the correct weight and number of weight points.

Expand Down Expand Up @@ -189,9 +189,11 @@ The macro will display error messages as output in case of incorrect input.
|No valid data in selected sensor|The provided sensor does not have valid data to work with, the sensor might be unavailable, or you need to provide a specific `attr_today` or `attr_tomorrow`|
|Time key not found in data|The time key can not be found in the source data, you might need to proviee a `time_key` parameter|
|Value key not found in data|The value key can not be found in the source data, you might need to provide a `value_key` parameter|
|Boolean input expected for {parameter}|The mentioned parameter expects a boolean input, but something else is provided. You can provice values like `0`, `false`, `"True"` but not `"banana"`|
|Invalid mode selected|An invalid value for the `mode` parameter was provided, check your input|
|Selected program is not available or has no data|The value provided for the `program` parameter can not be found in the sensor, or has no data|
|Data plot for selected program not complete|The data plot for the value in the `program` parameter is incomplete|
|Invalid combination of data points per hour and number of weight points|The number of weight points does not match with the datapoints per hour provided by the sensor. If you eg have quarterly prices, you can't have 6 datapoints per hour, as 15 is not divisable by 10|
|No(t enough) data within current selection|There is no, or not enough data to match your input. This can happen if you eg want a consecutive block of 4 hours, and you only use todays data for future hours, when it's already after 21:00|

# Thanks to
Expand Down
5 changes: 3 additions & 2 deletions cheapest_energy_hours.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
no_weight_points=1,
weight=none,
program=none
) -%}
{%- set modes = ['min', 'max', 'average', 'start', 'end', 'list', 'weighted_average','time_min','time_max', 'split'] -%}
)
-%}
{%- set modes = ['min', 'max', 'average', 'start', 'end', 'list', 'weighted_average','time_min','time_max', 'split'] %}
{# Get data out of the selected entity #}
{%- set today = state_attr(sensor, attr_today) -%}
{%- set tomorrow = state_attr(sensor, attr_tomorrow) -%}
Expand Down
59 changes: 35 additions & 24 deletions example_package/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ script:
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
}}
{{ [
'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: >
Expand Down Expand Up @@ -94,55 +94,66 @@ template:
- trigger:
- platform: event
event_type: update_energy_plot
id: plot_update
- platform: homeassistant
event: start
id: remove_incomplete
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 -%}
{%- if trigger.id == 'plot_update' and trigger.event.data is defined -%}
{%- set st = trigger.event.data.status | default('unknown') -%}
{%- set d = trigger.event.data.description | default('unknown') -%}
{%- if st == 'remove' -%}
{%- set d = trigger.event.data.description | default('unknown') ~ ('(incomplete)' if not st in ['complete', 'remove'] else '') -%}
{%- if st == 'remove_all' -%}
{{ dict() }}
{%- elif st == 'remove' -%}
{{ dict(c.items() | rejectattr('0', 'eq', d)) }}
{%- else -%}
{%- set s = trigger.event.data.state | default(0) -%}
{%- set wp = trigger.event.data.no_weight_points | default(none) %}
{%- set dt = now().replace(microsecond=0).isoformat() -%}
{%- if st == 'first' -%}
{%- set p = {d: dict(data=[], state=s, start=s, no_weight_points=wp, last_update=dt, complete=false)} -%}
{%- elif st == 'complete' -%}
{%- set values = c.get(d, {}) -%}
{%- set data = values.get('data', []) -%}
{%- set u = (values.get('state', 0) - values.get('start', 0)) | round(3) -%}
{%- 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, kwh_used=u, no_weight_points=wp, last_update=dt, complete=true)} -%}
{%- set p = {d: dict(data=[], state=s, start=s, start_time=now().isoformat(), no_weight_points=wp, last_update=dt)} -%}
{%- elif st == 'ongoing' -%}
{%- set values = c.get(d, {}) -%}
{%- set data = values.get('data', []) -%}
{%- set u = s - values.get('state', 0) -%}
{%- set start = values.get('start', 0) -%}
{%- set start_time = values.get('start_time', now().isoformat()) -%}
{%- set data = data + [u | round(3)] -%}
{%- set p = {d: dict(data=data, state=s, start=start, no_weight_points=wp, last_update=dt, complete=false)} -%}
{%- else -%}
{%- set p = {} -%}
{%- set p = {d: dict(data=data, state=s, start=start, start_time=start_time, no_weight_points=wp, last_update=dt)} -%}
{%- elif st == 'complete' -%}
{%- set di = d~'(incomplete)' -%}
{%- set values = c.get(di, {}) -%}
{%- set data = values.get('data', []) -%}
{%- set u = (values.get('state', 0) - values.get('start', 0)) | round(3) -%}
{%- set start_time = values.get('start_time', now().isoformat()) -%}
{%- set duration = (now() - as_datetime(start_time)).total_seconds() | int %}
{%- 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 c = dict(c.items() | rejectattr('0', 'eq', di)) -%}
{%- set p = {d: dict(data=data, kwh_used=u, duration=duration, no_weight_points=wp, last_update=dt)} -%}
{%- endif -%}
{{ dict(c, **p) }}
{{ dict(c, **p | default({})) }}
{%- endif -%}
{%- elif trigger.id == 'remove_incomplete' -%}
{{ dict(c.items() | rejectattr('0', 'search', '\(incomplete\)$')) }}
{%- else -%}
{{ c }}
{%- endif -%}
## AUTOMATION TO START THE SCRIPT ##
automation:
- id: 2794cd64-a5d0-48e3-9edb-08527ac231bc
alias: "F02 - Plot Wasmachine Energy"
alias: "F2L - Plot Wasmachine Energy"
trigger:
- platform: state
entity_id: sensor.wasmachine
entity_id: binary_sensor.wasmachine_door_lock
from: "off"
to: "on"
action:
Expand Down
12 changes: 6 additions & 6 deletions example_package/script.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ plot_energy_usage:
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
}}
{{ [
'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: >
Expand Down
43 changes: 27 additions & 16 deletions example_package/sensor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,55 @@ template:
- trigger:
- platform: event
event_type: update_energy_plot
id: plot_update
- platform: homeassistant
event: start
id: remove_incomplete
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 -%}
{%- if trigger.id == 'plot_update' and trigger.event.data is defined -%}
{%- set st = trigger.event.data.status | default('unknown') -%}
{%- set d = trigger.event.data.description | default('unknown') -%}
{%- if st == 'remove' -%}
{%- set d = trigger.event.data.description | default('unknown') ~ ('(incomplete)' if not st in ['complete', 'remove'] else '') -%}
{%- if st == 'remove_all' -%}
{{ dict() }}
{%- elif st == 'remove' -%}
{{ dict(c.items() | rejectattr('0', 'eq', d)) }}
{%- else -%}
{%- set s = trigger.event.data.state | default(0) -%}
{%- set wp = trigger.event.data.no_weight_points | default(none) %}
{%- set dt = now().replace(microsecond=0).isoformat() -%}
{%- if st == 'first' -%}
{%- set p = {d: dict(data=[], state=s, start=s, no_weight_points=wp, last_update=dt, complete=false)} -%}
{%- elif st == 'complete' -%}
{%- set values = c.get(d, {}) -%}
{%- set data = values.get('data', []) -%}
{%- set u = (values.get('state', 0) - values.get('start', 0)) | round(3) -%}
{%- 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, kwh_used=u, no_weight_points=wp, last_update=dt, complete=true)} -%}
{%- set p = {d: dict(data=[], state=s, start=s, start_time=now().isoformat(), no_weight_points=wp, last_update=dt)} -%}
{%- elif st == 'ongoing' -%}
{%- set values = c.get(d, {}) -%}
{%- set data = values.get('data', []) -%}
{%- set u = s - values.get('state', 0) -%}
{%- set start = values.get('start', 0) -%}
{%- set start_time = values.get('start_time', now().isoformat()) -%}
{%- set data = data + [u | round(3)] -%}
{%- set p = {d: dict(data=data, state=s, start=start, no_weight_points=wp, last_update=dt, complete=false)} -%}
{%- else -%}
{%- set p = {} -%}
{%- set p = {d: dict(data=data, state=s, start=start, start_time=start_time, no_weight_points=wp, last_update=dt)} -%}
{%- elif st == 'complete' -%}
{%- set di = d~'(incomplete)' -%}
{%- set values = c.get(di, {}) -%}
{%- set data = values.get('data', []) -%}
{%- set u = (values.get('state', 0) - values.get('start', 0)) | round(3) -%}
{%- set start_time = values.get('start_time', now().isoformat()) -%}
{%- set duration = (now() - as_datetime(start_time)).total_seconds() | int %}
{%- 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 c = dict(c.items() | rejectattr('0', 'eq', di)) -%}
{%- set p = {d: dict(data=data, kwh_used=u, duration=duration, no_weight_points=wp, last_update=dt)} -%}
{%- endif -%}
{{ dict(c, **p) }}
{{ dict(c, **p | default({})) }}
{%- endif -%}
{%- elif trigger.id == 'remove_incomplete' -%}
{{ dict(c.items() | rejectattr('0', 'search', '\(incomplete\)$')) }}
{%- else -%}
{{ c }}
{%- endif -%}

0 comments on commit cc28e61

Please sign in to comment.