ESPHome modbus Growatt ShineWiFi-S

I’ve now got my SPH5000 set up to my satisfaction - thank you very much to @scudderfish, @Plawa and @RT1080, your posts here were invaluable.

For the record - I’m using a mini_d1 connected to the serial port (as per @scudderfish) and am no longer using the shine dongle. Switching between Battery First / Load First (I’ve not needed grid first yet) using the code here is working flawlessly, so I’ve no need for the growatt servers.

Cheers,
Tim

2 Likes

I’m using ESPHome in the ShineWifi-X to read PV and battery info from my MOD 10KTL3-XH(BP).

All registers from the pdf work, but some of them (depending on the order in which they are placed in the yaml, is my current theory) now and then give 0, 1 or a massive number (around max int 16 or 32 bit) back. For example, the battery SOC (0-100) jumps to 0 or 1 all the time. The register for total energy into the battery, jumps to the massive number all the time and then comes back to normal.

Is this a known issue? I also have a WaveShare PoE, does the modbus from the big connector maybe give better results?

This might be a stupid qestion, but ill try anyway.
I have a modbus line going from my raspberry pi to a systemair ventilation unit. Could I just tap in on this line and connect my growatt inverter to the same bus?

Hello :wave:,

Add the moment I have shinewife-X stick flashed with: GitHub - pvprodk/GrowattESPHome: ESPHome based code for Growatt inverters

It all works fine, but add the moment I can only read data.

In this topic I saw several times that some have the ability to reduce there output.

Can I achieve something similar?

The goal is, when I return to the grid, to lower the inverter so it stays around 0 watts uses. ( we have to pay now for everything that we don’t use and that’s put back on the grid)

Depends on your inverter and if you have an external meter connected (either via clamps or a modbus connection)

If so yes, it’s possible to limit export.

I have a Min TL-XH. I know, SPH and MIN uses different Modbus Adresses.

I testes this YAML, but the Error Message i got was:
INFO ESPHome 2024.7.0
INFO Reading configuration /config/esphome/growatt.yaml…
Failed config

esphome: None
name: growatt
friendly_name: Growatt
on_boot:
priority: -100
then:
- delay: 20s
- logger.log: ************* In da boot *******************
-
Unable to find action with the name ‘script.execute’.
script.execute:
id: setClock
- script.execute:
id: |-
setBatteryTimes

Used YAML:

esphome:
  name: "growatt"
  friendly_name: Growatt
  on_boot:
    priority: -100
    then:
      - delay: 20s
      - logger.log: "************* In da boot *******************"
      - script.execute:
          id: setClock
      - script.execute:
          id: setBatteryTimes
      
             std::vector<uint16_t> gridfirst_data = {0,23<<8|59,0,0,0,0,0,0,0};
             std::vector<uint16_t> batteryfirst_data = {100,100,1,0,0,0,0,0,0,0,0,23<<8|59,0,0,0,0,0,0,0};
             std::vector<uint16_t> loadfirst_data = {0,23<<8|59,0,0,0,0,0,0,0};

             // Create a modbus command item with the time information as the payload
             esphome::modbus_controller::ModbusCommandItem set_gridfirst_command =
                 esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller, 1080, gridfirst_data.size(), gridfirst_data);
             esphome::modbus_controller::ModbusCommandItem set_batfirst_command =
                 esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller, 1090, batteryfirst_data.size(), batteryfirst_data);
             esphome::modbus_controller::ModbusCommandItem set_loadfirst_command =
                 esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller, 1110, loadfirst_data.size(), loadfirst_data);
            
             // Submit the command to the send queue
             controller->queue_command(set_gridfirst_command);
             controller->queue_command(set_batfirst_command);
             controller->queue_command(set_loadfirst_command);
             ESP_LOGI("Lambda","Setting Grid/Battery/Load");

Whats wrong? Is this YAML not compatible with MIN?

I have the same problem with MOD10ktl3-XH-BP.
With the original WiFi-X stick I can read/write the Register (3049) via the website.
With the custom flashed WiFi-X stick → ESP-Home → Home-Assistant I can’t read or write the register.

Now i tried this Code, and it does nothing with my MIN TL-XH.
Any Ideas?

