Last active
October 9, 2025 14:16
-
-
Save JohanAlvedal/66b21a648a1a4ca261f6f3476b3f82e3 to your computer and use it in GitHub Desktop.
This blueprints uses the nordpool integration and lets you choose howe many hours you will define as expesive, and make a sensor block temperature based on that information.
This file contains hidden or 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
| blueprint: | |
| name: Block heat (15-min safe) | |
| description: > | |
| Blockerar värme (sätter virtuell temperatur) under de dyraste timmarna baserat | |
| på Nordpool-priser. Under billiga perioder speglar den utetemperaturen med | |
| ett valt uppdateringsintervall. Fungerar med 60- och 15-minuterspriser samt DST. | |
| domain: automation | |
| input: | |
| grid_area: | |
| name: Grid Area Sensor | |
| description: Din Nordpool-prissensor | |
| selector: | |
| entity: | |
| domain: [sensor] | |
| integration: nordpool | |
| multiple: false | |
| expensive_hours: | |
| name: Expensive Hours | |
| description: Antal timmar att blockera (omvandlas till slots automatiskt) | |
| default: 4 | |
| selector: | |
| number: | |
| min: 0.0 | |
| max: 24.0 | |
| mode: slider | |
| step: 1.0 # sätt 0.25 om du vill ha kvartsteg | |
| temperature_sensor: | |
| name: Temperature Sensor | |
| description: Din riktiga utetemperatursensor | |
| selector: | |
| entity: | |
| domain: [sensor] | |
| device_class: [temperature] | |
| multiple: false | |
| refresh_temperature_delay: | |
| name: Cheap Hours - Refresh Controllable Temperature Delay Time | |
| description: Hur ofta den kontrollerbara temperaturen ska spegla ute-tempen under billiga perioder. | |
| default: 5 | |
| selector: | |
| number: | |
| min: 0.0 | |
| max: 10.0 | |
| step: 0.25 | |
| unit_of_measurement: Minutes | |
| mode: slider | |
| controll_sensor: | |
| name: Controllable Sensor | |
| description: Din kontrollerbara sensor (t.ex. MQTT number) | |
| selector: | |
| entity: | |
| domain: [number] | |
| integration: mqtt | |
| multiple: false | |
| virtual_temperature: | |
| name: Virtual Block Temp | |
| description: Virtuell temperatur under dyra perioder (för att blockera värmen) | |
| default: 20 | |
| selector: | |
| number: | |
| min: 0.0 | |
| max: 30.0 | |
| mode: slider | |
| step: 1.0 | |
| unit_of_measurement: "°C" | |
| source_url: https://gist.github.com/JohanAlvedal/66b21a648a1a4ca261f6f3476b3f82e3 | |
| variables: | |
| grid_area: !input grid_area | |
| expensive_hours: !input expensive_hours | |
| temperature_sensor: !input temperature_sensor | |
| refresh_temperature_delay: !input refresh_temperature_delay | |
| controll_sensor: !input controll_sensor | |
| virtual_temperature: !input virtual_temperature | |
| trigger: | |
| - platform: state | |
| entity_id: !input grid_area | |
| - platform: homeassistant | |
| event: start | |
| - platform: time_pattern | |
| seconds: 30 | |
| mode: restart | |
| action: | |
| - choose: | |
| - conditions: | |
| - condition: template | |
| # DYRT nu? -> blockera (sätt virtuell temperatur) | |
| value_template: > | |
| {% set cur = states(grid_area) | float(default=none) %} | |
| {% set raw = state_attr(grid_area, 'raw_today') or [] %} | |
| {% if cur is none or raw | length == 0 %} | |
| false | |
| {% else %} | |
| {% set prices = raw | map(attribute='value') | map('float') | list %} | |
| {% set L = prices | length %} | |
| {% set slots = (expensive_hours * L / 24) | int %} | |
| {% set slots = 1 if slots < 1 else (L if slots > L else slots) %} | |
| {% set threshold = (prices | sort)[L - slots] %} | |
| {{ cur >= threshold }} | |
| {% endif %} | |
| sequence: | |
| - service: number.set_value | |
| target: | |
| entity_id: !input controll_sensor | |
| data: | |
| value: !input virtual_temperature | |
| - conditions: | |
| - condition: template | |
| # BILLIGT nu? -> spegla ute-temp, repetera tills det blir dyrt | |
| value_template: > | |
| {% set cur = states(grid_area) | float(default=none) %} | |
| {% set raw = state_attr(grid_area, 'raw_today') or [] %} | |
| {% if cur is none or raw | length == 0 %} | |
| false | |
| {% else %} | |
| {% set prices = raw | map(attribute='value') | map('float') | list %} | |
| {% set L = prices | length %} | |
| {% set slots = (expensive_hours * L / 24) | int %} | |
| {% set slots = 1 if slots < 1 else (L if slots > L else slots) %} | |
| {% set threshold = (prices | sort)[L - slots] %} | |
| {{ cur < threshold }} | |
| {% endif %} | |
| sequence: | |
| - alias: Refresh controllable temperature during cheap period | |
| repeat: | |
| until: > | |
| {% set cur = states(grid_area) | float(default=none) %} | |
| {% set raw = state_attr(grid_area, 'raw_today') or [] %} | |
| {% if cur is none or raw | length == 0 %} | |
| true | |
| {% else %} | |
| {% set prices = raw | map(attribute='value') | map('float') | list %} | |
| {% set L = prices | length %} | |
| {% set slots = (expensive_hours * L / 24) | int %} | |
| {% set slots = 1 if slots < 1 else (L if slots > L else slots) %} | |
| {% set threshold = (prices | sort)[L - slots] %} | |
| {{ cur >= threshold }} | |
| {% endif %} | |
| sequence: | |
| - service: number.set_value | |
| target: | |
| entity_id: !input controll_sensor | |
| data: | |
| value: "{{ states(temperature_sensor) | float(0) }}" | |
| - delay: | |
| minutes: !input refresh_temperature_delay | |
| default: [] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment