Sungrow SH10.RT Modbus integration

I‘ve another question.
The template sensor of the sungrow inverter state is allways “Unknown - should not see me!” because the modbus sensor of the system state is 0 if the inverter is running normal.

In the Logs I can also find these values for the system state modbus sensor: 0, 21760, 5120 and 5632.

I’m using a SH10RT. All other values for example for the device type are correct.

      - name: System state
        unique_id: sg_system_state
        slave: !secret sungrow_modbus_slave
        address: 12999 # reg 13000
        input_type: input
        count: 1
        data_type: uint16
        swap: word
        precision: 0
        scale: 1
        scan_interval: 10

  - name: Sungrow inverter state
    unique_id: sg_inverter_state
    state: >-
      {% if ((states('sensor.system_state') | int(default=0)) == 0x0002) %}
        Stop
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0008) %}
        Standby
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0010) %}
        Initial Standby
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0020) %}
        Startup
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0040) %}
        Running
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0100) %}
        Fault
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0400) %}
        Maintain mode
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x0800) %}
        Forced mode
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x1000) %}
        Off-grid mode
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x2501) %}
        Restarting
      {% elif ((states('sensor.system_state') | int(default=0)) == 0x4000) %}
        External EMS mode
      {% else %}
        Unknown - should not see me!
      {% endif %}

Hallo,
the integration is not running since the last core update.
Has anyone the same Problem? I Can’t restart HA too

Had also applied the update last night and the Modbus integration stopped working. Fortunately I had made a backup that I could undo the update.

ok i never restored a back up … i hope it is working for me too and not crashing my HA :slight_smile: How long needs it to restore it?

10 minutes

Same problem here.

maybe it’s the same modbus issue:

Just install 2023.8.2 and wait for 2023.8.4. the current release 2023.8.3 the modbus is broken. You also don’t need to restore a backup. Just use terminal and execute „ha core update —version 2023.8.2“

check the last update - it was an issue with my code :slight_smile:

I used “word swaps” for int16 uint16 data types, which does no sense. The latest modbus updates found this possible issue and the validator was updated accordingly. Then it did not allow the integration to load, which is actually a desired behaviour…

Hello mkai,

great work, great support, top !

I installed your cool sungrow integration for our SH10RT, it works but i dont get the battery charge/discharge gauge working. The binary types also are still without function.
Is this a known issue ? what can i check ?

Also the power flow shows only the total power data. I configured it like you sayed in dec '21
Total … parameters
What is wrong there ?

Thank you very much for some tip
Thomas

additional info, just have a look to the sensor parameter… the “Battery discharging power” has a value of 0, the “Battery power raw” shows the right value

I have this issue too — on/off indicators are all off and some of the sensors are displaying 0. I also have the problem with running_state being 0 and Sungrow inverter state being “Unknown - should not see me!”

Did anyone have any luck figuring out how to get these working? I’ve tried a couple of things in this thread but nothing has fixed it yet. SH6.0RS inverter and SBR096 battery

Oh my god … have found the inconsistency :frowning:
I have configured the wrong Lan port, it seems that the one on WinNetS can also do a little bit ModBus, but does not deliver everything. After the changeover, I now receive correct values.

The data for the energy display is also correct if you understand that the daily values are displayed there. I was of the (stupid) opinion that the flow is displayed there :frowning:
Just learning how homeassitant is working :wink:

most of the “some sensors are not correct”-issues are related to not using the internal LAN port.

The Ethernet by WiNetS only provides a subset of the functions (same with the WLAN).

So use the internal Ethernet port of the Inverter (NOT the WinetS).

btw. there are currently some issues with the new HA version 2023.9 and pymodbus (which this integration relys on). In some cases this leads to a stopped communication after some minutes.

If you are affected, downgrade to 2023.8.

If you are still on <= 2023.8: Stay, until the github message says “cleared” :slight_smile:

I just updated the description in the github to clarify more :slight_smile:

1 Like

As I also couldn’t find any entity for the total energy used by the complete load / all devices / my home (whatever you wanna call it).
Do you calculate it on your own now (how exactly)?

For the current value (W instead of kWh) we have the power consumption as entity “Load power”.

Before I installed the solar panels, the used energy of the house was simply the value on the smart meter of my grid provider, and it was always a good indicator to see if I use more or less energy over time and if there’s room for improvement or savings.
So I want to implement this again, even if the smart meter can’t provide it anymore because of the savings of the solar installation.