button:
  - platform: template
    name: "Battery First"
    on_press:
      then:
          lambda: |-
            esphome::modbus_controller::ModbusController *controller = id(growatt);
            std::vector<uint16_t> on={0,23*256+59,1};
            std::vector<uint16_t> off={0,23*256+59,0};
            int size = on.size();

            ESP_LOGI("ModbusLambda","Enqueue Writes");
            //BF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1100,size,on));
            //LF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1110,size,off));
            //GF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1080,size,off));
            ESP_LOGI("ModbusLambda","Writes");

  - platform: template
    name: "Load First"
    on_press:
      then:
          lambda: |-
            esphome::modbus_controller::ModbusController *controller = id(growatt);
            std::vector<uint16_t> on={0,23*256+59,1};
            std::vector<uint16_t> off={0,23*256+59,0};
            int size = on.size();

            ESP_LOGI("ModbusLambda","Enqueue Writes");
            //BF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1100,size,off));
            //LF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1110,size,on));
            //GF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1080,size,off));
            ESP_LOGI("ModbusLambda","Writes");

  - platform: template
    name: "Grid First"
    on_press:
      then:
          lambda: |-
            esphome::modbus_controller::ModbusController *controller = id(growatt);
            std::vector<uint16_t> on={0,23*256+59,1};
            std::vector<uint16_t> off={0,23*256+59,0};
            int size = on.size();

            ESP_LOGI("ModbusLambda","Enqueue Writes");
            //BF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1100,size,off));
            //LF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1110,size,off));
            //GF1
            controller->queue_command(esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(controller,1080,size,on));
            ESP_LOGI("ModbusLambda","Writes");

Based on the knowledge in this topic I created a Growatt monitor using a m5stack-atom-s3-lite and rs232 base. I have an old Growatt inverter hence it works with the esphome growatt platform (no battery just solar) out of the box. Really happy that it works! It is even powered by pin9 on the connector as the rs232base has a chip to convert the 12v. Thanks to all who contributed to this topic!

This is what it looks like (need to tidy up the wires and connector):

3 Likes

Would it be possible to share your config for this? It seems like nobody shared their RS232 config and everyone works with RS485 modbus.

Regards,
Paul

Here’s the config I used with the RS232 base from m5stack:

esphome:
  name: growattpv1
  friendly_name: Growatt PV Inverter Zolder

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

  
# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_encryption_key

ota:
  - platform: esphome
    password: !secret ota_password 

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

uart:
  - id: mod_bus
    tx_pin: 6
    rx_pin: 5
    baud_rate: 9600

modbus:
  id: modbus1
  uart_id: mod_bus
  flow_control_pin: GPIO4

modbus_controller:
  - id: growatt
    address: 0x1
    modbus_id: modbus1
    setup_priority: -10

sensor:
  - platform: growatt_solar
    protocol_version: RTU

    inverter_status:
      name: "Growatt Status Code"

    phase_a:
      voltage:
          name: "Growatt Voltage Phase A"
      current:
          name: "Growatt Current Phase A"
      active_power:
          name: "Growatt Power Phase A"
    phase_b:
      voltage:
          name: "Growatt Voltage Phase B"
      current:
          name: "Growatt Current Phase B"
      active_power:
          name: "Growatt Power Phase B"
    phase_c:
      voltage:
          name: "Growatt Voltage Phase C"
      current:
          name: "Growatt Current Phase C"
      active_power:
          name: "Growatt Power Phase C"

    pv1:
      voltage:
          name: "Growatt PV1 Voltage"
      current:
          name: "Growatt PV1 Current"
      active_power:
          name: "Growatt PV1 Active Power"

    pv2:
      voltage:
          name: "Growatt PV2 Voltage"
      current:
          name: "Growatt PV2 Current"
      active_power:
          name: "Growatt PV2 Active Power"

    active_power:
      name: "Growatt Grid Active Power"

    pv_active_power:
      name: "Growatt PV Active Power"

    frequency:
      name: "Growatt Frequency"

    energy_production_day:
      name: "Growatt Today's Generation"

    total_energy_production:
      name: "Growatt Total Energy Production"

    inverter_module_temp:
      name: "Growatt Inverter Module Temp"

