Skip to content

Instantly share code, notes, and snippets.

@dougrathbone
Created April 14, 2026 04:41
Show Gist options
  • Select an option

  • Save dougrathbone/e7bb3667e80e30338d82956750680696 to your computer and use it in GitHub Desktop.

Select an option

Save dougrathbone/e7bb3667e80e30338d82956750680696 to your computer and use it in GitHub Desktop.
Home Assistant Blueprint: Amber Electric Negative Price Load Shedding - Automatically activates high-energy devices (heating, towel rails, AC) during negative price windows to consume excess solar rather than exporting at a loss.
blueprint:
name: Amber Electric Negative Price Load Shedding
description: >-
Automatically turns on high-energy devices (heating, towel rails, AC) during
negative Amber Electric price windows to consume excess solar rather than
exporting at a loss. Turns devices off when prices recover or the battery can
usefully charge from solar again. Sends mobile notifications on each transition.
Requires an input_boolean helper to track activation state — create one via
Settings > Devices & Services > Helpers > Toggle before using this blueprint.
domain: automation
source_url: https://gist.github.com/dougrathbone/e7bb3667e80e30338d82956750680696
input:
# --- State tracking ---
load_active_boolean:
name: Load Active Toggle
description: >-
An input_boolean helper that tracks whether this automation has activated
devices. Create one via Settings > Helpers > Toggle if you don't have one.
selector:
entity:
domain: input_boolean
multiple: false
# --- Price sensors ---
general_price_sensor:
name: General Price Sensor
description: Amber Electric general/import price sensor (c/kWh).
default: sensor.amber_electric_general_price
selector:
entity:
domain: sensor
multiple: false
feed_in_price_sensor:
name: Feed-in Price Sensor
description: Amber Electric feed-in/export price sensor (c/kWh).
default: sensor.amber_electric_feed_in_price
selector:
entity:
domain: sensor
multiple: false
# --- Battery & solar sensors ---
battery_charge_sensor:
name: Battery Charge Sensor
description: Battery state of charge sensor (0-100%).
default: sensor.home_energy_gateway_charge
selector:
entity:
domain: sensor
device_class: battery
multiple: false
site_power_sensor:
name: Site Power Sensor
description: >-
Net grid power sensor (kW). Negative values = exporting to grid.
default: sensor.home_energy_gateway_site_power
selector:
entity:
domain: sensor
device_class: power
multiple: false
battery_power_sensor:
name: Battery Power Sensor
description: >-
Battery charge/discharge power sensor (kW). Positive = charging.
default: sensor.home_energy_gateway_battery_power
selector:
entity:
domain: sensor
device_class: power
multiple: false
outdoor_temp_sensor:
name: Outdoor Temperature Sensor
description: Used to decide AC heat vs cool mode.
default: sensor.outdoor_temperature
selector:
entity:
domain: sensor
device_class: temperature
multiple: false
# --- Devices to activate ---
heating_switches:
name: Heating & Towel Rail Switches
description: Switches to turn on/off during load shedding (floor heating, towel rails, etc).
selector:
entity:
domain: switch
multiple: true
climate_zones:
name: Air Conditioning Zones
description: Climate entities to activate during load shedding.
default: []
selector:
entity:
domain: climate
multiple: true
# --- Notification devices ---
notify_device_1:
name: First Phone to Notify
description: First mobile device to receive notifications.
selector:
device:
integration: mobile_app
notify_device_2:
name: Second Phone to Notify
description: Second mobile device to receive notifications. Leave empty if not needed.
default: {}
selector:
device:
integration: mobile_app
# --- Thresholds ---
battery_full_pct:
name: Battery Full Threshold (%)
description: Battery is considered full at or above this percentage.
default: 99
selector:
number:
min: 90
max: 100
step: 1
unit_of_measurement: '%'
mode: slider
battery_resume_charge_pct:
name: Battery Resume Charge Threshold (%)
description: >-
Deactivate load shedding when battery drops below this percentage
(allows battery to charge from solar). Should be lower than the full
threshold to prevent oscillation.
default: 95
selector:
number:
min: 80
max: 99
step: 1
unit_of_measurement: '%'
mode: slider
battery_charge_rate_kw:
name: Battery Max Charge Rate (kW)
description: >-
Activate when battery is charging above this rate (even if not 100% full).
Set slightly below your battery's actual max charge rate.
default: 8
selector:
number:
min: 1
max: 20
step: 0.5
unit_of_measurement: kW
mode: slider
export_threshold_kw:
name: Export Threshold (kW)
description: >-
Minimum export power to trigger activation (as a positive number).
The automation checks for site_power below the negative of this value.
default: 0.5
selector:
number:
min: 0.1
max: 5
step: 0.1
unit_of_measurement: kW
mode: slider
activation_delay_min:
name: Activation Delay (minutes)
description: How long conditions must hold before activating devices.
default: 2
selector:
number:
min: 1
max: 10
step: 1
unit_of_measurement: min
mode: slider
deactivation_delay_min:
name: Deactivation Delay (minutes)
description: >-
How long conditions must hold before deactivating. Set higher than
activation delay to prevent rapid on/off cycling.
default: 3
selector:
number:
min: 1
max: 15
step: 1
unit_of_measurement: min
mode: slider
heat_temp:
name: Heating Temperature
description: Target temperature when AC is set to heat mode.
default: 22
selector:
number:
min: 18
max: 28
step: 0.5
unit_of_measurement: °C
mode: slider
cool_temp:
name: Cooling Temperature
description: Target temperature when AC is set to cool mode.
default: 24
selector:
number:
min: 18
max: 28
step: 0.5
unit_of_measurement: °C
mode: slider
heat_below_outdoor:
name: Heat When Outdoor Temp Below
description: Use heat mode when outdoor temperature is below this value.
default: 22
selector:
number:
min: 15
max: 30
step: 1
unit_of_measurement: °C
mode: slider
cool_above_outdoor:
name: Cool When Outdoor Temp Above
description: Use cool mode when outdoor temperature is above this value.
default: 25
selector:
number:
min: 20
max: 35
step: 1
unit_of_measurement: °C
mode: slider
# trigger_variables are available inside trigger templates (evaluated before triggers)
trigger_variables:
general_price_sensor: !input general_price_sensor
feed_in_price_sensor: !input feed_in_price_sensor
battery_charge_sensor: !input battery_charge_sensor
site_power_sensor: !input site_power_sensor
battery_power_sensor: !input battery_power_sensor
battery_full_pct: !input battery_full_pct
battery_resume_charge_pct: !input battery_resume_charge_pct
battery_charge_rate_kw: !input battery_charge_rate_kw
export_threshold_kw: !input export_threshold_kw
# variables are available in conditions and actions
variables:
general_price_sensor: !input general_price_sensor
feed_in_price_sensor: !input feed_in_price_sensor
battery_charge_sensor: !input battery_charge_sensor
site_power_sensor: !input site_power_sensor
battery_power_sensor: !input battery_power_sensor
outdoor_temp_sensor: !input outdoor_temp_sensor
heating_switches: !input heating_switches
climate_zones: !input climate_zones
load_active_boolean: !input load_active_boolean
battery_full_pct: !input battery_full_pct
battery_resume_charge_pct: !input battery_resume_charge_pct
battery_charge_rate_kw: !input battery_charge_rate_kw
export_threshold_kw: !input export_threshold_kw
heat_temp: !input heat_temp
cool_temp: !input cool_temp
heat_below_outdoor: !input heat_below_outdoor
cool_above_outdoor: !input cool_above_outdoor
notify_device_1: !input notify_device_1
notify_device_2: !input notify_device_2
triggers:
- trigger: template
id: activate
value_template: >-
{% set price = states(general_price_sensor) | float(99) %}
{% set feed_in = states(feed_in_price_sensor) | float(99) %}
{% set soc = states(battery_charge_sensor) | float(0) %}
{% set site = states(site_power_sensor) | float(0) %}
{% set batt = states(battery_power_sensor) | float(0) %}
{{
(price < 0 or feed_in < 0) and
(
(soc >= battery_full_pct and site < (export_threshold_kw * -1))
or
(batt > battery_charge_rate_kw)
)
}}
for:
minutes: !input activation_delay_min
- trigger: template
id: deactivate
value_template: >-
{% set price = states(general_price_sensor) | float(-99) %}
{% set feed_in = states(feed_in_price_sensor) | float(-99) %}
{% set soc = states(battery_charge_sensor) | float(100) %}
{{
(price > 0 and feed_in > 0)
or
(soc < battery_resume_charge_pct and price > 0)
}}
for:
minutes: !input deactivation_delay_min
actions:
- choose:
# --- ACTIVATE ---
- conditions:
- condition: trigger
id: activate
- condition: state
entity_id: !input load_active_boolean
state: 'off'
sequence:
- action: input_boolean.turn_on
target:
entity_id: !input load_active_boolean
- action: switch.turn_on
target:
entity_id: !input heating_switches
- choose:
- conditions:
- condition: numeric_state
entity_id: !input outdoor_temp_sensor
below: !input heat_below_outdoor
sequence:
- action: climate.set_temperature
target:
entity_id: !input climate_zones
data:
hvac_mode: heat
temperature: !input heat_temp
- conditions:
- condition: numeric_state
entity_id: !input outdoor_temp_sensor
above: !input cool_above_outdoor
sequence:
- action: climate.set_temperature
target:
entity_id: !input climate_zones
data:
hvac_mode: cool
temperature: !input cool_temp
default:
- action: climate.set_temperature
target:
entity_id: !input climate_zones
data:
hvac_mode: heat
temperature: !input heat_temp
- variables:
price_now: "{{ states(general_price_sensor) }}"
battery_pct: "{{ states(battery_charge_sensor) }}"
outdoor_temp: "{{ states(outdoor_temp_sensor) | float(0) | round(1) }}"
ac_mode: >-
{% if states(outdoor_temp_sensor) | float(0) > cool_above_outdoor %}cool at {{ cool_temp }}°C
{% else %}heat at {{ heat_temp }}°C{% endif %}
notification_title: >-
{% if states(battery_charge_sensor) | float(0) >= battery_full_pct %}Battery full: Turning on devices to load shed
{% else %}Negative pricing: Turning on devices to use excess energy{% endif %}
notification_message: >-
Amber price is {{ states(general_price_sensor) }}c/kWh and battery
is at {{ states(battery_charge_sensor) }}%.
Activating floor heating, towel rails, and AC ({{ ac_mode }}) to
consume excess solar rather than exporting at a loss.
- domain: mobile_app
type: notify
device_id: !input notify_device_1
title: "{{ notification_title }}"
message: "{{ notification_message }}"
data:
tag: negative-price-load
group: energy
- if:
- condition: template
value_template: "{{ notify_device_2 not in ({}, '', none, 'None') }}"
then:
- domain: mobile_app
type: notify
device_id: !input notify_device_2
title: "{{ notification_title }}"
message: "{{ notification_message }}"
data:
tag: negative-price-load
group: energy
# --- DEACTIVATE ---
- conditions:
- condition: trigger
id: deactivate
- condition: state
entity_id: !input load_active_boolean
state: 'on'
sequence:
- action: input_boolean.turn_off
target:
entity_id: !input load_active_boolean
- action: switch.turn_off
target:
entity_id: !input heating_switches
- action: climate.set_hvac_mode
target:
entity_id: !input climate_zones
data:
hvac_mode: 'off'
- variables:
notification_title: >-
{% if states(battery_charge_sensor) | float(100) < battery_resume_charge_pct %}Prices positive: Letting battery charge from solar
{% else %}Prices positive: Turning off load shedding devices{% endif %}
notification_message: >-
Amber price is now {{ states(general_price_sensor) }}c/kWh and battery
is at {{ states(battery_charge_sensor) }}%.
Turning off floor heating, towel rails, and AC.
- domain: mobile_app
type: notify
device_id: !input notify_device_1
title: "{{ notification_title }}"
message: "{{ notification_message }}"
data:
tag: negative-price-load
group: energy
- if:
- condition: template
value_template: "{{ notify_device_2 not in ({}, '', none, 'None') }}"
then:
- domain: mobile_app
type: notify
device_id: !input notify_device_2
title: "{{ notification_title }}"
message: "{{ notification_message }}"
data:
tag: negative-price-load
group: energy
mode: single
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment