sungrow-isolarcloud
A maintained fork of the pysolarcloud library for interacting with Sungrow's iSolarCloud API.
Install from PyPI:
pip install sungrow-isolarcloud
This fork adds:
- Support for requesting additional / custom measure points without modifying the upstream point map (useful for battery charge/discharge power fields that vary by inverter model).
- A per-device realtime helper for devices such as EV chargers (
Plants.async_get_device_realtime), which can optionally fall back to aUserAuthsession (passuser_auth=) when the OpenAPI per-device endpoint is unavailable for the account/region — returning the same{uuid: {code: {...}}}shape so callers need no changes. When the endpoint is unavailable and no fallback session is supplied it raisesDeviceEndpointUnavailable; an empty dict means "available, but this device type has no points".Plants.async_device_realtime_supported(...)probes the capability once per session. - A heartbeat helper for External EMS dispatch mode (
Control.async_heartbeat/Control.heartbeat_loop). - Convenience constants for dispatch command value sets (
Control.CHARGE_DISCHARGE_COMMANDS,Control.FORCED_CHARGING).
The package supports the following functionality:
- OAuth2 authentication
- Getting a list plants
- Getting details of a plant
- Getting devices of a plant
- Getting "real-time" data of a plant (Data is updated every 5 minutes according to Sungrow's documentation)
- Getting historical data
- Getting and updating grid control settings
Quirks
The iSolarCloud API is quite new and not very mature. Some tips:
- The authorisation flow is based on OAuth2 but doesn't work exactly as you would expect
- The
stateparameter is not passed back after to the authorisation step. This makes it more tricky to resume the flow in a client application. - User is asked to approve the authorisation if the flow is invoked again, e.g. in case the tokens have expired - unlike many OAuth2 implementations who will perform a "silent" authorisation if the user has already approved the access.
- The API documentation lists a lot of data points which do not seem to be returned from my inverter, it probably varies between models.
- There are different iSolarCloud servers for different regions, see the
pysolarcloud.Serverenum - API endpoints accept a language code but respond with Chinese text when when English is requested
Usage
Register your app
- Create an account in the iSolarCloud Developer Portal
- Create an app in the developer portal
- Answer "Yes" to authorize with OAuth2.0
- Enter a Redirect URL for your app (this can be changed later)
- Wait for approval by Sungrow
- Find the needed configuration details in the developer portal. You will need:
- Appkey
- Secret Key
- Application Id (This is shown as a query parameter within the Authorize URL in the developer portal)
Example
from pysolarcloud import Auth, Server
from pysolarcloud.plants import Plants
app_key = "your app key"
secret_key = "your secret key"
app_id = "your app id"
redirect_uri = "your redirect uri"
auth = Auth(Server.Europe, app_key, secret_key, app_id)
url = auth.auth_url(redirect_uri)
- Redirect user to
url - User selects plant(s) and grants authorisation
- iSolarCloud will redirect the user to
redirect_uriwith query parametercode
await auth.async_authorize(code, redirect_uri)
plants_api = Plants(auth)
plant_list = await plants_api.async_get_plants()
if plant_list:
print(f"{len(plant_list)} plants found:")
for plant in plant_list:
print(f"Plant ID: {plant["ps_id"]}, Name: {plant["ps_name"]}")
else:
print("No plants found.")
return
print("\nFetching detailed information for each plant...\n")
plant_ids = [str(plant["ps_id"]) for plant in plant_list]
plant_details = await plants_api.async_get_plant_details(plant_ids)
for plant in plant_details:
print(f"Details for Plant ID {plant["ps_id"]}: {plant}")
print("\nFetching real-time data for each plant...\n")
real_time_data = await plants_api.async_get_realtime_data(plant_ids)
for plant_id, data in real_time_data.items():
# Print only the data points where value is not None
data_values = {k: v for k, v in data.items() if v and v.get("value") is not None}
print(f"Real-time data for Plant ID {plant_id}: {data_values}")
The Auth class keeps the access between calls and refreshes it when needed. If you prefer to manage this state yourself, you can create your own subclass of AbstractAuth.
Grid Control
The Control class enables retrieving and updating grid control settings. Parameters and value sets are documented in the iSolarCloud Developer portal.
Example
from pysolarcloud.control import Control
from pysolarcloud.plants import DeviceType
devices = await plants_api.async_get_plant_devices(plant_id, device_types=[DeviceType.ENERGY_STORAGE_SYSTEM])
device_uuid = devices[0]["uuid"]
control_api = Control(auth)
# Fetch current config
current_settings = await control_api.async_read_parameters(device_uuid)
print(current_settings)
# Make an update using the canonical command values.
# energy_management_mode (10003) must leave Self-consumption for charge/discharge to actuate:
# 0 self-consumption, 2 compulsory/forced, 3 external energy dispatch, 4 VPP.
await control_api.async_update_parameters(
device_uuid,
{
"energy_management_mode": Control.encode_parameter("energy_management_mode", "compulsory"),
"charge_discharge_command": Control.CHARGE_DISCHARGE_COMMANDS["charge"],
"charge_discharge_power": "2500",
},
)
# When using External EMS / forced dispatch, send a heartbeat periodically.
# 10017 = external_ems_heartbeat, value is the heartbeat interval in seconds (1-1000).
# Appendix 10: send the heartbeat when switching EMS modes through the API.
await control_api.async_heartbeat(device_uuid, interval_seconds=60)
User-account login (unofficial, experimental)
In addition to the official OpenAPI OAuth flow (Auth), this fork provides UserAuth,
which logs in with a normal iSolarCloud user account (email + password) via the
reverse-engineered app/web API — no developer application required.
from pysolarcloud import Server, UserAuth
async with UserAuth(Server.Europe, "you@example.com", "password") as auth:
plants = await auth.async_get_plants()
print(plants)
⚠️ Unofficial and experimental. This is not Sungrow's documented OpenAPI. It may change or break without notice and its use may be subject to Sungrow's terms of service. The protocol was reimplemented clean-room from the MIT-licensed homebridge-platform-isolarcloud (see
NOTICE). Credentials are only sent to iSolarCloud over TLS and are never logged.
User-account read helpers
UserAuth mirrors the iSolarCloud app's read API. All of the following are read-only;
endpoint paths and parameter names were verified against the app, but where the app uses
undocumented enum values (e.g. date_type, query_type, fault type/share codes) those are
left as caller-supplied optional arguments and documented as unverified against a live device.
| Method | App endpoint |
|---|---|
async_get_plants() |
getPsList |
async_get_plant_detail(ps_id) |
getPsDetailWithPsType (realtime household view) |
async_get_plant_detail_daily(ps_id, date_id) |
getPsDetail (daily view) |
async_get_devices(ps_id) |
queryDeviceList |
async_get_device_realtime(ps_key, *, point_ids=None) |
queryDeviceRealTimeDataByPsKeys |
async_get_historical_data(...) |
queryMutiPointDataList |
async_get_charging_piles(ps_id) / async_get_charge_pile_overview(ps_id) |
getChargingPileList / getChargePileOverviewInfo |
async_get_charging_pile_realtime(uuid) / async_get_charging_pile_last_data(uuid) |
getChargingPileRealData / getChargingPileLastData |
async_get_charging_pile_property(uuid, point_id) |
getChargingPileProperty |
async_get_battery_capacity(ps_id) / async_get_soc_by_ps_id(ps_id) / async_get_soc_by_sn(bt_sn) |
getBatteryCapacityByPsIdV2 / querySocByPsId / querySocBySn |
async_get_battery_info(ps_id, ...) |
getPsBatteryInfo |
async_get_fault_count(ps_id) / async_query_faults(...) / async_get_fault_detail(fault_code) |
getDevFaultCountByPsId / queryFaultList / getFaultDetail |
async_get_open_fault_num() / async_get_unread_fault_count(...) |
getPsOpenFaultNum / getNotReadFaultCount |
async_get_household_storage_report(ps_id, ...) / async_get_energy_summary(ps_id, ...) |
getHouseholdStoragePsReport / getPsEnergySummaryInfo |
async_get_device_day_month_year_history(ps_key, ...) / async_get_device_minute_history(ps_key, ...) |
queryDevicePointsDayMonthYearDataList / queryDevicePointMinuteDataList |
async_get_home_setting(ps_id, home_setting_type) |
getHomeSettingDetail |
async_set_operation_mode(ps_id, uuid=…, device_type=…, energy_management_model=…) |
paramSetHomeSettingOperationMode |
async_get_discharge_template_info(ps_id, fast_discharging_uuid) |
getDischargeTemplateInfo |
async_add_or_update_discharge_plan(ps_id, week_days=…, cycle_type=…, …) |
addOrUpdateDischargePlan |
async_delete_discharge_plan(ps_id) / async_select_discharge_plan(ps_id) |
deleteDischargePlan / selectDischargePlan |
async_set_system_power_backup_param(ps_id, task_name=…, mode=…, status=…, config=…) |
setSysPowerBackupParam |
⚠️ Breaking change in 0.16.0 —
async_get_device_realtimenow takes a deviceps_key(fromasync_get_devices) as its single positional argument instead of(ps_id, device_sn), and returns data keyed by deviceuuid({uuid: {point_id: {"id", "value", "unit", "name"}}}) instead of a flat{point_id: {"value", "unit"}}map. It now posts toqueryDeviceRealTimeDataByPsKeys; the previous/v1/devService/queryDevicepath did not exist in the app. Migrate by passing the deviceps_keyand reading points under eachuuid.
Contributions
Ideas or contributions are welcome. I am not affiliated with Sungrow, I'm just another user of the API. My main use case will be a HomeAssistant integration based on this package.
See CONTRIBUTING.md for the development setup, the checks CI runs, and the
rules that main enforces — notably that commits must be signed and that pull requests
need the branch up to date with main.
Enjoy!
Metadata
Release files for sungrow-isolarcloud 0.18.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sungrow_isolarcloud-0.18.0.tar.gz | 57.6 kB | With provenance | Details for sungrow_isolarcloud-0.18.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sungrow_isolarcloud-0.18.0-py3-none-any.whl | Python 3 | none | any | Details for sungrow_isolarcloud-0.18.0-py3-none-any.whl |
Total release size: 114.5 kB
Release files / sungrow_isolarcloud-0.18.0.tar.gz
| Download URL | sungrow_isolarcloud-0.18.0.tar.gz |
|---|---|
| Size | 57.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3adf7c4466381943e23ed5828353cb0566e335041d592bc6752169342c00d4d3
|
|
BLAKE2b-256 checksum How to use checksums |
c5cf5aadfcf3fd4617afa86cfef1659b6c45d9eb6c6e6419fcfc6e6e6ea78721
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logRelease files / sungrow_isolarcloud-0.18.0-py3-none-any.whl
| Download URL | sungrow_isolarcloud-0.18.0-py3-none-any.whl |
|---|---|
| Size | 56.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
26af52d24b49a736f3f0df5f5d14eccd5af8549e85d454373141d7b00380b505
|
|
BLAKE2b-256 checksum How to use checksums |
10846bfed47f5e35522891581d3b7a94cac68ff3d5b79cf2936a5b562b4aa543
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logSecurity for sungrow-isolarcloud 0.18.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for sungrow_isolarcloud-0.18.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.