I’m also trying to build a logger using a Wemos D1 mini, the RS485 converter and ESPHome. It was a puzzle to get it working, as the hardware TX and RX UART pins were not working. At the end I’ve chosen two other GPIO pins (GPIO4 and GPIO5) and this works! I only have the trouble that the Wemos is unexpectedly resetting a few times per day. And once per week it is fully crashing and the only way to resolve this is to uplug and replug the power.

I’ve changed the Wemos as I was thinking it might be a fault of the device. With the new Wemos the crases seem to occur less, but are still occuring. In the code you can see that I’ve disabled the logger on the UART, so that should not be the cause of the problem.

Is there anybody with a simlar problem? Or ideas how to debug this?

This is the code I’m using:

substitutions:
  device_name: "esp-growatt"
  friendly_name: "Growatt"
  fixed_ip: "192.168.200.34"

packages:
  common: !include includes/common.yaml

esphome:
  name: "${device_name}"
  friendly_name: "${friendly_name}"

esp8266:
  board: d1_mini

debug:
  update_interval: 5s

logger:
 level: DEBUG
 baud_rate: 0   


uart:
  id: mod_bus
  tx_pin: D5 #werkte niet op de standaard TX en RX pins (die schijnen al bezet te zijn)
  rx_pin: D6
  baud_rate: 9600

modbus:
  id: modbus1
  uart_id: mod_bus

modbus_controller:
  - id: growatt
    address: 0x1
    modbus_id: modbus1
    setup_priority: -10  

sensor:
  - platform: growatt_solar
    protocol_version: RTU
    pv1:
      voltage:
          name: "Growatt DC Voltage - v2 GS"


  - platform: modbus_controller
    address: 0
    register_type: "read"
    internal: true
    accuracy_decimals: 0
    id: status

  - platform: modbus_controller
    name: "${friendly_name} DC Power" # zelfde waarde als 5
    address: 1
    register_type: "read"
    unit_of_measurement: W
    device_class: power
    icon: mdi:flash
    value_type: U_DWORD
    accuracy_decimals: 1
    id: DC_power
    filters:
    - multiply: 0.1
        
  - platform: modbus_controller
    name: "${friendly_name} AC Power - Three/single phase grid output"
    address: 40
    register_type: "read"
    unit_of_measurement: W
    device_class: power
    icon: mdi:flash
    value_type: U_DWORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1

    
  - platform: modbus_controller
    name: "${friendly_name} AC Power"
    address: 35
    register_type: "read"
    unit_of_measurement: W
    device_class: power
    icon: mdi:flash
    value_type: U_DWORD
    accuracy_decimals: 1
    id: AC_power
    filters:
    - multiply: 0.1
    

  - platform: modbus_controller
    name: "${friendly_name} Temperature"
    address: 93 #kan ook 3093 gebruiken, 94 is ook hetzelfde
    register_type: "read"
    unit_of_measurement: °C
    device_class: temperature
    icon: mdi:thermometer
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1

  - platform: modbus_controller
    name: "${friendly_name} Temperature - v2"
    address: 97 #kan ook 3097 gebruiken
    register_type: "read"
    unit_of_measurement: °C
    device_class: temperature
    icon: mdi:thermometer
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1

  - platform: modbus_controller
    name: "${friendly_name} DC Voltage"
    address: 3
    register_type: "read"
    unit_of_measurement: V
    device_class: voltage
    icon: mdi:sine-wave
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1
    
  - platform: modbus_controller
    name: "${friendly_name} DC Input Current"
    address: 4
    register_type: "read"
    unit_of_measurement: A
    device_class: current
    icon: mdi:flash
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1
    
  - platform: modbus_controller
    name: "${friendly_name} AC Frequency"
    address: 37
    register_type: "read"
    unit_of_measurement: Hz
    icon: mdi:sine-wave
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.01
  
  - platform: modbus_controller
    name: "${friendly_name} AC Voltage"
    address: 38
    register_type: "read"
    unit_of_measurement: V
    device_class: voltage
    icon: mdi:flash
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1
  
  - platform: modbus_controller
    name: "${friendly_name} AC Output Current"
    address: 39
    register_type: "read"
    unit_of_measurement: A
    device_class: current
    icon: mdi:flash
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1

  - platform: modbus_controller
    name: "${friendly_name} Production Today"
    address: 53
    register_type: "read"
    unit_of_measurement: kWh
    device_class: energy
    icon: mdi:flash
    value_type: U_DWORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1
    - lambda: |
        if (x < 0) return {}; 
        else if (x > 100000) return {}; 
        else return x;
    
  - platform: modbus_controller
    name: "${friendly_name} Production Total"
    address: 55
    register_type: "read"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy
    icon: mdi:flash
    value_type: U_DWORD
    accuracy_decimals: 1
    filters:
    - multiply: 0.1
    - lambda: |
        if (x < 0) return {}; 
        else if (x > 100000) return {}; 
        else return x;

  - platform: template
    name: "Inverter efficiency"
    lambda: |-
      return((id(AC_power).state / id(DC_power).state) * 100);
    unit_of_measurement: '%'

  - platform: debug
    free:
      name: "Heap Free"
    fragmentation:
      name: "Heap Fragmentation"
    block:
      name: "Heap Max Block"
    loop_time:
      name: "Loop Time"



