> ## 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.

# LUNA2000 Battery (ESS) Registers for V3 Inverters

> Modbus register reference for LUNA2000 energy storage on Huawei SUN2000 V3 inverters: SOC, charge/discharge power, voltage, and accumulated energy.

The V3 generation of the SUN2000 — specifically the **M3** and **MB0** series — introduces native support for the LUNA2000 battery system (ESS). Alongside the expanded inverter firmware, Huawei added a dedicated register block starting at address **37000** to expose battery state, power flow, and lifetime energy totals in real time.

<Note>
  ESS registers are only present on V3 series inverters (M3, MB0) with a LUNA2000 battery physically connected. On V2 inverters or V3 units without a battery, these addresses will return errors or undefined values.
</Note>

## ESS register table

| Register | Description                 | Type | Gain | Notes                                                                 |
| -------- | --------------------------- | ---- | ---- | --------------------------------------------------------------------- |
| 37000    | ESS unit 1 run state        | U16  | 1    | See state values below                                                |
| 37001    | Charge / discharge power    | I32  | 1    | W; positive = charging, negative = discharging                        |
| 37003    | Battery bus voltage         | U16  | 10   | V                                                                     |
| 37004    | SOC — ESS unit 1            | U16  | 10   | %; e.g. raw 955 = 95.5%                                               |
| 37066    | Total charge accumulated    | U32  | 100  | kWh                                                                   |
| 37068    | Total discharge accumulated | U32  | 100  | kWh                                                                   |
| SOH      | State of health             | U16  | 10   | % — address varies by series; check your Modbus Interface Definitions |

### ESS unit 1 run state (register 37000)

| Value | State   |
| ----- | ------- |
| 0     | Offline |
| 1     | Standby |
| 2     | Running |
| 3     | Fault   |
| 4     | Sleep   |

## ESS management modes

The ARM processor in V3 inverters manages the battery through two primary strategies:

* **Time-of-Use (TOU)** — you define time windows and charge/discharge targets aligned with grid tariff schedules. The inverter charges the battery during low-tariff periods and discharges during peak-tariff periods to minimize electricity costs.
* **Self-consumption** — the inverter prioritizes using solar generation to power loads directly, stores any surplus in the battery, and draws from the battery before importing from the grid. This mode maximizes self-sufficiency without requiring a tariff schedule.

Both modes are fully configured through the FusionSolar app or SmartLogger and are reflected in real time in the registers above.

## Python example: reading SOC and power flow

```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
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_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()

# ESS registers
ess_state        = read_u16(37000)
charge_power_w   = read_i32(37001)   # positive = charging, negative = discharging
bus_voltage_v    = read_u16(37003) / 10
soc_percent      = read_u16(37004) / 10
total_charge_kwh = read_u32(37066) / 100
total_disch_kwh  = read_u32(37068) / 100

STATE_LABELS = {0: "Offline", 1: "Standby", 2: "Running", 3: "Fault", 4: "Sleep"}

print(f"ESS state       : {STATE_LABELS.get(ess_state, ess_state)}")
print(f"Charge/discharge: {charge_power_w} W  (>0 charging, <0 discharging)")
print(f"Bus voltage     : {bus_voltage_v} V")
print(f"SOC             : {soc_percent} %")
print(f"Total charged   : {total_charge_kwh} kWh")
print(f"Total discharged: {total_disch_kwh} kWh")

client.close()
```
