Python library for monitoring and controlling solar panels, inverters, batteries and power retailers. an AlphaESS battery/inverter using the AlphaCloud opne API
- Amber (Australia)
- AlphaESS (using the Open API)
- AlphaESS (using the Open API)
- Goodwe (using the Open API) - in development
Register at https://open.alphaess.com/ for a (free) account to get your Developer ID (AppID) and Developer Secret (AppSecret).
Once registered, add your battery/inverter to the developer account via the web UI. (Adding a battery/inverter can also be automated using the get_verification_code()
and bind_system()
methods)
from openpower.alphaess import AlphaESS
APP_ID = "the AppID from step 1"
APP_SECRET = "the AppSecret from step 1"
api = AlphaESS(app_id=APP_ID, app_secret=APP_SECRET)
devices = api.list_systems()
print(devices)
for device in devices:
print("Currently consuming/feeding in:", api.for_device(device["sysSn"]).get_realtime_power_usage()["pgrid"])
Parameters:
app_id
: (str) (required) The app ID of your developer accountapp_secret
: (str) (required) The app secret of your developer accountdevice_serial_number
: (str) (optional) If specified, this will be used as the default serial number for methods related to a specific device, if none is specified in the method.
A convenience wrapper that clones the current instance and sets the serial number so that further calls do not need the serial number passed in. Every device-specified method can have the serial number provided in the method, in the class constructor or using this method.
Parameters:
serial_number
: The serial number of the device to scope future requests to, available fromlist_systems()
Returns:
A new instance of AlphaESS
with the serial number set
Lists the available systems to monitor/control. Additional systems can be added via the web UI or by calling get_verification_code()
and bind_system()
. Systems can also be removed with unbind_system()
.
Returns:
A list of systems, uncluding serial number (sysSn
) and model, that are whitelisted for this developer account
This is the first step to "binding" (adding) a new system to the developer account to allow it to be monitored and controlled. It will send an enamil to the registered owner of the system with a verification code that can be used on bind_system()
Parameters:
check_code
: (str) (required) The check code shown on the battery/inverter's physical label below the serial numberserial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns: Nothing.
Note that this method will email the battery/inverter's owner with a code, so check the details thoroughly.
Binds (adds) a battery/inverter to the developer's account to allow it to be monitored and controlled. This can only be done after calling get_verification_code()
(or via the web UI).
Parameters:
verification_code
: (str) (required) The code which was sent via email to the registered owner when callingget_verification_code()
. This is not the check code.serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns:
Nothing. The system will now be visible when you call list_systems()
Unbind (remove) a battery/inverter from the developer account.
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns: Nothing.
Gets the current power usage, typically in 30 second blocks.
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns: A dictionary of real-time data from the battery:
Field | Description | In-App Equivalent | Unit |
---|---|---|---|
ppv |
PV Power | Solar Power | W |
pload |
Power Load | Load | W |
soc |
Battery charge level | State of Charge | % [0...1] |
pgrid |
Grid Consumption (if negative, this is the feed-in value) | Grid Consumption / Feed-In | W |
pbat |
Power from battery (if negative, battery is charging) | Battery | W |
pev |
Total power of charging pile | ? | W |
Gets an overall summary of the system, including total power, CO2 savings, trees planted and profit/payback.
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns:
A dictionary of fields (todo: document these in detail). All electricity values are in kWh, all % are [0...1], CO2 is in kg and todayIncome
and totalIncome
is in the currency specified by moneyType
.
Gets the power usage for a specific day
Parameters:
date
(datetime.date) The date to get data forserial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Gets the energy usage for a specific day (todo: document the difference between power and energy - this is evident in the returned fields)
Parameters:
date
(datetime.date) The date to get data forserial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Gets the charging settings
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns:
Field | Description |
---|---|
batHighCap |
% to stop charging from grid at [0...1] |
gridCharge |
Whether to charge from the grid (0 or 1) |
timeChaf1 |
Start time of charging period 1 (HH:mm, 24 hour time, must be a 15 min interval) |
timeChae1 |
End time of charging period 1 (HH:mm, 24 hour time, must be a 15 min interval) |
timeChaf2 |
Start time of charging period 2 (HH:mm, 24 hour time, must be a 15 min interval) |
timeChae2 |
End time of charging period 2 (HH:mm, 24 hour time, must be a 15 min interval) |
set_charging_settings(stop_level: float, use_grid: bool, first_period: tuple[datetime.time, datetime.time], second_period: tuple[datetime.time, datetime.time])
Parameters:
stop_level
(float) % to stop charging from the grid at [0...1]use_grid
(bool) True to charge from the grid, False not tofirst_period
(tuple ofdatetime.time
) The start and end time of charging period 1 (the minutes for both fields must be one of :00, :15, :30, :45)second_period
(tuple ofdatetime.time
) The start and end time of charging period 2 (the minutes for both fields must be one of :00, :15, :30, :45)serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Gets the discharging settings
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns:
Field | Description |
---|---|
batUseCap |
% to stop discharging at [0...1] |
ctrDis |
Whether to enable time-based discharge control (0 or 1) |
timeDisf1 |
Start time of discharging period 1 (HH:mm, 24 hour time, must be a 15 min interval) |
timeDise1 |
End time of charging period 1 (HH:mm, 24 hour time, must be a 15 min interval) |
timeDisf2 |
Start time of discharging period 2 (HH:mm, 24 hour time, must be a 15 min interval) |
timeDise2 |
End time of discharging period 2 (HH:mm, 24 hour time, must be a 15 min interval) |
set_discharging_settings(stop_level: float, enable_time_control: bool, first_period: tuple[datetime.time, datetime.time], second_period: tuple[datetime.time, datetime.time])
Parameters:
stop_level
(float) % to stop discharging at [0...1]enable_time_control
(bool) True to use time-based discharging control, Flase not tofirst_period
(tuple ofdatetime.time
) The start and end time of discharging period 1 (the minutes for both fields must be one of :00, :15, :30, :45)second_period
(tuple ofdatetime.time
) The start and end time of discharging period 2 (the minutes for both fields must be one of :00, :15, :30, :45)serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Get a list of the the EV chargers in the battery system.
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns: A list of the EV chargers model and serial number.
Get the total maximum EV current draw allowed.
Parameters:
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns: The maximum current, in Amps, as a float
Set the maximum EV current draw to current_draw
Parameters:
current_draw
(float) The maximum current draw, in Amps, as a floatserial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Returns: Nothing if succesful. As with all requests, an exception will be raised if an error occurs.
Get the status of an EV charger
Parameters:
charger_serial_number
(str) The serial number to retrieve status for, seeget_ev_charger_list()
serial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
Enable or disable an EV charger
Parameters:
charger_serial_number
(str) The serial number to retrieve status for, seeget_ev_charger_list()
charging
(bool) True to enable the charger, False to disable chargingserial_number
(str) (optional) The serial number of the battery/inverter. This can alternatively be passed in via the constructor or by using thefor_device()
helper method
This is a direct implementation of Amber's developer API.
You must be an Amber customer to get a developer token.
- Login to the customer portal via the web UI
- In Settings, enable Developer Mode and refresh the page
- In For Developers (which appears after step #2), generate an API token
from openapi.amber import Amber
api = Amber(token="your API token from step 1")
sites = api.list_sites()
for site in sites:
print("Current prices are:", api.for_site(site["id"]).get_current_prices(previous=0, next=0))
Parameters:
token
(str) The API token to use (from the developer portal)site
(str) (optional) If specified, the default site ID to use if none is specified in the method and thefor_site()
helper method is not utilsied.
A convenience wrapper that clones the current instance and sets the site ID so that further calls do not need the site ID passed in. Every site-specified method can have the site ID provided in the method, in the class constructor or using this method.
Parameters:
site
: The site ID to scope future requests to, available fromlist_sites()
Returns:
A new instance of Amber
with the site ID set
If a previous API call has been made (excluding get_current_renewables()
), this will provide the latest rate limit information to assist in throttling additional requests. Currently, Amber allows 50 requests per 5 minutes.
Parameters: None.
Returns: If an API request has been made previously, this returns an object with:
limit
The maximum allowed requests in the time windowremaining
The remaining requests allowed in the time windowreset
The number of seconds until the count will be resetpolicy
The ratelimiting policy in effectrefreshed
(datetime.datetime) The time the rate limits were last retrieved (i.e. the tiem of the last API call)
In addition, there are two helper methods:
get_estimated_reset()
which returns adatetime.datetime
of when the rate limit will reset. This could be in the past ifrefreshed
is not recent.get_time_window()
which returns the current time window used for rate limiting. This is done by crudely parsing thepolicy
and could break if a more complex policy was implemented.
If there is no rate limit information yet, returns None
get_current_renewables(state: State, previous: Optional[int], next: Optional[int], resolution: Optional[int])
Gets the current % of renewables in the grid for a specific state. This request is not rate-limited and does not return rate-limit information so does not affect get_ratelimits()
Parameters:
state
(State) The state to get data for - seelist(State)
to get a list of allowed Statesprevious
(int) (optional) The number of prior data points to retrievenext
(int) (optional) The number of future predictions to retrieveresolution
(int) (optional) The time resolution (in minutes) to retrieve. Currently only supports 30
Returns: Information about the percentage of renewables in the grid
Example:
from openpower.amber import Amber, State
AMBER_TOKEN = "Your token here"
amber = Amber(AMBER_TOKEN)
print("Available states:", list(State))
print("Current renewables:", amber.get_current_renewables(State.VICTORIA, previous=0, next=0))
Gets a list of available sites linked to the current API token
Parameters: None
Returns:
A list of sites with ID, NMI, status and network. The ID is used as the site ID in other methods. At current, it appears customers can have only one active site, but may have multiple sites if they've moved address, so it is best to filter the results by status=active
.
get_current_prices(previous: Optional[int], next: Optional[int], resolution: Optional[int], site: Optional[str])
Get the current price of electricity on all channels. The results are supposed to be ordered by General, Controlled Load then Feed In (solar) however there have been times when this wasn't being done by Amber's API servers, so it is recommended to filter by channel
Parameters:
previous
(int) (optional) The number of prior data points to retrievenext
(int) (optional) The number of future predictions to retrieveresolution
(int) (optional) The time resolution (in minutes) to retrieve. Currently only supports 30
Returns: A list of channels and prices
Get historical price data for a site
Parameters:
start
(datetime.date) (optional) The first day to retrieve data for (inclusive), defaults to todayend
(datetime.date) (optional) The last day to retrieve data for (inclusive), defaults to todayresolution
(int) (optional) The time resolution (in minutes) to retrieve. Currently only supports 5 or 30 (default)
Returns: A list of pricing data for all channels. Note: This can take a very long time to return if a large amount of data is requested.
Get the usage data for a site
Parameters:
start
(datetime.date) (optional) The first day to retrieve data for (inclusive), defaults to todayend
(datetime.date) (optional) The last day to retrieve data for (inclusive), defaults to todayresolution
(int) (optional) The time resolution (in minutes) to retrieve. Currently only supports 30 (default)
Returns: A list of pricing data for all channels. Note: This can take a very long time to return if a large amount of data is requested. The documentation states it should be 30 days or less.