Skip to content

Repository files navigation

PeakShift

Live site License: MIT Python 3.11+ Price feeds Drivers

Website and live demo → steps-re.github.io/peakshift

Run your window AC on cheap electricity. PeakShift is an open-source controller that charges a plug-in battery during off-peak hours and runs your AC from that battery during peak hours. No electrician, no interconnection, no grid export. If you rent an apartment, this is battery arbitrage you can actually do.

Peak-hour electricity costs 2 to 10 times the off-peak rate on time-of-use plans. A window AC is the biggest plug-in load in most apartments and it runs hardest exactly when rates peak. Shifting it to stored off-peak power saves roughly $65 to $280 per year per 2 kWh battery depending on your utility (estimates, see Savings below).

Inspired by the category Every Electric pioneered in NYC. They give you managed hardware in ConEd territory. PeakShift is the DIY version for a battery you buy yourself, anywhere with a time-of-use rate.

How it works

Most LiFePO4 portable power stations (EcoFlow Delta, Bluetti, Anker Solix and others) have a UPS or passthrough mode. Your AC plugs into the battery. The battery plugs into the wall. When wall power is present the unit charges and passes power through. When wall power disappears the AC keeps running from the battery, switching in about 10 ms.

So the whole control problem reduces to one decision: when does the battery's input get power?

  • Off-peak: input on. Battery charges, AC runs on passthrough.
  • Peak: input off. AC runs from the battery.
  • Battery gets low during peak: input back on. Your AC never dies to save a dollar.

PeakShift makes that decision every 30 seconds, two ways:

  1. Smart plug (recommended, works with any passthrough battery): a Shelly Plug US between the wall and the battery input. PeakShift switches it locally over your LAN. No cloud.
  2. Battery API: for EcoFlow devices, PeakShift sets the AC charge rate to zero during peak through EcoFlow's developer API. Written to their published protocol but not yet bench-tested on hardware. Treat it as beta and prefer the smart plug.

Quickstart

git clone https://github.com/steps-re/peakshift && cd peakshift
python3 -m venv .venv && .venv/bin/pip install -e .
cp config.example.yaml config.yaml   # edit: your peak hours, your driver
.venv/bin/peakshift test-drive       # one off/on cycle to verify wiring
.venv/bin/peakshift run

