Skip to content
Draft
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.env
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down Expand Up @@ -28,4 +29,4 @@ share/python-wheels/
MANIFEST

# Symlink
examples/growattServer
examples/growattServer
73 changes: 73 additions & 0 deletions examples/inverter_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import json
import os

import requests

import growattServer

"""
# Example script controlling a classic Growatt inverter 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 environment variable or use test token
api_token = os.environ.get("GROWATT_API_TOKEN")
if not api_token:
# test token from official API docs https://www.showdoc.com.cn/262556420217021/1494053950115877
api_token = "6eb6f069523055a339d71e5b1f6c88cc" # noqa: S105

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"] == growattServer.DeviceType.INVERTER.value:
inverter_sn = device["device_sn"]
print(f"Processing inverter: {inverter_sn}")
device_class = api.get_device(inverter_sn, device["type"])

# Get device details
inverter_data = device_class.detail()
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 = device_class.energy()
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 = device_class.energy_history()
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)

# Read power rate
active_p_rate = device_class.read_parameter("pv_active_p_rate")
print("Current power rate:", active_p_rate, "%")

# Settings parameters - Uncomment to test

# Set active power rate
# device_class.write_parameter('pv_active_p_rate', 100)
# print("set active power rate to 100%")

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}")
13 changes: 7 additions & 6 deletions examples/min_example.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os

import requests

Expand All @@ -9,11 +10,11 @@
# 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
# Get the API token from environment variable or use test token
api_token = os.environ.get("GROWATT_API_TOKEN")
if not api_token:
# test token from official API docs https://www.showdoc.com.cn/262556420217021/1494053950115877
api_token = "6eb6f069523055a339d71e5b1f6c88cc" # noqa: S105

try:
# Initialize the API with token instead of using login
Expand All @@ -28,7 +29,7 @@
devices = api.device_list(plant_id)

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

Expand Down
13 changes: 7 additions & 6 deletions examples/min_example_dashboard.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os

import requests

Expand All @@ -9,11 +10,11 @@
using the V1 API with token-based authentication.
"""

# 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
# Get the API token from environment variable or use test token
api_token = os.environ.get("GROWATT_API_TOKEN")
if not api_token:
# test token from official API docs https://www.showdoc.com.cn/262556420217021/1494053950115877
api_token = "6eb6f069523055a339d71e5b1f6c88cc" # noqa: S105

try:
# Initialize the API with token
Expand All @@ -29,7 +30,7 @@
# Iterate over all devices
energy_data = None
for device in devices["devices"]:
if device["type"] == 7: # (MIN/TLX)
if device["type"] == growattServer.DeviceType.MIN.value:
inverter_sn = device["device_sn"]

# Get energy data
Expand Down
120 changes: 118 additions & 2 deletions growattServer/open_api_v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
from growattServer import GrowattApi
from growattServer.exceptions import GrowattV1ApiError

from .devices import AbstractDevice, Min, Sph
from .devices import AbstractDevice, Inverter, Min, Sph


class DeviceType(Enum):
"""Enumeration of Growatt device types."""

INVERTER = 1
INVERTER = Inverter.DEVICE_TYPE_ID
STORAGE = 2
OTHER = 3
MAX = 4
Expand Down Expand Up @@ -364,6 +364,8 @@ def device_list(self, plant_id):
def get_device(self, device_sn: str, device_type: int) -> AbstractDevice | None:
"""Get the device class by serial number and device_type id."""
match device_type:
case Inverter.DEVICE_TYPE_ID:
return Inverter(self, device_sn)
case Sph.DEVICE_TYPE_ID:
return Sph(self, device_sn)
case Min.DEVICE_TYPE_ID:
Expand All @@ -375,6 +377,120 @@ def get_device(self, device_sn: str, device_type: int) -> AbstractDevice | None:
)
return None

def inverter_detail(self, device_sn):
"""
Get detailed data for a classic inverter.

Args:
device_sn (str): The serial number of the classic inverter.

Returns:
dict: A dictionary containing the classic inverter details.

Raises:
GrowattV1ApiError: If the API returns an error response.
requests.exceptions.RequestException: If there is an issue with the HTTP request.

"""
return Inverter(self, device_sn).detail()

def inverter_energy(self, device_sn):
"""
Get energy data for a classic inverter.

Args:
device_sn (str): The serial number of the classic inverter.

Returns:
dict: A dictionary containing the classic inverter energy data.

Raises:
GrowattV1ApiError: If the API returns an error response.
requests.exceptions.RequestException: If there is an issue with the HTTP request.

"""
return Inverter(self, device_sn).energy()

def inverter_energy_history(
self,
device_sn,
start_date=None,
end_date=None,
timezone=None,
page=None,
limit=None,
):
"""
Get classic inverter data history.

Args:
device_sn (str): The ID of the classic inverter.
start_date (date, optional): Start date. Defaults to today.
end_date (date, optional): End date. Defaults to today.
timezone (str, optional): Timezone ID.
page (int, optional): Page number.
limit (int, optional): Results per page.

Returns:
dict: A dictionary containing the classic inverter history data.

Raises:
GrowattParameterError: If date interval is invalid (exceeds 7 days).
GrowattV1ApiError: If the API returns an error response.
requests.exceptions.RequestException: If there is an issue with the HTTP request.

"""
return Inverter(self, device_sn).energy_history(
start_date, end_date, timezone, page, limit
)

def inverter_read_parameter(
self, device_sn, parameter_id, start_address=None, end_address=None
):
"""
Read setting from classic inverter.

Args:
device_sn (str): The ID of the TLX inverter.
parameter_id (str): Parameter ID to read. Don't use start_address and end_address if this is set.
start_address (int, optional): Register start address (for set_any_reg). Don't use parameter_id if this is set.
end_address (int, optional): Register end address (for set_any_reg). Don't use parameter_id if this is set.

Returns:
dict: A dictionary containing the setting value.

Raises:
GrowattParameterError: If parameters are invalid.
GrowattV1ApiError: If the API returns an error response.
requests.exceptions.RequestException: If there is an issue with the HTTP request.

"""
return Inverter(self, device_sn).read_parameter(
parameter_id, start_address, end_address
)

def inverter_write_parameter(self, device_sn, parameter_id, parameter_values=None):
"""
Set parameters on a classic inverter.

Args:
device_sn (str): Serial number of the inverter
parameter_id (str): Setting type to be configured
parameter_values: Parameter values to be sent to the system.
Can be a single string (for param1 only),
a list of strings (for sequential params),
or a dictionary mapping param positions to values

Returns:
dict: JSON response from the server

Raises:
GrowattV1ApiError: If the API returns an error response.
requests.exceptions.RequestException: If there is an issue with the HTTP request.

"""
return Inverter(self, device_sn).write_parameter(parameter_id, parameter_values)

def min_detail(self, device_sn):
"""
Get detailed data for a MIN inverter.
Expand Down
1 change: 1 addition & 0 deletions growattServer/open_api_v1/devices/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# noqa: D104
from .abstract_device import AbstractDevice # noqa: F401
from .inverter import Inverter # noqa: F401
from .min import Min # noqa: F401
from .sph import Sph # noqa: F401
Loading
Loading