This document describes the public Python API exposed by the goodwe package for discovering, connecting to, and interacting with GoodWe inverters over the local network.
pip install goodwe- Python package:
goodwe - Network access to the inverter on the local network
- Supported protocols:
- UDP on port
8899 - Modbus/TCP on port
502
- UDP on port
The library can automatically detect and communicate with these inverter families:
- ET family:
ET,EH,BT,BH - ES family:
ES,EM,BP - DT family:
DT,MS,D-NS,XS
It also includes support for some white-label GoodWe-manufactured models such as selected GE/GEH/GEP variants.
The main public API is exposed from goodwe/__init__.py.
async def connect(
host: str,
port: int = 8899,
family: str | None = None,
comm_addr: int = 0,
timeout: int = 1,
retries: int = 3,
do_discover: bool = True,
) -> InverterConnects to an inverter and returns an initialized inverter instance.
host: IP address or hostname of the inverterport: communication port8899for UDP502for Modbus/TCP
family: optional explicit inverter family. Typical values:ET,EH,BT,BHES,EM,BPDT,MS,NS,XS
comm_addr: communication address overridetimeout: request timeout in secondsretries: number of retries for failed communicationdo_discover: ifTrue, attempt family auto-detection whenfamilyis not supplied
An instance of one of:
goodwe.ETgoodwe.ESgoodwe.DT
all of which inherit from goodwe.Inverter.
goodwe.InverterError
import asyncio
import goodwe
async def main():
inverter = await goodwe.connect("192.168.1.14")
data = await inverter.read_runtime_data()
print(data["ppv"])
asyncio.run(main())async def discover(
host: str,
port: int = 8899,
timeout: int = 1,
retries: int = 3,
) -> InverterAttempts to identify the inverter type automatically and returns the matching inverter implementation.
Use this when you know the host but do not know the family.
goodwe.InverterError
async def search_inverters() -> bytesBroadcasts a discovery request on the local network and returns the raw response payload.
This is useful for locating inverters on the LAN.
- raw
bytesresponse from the inverter discovery service
goodwe.InverterError
Abstract base class for all inverter implementations.
Concrete implementations:
goodwe.ETgoodwe.ESgoodwe.DT
These attributes are populated after read_device_info() or during connection/discovery:
model_name: str | Noneserial_number: str | Nonerated_power: intac_output_type: int | Nonefirmware: str | Nonearm_firmware: str | Nonemodbus_version: int | Nonedsp1_version: intdsp2_version: intdsp_svn_version: int | Nonearm_version: intarm_svn_version: int | None
Loads model and firmware metadata from the inverter.
Reads current runtime sensor values and returns a dictionary keyed by sensor id.
Example keys may include:
ppvvpv1battery_socactive_powerhouse_consumption
The exact sensor set depends on inverter family and model.
Reads a single sensor value by id.
Raises ValueError if the sensor is not supported by the inverter.
Reads one configuration setting by id.
Raises ValueError if the setting is not supported.
Writes a configuration setting.
Warning: this modifies inverter configuration and should be used carefully.
Reads all supported settings and returns them as a dictionary.
Sends a low-level command and returns the protocol response object.
Use this only for advanced protocol-level interactions.
Returns the current grid export limit.
Sets the grid export limit.
Warning: this modifies inverter operational settings.
Returns supported operation modes for the inverter.
Returns the active operation mode.
await inverter.set_operation_mode(
operation_mode,
eco_mode_power=100,
eco_mode_soc=100,
)Sets the inverter operation mode.
Special convenience modes:
OperationMode.ECO_CHARGEOperationMode.ECO_DISCHARGE
These are helper modes implemented through eco-mode scheduling rather than native inverter mode values.
Returns the current EMS mode.
Sets the inverter EMS mode.
Returns on-grid battery depth-of-discharge setting.
Sets on-grid battery depth of discharge.
Returns the list of supported runtime sensor definitions for this inverter.
Returns the list of supported settings definitions for this inverter.
Enables or disables persistent protocol connection behavior where supported.
Hybrid inverter implementation for ET/EH/BT/BH and related platform variants.
Typical runtime data includes:
- PV voltage/current/power
- on-grid values for up to 3 phases
- backup output metrics
- battery voltage/current/power
- battery SoC/SoH
- inverter temperature
- import/export energy
- diagnostic and warning/error flags
Typical settings and operations include:
- grid export limit
- battery depth of discharge
- operation mode
- EMS mode
- eco mode configuration
Single-phase hybrid inverter implementation for ES/EM/BP family.
Typical runtime data includes:
- PV channel voltage/current/power
- battery metrics
- on-grid voltage/current/frequency
- backup output values
- inverter temperature
- total/ daily energy generation and load
- work mode and diagnostic status
Typical settings include:
- backup supply
- off-grid charge
- shadow scan
- export limit
- battery charge/discharge voltage/current
- depth of discharge
- eco mode groups
Grid-only inverter implementation for DT/MS/D-NS/XS and related variants.
Typical runtime data includes:
- multiple PV strings
- line/grid voltage and current
- per-phase power
- total inverter power
- apparent/reactive power
- temperatures
- daily and lifetime generation
- meter communication status
- RSSI and derating information
Typical settings include:
- inverter time
- shadow scan
- start/stop/restart
- grid export enable/limit
A sensor definition describes a measurable value or configurable setting.
id_: machine-readable identifieroffset: register offset or data offsetname: human-readable labelsize_: sensor data sizeunit: engineering unit such asV,A,W,%kind: optionalSensorKind
runtime_data = await inverter.read_runtime_data()
for sensor in inverter.sensors():
if sensor.id_ in runtime_data:
print(sensor.id_, sensor.name, runtime_data[sensor.id_], sensor.unit)Logical sensor grouping.
Values:
SensorKind.PVSensorKind.ACSensorKind.UPSSensorKind.BATSensorKind.GRIDSensorKind.BMS
Supported inverter operation modes.
Important values include:
GENERALOFF_GRIDBACKUPECOPEAK_SHAVINGSELF_USEECO_CHARGEECO_DISCHARGE
Not every inverter supports every operation mode.
Energy management system control modes.
Values include:
AUTOCHARGE_PVDISCHARGE_PVIMPORT_ACEXPORT_ACCONSERVEOFF_GRIDBATTERY_STANDBYBUY_POWERSELL_POWERCHARGE_BATTERYDISCHARGE_BATTERY
Availability depends on inverter family and firmware.
The package exposes these exception types:
Base exception for inverter communication and protocol problems.
Raised when a request fails after retries.
Attributes:
messageconsecutive_failures_count
Raised when the inverter explicitly rejects a request.
Attributes:
message
Raised when response data is incomplete.
Attributes:
lengthexpected
Raised when retry count is exhausted.
import asyncio
import goodwe
async def main():
inverter = await goodwe.connect("192.168.1.14")
runtime_data = await inverter.read_runtime_data()
for sensor in inverter.sensors():
if sensor.id_ in runtime_data:
print(f"{sensor.id_}: {sensor.name} = {runtime_data[sensor.id_]} {sensor.unit}")
asyncio.run(main())import asyncio
import goodwe
async def main():
inverter = await goodwe.connect("192.168.1.14")
battery_soc = await inverter.read_sensor("battery_soc")
print("Battery SoC:", battery_soc)
asyncio.run(main())import asyncio
import goodwe
async def main():
inverter = await goodwe.connect("192.168.1.14")
settings = await inverter.read_settings_data()
print(settings)
asyncio.run(main())import asyncio
import goodwe
from goodwe import OperationMode
async def main():
inverter = await goodwe.connect("192.168.1.14")
await inverter.set_operation_mode(OperationMode.ECO)
asyncio.run(main())- All library interaction is asynchronous.
- Always use
awaitwith API methods that perform I/O. - Sensor and setting availability varies by inverter family, hardware platform, and firmware.
- Writing settings can alter inverter behavior. Validate values carefully before changing configuration.
- UDP communication may require retries because packet delivery is not guaranteed.