Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
c6703ba
Initial commit adding common methods for mix and min
GraemeDBlue Sep 24, 2025
6e487d6
Try tio simplify ,ethods and provide backwards compatible method names
GraemeDBlue Sep 24, 2025
8a07ba6
normalise method names
GraemeDBlue Sep 24, 2025
cf7d7b8
add Dashboard example for Mix V1
GraemeDBlue Sep 24, 2025
aa01035
Fixes for dashboard
GraemeDBlue Sep 24, 2025
1d1e8e2
Reworking
GraemeDBlue Sep 25, 2025
76b4548
added docs
GraemeDBlue Sep 29, 2025
52661fd
add backwards compatible methods for min_*
GraemeDBlue Sep 29, 2025
ce9afa5
uncomment code
GraemeDBlue Sep 29, 2025
21f9581
Fixing up example
GraemeDBlue Sep 29, 2025
fd98a51
fix example dashboard
GraemeDBlue Sep 29, 2025
7d4db09
debugging
GraemeDBlue Sep 30, 2025
837c78c
minor tweaks
GraemeDBlue Oct 2, 2025
f042b63
Code quality
GraemeDBlue Oct 2, 2025
0c03dfc
fixes
GraemeDBlue Oct 2, 2025
e4241e9
fix formatting and code quality
GraemeDBlue Oct 2, 2025
3f3790d
Merge pull request #1 from GraemeDBlue/cleanup
GraemeDBlue Oct 3, 2025
9baba05
revert changes in min_* example and add abckwards compatible wrapper …
GraemeDBlue Oct 10, 2025
f58d8b1
add missing renamed file for v1 example
GraemeDBlue Oct 10, 2025
48a8fc6
Merge pull request #2 from GraemeDBlue/cleanup
GraemeDBlue Oct 10, 2025
ae1f36e
Added all constants
GraemeDBlue Oct 13, 2025
4314600
Dynamically sum pev based on count of devices
GraemeDBlue Oct 13, 2025
8f75a8f
Remove white space
GraemeDBlue Oct 13, 2025
b32fd8d
Merge pull request #3 from GraemeDBlue/cleanup
GraemeDBlue Oct 13, 2025
c393caf
Fix max to 4 for sum
GraemeDBlue Oct 13, 2025
b90943c
Merge pull request #4 from GraemeDBlue/cleanup
GraemeDBlue Oct 13, 2025
5c75e6f
add tou
GraemeDBlue Oct 29, 2025
08668a3
New v1 example files
GraemeDBlue Oct 29, 2025
aae9343
Fix comments out code etc
GraemeDBlue Oct 29, 2025
0006892
Fix commented code
GraemeDBlue Oct 29, 2025
0125ebd
Merge pull request #5 from GraemeDBlue/read_tou
GraemeDBlue Oct 29, 2025
11e28ac
Add Write commands via interfaces for the input params
GraemeDBlue Oct 30, 2025
97b3e93
Add examples for setting charge time for SPH_MIX and MIN_TLX
GraemeDBlue Oct 30, 2025
b1429e8
add common methods
GraemeDBlue Oct 31, 2025
68dda25
fix device type check
GraemeDBlue Oct 31, 2025
1bba0a0
Merge pull request #7 from GraemeDBlue/write_values
GraemeDBlue Nov 3, 2025
33b84f8
Add additional params
GraemeDBlue Nov 6, 2025
4dc88d1
Merge pull request #8 from GraemeDBlue/write_values
GraemeDBlue Nov 6, 2025
a75df72
fixes spaces
GraemeDBlue Nov 6, 2025
68a6317
split tlx and sph read time segments logic
GraemeDBlue Nov 6, 2025
611e983
Add debug is .env variable if .env var is set
GraemeDBlue Nov 6, 2025
b1cd756
remove dead code
GraemeDBlue Nov 6, 2025
dc9648f
Merge pull request #9 from GraemeDBlue/write_values
GraemeDBlue Nov 6, 2025
7d183d3
Fix code quality
GraemeDBlue Nov 7, 2025
4ef89a5
Merge pull request #10 from GraemeDBlue/write_values
GraemeDBlue Nov 7, 2025
958dc88
Added ruff github action
indykoning Dec 27, 2025
06ad1bd
remove dead code
GraemeDBlue Jan 5, 2026
260ff84
Fix ruff issues in older file
GraemeDBlue Jan 5, 2026
55802ce
Fix more ruff issues
GraemeDBlue Jan 5, 2026
933c42d
more ruff fixes
GraemeDBlue Jan 5, 2026
36c7df8
more ruff fixes and formatting
GraemeDBlue Jan 5, 2026
bc0463b
more ruff fixes
GraemeDBlue Jan 5, 2026
3d3aba6
Fix more ruff issues
GraemeDBlue Jan 5, 2026
dfeca90
Fix for more ruff issues
GraemeDBlue Jan 5, 2026
97243ef
more ruff fixes
GraemeDBlue Jan 5, 2026
0b80fea
batch ruff fixes
GraemeDBlue Jan 5, 2026
733772b
Fixes for code quality and formatting
GraemeDBlue Jan 5, 2026
9774a9d
more ruff fixes
GraemeDBlue Jan 5, 2026
dfccc0f
more ruff fixes
GraemeDBlue Jan 5, 2026
fb141da
Fix ruff issues
GraemeDBlue Jan 5, 2026
5f473e0
fix some ruff issues
GraemeDBlue Jan 5, 2026
4eb774d
fix ruff issues
GraemeDBlue Jan 5, 2026
effe1ac
fix ruff issues
GraemeDBlue Jan 5, 2026
a92367f
more ruff issues
GraemeDBlue Jan 5, 2026
9654460
fixed ruff issues
GraemeDBlue Jan 5, 2026
f214c76
fixes for formatting
GraemeDBlue Jan 5, 2026
2c9f4ac
formatting for older files
GraemeDBlue Jan 5, 2026
30e3150
fixes for ruff in older files
GraemeDBlue Jan 5, 2026
022a457
ruff fixes
GraemeDBlue Jan 5, 2026
44f2cdd
more fixes for ruff formaTTING
GraemeDBlue Jan 5, 2026
0ee095c
more fixes for older files
GraemeDBlue Jan 5, 2026
e08d6ee
fix formatting
GraemeDBlue Jan 5, 2026
8be12b0
fix long line issues
GraemeDBlue Jan 5, 2026
8f991ac
fix long line issues
GraemeDBlue Jan 5, 2026
88ad246
fix some more ruff issues
GraemeDBlue Jan 5, 2026
97926a3
fix some lazy code
GraemeDBlue Jan 5, 2026
09cbdc5
reformat for long lines
GraemeDBlue Jan 5, 2026
50797c4
fixes for formatting
GraemeDBlue Jan 5, 2026
b551c7f
fix long line issue
GraemeDBlue Jan 5, 2026
8a645a1
Merge branch 'master' into master
GraemeDBlue Jan 5, 2026
8a192f5
apply ruff to pulled changes from master
GraemeDBlue Jan 5, 2026
6604c5f
rework some upstream changex to work with ruff
GraemeDBlue Jan 5, 2026
b782ea0
more fix for upstream changes
GraemeDBlue Jan 5, 2026
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
11 changes: 11 additions & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: Ruff
on:
- push
- pull_request

jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
*.json

# Symlink
examples/growattServer
25 changes: 25 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# The contents of this file is based on https://github.com/home-assistant/core/blob/dev/pyproject.toml

target-version = "py313"

[lint]
select = [
"ALL",
]

ignore = [
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
"D203", # no-blank-line-before-class (incompatible with formatter)
"D212", # multi-line-summary-first-line (incompatible with formatter)
"COM812", # incompatible with formatter
"ISC001", # incompatible with formatter
]

[lint.flake8-pytest-style]
fixture-parentheses = false

[lint.pyupgrade]
keep-runtime-typing = true

[lint.mccabe]
max-complexity = 25
25 changes: 24 additions & 1 deletion docs/openapiv1/min_tlx_settings.md

Large diffs are not rendered by default.

124 changes: 124 additions & 0 deletions docs/openapiv1/mix_sph_settings.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions examples/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Examples package for PyPi_GrowattServer."""
127 changes: 68 additions & 59 deletions examples/min_example.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,102 @@
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.
Example script for MIN/TLX Growatt inverters using the public API.

This script demonstrates controlling a MID/TLX Growatt
(MID-30KTL3-XH + APX battery) system.
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: ")
import json
from pathlib import Path

import requests

from . import growattServer

# test token from official API docs https://www.showdoc.com.cn/262556420217021/1494053950115877
api_token = "6eb6f069523055a339d71e5b1f6c88cc" # gitleaks:allow
# 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']
print(f"Plants: Found {plants['count']} plants") # noqa: T201
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}")
for device in devices["devices"]:
print(device) # noqa: T201
if device["device_type"] == growattServer.DeviceType.MIN_TLX.value:
inverter_sn = device["device_sn"]
device_type = device["device_type"]
print(f"Processing {device_type.name} inverter: {inverter_sn}") # noqa: T201

# 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:
inverter_data = api.min_detail(
device_sn=inverter_sn,
)
print("Saving inverter data to inverter_data.json") # noqa: T201
with Path("inverter_data.json").open("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:
energy_data = api.min_energy(
device_sn=inverter_sn,
)
print("Saving energy data to energy_data.json") # noqa: T201
with Path("energy_data.json").open("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)
energy_history_data = api.min_energy_history(
device_sn=inverter_sn,
)
print("Saving energy history data to energy_history.json") # noqa: T201
with Path("energy_history.json").open("w") as f:
json.dump(
energy_history_data.get("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:
settings_data = api.min_settings(
device_sn=inverter_sn,
)
print("Saving settings data to settings_data.json") # noqa: T201
with Path("settings_data.json").open("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))
tou = api.read_time_segments(
device_sn=inverter_sn,
device_type=device_type,
settings_data=settings_data,
)
print("Time-of-Use Segments:") # noqa: T201
with Path("tou_data.json").open("w") as f:
json.dump(tou, f, indent=4, sort_keys=True)

# 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")

discharge_power = api.common_read_parameter(
device_sn=inverter_sn,
device_type=device_type,
parameter_id="discharge_power",
)
print(f"Current discharge power: {discharge_power}%") # noqa: T201

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