Set your peak window by hand in config.yaml (it's printed on your utility bill), or look it up:

export NLR_API_KEY=...   # free key from https://developer.nlr.gov/signup/
.venv/bin/peakshift rates --zip 11201

peakshift rates lists the time-of-use tariffs for your ZIP from the NLR Utility Rate Database with the peak/off-peak spread for each. Rate databases go stale, so check the window against your bill before trusting it.

Dynamic prices (UK, EU, Australia, hourly US plans)

Outside fixed ToU windows, PeakShift can plan against live market prices. Swap the schedule: block for a prices: block and it picks the most expensive hours of each day to run on battery:

prices:
  provider: awattar        # see the table below
  params: {country: de}
  mode: top_hours          # battery during the day's priciest hours
  battery_hours: 4         # how long your battery carries the load
currency: EUR

peakshift prices shows today's price curve and the hours it plans to shift.

Provider Region Auth Verified live
urdb (schedule block) US ToU tariffs free NLR key yes
octopus_agile UK none yes
awattar Germany, Austria none yes
elering EE, LV, LT, FI none yes
spothintafi Finland none yes
comed US Illinois hourly none yes
pvpc Spain none yes
entsoe ~25 EU bidding zones free token not yet
tibber NO, SE, DE, NL account token not yet
amber Australia account token not yet

"Not yet" means written to the published API and unit-tested against recorded responses, but we haven't held a real token. If you run one, tell us how it went.

What you need

  • A time-of-use rate or a dynamic-price plan (ask your utility, most offer one).
  • A LiFePO4 power station with UPS/passthrough mode, sized to your AC. A 500 W window unit running a 5-hour peak wants roughly 2 kWh usable plus margin.
  • A way to switch the battery's input. Simplest is a smart plug: Shelly, Tasmota, or Kasa (about $25). Batteries that Home Assistant can control work through the homeassistant bridge driver, EcoFlow through its developer API, and Victron through Modbus TCP. Full matrix in docs/batteries.md.
  • Something to run PeakShift on: a Raspberry Pi, an old laptop, any always-on machine on the same LAN.

Safety, plainly

  • Keep total draw through a smart plug under 12 A (1,440 W) continuous. A big 15 A window unit does not belong behind a 15 A-rated plug at 100% duty.
  • Buy a battery listed to UL 2743 for indoor use. We don't certify anything, check the maker's spec page.
  • The battery cycles daily in this setup. LiFePO4 units are rated for 3,000+ cycles, which is 8+ years of summers. NMC units are not, avoid them here.
  • PeakShift fails toward grid power. Any error, low battery, or guard trip restores wall power to your AC. Comfort beats savings, always.

Savings, honestly

For a 2 kWh battery cycled once daily at 85% round-trip efficiency, our mid-2026 estimates by utility land between $65/yr (National Grid MA) and about $280/yr (SDG&E), with ConEd around $200/yr. Hardware runs $400 to $600 per kWh, so the battery pays itself back in roughly 4 to 6 years on arbitrage alone in the better territories. These are estimates from published tariffs, not guarantees. The data/ledger.csv file tracks what PeakShift actually shifted so you can see your own number.

Utilities and aggregators also run bring-your-own-device demand-response programs that pay for exactly the load reduction PeakShift performs. Enrollment and payment are between you and those programs. PeakShift doesn't enroll you in anything, it just does the physical load shifting.

Discharge to grid (EU and Australia, opt-in, off by default)

The default is behind-the-meter load shifting, which needs no interconnection anywhere. If you run a balcony-storage battery with a grid-tie microinverter (Marstek Venus and similar) in a market that allows it, PeakShift can also sell stored power back during the priciest hours. This is opt-in and gated:

export:
  enabled: true
  region: DE               # DE, AT, UK, AU only. US is refused.
  max_watts: 800           # capped to your region's legal limit
  min_sell_price: 0.20     # only sell above this price
  i_confirm_local_rules: true   # startup aborts unless this is true

US export is refused outright, because plug-in export is not permitted under UL 1741 and IEEE 1547. Read docs/regulations.md before enabling this anywhere. Passthrough power stations cannot export and will reject the config.

Central AC, no battery (thermostat pre-cooling)

Most homes, and almost the entire US South, have central AC that's hardwired, so the plug-in battery trick doesn't apply. For those homes PeakShift can store cold instead of electricity: it talks to a smart thermostat (Nest, ecobee, anything via Home Assistant), over-cools the house before the peak, then lets it coast through the peak with the compressor off, using the building's thermal mass as the battery.

thermostat:
  driver: homeassistant_climate
  params: {base_url: http://homeassistant.local:8123, climate_entity: climate.house}
  normal_temp: 74
  precool_temp: 70            # bank cold before the peak
  coast_temp: 78              # let it drift during the peak
  comfort_max_temp: 80        # hard ceiling, never coast past it
  precool_lead_minutes: 120
  occupancy_entity: binary_sensor.home_occupied   # optional
  away_max_temp: 84           # ride the peak harder when nobody's home

No hardware, works nationwide, and it's occupancy-aware: pre-cool gently when people or pets are home, coast harder when the house is empty. Comfort always wins, and any error falls back to normal cooling. Savings are lower per home than a battery, but the addressable market is every central-AC home instead of only window units.

Capacity-peak targeting (the high-value hours)

Energy arbitrage saves cents. Capacity and transmission-demand charges are set by a handful of system-peak intervals a year (ERCOT 4CP is four 15-minute intervals a summer, PJM PLC is five hours, ISO-NE ICAP is one hour), and ducking exactly those is worth far more, because the charge is a $/kW tag on a whole year of billing.

Add a capacity block and PeakShift shifts load during the predicted capacity window even when the energy price isn't spiking (capacity cost isn't in the price):

prices: {provider: comed, mode: threshold, peak_threshold: 0.50}
capacity:
  iso: ercot          # ercot | pjm | isone | caiso | generic
  threshold: 0.7      # call an event above this day-risk
  # event_dates: ["2026-07-15"]   # or force specific days

The day-risk model ships as a season/weekday heuristic. The real signal is the ISO's day-ahead system-load forecast against the running seasonal max, which plugs into one hook (risk_for_date). At fleet scale, peakshift fleet-plan --return-window 30 staggers each home's return to normal so the fleet doesn't create a rebound peak when the event ends.

Fleet and community VPP

One operator can coordinate many PeakShift homes into a virtual power plant. A utility, an aggregator, or a data center funding batteries for its neighbors can size and plan a fleet from a roster of sites (opaque ids only, no personal data):

peakshift fleet-report --roster sites.json     # capex, MW, annual value
peakshift fleet-plan --roster sites.json --shed-kw 100000 --window 16:00-21:00

The no-export load-shifting fleet needs no interconnection studies, so it scales at the speed of shipping boxes. An export fleet is regulated at every site.

Status

v0.3. Working and verified live: manual schedules, URDB lookup, seven price feeds, Shelly/Tasmota drivers, simulate driver, guards, savings ledger, and the fleet planning and reporting commands. Written but untested on hardware: EcoFlow, Home Assistant bridge, Kasa, MQTT (covers bluetti_mqtt setups), Victron and Marstek Modbus, and the grid-export path. If you own any of these, running peakshift test-drive and filing an issue with the result is the single most useful contribution right now. Wanted next: Home Assistant add-on packaging and a real control plane for fleet dispatch (OpenADR / IEEE 2030.5).

License

MIT.

About

Open-source home battery arbitrage: charge when power is cheap, run your AC off the battery through the evening peak. No grid export, no electrician. Scales into a community virtual power plant.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages