Loading...
Author Cloudapp
E.G.

Read the Huawei SUN2000 in Home Assistant Without a Custom Integration: Native Modbus YAML

June 23, 2026
Table of Contents

Almost every Huawei SUN2000 guide opens with the same line: "install the huawei-solar custom integration." And it works — right up until the next Home Assistant upgrade introduces a breaking change, the integration won't load, and suddenly half your Energy Dashboard is blank. That happened to me twice before I switched to the dependency-free route.

The SUN2000 speaks Modbus-TCP natively, and Home Assistant ships a built-in modbus: platform. You don't need a custom component — you declare each sensor yourself by its register address. That's a bit more YAML, but nothing breaks on upgrade and you understand exactly where every value comes from. This post gives you the complete register-to-YAML map for PV yield, battery and grid — ready for the Energy Dashboard.

Why native modbus YAML instead of a custom integration

The custom integration is convenient, but it's an extra dependency between you and your data. Every HA update risks it becoming incompatible, and you can end up two days without energy data until a maintainer catches up. The built-in modbus: platform is a core part of Home Assistant — it's maintained with the core and can't "go orphaned." The price is transparency instead of magic: you write a handful of lines per value with register address, data_type and scale. Those exact lines are what I hand you here.

The Modbus hub: point at the proxy, not directly at the SDongle

The SUN2000's SDongle allows only one concurrent Modbus connection. If HA, evcc and an AC·THOR all hit it directly, they block each other. That's why my Modbus hub doesn't point at the SDongle IP but at 127.0.0.1:5502 — the local caching proxy that polls the SDongle once and serves the result to any number of clients. Why and how that's needed is covered in the Modbus caching basics post. If you have only a single client, you can point host/port straight at the SDongle instead — the sensors underneath stay identical.

- name: huawei_inverter
  type: tcp
  host: 127.0.0.1
  port: 5502
  delay: 2
  timeout: 10
  sensors:
    - name: "PV Cumulative Yield"
      unique_id: huawei_pv_cumulative_yield
      slave: 1
      address: 32106
      input_type: holding
      data_type: uint32
      scale: 0.01
      precision: 2
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing
      scan_interval: 60

The two fields that matter for the Energy Dashboard are device_class: energy and state_class: total_increasing. Without them the sensor won't even show up as a selectable source in the energy configuration. The delay: 2 on the hub gives the (slow) SDongle two seconds after connecting before the first read — without it you'll see sporadic timeouts at startup.

Battery: total charge and discharge as uint32

The battery energy registers are cumulative counters — they only go up, which fits total_increasing perfectly. The key here is the data_type uint32: the values quickly exceed the 16-bit range and therefore occupy two consecutive registers (37780 and the following one). HA reads both together when you set data_type uint32 — no second address needed.

    - name: "Battery Total Charge"
      unique_id: huawei_battery_total_charge
      slave: 1
      address: 37780
      input_type: holding
      data_type: uint32
      scale: 0.01
      precision: 2
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing
      scan_interval: 60
    - name: "Battery Total Discharge"
      unique_id: huawei_battery_total_discharge
      slave: 1
      address: 37782
      input_type: holding
      data_type: uint32
      scale: 0.01
      precision: 2
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing
      scan_interval: 60

You enter these two sensors in the Energy Dashboard as "home battery storage" — charge as "energy into the battery," discharge as "energy out of the battery." That lets HA track the battery round-trip balance correctly.

Grid: import and export as signed int32

With the grid registers the classic mistake is the data_type. Grid values can come as signed int32 depending on firmware — if you accidentally read them as uint32, a value just above or below zero flips into a huge number (two's complement). So read them as int32 and the sign and magnitude line up.

    - name: "Grid Total Exported"
      unique_id: huawei_grid_exported_energy
      slave: 1
      address: 37119
      input_type: holding
      data_type: int32
      scale: 0.01
      precision: 2
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing
      scan_interval: 60
    - name: "Grid Total Imported"
      unique_id: huawei_grid_imported_energy
      slave: 1
      address: 37121
      input_type: holding
      data_type: int32
      scale: 0.01
      precision: 2
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing
      scan_interval: 60

Grid export and import are the last two sources the Energy Dashboard needs for the full balance: export under "return to grid," import under "grid consumption." Once PV yield, battery and grid are entered, you have the complete Sankey diagram without a single custom line.

scale, precision and data_type — the three pitfalls

Three fields decide whether the values are right. scale: Huawei delivers energy in tenth- or hundredth-units — 0.01 turns the raw register into kWh. If your value is off by a factor of 10 or 100, it's almost always the scale. data_type: energy counters are 32-bit (uint32/int32); an accidental uint16 clips at ~655 kWh and wraps back to zero. precision: cosmetic only (decimal places), but two digits keep the history clean. If something stays "unavailable" after a restart, check slave (device ID, usually 1) and input_type (holding) first.

Enabling and verifying

The sensor blocks go under the modbus: hub in your configuration.yaml (or a file pulled in via !include). After "reload YAML configuration" → "Modbus" (or a restart) the entities appear. Go to Developer Tools → States and filter for sensor.pv_cumulative_yield and the battery/grid sensors: if you see plausible kWh values, you have a complete, upgrade-proof data source — with no custom integration at all. If you want to build derived metrics like self-sufficiency on top of these raw registers, that's covered in the self-consumption sensors post.

Frequently asked questions

Why 127.0.0.1:5502 instead of the real SDongle IP?

Because the SUN2000 SDongle allows only one concurrent Modbus connection. As soon as HA and a second client (evcc, AC·THOR, a script) connect directly, they choke each other. 127.0.0.1:5502 is a local caching proxy that polls the SDongle once and serves any number of clients. With a single client you can point host/port straight at the SDongle IP.

Why uint32 / int32 and not just uint16?

Energy counters in kWh quickly exceed the 16-bit range (max ~655 with scale 0.01) and therefore live across two consecutive registers. data_type uint32 (or int32 for signed grid values) reads both together. With uint16 you clip the high part and the counter appears to jump backwards.

Will this break on a Home Assistant upgrade?

No — that's exactly the point. The modbus platform is part of the HA core and maintained with it. There's no third-party integration that could become incompatible. In the worst case the spelling of a config key changes, which the release notes announce — but your data source never "goes orphaned."

Do these register addresses apply to every SUN2000?

The addresses given here (32106 yield, 37780/37782 battery, 37119/37121 grid) apply to the common residential SUN2000 inverters with LUNA storage. For different firmware or other models, check the official Huawei Modbus interface document — layout and scale can differ slightly between generations, but the YAML structure stays the same.

Related articles