SolarEdge zero export through modbus meter proxy

Hi! I am trying to achieve zero export for my SolarEdge SE5K inverter. Inspired by nmakel’s script, I am trying to adapt this for ESPhome modbus server.

I have a succesful modbus connection, the inverter is receiving import-/export power values for a little while. But then this error shows up in the ESPhome log:
[Unexpected response from address 2, which is mapped to this device.]
After a little while, the inverter is no longer updating values and eventually shows values as NA.

Hardware: Xiao ESP32 C3 with RS485 breakout board, connected to RS485-1 on the inverter. Both ends are terminated. Address 1 = inverter, address 2 = meter proxy. P1 energy meter values are coming from a SlimmeLezer.

How should I troubleshoot this / pinpoint the issue? I tried some random things but none of them seem to work. E.g. changed the update_interval to 5 seconds. Tried different rx_buffer_size, rx_full_treshold and rx_timeout. No effect on this error. Enabled UART logging but got no meaningful info that I could figure out how to act on.

Can anyone help how to best tackle this?

This is the ESPhome YAML:

# Board: Seeed XIAO ESP32C3 (Seeed Studio)
# Definition: definitions/boards/seeed-xiao-esp32c3/manifest.yaml

esphome:
  name: solaredge-meterproxy
  friendly_name: solaredge-meterproxy

esp32:
  variant: esp32c3
  flash_size: 4MB
  framework:
    type: esp-idf

logger:
  baud_rate: 0
  level: DEBUG
  logs:
    uart: NONE
    modbus: DEBUG
    modbus_server: DEBUG
    sensor: WARN
    api.service: WARN
    homeassistant.sensor: WARN

api:
  encryption:
    key: "xxxxxxxx"

ota:
  - platform: esphome
    password: !secret solaredge_meterproxy__ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: solaredge-meter Fallback Hotspot
    password: "xxxxx"

captive_portal:

uart:
  id: uart_rs485
  tx_pin: GPIO6
  rx_pin: GPIO7
  baud_rate: 9600
  flow_control_pin: GPIO4
  parity: NONE
  stop_bits: 1
  # rx_buffer_size: 256
  # rx_full_threshold: 2
  # rx_timeout: 2

  #Activeer dit alleen tijdelijk voor UART-debugging.
  # debug:
  #   direction: BOTH
  #   dummy_receiver: false
  #   after:
  #     timeout: 10ms
  #   sequence:
  #     - lambda: |-
  #         UARTDebug::log_hex(direction, bytes, ' ');

modbus:
  id: mb
  uart_id: uart_rs485
  role: server

