Created
April 14, 2026 04:41
-
-
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.
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: 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