I think I need new template sensors like this, maybe someone with more experience in solar stuff can tell me if I understand the values correctly:

sensor.total_exported_energy_from_battery = sensor.total_exported_energy - sensor.total_exported_energy_from_pv

sensor.total_direct_battery_consumption = sensor.total_battery_discharge - sensor.total_exported_energy_from_battery

sensor.total_load_energy = sensor.total_imported_energy + sensor.total_direct_energy_consumption + sensor.total_direct_battery_consumption

@mkai if this makes sense, do you think this would be useful for others too and you might add it to your repo?
Otherwise I add it to my local config …

Thanks, everyone

Does this integration also work with SGx.0RT inverters?

Partly.
Some things do not work. The SG inverter uses partly other registers and you don’t need the battery section.
Here is the code for my SG. The code is based on the code from @mkai.

modbus:
  - name: WR2_Sungrow_SG6.0RT
    type: tcp
    host: !secret sungrow_wr2_modbus_host_ip
    port: !secret sungrow_wr2_modbus_port
    retries: 10

    sensors:
      - name: WR2_Sungrow device type code
        unique_id: wr2_dev_code
        slave: !secret sungrow_wr2_modbus_slave
        address: 4999 # reg 5000
        input_type: input
        
        data_type: uint16
        
        scan_interval: 600

      - name: WR2_Inverter temperature
        unique_id: wr2_inverter_temperature
        slave: !secret sungrow_wr2_modbus_slave
        address: 5007 # reg 5008
        input_type: input
        
        data_type: int16
        precision: 1
        unit_of_measurement: °C
        device_class: Temperature
        scale: 0.1
        scan_interval: 10

      - name: WR2_MPPT1 voltage
        unique_id: wr2_mppt1_voltage
        slave: !secret sungrow_wr2_modbus_slave
        address: 5010 # reg 5011
        input_type: input
        
        data_type: uint16
        
        precision: 1
        unit_of_measurement: V
        device_class: Voltage
        scale: 0.1
        scan_interval: 10

      - name: WR2_MPPT1 current
        unique_id: wr2_mppt1_current
        slave: !secret sungrow_wr2_modbus_slave
        address: 5011 # reg 5012
        input_type: input
        
        data_type: uint16
        
        precision: 2
        unit_of_measurement: A
        device_class: Current
        scale: 0.1
        scan_interval: 10

      - name: WR2_MPPT2 voltage
        unique_id: wr2_mppt2_voltage
        slave: !secret sungrow_wr2_modbus_slave
        address: 5012 # reg 5013
        input_type: input
        
        data_type: uint16
        
        precision: 1
        unit_of_measurement: V
        device_class: Voltage
        scale: 0.1
        scan_interval: 10

      - name: WR2_MPPT2 current
        unique_id: wr2_mppt2_current
        slave: !secret sungrow_wr2_modbus_slave
        address: 5013 # reg 5014
        input_type: input
        
        data_type: uint16
        
        precision: 2
        unit_of_measurement: A
        device_class: Current
        scale: 0.1
        scan_interval: 10

      - name: WR2_Total DC power
        unique_id: wr2_total_dc_power
        slave: !secret sungrow_wr2_modbus_slave
        address: 5016 # reg 5017
        input_type: input
        
        data_type: uint32
        swap: word
        precision: 0
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        scale: 1
        scan_interval: 10

      - name: WR2_Grid frequency
        unique_id: wr2_grid_frequency
        slave: !secret sungrow_wr2_modbus_slave
        address: 5035 # reg 5036
        input_type: input
        
        data_type: uint16
        
        precision: 2
        unit_of_measurement: "Hz"
        device_class: frequency
        state_class: measurement
        scale: 0.1
        scan_interval: 10

      - name: WR2_Reactive power
        unique_id: wr2_reactive_power
        slave: !secret sungrow_wr2_modbus_slave
        address: 5032 # reg 5033
        input_type: input
        
        data_type: int32
        swap: word
        precision: 0
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        scale: 1
        scan_interval: 10

      - name: WR2_Power factor
        unique_id: wr2_power_factor
        slave: !secret sungrow_wr2_modbus_slave
        address: 5034 # reg 5035
        input_type: input
        data_type: int16
        precision: 3
        unit_of_measurement: "%"
        device_class: power_factor
        state_class: measurement
        scale: 0.001
        scan_interval: 10

      - name: WR2_Meter active power raw
        unique_id: wr2_meter_active_power_raw
        slave: !secret sungrow_wr2_modbus_slave
        address: 5600 # reg 5601
        input_type: input
        
        data_type: int32
        swap: word
        precision: 0
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        scale: 1
        scan_interval: 10

      - name: WR2_BDC rated power
        unique_id: wr2_bdc_rated_power
        slave: !secret sungrow_wr2_modbus_slave
        address: 5627 # reg 5628
        input_type: input
        
        data_type: uint16
        
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        scale: 100
        scan_interval: 600

      - name: WR2_System state
        unique_id: wr2_system_state
        slave: !secret sungrow_wr2_modbus_slave
        address: 5037 # reg 5038
        input_type: input
        
        data_type: uint16
        
        precision: 0
        scale: 1
        scan_interval: 10

      # register running state is not available for certain SH*RS inverters
      # template sensors are used to determine the states based on other sensors
      - name: WR2_Running state
        unique_id: wr2_running_state
        slave: !secret sungrow_wr2_modbus_slave
        address: 5038 # reg 5039
        input_type: input
        
        data_type: uint16
        
        precision: 0
        scale: 1
        scan_interval: 10

      - name: WR2_Daily PV generation
        unique_id: wr2_daily_pv_generation
        slave: !secret sungrow_wr2_modbus_slave
        address: 5002 # reg 5003
        input_type: input
        
        data_type: uint16
        
        precision: 1
        unit_of_measurement: kWh
        device_class: energy
        state_class: total_increasing
        scale: 0.1
        scan_interval: 600

      - name: WR2_Total PV generation
        unique_id: wr2_total_pv_generation
        slave: !secret sungrow_wr2_modbus_slave
        address: 5003 # reg 5004
        input_type: input
        
        data_type: uint32
        swap: word
        precision: 1
        unit_of_measurement: kWh
        device_class: energy
        state_class: total

        scan_interval: 600


# 'virtual' template sensors for better readability
template:
  - binary_sensor:
      - name: WR2_PV generating
        unique_id: wr2_pv_generating
        availability: >-
          {{states('sensor.wr2_running_state')|is_number or 
            states('sensor.wr2_total_dc_power')|is_number
          }}
        delay_on:
          seconds: 60
        state: >-
          {% if states('sensor.wr2_running_state')|is_number %}
            {# use available sensor running_state #}
            {{ states('sensor.wr2_running_state')|int(default=0)|bitwise_and(0x1) > 0 }}
          {% else %} 
            {# workaround for SH*RS inverters without working running_state #}
            {% if states('sensor.wr2_total_dc_power')|int > 0 %}
              1
            {% else %} 
              0 
            {% endif %}
          {% endif %}


  - sensor:
      - name: WR2_MPPT1 power
        unique_id: wr2_mppt1_power
        unit_of_measurement: W
        device_class: power
        availability: "{{states('sensor.wr2_mppt1_voltage')|is_number and states('sensor.wr2_mppt1_current')|is_number }}"
        state: "{{ (states('sensor.wr2_mppt1_voltage') | float * states('sensor.wr2_mppt1_current') | float) |int }}"

      - name: WR2_MPPT2 power
        unique_id: wr2_mppt2_power
        unit_of_measurement: W
        device_class: power
        availability: "{{states('sensor.wr2_mppt2_voltage')|is_number and states('sensor.wr2_mppt2_current')|is_number }}"
        state: "{{ (states('sensor.wr2_mppt2_voltage') | float * states('sensor.wr2_mppt2_current') | float) |int }}"

      - name: WR2_Sungrow inverter state
        unique_id: wr2_inverter_state
        state: >-
          {% if ((states('sensor.wr2_system_state') | int(default=0)) == 0x8000) %}
            Stop
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x1400) %}
            Standby
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x1200) %}
            Initial Standby
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x1600) %}
            Startup
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x0) %}
            Running
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x5500) %}
            Fault
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x1500) %}
            Emergency Stop
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x1200) %}
            Initial standby
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x9100) %}
            Alarm run
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x8100) %}
            Derating run
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x8200) %}
            Dispatch run
          {% elif ((states('sensor.wr2_system_state') | int(default=0)) == 0x1300) %}
            Key stop
          {% else %}
            Unknown - should not see me!
          {% endif %}

      - name: WR2_Sungrow device type
        unique_id: wr2_device_type
        state: >-
          {% if ((states('sensor.wr2_sungrow_device_type_code') | int(default=0))  == 0x243D) %}
            SG3.0RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x243E) %}
            SG4.0RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2430) %}
            SG5.0RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2431) %}
            SG6.0RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x243C) %}
            SG7.0RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2432) %}
            SG8.0RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2433) %}
            SG10RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2434) %}
            SG12RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2435) %}
            SG15RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2436) %}
            SG17RT
          {% elif ((states('sensor.wr2_sungrow_device_type_code') | int(default=0)) == 0x2437) %}
            SG20RT
          {% else %}
            Unknown device code!
          {% endif %}