modbus_server:
  id: se_meter
  modbus_id: mb
  address: 2

  courtesy_response:
    enabled: true
    register_last_address: 2000
    register_value: 0

  registers:
    # 1700 block - identification

    - address: 1700
      value_type: U_DWORD_R
      read_lambda: |-
        return 0x143BD6DC;

    - address: 1702
      value_type: U_DWORD_R
      read_lambda: |-
        return 0;

    - address: 1704
      value_type: U_DWORD_R
      read_lambda: |-
        return 0;

    - address: 1706
      value_type: U_WORD
      read_lambda: |-
        return 202;

    - address: 1707
      value_type: U_WORD
      read_lambda: |-
        return 31;

    - address: 1708
      value_type: U_WORD
      read_lambda: |-
        return 0;

    - address: 1709
      value_type: U_WORD
      read_lambda: |-
        return 0;

    # 1650 block - communication config

    - address: 1650
      value_type: U_WORD
      read_lambda: |-
        return 0;
      write_lambda: |-
        return true;

    - address: 1651
      value_type: U_WORD
      read_lambda: |-
        return 2;
      write_lambda: |-
        return true;

    - address: 1652
      value_type: U_WORD
      read_lambda: |-
        return 4;
      write_lambda: |-
        return true;

    - address: 1653
      value_type: U_WORD
      read_lambda: |-
        return 0;
      write_lambda: |-
        return true;

    - address: 1654
      value_type: U_WORD
      read_lambda: |-
        return 0;
      write_lambda: |-
        return true;

    - address: 1655
      value_type: U_WORD
      read_lambda: |-
        return 5;
      write_lambda: |-
        return true;

    # 1600 block - meter configuration

    - address: 1600
      value_type: U_DWORD_R
      read_lambda: |-
        return 0;
      write_lambda: |-
        return true;

    - address: 1602
      value_type: U_WORD
      read_lambda: |-
        return 5;
      write_lambda: |-
        return true;

    - address: 1603
      value_type: U_WORD
      read_lambda: |-
        return 5;
      write_lambda: |-
        return true;

    - address: 1604
      value_type: U_WORD
      read_lambda: |-
        return 5;
      write_lambda: |-
        return true;

    - address: 1605
      value_type: U_WORD
      read_lambda: |-
        return 5;
      write_lambda: |-
        return true;

    - address: 1606
      value_type: U_WORD
      read_lambda: |-
        return 0;
      write_lambda: |-
        return true;

    - address: 1607
      value_type: U_WORD
      read_lambda: |-
        return 1;
      write_lambda: |-
        return true;

    - address: 1608
      value_type: S_WORD
      read_lambda: |-
        return 0;
      write_lambda: |-
        return true;

    - address: 1609
      value_type: U_WORD
      read_lambda: |-
        return 15;
      write_lambda: |-
        return true;

    - address: 1610
      value_type: U_WORD
      read_lambda: |-
        return 1;
      write_lambda: |-
        return true;

    - address: 1617
      value_type: U_WORD
      read_lambda: |-
        return 1500;
      write_lambda: |-
        return true;

    - address: 1618
      value_type: S_WORD
      read_lambda: |-
        return 120;
      write_lambda: |-
        return true;

    - address: 1621
      value_type: U_WORD
      read_lambda: |-
        return 20000;
      write_lambda: |-
        return true;

    # 1000 block - live values
    # FP32_R = 32-bit floating point, little word order

    # Energie in Wh
    - address: 1000
      value_type: FP32_R
      read_lambda: |-
        return id(total_energy_active).state;

    - address: 1002
      value_type: FP32_R
      read_lambda: |-
        return id(import_energy_active).state;

    - address: 1004
      value_type: FP32_R
      read_lambda: |-
        return id(total_energy_active).state;

    - address: 1006
      value_type: FP32_R
      read_lambda: |-
        return id(import_energy_active).state;

    # Vermogen in W
    - address: 1008
      value_type: FP32_R
      read_lambda: |-
        return id(power_active_total).state;

    - address: 1010
      value_type: FP32_R
      read_lambda: |-
        return id(l1_power_active).state;

    - address: 1012
      value_type: FP32_R
      read_lambda: |-
        return id(l2_power_active).state;

    - address: 1014
      value_type: FP32_R
      read_lambda: |-
        return id(l3_power_active).state;

    # Spanning in V
    - address: 1016
      value_type: FP32_R
      read_lambda: |-
        return id(voltage_ln).state;

    - address: 1018
      value_type: FP32_R
      read_lambda: |-
        return id(l1n_voltage).state;

    - address: 1020
      value_type: FP32_R
      read_lambda: |-
        return id(l2n_voltage).state;

    - address: 1022
      value_type: FP32_R
      read_lambda: |-
        return id(l3n_voltage).state;

    - address: 1024
      value_type: FP32_R
      read_lambda: |-
        return id(voltage_ll).state;

    - address: 1026
      value_type: FP32_R
      read_lambda: |-
        return id(l12_voltage).state;

    - address: 1028
      value_type: FP32_R
      read_lambda: |-
        return id(l23_voltage).state;

    - address: 1030
      value_type: FP32_R
      read_lambda: |-
        return id(l31_voltage).state;

    # Frequentie in Hz
    - address: 1032
      value_type: FP32_R
      read_lambda: |-
        return id(grid_frequency).state;

    # 1100 block - extra energy and power
    # Alle energievelden zijn in Wh

    - address: 1100
      value_type: FP32_R
      read_lambda: |-
        return id(l1_energy_active).state;

    - address: 1102
      value_type: FP32_R
      read_lambda: |-
        return id(l2_energy_active).state;

    - address: 1104
      value_type: FP32_R
      read_lambda: |-
        return id(l3_energy_active).state;

    - address: 1106
      value_type: FP32_R
      read_lambda: |-
        return id(l1_import_energy_active).state;

    - address: 1108
      value_type: FP32_R
      read_lambda: |-
        return id(l2_import_energy_active).state;

    - address: 1110
      value_type: FP32_R
      read_lambda: |-
        return id(l3_import_energy_active).state;

    - address: 1112
      value_type: FP32_R
      read_lambda: |-
        return id(export_energy_active).state;

    - address: 1114
      value_type: FP32_R
      read_lambda: |-
        return id(export_energy_active).state;

    - address: 1116
      value_type: FP32_R
      read_lambda: |-
        return id(l1_export_energy_active).state;

    - address: 1118
      value_type: FP32_R
      read_lambda: |-
        return id(l2_export_energy_active).state;

    - address: 1120
      value_type: FP32_R
      read_lambda: |-
        return id(l3_export_energy_active).state;

    - address: 1122
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1124
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1126
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1128
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1130
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1132
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1134
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1136
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1138
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1140
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1142
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1144
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1146
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1148
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1150
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1152
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1154
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1156
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1158
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1160
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1162
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1164
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1166
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1168
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1170
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1172
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1174
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1176
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1178
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1180
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1182
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1184
      value_type: FP32_R
      read_lambda: |-
        return 0;

    - address: 1186
      value_type: FP32_R
      read_lambda: |-
        return 0;


