Reading data from Huawei inverter SUN 2000 (3KTL-10KTL) via modbus TCP and RTU

Yes, I will. I am on business strip until Thursday evening but can share the config then. So far, I have not tried to do write attempts, but this is on my agenda to. But according to spec, that seems possible.

For me writing did not work with the openHAB Modbus binding. I ran into countless issues.
Most notable the support for uint8 is missing and does not work.

I completely switched to the python huawei solar library. Strangely it does also have less connection issues than the OH modbus binding so I suspect some threading issues with the OH modbus binding as well.

Hi Sebastian,

with the SDongle I can do writes. Let me know what register you want to write, I can share my setup.

Yes - some writes worked.
If I remember correctly it was the charge-from-ac register which was not supported because it was just one byte.

As I’ve said I’ve had many problems with the modbus OH binding and significantly less problems with the python implementation so currently I have no desire to switch back :wink:

Thank you for the offer though …

Hi @ollo ,

here you are, I even take it every 10 seconds for most values:

Bridge modbus:tcp:SUN2000 [
  host="<IP>",
  port=502,
  id=3,
  timeBetweenTransactionsMillis=60,
  reconnectAfterMillis=1000,
  timeBetweenReconnectMillis=1000,
  connectTimeoutMillis=10000,
  afterConnectionDelayMillis=1000
  ]{

  // Solaranlagenstatus
  Bridge poller poll32000 [
    start=32000,
    length=11,
    refresh=10000,
    type="holding" ]{  
      Thing data sun2000_status_rawdata                         [ readStart="32000", readValueType="uint16",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_standby                         [ readStart="32000", readValueType="uint16",  readTransform="JS(mathBitMaskToBinaryX.js?mask=1)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_ongrid                          [ readStart="32000", readValueType="uint16",  readTransform="JS(mathBitMaskToBinaryX.js?mask=2)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_ongrid_normal                   [ readStart="32000", readValueType="uint16",  readTransform="JS(mathBitMaskToBinaryX.js?mask=6)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_stop_error                      [ readStart="32000", readValueType="uint16",  readTransform="JS(mathBitMaskToBinaryX.js?mask=64)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_shutdown_normal                 [ readStart="32000", readValueType="uint16",  readTransform="JS(mathBitMaskToBinaryX.js?mask=288)", updateUnchangedValuesEveryMillis="10000" ]

      Thing data sun2000_status_alarm_01                        [ readStart="32008", readValueType="uint16",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_alarm_02                        [ readStart="32009", readValueType="uint16",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_alarm_03                        [ readStart="32010", readValueType="uint16",  updateUnchangedValuesEveryMillis="10000" ]
    }

  // Solaranlage Basis Leistungs- und Statusdaten
  Bridge poller poll32064 [
    start=32064,
    length=26,
    refresh=10000,
    type="holding" ]{  
      Thing data sun2000_production_panels_dcpower_current      [ readStart="32064", readValueType="int32",  readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_production_panels_dcpower_peakday      [ readStart="32078", readValueType="int32",  readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="60000" ]

      Thing data sun2000_output_system_acpower_current          [ readStart="32080", readValueType="int32",  readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_efficiency                             [ readStart="32086", readValueType="uint16", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_temperature_current                    [ readStart="32087", readValueType="int16",  readTransform="JS(mathDivByX.js?by=10)",   updateUnchangedValuesEveryMillis="10000" ]
      Thing data sun2000_status_overall                         [ readStart="32089", readValueType="uint16", readTransform="JS(mathDivByX.js?by=1)",    updateUnchangedValuesEveryMillis="10000" ]
  }
  Bridge poller poll32106 [
    start=32106,
    length=10,
    refresh=10000,
    type="holding" ]{  
      Thing data sun2000_production_system_acoutput_total       [ readStart="32106", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)", updateUnchangedValuesEveryMillis="30000" ]
      Thing data sun2000_production_panels_dcoutput_total       [ readStart="32108", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)", updateUnchangedValuesEveryMillis="30000" ]
      Thing data sun2000_production_system_acoutput_day         [ readStart="32114", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)", updateUnchangedValuesEveryMillis="30000" ]
  }



  // Batteriestatus
  Bridge poller poll37000 [
    start=37000,
    length=26,
    refresh=10000,
    type="holding" ]{  
      Thing data luna2000_charging_power_current_raw            [ readStart="37001", readValueType="int32",  readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data luna2000_charging_power_current_corrected      [ readStart="37001", readValueType="int32",  readTransform="JS(|parseFloat(input) / 1000 * 0.99 + 0.035)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data luna2000_capacity_status_current               [ readStart="37004", readValueType="uint16", readTransform="JS(mathDivByX.js?by=10)",  updateUnchangedValuesEveryMillis="60000" ]

      Thing data luna2000_charging_power_charged_day            [ readStart="37015", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)", updateUnchangedValuesEveryMillis="30000" ]
      Thing data luna2000_charging_power_discharged_day         [ readStart="37017", readValueType="uint32", readTransform="JS(mathDivByX.js?by=-100)", updateUnchangedValuesEveryMillis="30000" ]

      Thing data luna2000_temperature_current                   [ readStart="37022", readValueType="int16",  readTransform="JS(mathDivByX.js?by=10)",  updateUnchangedValuesEveryMillis="30000" ]
      //Not working, always 0:
      //Thing data luna2000_charging_time_remaining          [ readStart="37025", readValueType="uint16", readTransform="JS(mathDivByX.js?by=1)",  updateUnchangedValuesEveryMillis="30000" ]
  }

  Bridge poller poll37066 [
    start=37066,
    length=4,
    refresh=10000,
    type="holding" ]{  
      Thing data luna2000_charging_power_charged_total          [ readStart="37066", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)", updateUnchangedValuesEveryMillis="30000" ]
      Thing data luna2000_charging_power_discharged_total       [ readStart="37068", readValueType="uint32", readTransform="JS(mathDivByX.js?by=-100)", updateUnchangedValuesEveryMillis="30000" ]

      Thing data sun2000_production_panels_dcpower_current      [ readStart="37066", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)", updateUnchangedValuesEveryMillis="30000" ]
      Thing data sun2000_production_panels_dcpower_current      [ readStart="37068", readValueType="uint32", readTransform="JS(mathDivByX.js?by=-100)", updateUnchangedValuesEveryMillis="30000" ]
  }

  Bridge poller poll37758 [
    start=37758,
    length=3,
    refresh=10000,
    type="holding" ]{  
      Thing data luna2000_capacity_total_abs                    [ readStart="37758", readValueType="uint32", readTransform="JS(mathDivByX.js?by=1)", updateUnchangedValuesEveryMillis="30000" ]
      Thing data luna2000_capacity_charged_rel                  [ readStart="37760", readValueType="uint16", readTransform="JS(mathDivByX.js?by=10)", updateUnchangedValuesEveryMillis="30000" ]
  }
}

// This should be the Emma
Bridge modbus:tcp:EMMA [
  host="<IP>",
  port=502,
  id=0,
  timeBetweenTransactionsMillis=60,
  reconnectAfterMillis=1000,
  timeBetweenReconnectMillis=1000,
  connectTimeoutMillis=10000,
  afterConnectionDelayMillis=1000
  ] {

  // Energiemesspunkte Emma
  Bridge poller poll30306 [
    start=30306,
    length=56,
    refresh=10000,
    type="holding" ]{  
      Thing data emma_energy_battery_in_today         [ readStart="30306", readValueType="uint32", readTransform="JS(mathDivByX.js?by=-100)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_energy_battery_out_today        [ readStart="30312", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]

      Thing data emma_energy_battery_in_total         [ readStart="30308", readValueType="uint64", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_energy_battery_out_total        [ readStart="30314", readValueType="uint64", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]

      Thing data emma_power_current_production        [ readStart="30354", readValueType="uint32", readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_power_current_consumption       [ readStart="30356", readValueType="uint32", readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_power_current_grid              [ readStart="30358", readValueType="int32",  readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_power_current_battery           [ readStart="30360", readValueType="int32",  readTransform="JS(mathDivByX.js?by=1000)", updateUnchangedValuesEveryMillis="10000" ]

      Thing data emma_energy_productionuse_today      [ readStart="30342", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_energy_productionuse_today_raw  [ readStart="30346", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_energy_consumption_today        [ readStart="30324", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]

      Thing data emma_energy_grid_in_today            [ readStart="30330", readValueType="uint32", readTransform="JS(mathDivByX.js?by=-100)", updateUnchangedValuesEveryMillis="10000" ]
      Thing data emma_energy_grid_out_today           [ readStart="30336", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]

      Thing data emma_energy_inverter_today           [ readStart="30342", readValueType="uint32", readTransform="JS(mathDivByX.js?by=100)",  updateUnchangedValuesEveryMillis="10000" ]
    }
}

Does that help?

Thanks, this is what I’ve been looking for. 10sec refresh is fantastic!

Last week I did a test with the old dongle with V126 (from memory) and a 5 seconds refresh interval gave me one exception in a whole day for polling the Battery charge current. I polled other values parallel in 1, 5, 15 and 60 min intervals, too.
With the new dongle I expect things to be even better but I haven’t done any tests yet.

I checked writing now, too. That also works. so you should be fine, @ollo .

After updating SDongleA-05 to version V200R022C10SPC310 and setting 19200 baudrate is a bit better. I have ~ 40 errors in the first 24 hours but it depends on number of registers and polling as well.

Hi all Modbus guru’s,

What parameters in the OH thing “Modbus TCP Slave” should be used to avoid this?
I’m using the “Modbus TCP Slave” with SunSpec to read a Solaredge inverter and import/export meter, and have a lot of these errors where “Transaction id of request (xxxxx) does not equal response (xxxxx)”. The later is always 1 number lower.

Hi @thicknesss,

This thread is about Huawei inverters, Idk how Modbus works with Solaredge inverters.

You may start by polling for data less often, like every 30sec only.

For Huawei inverters it is important to have some connection warm-up time like this:

afterConnectionDelayMillis=1000

Start with a few registers only before you add larger register ranges.

Good luck!