input_select:
  wr2_set_inverter_run_mode:
    name: WR2_Inverter mode
    options:
      - "Enabled"
      - "Shutdown"

# Automations: Write modbus registers on input changes via GUI
# note: If you change a value by the sliders, it will take up to 60 seconds until the state variables are updated
# Unfortunately, I could not find a way to "force update" modbus registers, yet...
automation:
  - id: "automation_wr2_sungrow_inverter_state"
    alias: "sungrow wr2 inverter state"
    description: "Enables/ stops the inverter"
    trigger:
      - platform: state
        entity_id:
          - input_select.wr2_set_inverter_run_mode
    condition: []
    variables:
      sg_start: 0xCF
      sg_stop: 0xCE
    action:
      - service: modbus.write_register
        data_template:
          hub: WR2_Sungrow_SG6.0RT
          slave: !secret sungrow_wr2_modbus_slave
          address: 12999 # reg 13000
          value: >
            {% if is_state('input_select.wr2_set_inverter_run_mode', 'Enabled') %}
            {{sg_start}}
            {% else %}
            {{sg_stop}}
            {% endif %}
    mode: single

  - id: "automation_wr2_sungrow_inverter_state_input_selector_update"
    alias: "sungrow wr2 inverter enable/ stop input selector update"
    description: "Updates enable/ stops input selector"
    trigger:
      - platform: state
        entity_id:
          - sensor.wr2_system_state
    condition: []
    action:
      - service: input_select.select_option
        target:
          entity_id: input_select.wr2_set_inverter_run_mode
        data:
          option: >
            {% if is_state('sensor.wr2_sungrow_inverter_state', 'Stop') %}
            "Shutdown"
            {% else %}
            "Enabled"
            {% endif %}
    mode: single

1 Like

I am planning to provide some auto-generated yaml-files with different config settings in the future (using github actions for automated copy/pasting). I guess that will take 1-2 month, depending on my schedule…

Just try to add the integration. Most Registers for SG* work also for SH* inverters.

@basti242 : do you have a list of differences at hand? I don’t have the time at the moment to manually diff the modbus register description from sungrow

1 Like

@Thyraz

will check it, soon. Sorry, not much time at the moment :slight_smile:
but it totally makes sense to integrate a template sensor for this!

I use the Home Assistant Energy Dashboard to get the house load in energy/kWh

The Energy Dashboard uses these sensors as input:

Total imported energy
Total exported energy

Total PV generation

Total battery discharge
Total battery charge

I assume:
total_load_energy = Total PV generation - Total exported energy + Total imported energy - Total battery charge + Total battery discharge

@mkai
Tomorow I will create a list for you.

Hi,
am I the only one having issues with modbus and 2023.10.0?
After updating the sensors are “unavailable” again… :upside_down_face:

Invalid config for [modbus]: BDC rated power: count: 1 cannot be combined with data_type: uint16 @ data[‘modbus’][0][‘sensors’][19]. Got {‘name’: ‘BDC rated power’, ‘unique_id’: ‘sg_bdc_rated_power’, ‘slave’: 1, ‘address’: 5627, ‘input_type’: ‘input’, ‘count’: 1, ‘data_type’: ‘uint16’, ‘swap’: ‘none’, ‘unit_of_measurement’: ‘W’, ‘device_class’: ‘power’, ‘state_class’: ‘measurement’, ‘scale’: 100, ‘scan_interval’: 600} BMS max. charging current: count: 1 cannot be combined with data_type: uint16 @ data[‘modbus’] …

I found this issue maybe related to my problem:

Any ideas? Shall I downgrade?