text_sensor:

  - platform: debug
    device:
      name: "Device Info"
    reset_reason:
      name: "Reset Reason"      


I use tx_pin: 1 and rx_pin: 3 also a wemos d1 mini - no problems for 2 years.

Will share my config when back from holiday.

1 Like

@RT1080 , thanks for sharing your experience, that would be great!

In the meanwhile I’ve included the logger component, there I learn that the reboots are caused by the ‘Hardware watchdog’ and ‘Software watchdog’ (not always the same). This is the info logged at the last reset:

2024.7.3|Flash: 4096kB Speed:40MHz Mode:DOUT|Chip: 0x007ce14a|SDK: 2.2.2-dev(38a443e)|Core: 3.1.2|Boot: 6|Mode: 1|CPU: 80|Flash: 0x0016405e|Reset: Software Watchdog|Fatal exception:4 flag:3 (Software Watchdog) epc1:0x4026c2c6 epc2:0x00000000 epc3:0x000000

Edit: issue is possibly fixed by connecting the RS485 to the 3.3V connector on the ESP device, instead of the 5V connector. Possibly a too high voltage on the GPIO pins caused these crashes

Have you seen my post from the MOD TL-XH (post 315). It uses the same registers. I have explained it quite detailed, but you couldt just try my code. It looks like the code you used here, but with other numbers in the vectors. I have explained my vectors in the text.

1 Like

any suggestions where to start if I want to change the values of some registers of a GROWATT SPH 4600 single phase inverter ?

Thanks

What you have? Hardware, code, registers…

SPH 4600 connected via modbus to Eastron SDM 630
and
also connected to via Modbus to Pi / Homeassistant

like here in the bottome part (upper Part AC cabling)

In the long term I want to move Home Assistant Pi into the middle by using a proxy which means 1 ModBus from Eastron SDM 630 via Pi 4 to the SPH4600
to be able to use the other modbus port on the SPH 4600 via Laptop etc

which you can find here

I want to control the registers for charging the battery to have control over the charging speed .

Currently I am running that manually with the SPH onboard times slots like “battery first” from 11 am to 3 pm .
But that is not working as I wanted cause the charging power is jumping constantly from 0 to 1800 W and back close to 0 in 3 or 5 steps , sometimes up to 3000 W even in constant sunshine instead of showing a straight line.

I usually then change the power rate to 35% which then pushes the charging up to 3200 to 3300 Watt based on growatt figures. 65% x 4600 = 3000 W from the panels used for dc charging the battery out of 4600 Watt possible, so 1600 Watt AC left.

But I want to get rid of the manual interaction and the timer that is required now.

The SPH 4600 has 2x 2.800 Wp strings, so each string overpanelled by 500 Wp.

Therefore I am asking cause I miss this feature.

Hi there,

Can you still use this code?

A tip for whoever is using this drawing. I had an issue of sudden watchdog resets of my ESP device. After a lot of troubleshooting (replacing the ESP device, trying ESP32, replacing the RS485 converter, changing GPIO ports, etc etc) I found out that the RS485 convertor should be connected to the 3.3V pin of the ESP instead of the 5V. By connecting it to the 5V it is crashing the ESP every now and then. Possibly because a too high voltage on the GPIO pins

1 Like