A battery scheduler
Project description
The MoaT Battery Scheduler
% start synopsis % start main
This module implements a scheduling algorithm for a photovoltaic system with battery. It considers varying projected PV gain, local load, and buy/sell prices for grid power.
% end synopsis
Operation
The standalone program is started with the command moat ems sched analyze.
Use --help for usages.
Channels
moat ems sched analyze reads the data it needs from a variety of possible
channels. Likewise, it sends its output to them.
% end main
Data per interval
load
The internal load, in kW.
Source: You should extrapolate from past system behavior. This is where a neural network might be a good idea.
:::{Note} time-of-day and day-of-week inputs to a neural net should be cyclic, i.e. instead of one input you use two, with sin(X*2*pi) and cos(X*2*pi) as X goes from 0 to 1. :::
One value per interval.
solar
The projected solar yield, in kW.
Source: Calculate from weather forecast and solar array positioning. There are services that do this for you.
One value per interval.
price_sell
Price you get per kW you sell to the grid. Depending on your contract this value might be fixed, set some time in advance, or maybe you need to extrapolate from past prices.
One value per interval.
price_buy
The cost per kW you buy from the grid.
As "price_sell". There's a mode that calculates buy from sell price.
One value per interval.
Fixed data
soc
The charge in your battery which your calculation starts off with.
Outputs
Output data contain these values:
- grid: power to feed to / pull from the grid
- soc: projected battery state-of-charge at the end of the interval
- batt: power to feed to / pull from the battery
- money: income / cost during this interval
result
Data for the first interval is sent to this channel. You typically use this to control your inverter.
results
This channel receives projected data for all intervals. You typically use this to display a nice graph.
Configuration
MoaT uses a YAML-based configuration.
moat ems sched dump prints the config data. You can modify it in three
ways:
-
add your config data to your global MoaT configuration:
ems: sched: solar: lat: 50.2 long: 11.8 -
load a config file with
moat ems sched -c ‹path›:solar: lat: 50.2 long: 11.8 -
modify the configuration from the command line:
moat ems sched -e solar.lat 50.2 -e solar.long 11.8
There's an -e and a -v option. The former is evaluated, i.e.
used for numerical values, while the latter is not (text, file paths).
Later values override earlier ones.
Sources
This section concerns both sources (i.e. ways to get data into the scheduler) and sinks (ways to get them back out).
You can use moat ems sched modes to list the scheduler's supported inputs
and outputs. Each mode supports a subset of data sources.
You configure which input/output to use with the mode.‹channel›
configuration. Thus, to load the read the SoC from a file you'd use:
mode:
soc:
file
data:
file:
soc: "/path/to/whereever.cvs"
or, equivalently,
moat ems sched -v mode.soc file -v data.file.soc /path/to/whereever.cvs analyze.
file
Source for per-interval data. Files consist of lines with one float number each. There's no support for comments, blank lines, or other fanciness.
file2
Source for price_buy that's derived from price_sell.
stdout
YAML data for either the first result results
Config hints
Panels
Your solar array can have multiple groups of panels.
Battery
The battery.soc.value.current and battery.soc.value.end configurations
assign a value to a full battery, during / at the end of the simulation.
This tells the simulator that you want to keep the battery charged, and prevents it from draining the battery for the monetary value of its energy. This is a real problem for short simulation runs.
Best results if the "end" value is somewhere between the buy and sell price of the battery's energy. The "current" value should be smaller; it biases the system towards keeping the battery charged.
The simulator tolerates when you start off with a SoC that's outside of the min/max range, but it (currently) will force the battery to be in that range during the first time slot. Fixing this is planned.
Algorithm
The scheduler uses a simple linear optimizer (for some value of "simple" …) based on Google's OR Tools. It models a DC-connected battery and solar array.
TODO
Modeling an AC-connected solar array is straightforward but hasn't been implemented yet.
Currently we're using a linear optimizer. There are a heap of non-linear extensions that would really improve the simulation:
-
Grid power that becomes more expensive beyond a threshold
-
inverter/charger/battery efficiencies that depend on the load
-
Inverter efficiency decreases when it runs on high load for too long (needs cooling).
-
the maximum battery charge/discharge power decreases when close to the top/bottom of SoC
-
support discretionary loads (e.g. an electric car that requires 4h of max power to be charged, and you need it to be fully charged by tomorrow evening)
-
some discretionary loads can be interrupted (electric car); others can't (oven, washing machine).
-
some discretionary loads are intermittent; e.g. a heat pump with an 8-hour buffer that can be "recharged" by running the pump for three hours. (Efficiency might depend on outside temperature.)
-
some discretionary loads are less efficient when not running on full power. E.g. the car might take 9h to charge at half load because of charger inefficiency and/or because it consumes some power when it's turned on.
-
some loads require reactive power; some older electric cars, like the 1st gen Renault Zoë, are notorious for this. If you run such a load while offsetting local consumption from PV or battery, the result is that you send all that reactive power to the grid, with a cos(φ) of (close to) zero. This may or may not be allowed.
-
In some countries you get subsidized for the energy you sell to the grid so that you earn more than you'd pay when you buy it. This has a couple of implications:
- Obviously you can't sell and buy power at the same time.
- The control algorithm needs to remember how much of the battery's energy has been imported from the grid; it must not feed that energy back to the grid.
- Using energy from the PV array to power local loads de-contaminates the battery even if the SoC doesn't change: It's conceptually the same as taking energy from the battery, then recharging the battery from solar.
There are several services that supply weather and PV forecasts. They should be supported.
Batteries don't want to be fully charged / discharged for too long. We want the scheduler to avoid that.
Some batteries need regular balancing. We want the scheduler to prefer to fully charge the battery weekly, and force it to do so every 20 days. (Numbers are an example.)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file moat_ems_sched-0.2.16.tar.gz.
File metadata
- Download URL: moat_ems_sched-0.2.16.tar.gz
- Upload date:
- Size: 17.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3df5b05ddc1a718feb013578cff01e19f5edcf6db9e6282924206719bc81cb1
|
|
| MD5 |
166d1e9d4383b28809b7175260000be8
|
|
| BLAKE2b-256 |
6bfb6c0ee1458df6f9ce1ad7978d8fe8ae95b3676d3a71fe0dabacafba72797d
|
File details
Details for the file moat_ems_sched-0.2.16-py3-none-any.whl.
File metadata
- Download URL: moat_ems_sched-0.2.16-py3-none-any.whl
- Upload date:
- Size: 16.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27765c47845fbc07dcfdd42d15c9dde57311978ef9426f57099ac75172509460
|
|
| MD5 |
438b1d16269de6fe6a50aab3b6b227b5
|
|
| BLAKE2b-256 |
b6051fb8b169d2bc1ce8ee62f2724e869421995a17b76ff146588faaff0af178
|