Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions skills/mrbese/grid-aware-energy-load-shifter/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Grid-Aware Energy Load Shifter — Environment Configuration
# Copy this file to .env and fill in your values.
#
# Required only for REST API mode.
# If using OpenClaw's MCP connection to Home Assistant, these are not needed.

# Home Assistant base URL (no trailing slash)
HA_URL=http://homeassistant.local:8123

# Long-Lived Access Token
# Generate at: http://homeassistant.local:8123/profile → Long-Lived Access Tokens
HA_TOKEN=your_long_lived_access_token_here
57 changes: 57 additions & 0 deletions skills/mrbese/grid-aware-energy-load-shifter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Grid-Aware Energy Load Shifter

An OpenClaw skill that bridges Home Assistant's energy management data to an autonomous AI agent. Reads real-time electricity prices, solar production forecasts, battery state of charge, and consumption data from Home Assistant. Schedules deferrable household loads - EV charging, HVAC pre-conditioning, pool pumps, water heaters, dishwashers, and laundry - to the cheapest rate windows, optimizing solar self-consumption and supporting demand response / virtual power plant (VPP) signals.

## What This Skill Does

| Capability | Description |
|---|---|
| **Price-Aware Scheduling** | Reads TOU (time-of-use), dynamic, and real-time pricing from Nordpool, ENTSO-e, Tibber, Octopus Energy, Amber Electric, and any utility rate plan worldwide |
| **Solar Self-Consumption** | Aligns load timing with solar production forecasts (Solcast, Forecast.Solar) to minimize grid import |
| **Battery Arbitrage** | Charges home batteries (Tesla Powerwall, Enphase) during off-peak/solar, discharges during peak |
| **HVAC Pre-Conditioning** | Pre-cools or pre-heats during cheap hours so the home coasts through expensive peak periods |
| **Water Heater Scheduling** | Heats during cheapest window, coasts through peak (4.5 kW typical load) |
| **Demand Response / VPP** | Sheds load during DR events, estimates DR payments for enrolled homes |
| **Cost Estimation** | Calculates per-device savings from each recommended load shift |

## Files

| File | Purpose |
|---|---|
| `SKILL.md` | Agent-facing instructions with load-shifting workflow, price interpretation, and DER optimization strategies |
| `scripts/ha_bridge.py` | REST API bridge - 5 CLI commands, zero pip dependencies, Python stdlib only |
| `references/energy_entities.md` | Comprehensive entity reference for 7+ energy pricing providers and all HA energy entity patterns |
| `.env.example` | Configuration template for HA REST API mode |

## Quick Start

```bash
# Set HA connection (REST API mode)
export HA_URL=http://homeassistant.local:8123
export HA_TOKEN=your_long_lived_access_token

# Discover energy entities
python3 scripts/ha_bridge.py discover

# Get full energy dashboard
python3 scripts/ha_bridge.py energy-summary

# Control a device
python3 scripts/ha_bridge.py call-service switch/turn_on --entity-id switch.ev_charger
```

## Technical Design

- **Zero external dependencies** - uses only Python standard library (`urllib`, `json`, `argparse`)
- **Universal compatibility** - no hardcoded rate schedules; reads whatever pricing entities HA provides
- **Dual connectivity** - works via HA MCP server or REST API fallback
- **JSON output** - all commands emit structured JSON for agent parsing
- **Exit codes** - `0` success, `1` API error, `2` configuration error

## Keywords

Distributed energy resources (DER), demand-side management (DSM), time-of-use (TOU) rate optimization, dynamic electricity pricing, residential load shifting, grid-edge intelligence, virtual power plant (VPP), demand response (DR), behind-the-meter optimization, home energy management system (HEMS), smart grid, energy arbitrage, solar self-consumption, battery storage optimization, EV managed charging, HVAC pre-conditioning, thermal storage.

---

Built by [Omer Bese](https://linkedin.com/in/omerbese) | Energy Systems Engineer | Columbia University MS Sustainability Management
145 changes: 145 additions & 0 deletions skills/mrbese/grid-aware-energy-load-shifter/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
name: grid-aware-energy-load-shifter
description: >
Grid-aware energy load shifter for Home Assistant. Reads real-time
electricity prices (TOU, time-of-use, dynamic pricing), solar production
forecasts, battery state of charge, and consumption data from Home
Assistant. Schedules deferrable household loads (EV charging, HVAC
pre-conditioning, pool pump, dishwasher, laundry, water heater) to
cheapest rate windows. Calculates cost savings, optimizes solar
self-consumption, and supports virtual power plant (VPP) demand response
signals. Works with Nordpool, ENTSO-e, Tibber, Octopus Energy, Amber
Electric, and any utility rate plan worldwide. Built for distributed
energy resource (DER) optimization and residential demand-side management.
metadata:
openclaw:
emoji: "⚡"
tags:
- energy
- home-assistant
- load-shifting
- time-of-use
- solar
- battery-storage
- demand-response
- vpp
- ev-charging
- smart-home
- DER
- grid-optimization
---

# Grid-Aware Energy Load Shifter

Shift heavy residential loads to the cheapest electricity hours using Home Assistant energy data.

## Quick Start

```bash
# Find all energy-related entities in HA
python3 {baseDir}/scripts/ha_bridge.py discover

# Get a full energy dashboard snapshot (prices, solar, consumption, batteries)
python3 {baseDir}/scripts/ha_bridge.py energy-summary

# Turn on the EV charger
python3 {baseDir}/scripts/ha_bridge.py call-service switch/turn_on --entity-id switch.ev_charger
```

## Connection

Two paths to reach Home Assistant:

1. **MCP (preferred):** If the HA MCP server is configured, use `mcporter call homeassistant.<tool>` directly.
2. **REST API:** Use `python3 {baseDir}/scripts/ha_bridge.py`. Requires `HA_URL` and `HA_TOKEN` environment variables (see [.env.example](.env.example)).

## Commands

| Command | What it does | Example |
|---|---|---|
| `discover` | List all energy entities | `ha_bridge.py discover` |
| `energy-summary` | One-shot dashboard (prices + consumption + solar + storage) | `ha_bridge.py energy-summary` |
| `status <entity>` | Read a single entity's state and attributes | `ha_bridge.py status sensor.electricity_price` |
| `call-service <d/s>` | Call any HA service | `ha_bridge.py call-service switch/turn_on --entity-id switch.ev_charger` |
| `history <entity>` | Get state changes over last N hours | `ha_bridge.py history sensor.grid_import --hours 24` |

All commands output JSON to stdout.

## Load-Shifting Workflow

Follow these steps when asked about energy optimization:

1. **Discover** available energy entities: run `discover` or `energy-summary`
2. **Read prices**: Check pricing entities' state and attributes — look for:
- Hourly price arrays in `today` / `tomorrow` / `prices_today` / `rates` attributes
- `price_level` attribute (CHEAP / NORMAL / EXPENSIVE)
- Current vs. average price comparison
3. **Identify deferrable loads**: Find `switch.*` entities for schedulable devices (EV charger, pool pump, dishwasher, washer/dryer, water heater)
4. **Find the cheapest window**: Scan hourly prices for the contiguous N-hour block with the lowest sum (N = estimated run time of device)
5. **Execute**: Call `switch/turn_on` at the optimal time, or `automation/trigger` if the user has an existing automation

## Interpreting Price Data

Different integrations expose prices differently:

- **Hourly arrays** (Nordpool, ENTSO-e, Octopus): Read `today`/`tomorrow` attributes → find cheapest hours
- **Price level** (Tibber): Read `price_level` → act when CHEAP or VERY_CHEAP
- **Real-time** (Amber Electric): Read 5-minute pricing → shift loads immediately when cheap
- **Utility meter tariffs**: Read `sensor.*_peak` vs `sensor.*_offpeak` → user's HA automations switch tariffs at configured times
- **Static TOU**: Read `current_price` attribute → compare against historical average

## Cost Savings Estimate

When recommending a shift, show estimated savings:

```
savings = (current_rate - cheapest_rate) × device_power_kw × run_duration_hours
```

## Solar Self-Consumption

If solar sensors exist, align loads with peak production:

- Read `sensor.forecast_solar_*` or `sensor.solcast_*` for today's forecast
- Shift loads to hours with highest expected production
- This avoids grid import entirely — savings = full retail rate × kWh shifted

## HVAC Pre-Conditioning

HVAC is the largest residential load (40-50% of electricity). Pre-cool or pre-heat during cheap/solar hours so the home coasts through expensive peak periods:

1. Read `climate.*` entities for current HVAC mode and setpoint
2. During cheapest window: lower cooling setpoint by 2-3F (pre-cool) or raise heating setpoint by 2-3F (pre-heat)
3. During peak window: raise cooling setpoint by 2-3F to coast on thermal mass
4. Savings estimate: 1.5-3 kW shifted × price differential × hours

## Water Heater Scheduling

Electric water heaters (4.5 kW typical) are ideal deferrable loads:

1. Find `switch.water_heater` or `water_heater.*` entities
2. Heat during cheapest/solar window to full temperature
3. Turn off during peak hours (tank maintains temperature for 4-6 hours)
4. Savings estimate: 4.5 kW × price differential × 3-4 hours/day

## Battery Arbitrage

If home battery entities exist (`sensor.battery_soc`, `sensor.powerwall_*`, `sensor.enphase_*`):

1. Read current state of charge and charge/discharge rate limits
2. Charge from grid during cheapest hours (or from solar)
3. Discharge to home during peak price hours to avoid grid import
4. Advanced: If battery supports grid export and VPP enrollment, discharge to grid during extreme price events ($2,000+/MWh)
5. Savings estimate: battery_capacity_kwh × (peak_rate - valley_rate)

## Demand Response / VPP Integration

For homes enrolled in utility demand response or virtual power plant programs:

1. Read demand response signal entities (if available via HA integration)
2. When DR event active: shed non-critical loads, pre-cool/pre-heat, discharge battery
3. Estimate DR payment: kW reduced × event duration × program rate

## Entity Reference

For detailed entity patterns across providers, read: [energy_entities.md](references/energy_entities.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Home Assistant Energy Entity Reference

Reference for interpreting energy-related entities in Home Assistant. Read this when you need deeper context about entity attributes or discovery patterns.

## Table of Contents

1. [Electricity Price Sensors](#electricity-price-sensors)
2. [Consumption Sensors](#consumption-sensors)
3. [Solar Production Sensors](#solar-production-sensors)
4. [Battery / Storage Sensors](#battery--storage-sensors)
5. [Utility Meter Entities](#utility-meter-entities)
6. [Controllable Devices](#controllable-devices)
7. [HVAC & Water Heater Entities](#hvac--water-heater-entities)
8. [Common HA Services for Load Control](#common-ha-services-for-load-control)
9. [Supported Integrations](#supported-integrations)

---

## Electricity Price Sensors

These track the current electricity rate from the user's utility provider.

| Integration | Typical Entity ID | Key Attributes |
|---|---|---|
| Nordpool | `sensor.nordpool_kwh_*` | `today` (24-element array of hourly prices), `tomorrow` (available after ~13:00), `current_price`, `average`, `peak`, `off_peak_1`, `off_peak_2`, `unit` |
| Tibber | `sensor.tibber_prices` | `price_level` (VERY_CHEAP / CHEAP / NORMAL / EXPENSIVE / VERY_EXPENSIVE), `estimated_annual_consumption` |
| ENTSO-e | `sensor.entsoe_*` | `prices_today` (hourly array), `prices_tomorrow`, `min_price`, `max_price`, `avg_price` |
| Amber Electric | `sensor.amber_*` | `price`, `renewables_percentage`, `spike_status` |
| Octopus Energy | `sensor.octopus_energy_*` | `rates` (array of rate objects with `start`, `end`, `value_inc_vat`) |
| Manual / Static | `sensor.electricity_price` | `current_price`, `unit_of_measurement` (e.g. USD/kWh) |
| Utility Meter Tariff | `sensor.daily_electricity_peak` | `tariff` (peak / offpeak / shoulder), `status` |

**How to find the cheapest window:** Read the hourly price array attributes (`today`/`tomorrow`/`prices_today`/`rates`), find the contiguous block of N hours with the lowest sum. That's your optimal load-shifting window.

---

## Consumption Sensors

Track energy drawn from the grid or consumed by devices.

| Pattern | Example Entity | Description |
|---|---|---|
| Grid import | `sensor.grid_consumption`, `sensor.grid_import_energy` | Total kWh imported from grid |
| Grid export | `sensor.grid_export_energy`, `sensor.grid_feed_in` | kWh returned to grid (solar) |
| Device power | `sensor.<device>_power` | Instantaneous watts (W) |
| Device energy | `sensor.<device>_energy` | Cumulative kWh consumed |
| Whole-home | `sensor.house_consumption`, `sensor.total_power` | Sum of all loads |

**Required attributes for Energy Dashboard compatibility:**
- `device_class: energy`
- `state_class: total_increasing`
- `unit_of_measurement: kWh`

---

## Solar Production Sensors

| Pattern | Example Entity | Key Attributes |
|---|---|---|
| Current production | `sensor.solar_production`, `sensor.pv_power` | Instantaneous W or kW |
| Total production | `sensor.solar_energy_today` | Cumulative kWh today |
| Forecast | `sensor.energy_production_today`, `sensor.energy_production_tomorrow` | From Forecast.Solar or Solcast |
| Solcast detail | `sensor.solcast_pv_forecast_*` | `detailedForecast` (30-min intervals), `forecast_today`, `forecast_tomorrow` |

**Self-consumption optimization:** Compare solar production forecast against planned load timing. Shifting loads to align with solar peaks avoids grid import entirely.

---

## Battery / Storage Sensors

| Pattern | Example Entity | Key Attributes |
|---|---|---|
| State of charge | `sensor.<battery>_soc`, `sensor.<battery>_battery_level` | Value in %, `device_class: battery` |
| Power flow | `sensor.<battery>_power` | Positive = charging, negative = discharging (W) |
| Capacity | `sensor.<battery>_energy_capacity` | Total capacity in kWh |

**Battery arbitrage:** Charge during off-peak or solar surplus. Discharge during peak to avoid expensive grid import.

---

## Utility Meter Entities

Home Assistant's Utility Meter helper creates tariff-aware sensors.

| Example | Description |
|---|---|
| `sensor.daily_electricity_peak` | kWh consumed during peak tariff |
| `sensor.daily_electricity_offpeak` | kWh consumed during off-peak tariff |
| `sensor.monthly_electricity` | Monthly total |

**Tariff switching:** HA automations call `utility_meter.select_tariff` at scheduled times to switch between `peak` and `offpeak`.

---

## Controllable Devices

These are the entities you control to shift loads:

| Domain | Example | Action |
|---|---|---|
| `switch` | `switch.ev_charger`, `switch.pool_pump`, `switch.dishwasher` | `switch.turn_on` / `switch.turn_off` |
| `automation` | `automation.charge_ev_offpeak` | `automation.trigger` to run now |
| `script` | `script.start_laundry_cycle` | `script.turn_on` to execute |
| `input_boolean` | `input_boolean.allow_ev_charging` | Toggle to enable/disable automations |
| `climate` | `climate.water_heater` | `climate.set_temperature` to pre-heat |

---

## HVAC & Water Heater Entities

| Pattern | Example Entity | Key Attributes |
|---|---|---|
| HVAC | `climate.thermostat`, `climate.heat_pump` | `hvac_mode`, `temperature`, `current_temperature` |
| Water heater | `switch.water_heater`, `water_heater.tank` | `current_temperature`, `target_temp_high` |
| HVAC power | `sensor.hvac_power`, `sensor.heat_pump_energy` | `device_class: power`, unit `W` or `kW` |

---

## Common HA Services for Load Control

```
switch.turn_on {"entity_id": "switch.ev_charger"}
switch.turn_off {"entity_id": "switch.pool_pump"}
automation.trigger {"entity_id": "automation.offpeak_dishwasher"}
script.turn_on {"entity_id": "script.delayed_charge"}
climate.set_temperature {"entity_id": "climate.thermostat", "temperature": 68}
homeassistant.turn_on {"entity_id": "switch.dryer"} # generic, works on any domain
homeassistant.turn_off {"entity_id": "switch.dryer"}
```

---

## Supported Integrations

| Integration | Price Entity Pattern | Forecast Available |
|---|---|---|
| Nordpool | `sensor.nordpool_*` | today + tomorrow arrays |
| ENTSO-e | `sensor.entsoe_*` | today + tomorrow arrays |
| Tibber | `sensor.tibber_*` | price_level attribute |
| Octopus Energy | `sensor.octopus_*` | current + upcoming rates |
| Amber Electric | `sensor.amber_*` | real-time 5-min pricing |
| Solcast | `sensor.solcast_*` | solar forecast |
| Forecast.Solar | `sensor.forecast_solar_*` | solar forecast |
| Tesla Powerwall | `sensor.powerwall_*` | battery SOC + grid status |
| Enphase | `sensor.enphase_*` | battery + solar + grid |
| Pila Energy | (upcoming) | mesh battery fleet |
Loading