Closed benjaminvdb closed 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.
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.
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?
Please use the default SN from the example. The specific serial number isn't important / respected.
Ah - thx! Will try.
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?
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!
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!
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.
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?
@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?
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...
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
>>>
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.
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.
>>>
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.
Please try 6868
and 2014
.
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).
Please try
6868
and2014
.
Sorry - was typing at the same time as you. 6868 has done the trick. I've got modbus enabled now.
Still no inbound modbus however, will see about switching back to uart0
BINGO! That's the ticket. Running like a charm now.
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(?).
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).
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?)
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"
@kidwellj Friendly reminder.
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?