[TASK] Added README.md to explain the configuration of the script
This commit is contained in:
61
README.md
Normal file
61
README.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Boiler Control - AppDaemon
|
||||||
|
|
||||||
|
AppDaemon script that optimizes when to power (heat up) the boiler with respect to the hourly (dynamic) electricity prices.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
Copy boilercontrol.py to your appdaemon config `/apps` folder.
|
||||||
|
|
||||||
|
In `apps.yaml`, activate the app by adding something like this:
|
||||||
|
```yml
|
||||||
|
boiler_control:
|
||||||
|
module: boilercontrol
|
||||||
|
class: BoilerControl
|
||||||
|
# Switch entity that turns on/off the boiler
|
||||||
|
boiler_switch: switch.boiler_switch_0
|
||||||
|
# Sensor entity which contains the current dynamic electricity prices. This sensor should have an attribute "raw_today", which contains a dictionary with the prices per hour
|
||||||
|
price_sensor: sensor.nordpool
|
||||||
|
# (Optional) sensor to add to home assistant which contains the output of the optimization script
|
||||||
|
output_sensor: sensor.boiler_control_output
|
||||||
|
|
||||||
|
# Minimal number of hours the boiler should be powered per day
|
||||||
|
boiler_on_for_hours: 6
|
||||||
|
# The algorithm splits the day up into equal size "periods", and tries to ensure the boiler gets at least one hour of power during each period.
|
||||||
|
# This variable controls how many periods of boiler activity each day should have
|
||||||
|
boiler_reheat_periods_per_day: 4
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use [ApexCharts](https://github.com/RomRider/apexcharts-card) to display to output of the algorithm. Config:
|
||||||
|
```yml
|
||||||
|
type: custom:apexcharts-card
|
||||||
|
graph_span: 24h
|
||||||
|
header:
|
||||||
|
title: Energy price today (€/kWh)
|
||||||
|
show: true
|
||||||
|
span:
|
||||||
|
start: day
|
||||||
|
now:
|
||||||
|
show: true
|
||||||
|
label: Now
|
||||||
|
series:
|
||||||
|
- entity: sensor.nordpool
|
||||||
|
float_precision: 3
|
||||||
|
type: column
|
||||||
|
data_generator: |
|
||||||
|
return entity.attributes.raw_today.map((start, index) => {
|
||||||
|
return [new Date(start["start"]).getTime() + 30 * 1000 * 60, entity.attributes.raw_today[index]["value"]];
|
||||||
|
});
|
||||||
|
- entity: sensor.boiler_control_output
|
||||||
|
float_precision: 0
|
||||||
|
name: Boiler controller
|
||||||
|
type: line
|
||||||
|
curve: stepline
|
||||||
|
stroke_width: 2
|
||||||
|
data_generator: |
|
||||||
|
const val = entity.attributes.average_price
|
||||||
|
return [[0,0], ...entity.attributes.merged_blocks.flatMap(b => {
|
||||||
|
return [[new Date(b["start"]).getTime(), val], [new Date(b["end"]).getTime(), 0]]
|
||||||
|
})]
|
||||||
|
yaxis:
|
||||||
|
- min: 0
|
||||||
|
decimals: 2
|
||||||
|
```
|
||||||
@@ -78,7 +78,7 @@ class BoilerControl(hass.Hass):
|
|||||||
self.run_at(self.turn_boiler_off, block["end"])
|
self.run_at(self.turn_boiler_off, block["end"])
|
||||||
|
|
||||||
if (self.output_sensor != None):
|
if (self.output_sensor != None):
|
||||||
self.set_state(self.output_sensor, state="on" if currently_on else "off", attributes={"active_blocks": boiler_active_blocks, "merged_blocks": merged_blocks})
|
self.set_state(self.output_sensor, state="on" if currently_on else "off", attributes={"active_blocks": boiler_active_blocks, "merged_blocks": merged_blocks, "average_price": sum([block["value"] for block in boiler_active_blocks]) / len(boiler_active_blocks)})
|
||||||
|
|
||||||
|
|
||||||
def turn_boiler_on(self, cb_args=None):
|
def turn_boiler_on(self, cb_args=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user