syssi / esphome-solax-x1-mini

ESPHome component to monitor a Solax X1 mini via RS485
Apache License 2.0
39 stars 11 forks source link

Support for SolaX X1 (ModbusRTU via RS485) #31

Closed benjaminvdb closed 1 year ago

benjaminvdb commented 1 year ago

From the readme I understand that the SolaX X1 (not mini) isn't supported, but is there any reason to believe this project won't work with that inverter?

syssi commented 1 year ago

There are not much informations available about the different inverter models. Therefore it's hard to make a prediction about the supported protocols of the firmware.

If you own the device please give it a try! If you don't own the device: If this implementation doesn't work it's likely the inverter supports Modbus and responds to some well known registers.

kidwellj commented 1 year ago

I'm working on this just now - with an X1. Will report back on whether I can get it to run. I can confirm that it's built with RS485 / modbus. It does seem like there may be an issue with the data integrity check on device serial number, as it seems mine is alphanumeric and not hexadecimal, so am getting tripped up in compile stage with esphome.

kidwellj commented 1 year ago

Seems my python coding skills (which are not great) have proven insufficient. I'd meant to simply cut out the integrity check requirement for hexadecimal, but the whole thing fails now. I have triple checked that my serial number is indeed alphanumeric - and I'm pretty sure it is a serial number as it is still 14 chars, and is listed on solax as "Inverter SN". Any chance someone else with more python skills than I could create a branch I could test that does this test as 14 char alphanumeric?

syssi commented 1 year ago

Please use the default SN from the example. The specific serial number isn't important / respected.

kidwellj commented 1 year ago

Ah - thx! Will try.

benjaminvdb commented 1 year ago

None of the projects I found seemed to work for my newest generation Solax X1 Boost (serial number starts with XB33). At some point, I wondered whether I could write a configuration for vanilla ESPHome instead, and I got it to work!

I've submitted the configuration to the repository of the creator of the Modbus shield that I'm using, but it should work if you wired things together yourself if you change the pinout.

@syssi Perhaps you can use the default baud rate, address, registers, etc. from my configuration for your project in order to support the X1 Boost?

kidwellj commented 1 year ago

I can confirm this module doesn't work for my X1 (firmware flashed ok and unit connected to HAOS no probs). So far no data received on any of the entities created by the device in ESPHome. I'm working with an XY-017 unit wired into my esp32doit-devkit-v1, so will have a check and see how this corresponds to your modbus shield @benjaminvdb. Many thanks for this extremely useful info!

kidwellj commented 1 year ago

None of the projects I found seemed to work for my newest generation Solax X1 Boost (serial number starts with XB33). At some point, I wondered whether I could write a configuration for vanilla ESPHome instead, and I got it to work!

I've submitted the configuration to the repository of the creator of the Modbus shield that I'm using, but it should work if you wired things together yourself if you change the pinout.

@syssi Perhaps you can use the default baud rate, address, registers, etc. from my configuration for your project in order to support the X1 Boost?

PS, that modbus shield is a great piece of kit. Might get one of them as well!

kidwellj commented 1 year ago

No luck for me either way. Looks like I need to debug hardware setup a bit as I'm getting nothing from modbus (and have tried both UART0 and UART2):

[15:56:55][D][modbus_controller:032]: Modbus command to device=1 register=0x400 countdown=0 no response received - removed from send queue

Suspect it's a bad connection somewhere between esp32 and XY-017... Will report back as things progress.

syssi commented 1 year ago

At the modbus_controller approach you have to make sure the address matches with the Modbus address of the inverter configuration. Sometimes you have to enable Modbus at the inverter settings and double check the modbus address.

If you enable the debug mode of the uart component you can see the outgoing and incoming traffic at the logs. Does the TX led of your RS485 converter blink periodically?

kidwellj commented 1 year ago

@syssi how are you accessing the inverter configuration? I have a Pocket Wifi V3.0 Dongle, which won't allow access using admin:admin (I guess Solax is trying to push their cloud / api product?). But perhaps there's an alternative I'm missing here?

kidwellj commented 1 year ago

