> ## Documentation Index
> Fetch the complete documentation index at: https://fop-50527c4b.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# SUN2000 Modbus Register Map: V2 and V3

> Complete Modbus register reference for Huawei SUN2000 inverters: system info, DC, AC, energy, temperature, and inverter state decode table.

The SUN2000 register map is organized into functional groups. You read all registers with **FC 03** (Read Holding Registers). INT32 and UINT32 values span two consecutive registers — always request both in a single transaction to guarantee consistency. Divide each raw integer by its gain to obtain the real physical value.

<Warning>
  Register addresses differ between SUN2000 series (L0, L1, M0, M1, M2, M3, MA, MB0). The addresses below match the SUN2000MA and SUN2000-M1/M3 Modbus Interface Definitions (Issue 08, 2024-11-07). Verify every address against the Modbus Interface Definitions for your specific model before deploying to production.
</Warning>

## System information registers (read-only)

| Register | Description        | Type   | Gain |
| -------- | ------------------ | ------ | ---- |
| 30000    | Inverter model     | String | —    |
| 30015    | Serial number (SN) | String | —    |
| 32089    | Run state          | U16    | 1    |

Register **32089** returns one of the coded integers in the [state decode table](#inverter-state-decode-register-32089) below.

## DC side registers (solar panels)

| Register | Description    | Type | Gain | Unit |
| -------- | -------------- | ---- | ---- | ---- |
| 32016    | PV1 voltage    | I16  | 10   | V    |
| 32017    | PV1 current    | I16  | 100  | A    |
| 32064    | DC input power | I32  | 1    | W    |

## AC side registers (grid)

| Register | Description             | Type | Gain | Unit |
| -------- | ----------------------- | ---- | ---- | ---- |
| 32066    | Line voltage L1-L2 (AB) | U16  | 10   | V    |
| 32069    | Phase voltage A (L1-N)  | U16  | 10   | V    |
| 32070    | Phase voltage B (L2-N)  | U16  | 10   | V    |
| 32071    | Phase voltage C (L3-N)  | U16  | 10   | V    |
| 32072    | Phase A current         | I16  | 10   | A    |
| 32074    | Phase B current         | I16  | 10   | A    |
| 32076    | Phase C current         | I16  | 10   | A    |
| 32078    | Reactive power          | I32  | 1    | var  |
| 32080    | Active power            | I32  | 1    | W    |
| 32082    | Power factor            | I16  | 1000 | —    |
| 32085    | Grid frequency          | U16  | 100  | Hz   |

Register **32080** (Active power) is signed: positive values indicate generation, negative values indicate consumption from the grid.

## Energy and temperature registers

| Register | Description          | Type | Gain | Unit |
| -------- | -------------------- | ---- | ---- | ---- |
| 32106    | Daily yield          | U32  | 100  | kWh  |
| 32109    | Total yield          | U32  | 100  | kWh  |
| 32087    | Internal temperature | I16  | 10   | °C   |

## Inverter state decode (register 32089)

| Raw value | State                          |
| --------- | ------------------------------ |
| 0         | Idle: Initializing             |
| 1         | Idle: Detecting ISO            |
| 2         | Idle: Detecting irradiation    |
| 3         | Idle: Grid Detecting           |
| 256       | Starting                       |
| **512**   | **On-Grid (normal operation)** |
| 513       | On-Grid: Power Limit           |
| 514       | On-Grid: Self-derating         |
| 768       | Shutdown: Fault                |
| 769       | Shutdown: Command              |
| 770       | Shutdown: OVGR                 |
| 771       | Shutdown: Comm. disconnected   |
| 772       | Shutdown: Power Limit          |
| 1280      | Spot-check                     |
| 2048      | IV Scanning                    |
| 40960     | Idle: No irradiation           |

## Top 10 registers for Home Assistant, Node-RED, and SCADA

These registers cover the most common monitoring requirements with minimal polling overhead:

| Register | Parameter              | Type | Gain | Notes                                         |
| -------- | ---------------------- | ---- | ---- | --------------------------------------------- |
| 32064    | DC input power         | I32  | 1    | Total power from panels (W)                   |
| 32069    | Phase voltage A (L1-N) | U16  | 10   |                                               |
| 32070    | Phase voltage B (L2-N) | U16  | 10   |                                               |
| 32071    | Phase voltage C (L3-N) | U16  | 10   |                                               |
| 32080    | Active power AC        | I32  | 1    | positive = generation, negative = consumption |
| 32085    | Grid frequency         | U16  | 100  |                                               |
| 32087    | Internal temperature   | I16  | 10   | °C                                            |
| 32089    | Inverter run state     | U16  | 1    | 512 = On-Grid                                 |
| 32106    | Daily yield            | U32  | 100  | kWh                                           |
| 32109    | Total yield            | U32  | 100  | kWh                                           |

## Python example: reading key registers

The example below uses the `pymodbus` library to connect over Modbus TCP and read a selection of the registers above.

```python theme={null}
from pymodbus.client import ModbusTcpClient
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder

HOST = "192.168.200.1"  # Inverter Wi-Fi AP address
PORT = 6607             # New-firmware SDongle port; use 502 for old firmware
SLAVE_ID = 1

client = ModbusTcpClient(HOST, port=PORT)
client.connect()

def read_u16(address):
    result = client.read_holding_registers(address, count=1, slave=SLAVE_ID)
    return result.registers[0]

def read_i16(address):
    raw = read_u16(address)
    return raw if raw < 0x8000 else raw - 0x10000

def read_i32(address):
    result = client.read_holding_registers(address, count=2, slave=SLAVE_ID)
    decoder = BinaryPayloadDecoder.fromRegisters(
        result.registers, byteorder=Endian.BIG, wordorder=Endian.BIG
    )
    return decoder.decode_32bit_int()

def read_u32(address):
    result = client.read_holding_registers(address, count=2, slave=SLAVE_ID)
    decoder = BinaryPayloadDecoder.fromRegisters(
        result.registers, byteorder=Endian.BIG, wordorder=Endian.BIG
    )
    return decoder.decode_32bit_uint()

# DC side
dc_power_w    = read_i32(32064)

# AC side
phase_a_v     = read_u16(32069) / 10   # Volts
active_power_w = read_i32(32080)        # W, positive = generation
grid_freq_hz  = read_u16(32085) / 100  # Hz
temperature_c = read_i16(32087) / 10   # °C
run_state     = read_u16(32089)

# Energy
daily_kwh     = read_u32(32106) / 100
total_kwh     = read_u32(32109) / 100

print(f"DC input power : {dc_power_w} W")
print(f"Phase A voltage: {phase_a_v} V")
print(f"Active power   : {active_power_w} W")
print(f"Grid frequency : {grid_freq_hz} Hz")
print(f"Temperature    : {temperature_c} °C")
print(f"Run state      : {run_state}  (512 = On-Grid)")
print(f"Daily yield    : {daily_kwh} kWh")
print(f"Total yield    : {total_kwh} kWh")

client.close()
```
