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
178 changes: 177 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ Package to retrieve PV information from the growatt server.
Special thanks to [Sjoerd Langkemper](https://github.com/Sjord) who has provided a strong base to start off from https://github.com/Sjord/growatt_api_client
These projects may merge in the future since they are simmilar in code and function.

This library supports both the classic password-based API and the token-based V1 API, officially supported by Growatt. Currently, the V1 API implementation supports MIN and SPH devices, where MIN broadly corresponds to classic TLX and SPH to classic MIX. If your inverter supports the V1 API, it is encouraged to use this over the classic API, as it offers better security, more features, and more relaxed rate limiting.

## Usage

### Legacy API

Uses username/password basic authentication

```python
import growattServer

Expand All @@ -16,16 +22,39 @@ login_response = api.login(<username>, <password>)
print(api.plant_list(login_response['user']['id']))
```

### V1 API

The public v1 API requires token-based authentication

```python
import growattServer

api = growattServer.OpenApiV1(token="YOUR_API_TOKEN")
#Get a list of growatt plants.
plants = api.plant_list_v1()
print(plants)
```

## Methods and Variables

### Methods

Any methods that may be useful.

`api.login(username, password)` Log into the growatt API. This must be done before making any request. After this you will be logged in. You will want to capture the response to get the `userId` variable.
#### Legacy API Methods

`api.login(username, password)` Log into the growatt API. This must be done before making any request. After this you will be logged in. You will want to capture the response to get the `userId` variable. Should not be used for public v1 APIs.

`api.plant_list(user_id)` Get a list of plants registered to your account.

`api.plant_list_v1()` Get a list of plants registered to your account, using public v1 API.

`api.plant_details_v1(plant_id)` Get detailed information about a power station, using public v1 API.

`api.plant_energy_overview_v1(plant_id)` Get energy overview data for a plant, using public v1 API.

`api.plant_energy_history_v1(plant_id, start_date, end_date, time_unit, page, perpage)` Get historical energy data for a plant for multiple days/months/years, using public v1 API.

`api.plant_info(plant_id)` Get info for specified plant.

`api.plant_settings(plant_id)` Get the current settings for the specified plant
Expand All @@ -38,6 +67,8 @@ Any methods that may be useful.

`api.device_list(plant_id)` Get a list of devices in specified plant.

`api.device_list_v1(plant_id)` Get a list of devices in specified plant using the public v1 API.

`api.inverter_data(inverter_id, date)` Get some basic data of a specific date for the inverter.

`api.inverter_detail(inverter_id)` Get detailed data on inverter.
Expand Down Expand Up @@ -96,6 +127,54 @@ Any methods that may be useful.

`api.update_noah_settings(serial_number, setting_type, parameters)` Applies the provided parameters (dictionary or array) for the specified setting on the specified noah device; see 'Noah settings' below for more information

#### V1 API Methods

`api.plant_list()` Get a list of plants registered to your account, using public v1 API.

`api.plant_details(plant_id)` Get detailed information about a power station, using public v1 API.

`api.plant_energy_overview(plant_id)` Get energy overview data for a plant, using public v1 API.

`api.plant_energy_history(plant_id, start_date, end_date, time_unit, page, perpage)` Get historical energy data for a plant for multiple days/months/years, using public v1 API.

`api.device_list(plant_id)` Get a list of devices in specified plant using the public v1 API.

`api.min_energy(device_sn)` Get current energy data for a min inverter, including power and energy values.

`api.min_detail(device_sn)` Get detailed data for a min inverter.

`api.min_energy_history(device_sn, start_date=None, end_date=None, timezone=None, page=None, limit=None)` Get energy history data for a min inverter (7-day max range).

`api.min_settings(device_sn)` Get all settings for a min inverter.

`api.min_read_parameter(device_sn, parameter_id, start_address=None, end_address=None)` Read a specific setting for a min inverter.

`api.min_write_parameter(device_sn, parameter_id, parameter_values)` Set parameters on a min inverter. Parameter values can be a single value, a list, or a dictionary.

`api.min_write_time_segment(device_sn, segment_id, batt_mode, start_time, end_time, enabled=True)` Update a specific time segment for a min inverter.

`api.min_read_time_segments(device_sn, settings_data=None)` Read all time segments from a MIN inverter. Optionally pass settings_data to avoid redundant API calls.

`api.sph_detail(device_sn)` Get detailed data for an SPH hybrid inverter.

`api.sph_energy(device_sn)` Get current energy data for an SPH inverter, including power and energy values.

`api.sph_energy_history(device_sn, start_date=None, end_date=None, timezone=None, page=None, limit=None)` Get energy history data for an SPH inverter (7-day max range).

`api.sph_settings(device_sn)` Get all settings for an SPH inverter.

`api.sph_read_parameter(device_sn, parameter_id, start_address=None, end_address=None)` Read a specific setting for an SPH inverter.

`api.sph_write_parameter(device_sn, parameter_id, parameter_values)` Set parameters on an SPH inverter. Parameter values can be a single value, a list, or a dictionary.

`api.sph_write_ac_charge_time(device_sn, period_id, charge_power, charge_stop_soc, start_time, end_time, mains_enabled=True, enabled=True)` Update a specific AC charge time period for an SPH inverter (periods 1-3).

`api.sph_write_ac_discharge_time(device_sn, period_id, discharge_power, discharge_stop_soc, start_time, end_time, enabled=True)` Update a specific AC discharge time period for an SPH inverter (periods 1-3).

`api.sph_read_ac_charge_times(device_sn, settings_data=None)` Read all AC charge time periods from an SPH inverter. Optionally pass settings_data to avoid redundant API calls.

`api.sph_read_ac_discharge_times(device_sn, settings_data=None)` Read all AC discharge time periods from an SPH inverter. Optionally pass settings_data to avoid redundant API calls.

### Variables

Some variables you may want to set.
Expand All @@ -118,6 +197,8 @@ The library can be initialised to introduce randomness into the User Agent field

This has been added since the Growatt servers started checking for the presence of a `User-Agent` field in the headers that are sent.

#### Legacy API Initialization

By default the library will use a pre-set `User-Agent` value which identifies this library while also appearing like an Android device. However, it is also possible to pass in parameters to the intialisation of the library to override this entirely, or just add a random ID to the value. e.g.

```python
Expand All @@ -128,6 +209,12 @@ api = growattServer.GrowattApi(True) # Adds a randomly generated User ID to the
api = growattServer.GrowattApi(False, "my_user_agent_value") # Overrides the default and uses "my_user_agent_value" in the User-Agent header
```

#### V1 API Initialization

```python
api = growattServer.GrowattApiV1(token="YOUR_API_TOKEN") # Initialize with your API token
```

Please see the `user_agent_options.py` example in the `examples` directory if you wish to investigate further.

## Examples
Expand Down Expand Up @@ -240,11 +327,100 @@ The four functions `update_tlx_inverter_setting`, `update_mix_inverter_setting`,

Only the settings described above have been tested with `update_tlx_inverter_setting` and they all take only one single parameter. It is very likely that the function works with all settings returned by `tlx_get_enabled_settings`, but this has not been tested. A helper function `update_tlx_inverter_time_segment` is provided for the settings that require more than one parameter.

## MIN/TLX Inverter Settings Using V1 API

For MIN/TLX systems, the public V1 API provides a more robust way to read and write inverter settings:

* **Read Parameter**
* function: `api.min_read_parameter`
* parameters:
* `device_sn`: The device serial number
* `parameter_id`: Parameter ID to read (e.g., "discharge_power")
* `start_address`, `end_address`: Optional, for reading registers by address

* **Write Parameter**
* function: `api.min_write_parameter`
* parameters:
* `device_sn`: The device serial number
* `parameter_id`: Parameter ID to write (e.g., "ac_charge")
* `parameter_values`: Value to set (single value, list, or dictionary)

* **Time Segments**
* function: `api.min_write_time_segment`
* parameters:
* `device_sn`: The device serial number
* `segment_id`: Segment number (1-9)
* `batt_mode`: Battery mode (0=Load First, 1=Battery First, 2=Grid First)
* `start_time`: Datetime.time object for segment start
* `end_time`: Datetime.time object for segment end
* `enabled`: Boolean to enable/disable segment

* **Read Time Segments**
* function: `api.min_read_time_segments`
* parameters:
* `device_sn`: The device serial number
* `settings_data`: Optional settings data to avoid redundant API calls

## SPH Inverter Settings Using V1 API

For SPH (hybrid inverter) systems, the public V1 API provides methods to read and write inverter settings. SPH inverters have different time period configurations compared to MIN inverters:

* **Read Parameter**
* function: `api.sph_read_parameter`
* parameters:
* `device_sn`: The device serial number
* `parameter_id`: Parameter ID to read (e.g., "discharge_power")
* `start_address`, `end_address`: Optional, for reading registers by address

* **Write Parameter**
* function: `api.sph_write_parameter`
* parameters:
* `device_sn`: The device serial number
* `parameter_id`: Parameter ID to write (e.g., "ac_charge")
* `parameter_values`: Value to set (single value, list, or dictionary)

* **AC Charge Time Periods**
* function: `api.sph_write_ac_charge_time`
* parameters:
* `device_sn`: The device serial number
* `period_id`: Period number (1-3)
* `charge_power`: Charging power percentage (0-100)
* `charge_stop_soc`: Stop charging at this SOC percentage (0-100)
* `start_time`: Datetime.time object for period start
* `end_time`: Datetime.time object for period end
* `mains_enabled`: Boolean to enable/disable grid charging (default: True)
* `enabled`: Boolean to enable/disable period (default: True)

* **AC Discharge Time Periods**
* function: `api.sph_write_ac_discharge_time`
* parameters:
* `device_sn`: The device serial number
* `period_id`: Period number (1-3)
* `discharge_power`: Discharge power percentage (0-100)
* `discharge_stop_soc`: Stop discharging at this SOC percentage (0-100)
* `start_time`: Datetime.time object for period start
* `end_time`: Datetime.time object for period end
* `enabled`: Boolean to enable/disable period (default: True)

* **Read AC Charge Time Periods**
* function: `api.sph_read_ac_charge_times`
* parameters:
* `device_sn`: The device serial number
* `settings_data`: Optional settings data to avoid redundant API calls

* **Read AC Discharge Time Periods**
* function: `api.sph_read_ac_discharge_times`
* parameters:
* `device_sn`: The device serial number
* `settings_data`: Optional settings data to avoid redundant API calls

## Noah Settings

The noah settings function allow you to change individual values on your noah system e.g. system default output power, battery management, operation mode and currency
From what has been reverse engineered from the api, each setting has a `setting_type` and a set of `parameters` that are relevant to it.

Known working settings & parameters are as follows (all parameter values are strings):

* **Change "System Default Output Power"**
* function: `api.update_noah_settings`
* setting type: `default_power`
Expand Down
93 changes: 93 additions & 0 deletions examples/min_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import growattServer
import datetime
import json
import requests

"""
# Example script controlling a MID/TLX Growatt (MID-30KTL3-XH + APX battery) system using the public growatt API
# You can obtain an API token from the Growatt API documentation or developer portal.
"""

# Get the API token from user input or environment variable
# api_token = os.environ.get("GROWATT_API_TOKEN") or input("Enter your Growatt API token: ")

# test token from official API docs https://www.showdoc.com.cn/262556420217021/1494053950115877
api_token = "6eb6f069523055a339d71e5b1f6c88cc" # gitleaks:allow

try:
# Initialize the API with token instead of using login
api = growattServer.OpenApiV1(token=api_token)

# Plant info
plants = api.plant_list()
print(f"Plants: Found {plants['count']} plants")
plant_id = plants['plants'][0]['plant_id']

# Devices
devices = api.device_list(plant_id)

for device in devices['devices']:
if device['type'] == 7: # (MIN/TLX)
inverter_sn = device['device_sn']
print(f"Processing inverter: {inverter_sn}")

# Get device details
inverter_data = api.min_detail(inverter_sn)
print("Saving inverter data to inverter_data.json")
with open('inverter_data.json', 'w') as f:
json.dump(inverter_data, f, indent=4, sort_keys=True)

# Get energy data
energy_data = api.min_energy(device_sn=inverter_sn)
print("Saving energy data to energy_data.json")
with open('energy_data.json', 'w') as f:
json.dump(energy_data, f, indent=4, sort_keys=True)

# Get energy history
energy_history_data = api.min_energy_history(inverter_sn)
print("Saving energy history data to energy_history.json")
with open('energy_history.json', 'w') as f:
json.dump(energy_history_data['datas'],
f, indent=4, sort_keys=True)

# Get settings
settings_data = api.min_settings(device_sn=inverter_sn)
print("Saving settings data to settings_data.json")
with open('settings_data.json', 'w') as f:
json.dump(settings_data, f, indent=4, sort_keys=True)

# Read time segments
tou = api.min_read_time_segments(inverter_sn, settings_data)
print(json.dumps(tou, indent=4))

# Read discharge power
discharge_power = api.min_read_parameter(
inverter_sn, 'discharge_power')
print("Current discharge power:", discharge_power, "%")

# Settings parameters - Uncomment to test

# Turn on AC charging
# api.min_write_parameter(inverter_sn, 'ac_charge', 1)
# print("AC charging enabled successfully")

# Enable Load First between 00:00 and 11:59 using time segment 1
# api.min_write_time_segment(
# device_sn=inverter_sn,
# segment_id=1,
# batt_mode=growattServer.BATT_MODE_BATTERY_FIRST,
# start_time=datetime.time(0, 0),
# end_time=datetime.time(00, 59),
# enabled=True
# )
# print("Time segment updated successfully")


except growattServer.GrowattV1ApiError as e:
print(f"API Error: {e} (Code: {e.error_code}, Message: {e.error_msg})")
except growattServer.GrowattParameterError as e:
print(f"Parameter Error: {e}")
except requests.exceptions.RequestException as e:
print(f"Network Error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Loading