I see what you mean about RX/TX lights on the XY-017, I hadn't even noticed them! They are blinking symmetrically pretty often (e.g. every half second of so). That rules out lack of voltage to that board...

kidwellj commented 1 year ago

So I've enabled uart debug mode, but not quite sure what to make of the output. Here's a sample:

[16:42:57][D][modbus_controller:032]: Modbus command to device=1 register=0x414 countdown=0 no response received - removed from send queue
[16:42:57][D][uart_debug:114]: >>> 01:04:04:23:00:01:C1:30
[16:42:58][D][uart_debug:114]: >>> 01:04:04:23:00:01:C1:30
[16:42:59][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1031 count=1
[16:42:59][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1034 count=1
[16:42:59][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1059 count=1
[16:42:59][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1061 count=1
[16:42:59][D][uart_debug:114]: >>> 01:04:04:23:00:01:C1:30
[16:43:00][D][uart_debug:114]: >>> 01:04:04:23:00:01:C1:30
[16:43:01][D][uart_debug:114]: >>> 01:04:04:23:00:01:C1:30
[16:43:02][D][modbus_controller:032]: Modbus command to device=1 register=0x423 countdown=0 no response received - removed from send queue
[16:43:02][D][uart_debug:114]: >>> 01:04:04:07:00:01:81:3B
[16:43:03][D][uart_debug:114]: >>> 01:04:04:07:00:01:81:3B
[16:43:04][D][uart_debug:114]: >>> 01:04:04:07:00:01:81:3B
[16:43:05][D][uart_debug:114]: >>> 01:04:04:07:00:01:81:3B
[16:43:06][D][uart_debug:114]: >>> 01:04:04:07:00:01:81:3B
[16:43:07][D][modbus_controller:032]: Modbus command to device=1 register=0x407 countdown=0 no response received - removed from send queue
[16:43:07][D][uart_debug:114]: >>> 01:04:04:0A:00:01:10:F8
[16:43:08][D][uart_debug:114]: >>> 01:04:04:0A:00:01:10:F8
[16:43:09][D][uart_debug:114]: >>> 01:04:04:0A:00:01:10:F8
[16:43:10][D][uart_debug:114]: >>> 01:04:04:0A:00:01:10:F8
[16:43:11][D][uart_debug:114]: >>> 01:04:04:0A:00:01:10:F8
[16:43:12][D][modbus_controller:032]: Modbus command to device=1 register=0x40A countdown=0 no response received - removed from send queue
[16:43:12][D][uart_debug:114]: >>> 01:04:04:25:00:01:21:31
[16:43:13][D][uart_debug:114]: >>> 01:04:04:25:00:01:21:31
[16:43:14][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1024 count=5
[16:43:14][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1037 count=3
[16:43:14][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1044 count=2
[16:43:14][W][modbus_controller:113]: Duplicate modbus command found: type=0x4 address=1061 count=1
[16:43:14][D][uart_debug:114]: >>> 01:04:04:25:00:01:21:31
[16:43:15][D][uart_debug:114]: >>> 01:04:04:25:00:01:21:31
[16:43:16][D][uart_debug:114]: >>> 01:04:04:25:00:01:21:31
[16:43:17][D][modbus_controller:032]: Modbus command to device=1 register=0x425 countdown=0 no response received - removed from send queue
[16:43:17][D][uart_debug:114]: >>> 01:04:04:00:00:05:31:39
[16:43:18][D][uart_debug:114]: >>> 01:04:04:00:00:05:31:39
[16:43:19][D][uart_debug:114]: >>> 01:04:04:00:00:05:31:39
[16:43:21][D][uart_debug:114]: >>> 01:04:04:00:00:05:31:39
[16:43:22][D][uart_debug:114]: >>> 01:04:04:00:00:05:31:39
[16:43:22][D][modbus_controller:032]: Modbus command to device=1 register=0x400 countdown=0 no response received - removed from send queue
[16:43:23][D][uart_debug:114]: >>> 01:04:04:0D:00:03:20:F8
[16:43:24][D][uart_debug:114]: >>> 01:04:04:0D:00:03:20:F8
[16:43:25][D][uart_debug:114]: >>> 01:04:04:0D:00:03:20:F8
syssi commented 1 year ago

>>> is outgoing traffic. If the inverter responds you should see <<< lines.

RE inverter settings: I assumed your inverter have a display and an item somewhere at the on screen menu to enable the modbus support + set the modbus address.

syssi commented 1 year ago

I see what you mean about RX/TX lights on the XY-017, I hadn't even noticed them! They are blinking symmetrically pretty often (e.g. every half second of so). That rules out lack of voltage to that board...

Please disconnect the inverter from the RS485 board. Now only the TX led should blink periodically. The RX led should stay off.

kidwellj commented 1 year ago

>>> is outgoing traffic. If the inverter responds you should see <<< lines.

RE inverter settings: I assumed your inverter have a display and an item somewhere at the on screen menu to enable the modbus support + set the modbus address.

That makes perfect sense. Thx for the interpretation here. I've been through the on-screen menu, but it seems they've set a 4 digit numeric password for this as well, the obvious options (0000, 1234, 9999) haven't worked so far.

syssi commented 1 year ago

Please try 6868 and 2014.

kidwellj commented 1 year ago

well, for future reference in case anyone else stumbles on this post with the same question, apparently the solax default installer password is 6868. These menus can also be accessed via https://www.solaxcloud.com, via "device management" and "remote setting". And just as you'd suggested, there's a place to enable modbus (was disabled!) and set the address (defaulted to 1).

kidwellj commented 1 year ago

Please try 6868 and 2014.

Sorry - was typing at the same time as you. 6868 has done the trick. I've got modbus enabled now.

kidwellj commented 1 year ago

Still no inbound modbus however, will see about switching back to uart0

kidwellj commented 1 year ago

BINGO! That's the ticket. Running like a charm now.

syssi commented 1 year ago

My Solar X1 mini turns off if it's dark out there / at night and doesn't respond anymore. I assume the Boost version behaves different because it's always on(?).

syssi commented 1 year ago

Good job! As last step I would be happy if you could try this custom component a last time. Just to make sure your inverter doesn't support the "special X1 mini protocol". It's possible your inverter is able to handle both protocols (special version + generic modbus registers).

kidwellj commented 1 year ago

Happy to test - there are other X1 users out there I'm sure. Am currently working off the config that @benjaminvdb mentioned above, which is:

substitutions:
  name: solax-x1-rs485_v2
  device_description: "Monitor a Solax X1 via RS485"
  tx_pin: GPIO1
  rx_pin: GPIO3
  prefix: solax

esphome:
  name: ${name}
  comment: ${device_description}
  platform: esp32
  board: esp32doit-devkit-v1

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  use_address: 192.168.2.170
  ap:
    ssid: "ESP-Modbus"
    password: "configesp"

ota:

# Enable Home Assistant API
api:

captive_portal:

# Enable/Disable logging
logger:
  level: verbose
  baud_rate: 0 ## Must be 0 to prevent reading issues and buffer overflows

uart:
  id: mod_bus
  tx_pin: ${tx_pin}
  rx_pin: ${rx_pin}
  stop_bits: 1
  baud_rate: 9600

modbus:
#  flow_control_pin: D5
  id: modbus1
  send_wait_time: 1000ms

modbus_controller:
  - id: solax
    address: 0x1
    modbus_id: modbus1
    setup_priority: -10
    #command_throttle: 250ms
    update_interval: 15s

sensor:
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} PV1 Input Voltage"
    address: 0x400
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} PV2 Input Voltage"
    address: 0x401
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} PV1 Input Current"
    address: 0x402
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: A
    device_class: current
    state_class: measurement
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} PV2 Input Current"
    address: 0x403
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: A
    device_class: current
    state_class: measurement
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Grid Voltage"
    address: 0x404
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Grid Frequency"
    address: 0x407
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 2
    unit_of_measurement: Hz
    device_class: frequency
    state_class: measurement
    filters:
      - multiply: 0.01
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Output Current"
    address: 0x40A
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: A
    device_class: current
    state_class: measurement
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Temperature"
    address: 0x40D
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 0
    unit_of_measurement: C
    device_class: temperature
    state_class: measurement
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Inverter Power"
    address: 0x40e
    register_type: read
    value_type: U_WORD
    unit_of_measurement: W
    device_class: power
    state_class: measurement
    accuracy_decimals: 0
  - platform: modbus_controller
    modbus_controller_id: solax
    id: ${prefix}_power_dc1
    name: "${prefix} Power DC1"
    address: 0x414
    register_type: read
    value_type: U_WORD
    unit_of_measurement: W
    device_class: power
    state_class: measurement
    accuracy_decimals: 0
  - platform: modbus_controller
    modbus_controller_id: solax
    id: ${prefix}_power_dc2
    name: "${prefix} Power DC2"
    address: 0x415
    register_type: read
    value_type: U_WORD
    unit_of_measurement: W
    device_class: power
    state_class: measurement
    accuracy_decimals: 0
    on_value:
      then:
        component.update: ${prefix}_total_dc_power
  - platform: template
    id: ${prefix}_total_dc_power
    name: "${prefix} Total DC Power"
    lambda: |-
      return (id(${prefix}_power_dc1).state + id(${prefix}_power_dc2).state);
    update_interval: never
    unit_of_measurement: W
    device_class: power
    state_class: measurement
    accuracy_decimals: 0
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Production Total"
    address: 0x423
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: kWh
    device_class: energy
    state_class: total_increasing
    filters:
      - multiply: 0.1
  - platform: modbus_controller
    modbus_controller_id: solax
    name: "${prefix} Production Today"
    address: 0x425
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    unit_of_measurement: kWh
    device_class: energy
    state_class: total_increasing
    filters:
      - multiply: 0.1

text_sensor:
  - platform: modbus_controller
    modbus_controller_id: solax
    id: ${prefix}_run_mode
    name: "${prefix} Run Mode"
    address: 0x40f
    bitmask: 0
    register_type: read
    raw_encode: HEXBYTES
    lambda: |-
      uint16_t value = modbus_controller::word_from_hex_str(x, 0);
      switch (value) {
        case 0: return std::string("Waiting");
        case 1: return std::string("Checking");
        case 2: return std::string("Normal");
        case 3: return std::string("Fault");
        case 4: return std::string("Permanent Fault");
        case 5: return std::string("Update");
        case 6: return std::string("Off-grid waiting");
        case 7: return std::string("Off-grid");
        case 8: return std::string("Self Testing");
        case 9: return std::string("Idle");
        case 10: return std::string("Standby");
        default: return std::string("Unknown");
      }
      return x;

which config would you like me to try? [https://github.com/syssi/esphome-modbus-solax-x1/blob/main/esp32-example.yaml](the example yml?)

syssi commented 1 year ago

Yes. Please try and adapt the example configuration: https://github.com/syssi/esphome-modbus-solax-x1/blob/main/esp32-example.yaml

This configuration should match your GPIO layout:

substitutions:
  name: solax-test
  device_description: "Monitor a Solax X1 via RS485"
  tx_pin: GPIO1
  rx_pin: GPIO3
  prefix: solax

esphome:
  name: ${name}
  comment: ${device_description}
  platform: esp32
  board: esp32doit-devkit-v1

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  use_address: 192.168.2.170
  ap:
    ssid: "ESP-Modbus"
    password: "configesp"

ota:

# Enable Home Assistant API
api:

captive_portal:

# Enable/Disable logging
logger:
  level: verbose
  baud_rate: 0 ## Must be 0 to prevent reading issues and buffer overflows

uart:
  id: mod_bus
  tx_pin: ${tx_pin}
  rx_pin: ${rx_pin}
  stop_bits: 1
  baud_rate: 9600

modbus_solax:
  - id: modbus0
    uart_id: mod_bus

solax_x1:
  modbus_solax_id: modbus0
  serial_number: "3132333435363737363534333231"
  address: 0x0A
  update_interval: 1s

text_sensor:
  - platform: solax_x1
    mode_name:
      name: "${name} mode name"
    errors:
      name: "${name} errors"

sensor:
  - platform: solax_x1
    ac_power:
      name: "${name} ac power"
    energy_today:
      name: "${name} energy today"
    energy_total:
      name: "${name} energy total"
syssi commented 1 year ago

@kidwellj Friendly reminder.