sensor:
  # Bronwaarden vanuit Home Assistant
  # Energie: kWh
  # Vermogen: kW
  # Spanning: V

  # Import energie in kWh vanuit Home Assistant
  - platform: homeassistant
    id: import_energy_tariff1
    entity_id: sensor.energy_consumed_tariff_1

  - platform: homeassistant
    id: import_energy_tariff2
    entity_id: sensor.energy_consumed_tariff_2

  # Export energie in kWh vanuit Home Assistant
  - platform: homeassistant
    id: export_energy_tariff1
    entity_id: sensor.energy_produced_tariff_1

  - platform: homeassistant
    id: export_energy_tariff2
    entity_id: sensor.energy_produced_tariff_2

  # Vermogen in kW vanuit Home Assistant
  - platform: homeassistant
    id: power_consumed_l1
    entity_id: sensor.power_consumed_phase_1

  - platform: homeassistant
    id: power_consumed_l2
    entity_id: sensor.power_consumed_phase_2

  - platform: homeassistant
    id: power_consumed_l3
    entity_id: sensor.power_consumed_phase_3

  - platform: homeassistant
    id: power_produced_l1
    entity_id: sensor.power_produced_phase_1

  - platform: homeassistant
    id: power_produced_l2
    entity_id: sensor.power_produced_phase_2

  - platform: homeassistant
    id: power_produced_l3
    entity_id: sensor.power_produced_phase_3

  # Import energie: kWh naar Wh
  - platform: template
    id: import_energy_active
    lambda: |-
      const float tariff1 = id(import_energy_tariff1).state;
      const float tariff2 = id(import_energy_tariff2).state;

      if (isnan(tariff1) || isnan(tariff2)) {
        return 0.0f;
      }

      return (tariff1 + tariff2) * 1000.0f;
    update_interval: 5s

  # Export energie: kWh naar Wh
  - platform: template
    id: export_energy_active
    lambda: |-
      const float tariff1 = id(export_energy_tariff1).state;
      const float tariff2 = id(export_energy_tariff2).state;

      if (isnan(tariff1) || isnan(tariff2)) {
        return 0.0f;
      }

      return (tariff1 + tariff2) * 1000.0f;
    update_interval: 5s

  # Totaal energie in Wh
  - platform: template
    id: total_energy_active
    lambda: |-
      return id(import_energy_active).state
           + id(export_energy_active).state;
    update_interval: 5s

  # Per-fase energie in Wh
  # Dit is een schatting: totaal wordt gelijk verdeeld over de drie fasen

  - platform: template
    id: l1_energy_active
    lambda: |-
      return id(total_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l2_energy_active
    lambda: |-
      return id(total_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l3_energy_active
    lambda: |-
      return id(total_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l1_import_energy_active
    lambda: |-
      return id(import_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l2_import_energy_active
    lambda: |-
      return id(import_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l3_import_energy_active
    lambda: |-
      return id(import_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l1_export_energy_active
    lambda: |-
      return id(export_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l2_export_energy_active
    lambda: |-
      return id(export_energy_active).state / 3.0f;
    update_interval: 5s

  - platform: template
    id: l3_export_energy_active
    lambda: |-
      return id(export_energy_active).state / 3.0f;
    update_interval: 5s

  # Actief vermogen: kW naar W
  - platform: template
    id: l1_power_active
    lambda: |-
      const float consumed = id(power_consumed_l1).state;
      const float produced = id(power_produced_l1).state;

      if (isnan(consumed) || isnan(produced)) {
        return 0.0f;
      }

      return (consumed - produced) * 1000.0f;
    update_interval: 5s

  - platform: template
    id: l2_power_active
    lambda: |-
      const float consumed = id(power_consumed_l2).state;
      const float produced = id(power_produced_l2).state;

      if (isnan(consumed) || isnan(produced)) {
        return 0.0f;
      }

      return (consumed - produced) * 1000.0f;
    update_interval: 5s

  - platform: template
    id: l3_power_active
    lambda: |-
      const float consumed = id(power_consumed_l3).state;
      const float produced = id(power_produced_l3).state;

      if (isnan(consumed) || isnan(produced)) {
        return 0.0f;
      }

      return (consumed - produced) * 1000.0f;
    update_interval: 5s

  # Totaal actief vermogen in W
  - platform: template
    id: power_active_total
    lambda: |-
      return id(l1_power_active).state
           + id(l2_power_active).state
           + id(l3_power_active).state;
    update_interval: 5s

  # L-N spanning in V
  - platform: homeassistant
    id: l1n_voltage
    entity_id: sensor.voltage_phase_1

  - platform: homeassistant
    id: l2n_voltage
    entity_id: sensor.voltage_phase_2

  - platform: homeassistant
    id: l3n_voltage
    entity_id: sensor.voltage_phase_3

  - platform: template
    id: voltage_ln
    lambda: |-
      const float l1 = id(l1n_voltage).state;
      const float l2 = id(l2n_voltage).state;
      const float l3 = id(l3n_voltage).state;

      if (isnan(l1) || isnan(l2) || isnan(l3)) {
        return 0.0f;
      }

      return (l1 + l2 + l3) / 3.0f;
    update_interval: 5s

  # L-L spanning in V
  # Geschat op basis van L-N spanning: L-L = L-N x sqrt(3)

  - platform: template
    id: l12_voltage
    lambda: |-
      const float voltage = id(l1n_voltage).state;

      if (isnan(voltage)) {
        return 0.0f;
      }

      return voltage * 1.7320508f;
    update_interval: 5s

  - platform: template
    id: l23_voltage
    lambda: |-
      const float voltage = id(l2n_voltage).state;

      if (isnan(voltage)) {
        return 0.0f;
      }

      return voltage * 1.7320508f;
    update_interval: 5s

  - platform: template
    id: l31_voltage
    lambda: |-
      const float voltage = id(l3n_voltage).state;

      if (isnan(voltage)) {
        return 0.0f;
      }

      return voltage * 1.7320508f;
    update_interval: 5s

  - platform: template
    id: voltage_ll
    lambda: |-
      const float l12 = id(l12_voltage).state;
      const float l23 = id(l23_voltage).state;
      const float l31 = id(l31_voltage).state;

      if (isnan(l12) || isnan(l23) || isnan(l31)) {
        return 0.0f;
      }

      return (l12 + l23 + l31) / 3.0f;
    update_interval: 5s

  # Frequentie in Hz
  # Vast ingesteld op 50 Hz

  - platform: template
    id: grid_frequency
    lambda: |-
      return 50.0f;
    # update_interval: 5s