You need configure modbus_controller:
Edit:
Ok 0xA1 it’s not standard .
Search for modbus_controller custom command.
Or try with Tasmota Scripting.
Edit2:
You need configure modbus_controller:
Edit:
Ok 0xA1 it’s not standard .
Search for modbus_controller custom command.
Or try with Tasmota Scripting.
Edit2:
Good catch! I did have the modbus_controller in there from someone elses but I must have overwritten it at some point.
Seems like I have got a little further and I’ve tried a couple of different options with the basic modbus controller sensor commented out and the custom command version running currently:
uart:
id: mod_bus
tx_pin: 17
rx_pin: 16
baud_rate: 9600
stop_bits: 1
debug:
modbus:
flow_control_pin: 4
id: modbus1
modbus_controller:
- id: ampinvt
## the Modbus device addr
address: 0x1
modbus_id: modbus1
setup_priority: -10
sensor:
# - platform: modbus_controller
# modbus_controller_id: ampinvt
# name: "Battery Voltage"
# id: battery_voltage
# register_type: holding
# address: 33
# unit_of_measurement: "V"
# device_class: energy
# value_type: U_WORD
- platform: modbus_controller
modbus_controller_id: ampinvt
name: "Battery Voltage"
id: battery_voltage
custom_command: [ 0x01, 0xA1 ]
value_type: U_WORD
From the modbus protocol doc for this unit linked in post #1, I really don’t know what to enter into the custom command. As far as I can figure out, I enter the unit address (0x01) and the master device query command 0xA1. The post you linked to has a bunch of other stuff but they are writing to registers whereas I just need to read.
I tried just adding the byte number in the address: field but that gives a checksum error. Should I be converting those to hex? For battery voltage, 32 is the high byte and 33 is the low byte.
So, reading through the linked post again and trying to figure out the rest of teh custom command, I changed that section to read:
- platform: modbus_controller
modbus_controller_id: ampinvt
name: "Battery Voltage"
id: battery_voltage
# custom_command to read Ampinvt registers
# device slave address: 0x01
# master device query command:0xA1
# commmand register 32 (MSB) decimal: 0x20
# number of registers to read: 0x0001
# number of bytes: 0x02 (1 parameter x 2 bytes)
custom_command: [ 0x01, 0xA1, 0x20, 0x0001, 0x02 ]
value_type: U_WORD
which results in the following in the log:
[17:12:16][V][modbus_controller:159]: Updating modbus component
[17:12:16][VV][modbus_controller:163]: Updating range 0xFAFE
[17:12:16][V][modbus_controller:126]: Range : FAFE Size: 1 (0) skip: 0
[17:12:16][V][modbus_controller:036]: Sending next modbus command to device 1 register 0xFAFE count 1
[17:12:16][VV][uart.arduino_esp32:150]: Flushing...
[17:12:16][V][modbus:205]: Modbus write raw: 01.A1.20.01.02 (5)
[17:12:16][V][modbus_controller:465]: Command sent 0 0xFAFE 1
[17:12:16][D][uart_debug:114]: >>> 01:A1:20:01:02:BB:A7
[17:12:16][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:16][V][modbus:058]: Modbus received Byte 161 (0Xa1)
[17:12:16][V][modbus:058]: Modbus received Byte 32 (0X20)
[17:12:16][V][modbus:058]: Modbus received Byte 2 (0X2)
[17:12:16][D][uart_debug:114]: <<< 01:A1:20:01:02:BB:A7
[17:12:16][V][modbus_controller:036]: Sending next modbus command to device 1 register 0xFAFE count 1
[17:12:16][VV][uart.arduino_esp32:150]: Flushing...
[17:12:16][V][modbus:205]: Modbus write raw: 01.A1.20.01.02 (5)
[17:12:16][V][modbus_controller:465]: Command sent 0 0xFAFE 1
[17:12:16][D][uart_debug:114]: >>> 01:A1:20:01:02:BB:A7
[17:12:16][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:16][V][modbus:058]: Modbus received Byte 161 (0Xa1)
[17:12:17][V][modbus:058]: Modbus received Byte 32 (0X20)
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 2 (0X2)
[17:12:17][D][uart_debug:114]: <<< 01:A1:20:01:02:BB:A7
[17:12:17][V][modbus_controller:036]: Sending next modbus command to device 1 register 0xFAFE count 1
[17:12:17][VV][uart.arduino_esp32:150]: Flushing...
[17:12:17][V][modbus:205]: Modbus write raw: 01.A1.20.01.02 (5)
[17:12:17][V][modbus_controller:465]: Command sent 0 0xFAFE 1
[17:12:17][D][uart_debug:114]: >>> 01:A1:20:01:02:BB:A7
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 161 (0Xa1)
[17:12:17][V][modbus:058]: Modbus received Byte 32 (0X20)
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 2 (0X2)
[17:12:17][D][uart_debug:114]: <<< 01:A1:20:01:02:BB:A7
[17:12:17][V][modbus_controller:036]: Sending next modbus command to device 1 register 0xFAFE count 1
[17:12:17][VV][uart.arduino_esp32:150]: Flushing...
[17:12:17][V][modbus:205]: Modbus write raw: 01.A1.20.01.02 (5)
[17:12:17][V][modbus_controller:465]: Command sent 0 0xFAFE 1
[17:12:17][D][uart_debug:114]: >>> 01:A1:20:01:02:BB:A7
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 161 (0Xa1)
[17:12:17][V][modbus:058]: Modbus received Byte 32 (0X20)
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 2 (0X2)
[17:12:17][W][modbus:096]: Modbus CRC Check failed! 4858!=201
[17:12:17][V][modbus:058]: Modbus received Byte 167 (0Xa7)
[17:12:17][D][uart_debug:114]: <<< 01:A1:20:01:02:BB:A7
[17:12:17][V][modbus_controller:036]: Sending next modbus command to device 1 register 0xFAFE count 1
[17:12:17][VV][uart.arduino_esp32:150]: Flushing...
[17:12:17][V][modbus:205]: Modbus write raw: 01.A1.20.01.02 (5)
[17:12:17][V][modbus_controller:465]: Command sent 0 0xFAFE 1
[17:12:17][D][uart_debug:114]: >>> 01:A1:20:01:02:BB:A7
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 161 (0Xa1)
[17:12:17][V][modbus:058]: Modbus received Byte 32 (0X20)
[17:12:17][V][modbus:058]: Modbus received Byte 1 (0X1)
[17:12:17][V][modbus:058]: Modbus received Byte 2 (0X2)
[17:12:17][W][modbus:096]: Modbus CRC Check failed! 4858!=201
[17:12:17][V][modbus:058]: Modbus received Byte 187 (0Xbb)
[17:12:17][D][uart_debug:114]: <<< 01:A1:20:01:02:BB:A7
[17:12:17][D][modbus_controller:032]: Modbus command to device=1 register=0xFAFE countdown=0 no response received - removed from send queue
I think what I am doing is adding the hex address of the high (MSB) address at byte 32 (0x20), reading one register with 2 bytes (32 and 33). Clearly, that is not what I’m actually doing but I can’t figure out why.
It’s modbus/rs485 only at wire level.
Payload isn’t standard…
Normal modbus
01 03 0001 0001 crc crc (as example)
" The Modbus Polynomial is 0xA001, but to calculate the Modbus CRC in the 'K40 you have to use the bit-reversed value 0x8005 ."
So you will need to do all the coding stuff.
You shoul got a big response per command.
Data validation is performed using ADD8 CheckSum, the sum of all bytes is calculated, and the low
byte data is used as the checksum. The data participating in the check is the entire content of one
frame of data. (does not include the check value itself), the check value is placed in the last 1 byte of a
frame of data.
4、Using a simplified protocol, the communication uses one transmission to exchange data, fixing the
length of each frame of data. The format is: address + command + data + accumulate and check (take
low byte).
5、The Master device queries the MPPT communication interval to be greater than or equal to 1
You could try
01 A1 01 00 00 00 00 5D
with 0x
Maybe with uart.write
I don’t know if is the correct way to calc checksum.
Related:
It seems like the modbus_controller is calculating and adding the checksum as the uart_debug always reports 2 additional bytes of data. If I omit the 5D checksum, the log shows…
01:A1:01:00:00:00:00:2f:71
If I add the 5D checksum, the log shows…
01:A1:01:00:00:00:00:5D:F1:25
Either way, I don’t get a payload and do get CRC check failures.
The Foxess post was where I began the research earlier this week but it makes more sense re-reading it now I am further along the learning journey. The post from @assembly on the deep sleep might also be a factor here so as it is night time and I have 10cm of snow on my panels, I’ll cease working on this until tomorrow and check that out.
I appreciate the help!
Hi’
As @nikito7 wrote, you’ll have to use uart.write
to send this fixed command string.
Your device is using a proprietary protocol with alternative CRC ckeck. The custom_command
will calculate and add the 2 byte CRC checksum itself and hereby render useless in this usecase.
You could do something like this instead and use the time component to issue the command at intervals:
time:
- platform: homeassistant
id: esptime
- platform: sntp
on_time:
# Request package every 10 seconds from inverter at slave address: 0x01
- seconds: /10
then:
- uart.write: [0x01, 0xA1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5D]
Hi. I haven’t read the entire thread, but had a quick look at the protocol.
It doesn’t seem to be standard modbus, so you probably won’t be getting very far with the esphome modbus component.
Instead try setting up a custom uart device. For testing purposes you could also try the custom uart text sensor, which is a bit simpler to set up.
As the 0xA1 query command for each device is fixed and doesn’t change, a simple uart.write
should be sufficient. The device will always reply with a fixed length 93 bytes reply.
To parse the reply I would build a custom component to target out the specific bytes needed and publish those. Similar to the projects we’ve done (Foxess, Delta Solivia)
Appreciate the responses guys.
Last night, I got to the stage that @htvekov posted above, abandoning the Esphome modbus and using the uart.write command which is where I started out from after seeing it in other threads for the Foxess and Delta Solivia.
My code section now is as follows:
uart:
id: mod_bus
tx_pin: 17
rx_pin: 16
rx_buffer_size: 1024
baud_rate: 9600
parity: NONE
stop_bits: 1
debug:
time:
- platform: homeassistant
id: esptime
on_time:
- seconds: 15
then:
- uart.write: [ 0x01, 0xA1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5D ]
switch:
- platform: gpio
pin: 4
name: "Solar Controller Writing mode" #if "on" reading from inverter doesn't work!
internal: true #switch is not exposed to HA frontend, should you ever need to write to the inverter, just comment this line
A couple of notes on it:
At this stage, I’m thinking that I have a hardware issue so I’m going to build a duplicate setup using the board with auto flow control identified by @nikito7. I’ll get back to you with results.
The RJ-45 pinout is listed as 1=485+, 2=485-, 7=VCC, 8-GND. The VCC is 5v. On the hardware I have, I am drawing 12v, using a step-down DC-DC to 5V and tying the grounds together. I think I might just build using the 5V from the controller and simplify it.
The platform for time component is not important. Homeassistant will do just fine
A bit odd with the checksum. On same page there’s another example with MPPT #03
.(If you query No.3 MPPT, format is:0x03 0xA1 0x01 0x00 0x00 0x00 0x00 0xA5
I searched a bit and found that they’re using CheckSum8 Modulo 256 and not CheckSum8 2s Complement as I actually expected. Both crc examples in doc checks out fine using this online crc calculator
So checksum in documentation is ok I guess and code should be revised accordingly.
Your problem with no replies could very well be hw related. I’ve only used rs485 ttl modules with hw controlled flow direction. Any led’s on the module that indicate bytes being sent/recieved ?
Are you certain that both MPPT number and uart settings match the actual device configuration ?
You could also try just send requests for the real time data only using the 0xA3 command instead
I use cheap 2 usd RS485 ttl modules like this without major issues:
I don’t think I’m certain of anything! LOL! I guess that is a good thing and I consider everything to be a cause of potential errors. The MPPT controller is set to address 1 and the docs confirm that it is acting as a slave so I’m pretty sure that the 0x01 address in the command is correct.
The board you show there is the one that @nikito7 recommends but is not the one I am currently using so I just finished up making a master with that one. Do you happen to know if pin 17 on the ESP32 (TXD) connects to TXD on that RS485 board or does it go to RXD on the RS485? I know that it can be trial and error. My install is on a building 300m away, not on the desk next to me.
I believe it’s tx to tx and Rx to Rx between the esp and rs485 module. I can check tomorrow as my production devices are also located outside my house. But at least not 300m away
Confirmed.
ESP8266 Rx to RS485 Rx and ESP8266 Tx to RS485 Tx.
Update for today:
Rebuilt the hardware using the auto-flow RS485 but still get no response from the MPPT controller.
I have confirmed with the manufacturer that there is no deep sleep state and the RJ-45 pins I am using are the correct ones.
I am content that the command I’m trying to send to the unit are as correct as they can be.
I have confirmed the unit is set at address 001 and 9600 bps
Next steps:
Until I can get some response from the unit, I’m at a standstill. We are due a decent snowfall over the weekend so I think I’ll pull the controller and put it on the desk here and hook up to it with a PC or RPi and see if I can get it talking.
@htvekov - thank you for the wiring confirmation.
Good idea to verify the rs-485 is working in another config setup.
Perhaps you could wire up two esp8266 with rs485 modules and let them talk with eachother ?
Any rx/tx led indication when connected to the MPPT unit ?
I have only previously had one issue with the cheap rs485 modules. For some strange, unknown reason, only one of the pcb versions I got of the same module actually worked with my Delta Inverter.
I don’t believe that’s the case at your end (especially if tx led lights up when all is connected and you’re issuing a command), but you never know.
Link to my issue: RS485 to TTL - Difference in two visually identical devices
In an effort to move forward, I tried hooking up a Raspberry Pi 4 and using pymodbus but didn’t get anywhere. I also tried using an Arduino Uno but couldn’t figure that out either; I can get it to write commands but not show any feedback from the controller. I ordered a USB to RS485 cable so I can use some Windows tools for debugging but that won’t arrive for a week.
The Arduino foray caused me to think about the communication line and I started thinking that in the YAML code above, I am writing to the uart but not reading from it and if I’m not reading from it, how would it display in the log? A little research on uart reads in Esphome led me to the custome UART Text Sensor. A quick copy/paste and a couple of changes and I am now seeing responses in the log window. Progress at last!
I now need to make sense of the output but I confirmed the output is coming from the controller by changing the A3 control code to A1 (that delivers the full register dump so a much longer hex string than A3) and it does indeed change as expected.
Once I get this figured, I’ll go ahead and make it available for others as you guys have done.
I’ve emailed the manufacturer for some help but I’ll share the challenge here too.
The string being returned by an 0xA3 query is 01:A3:01:00:0D:00:02:B2:05:15:00:F6:00:A8:00:00:00:20:00:00:3E
I know the first 3 bytes are address, command type and control code. The last is the checksum. That leaves 17 bytes but in the doc, it states that there will be a 37 bytes response. and I’m only getting 21 bytes unless I am missing something. At first, I thought that maybe I wasn’t reading all the output but the checksum is correct for the 20 bytes returned.
Am I missing something here?
Edit:
I noticed a few mistakes in the doc so I’m not at all confident that it is up-to-date, correct etc. Take the ‘Remarks’ section of byte 6/7 (PV Voltage): “Take 1 decimal place; 0x0C43=1219 means PV voltage is 121.9V”
I have no clue at all how they are deriving 1219 from a hex value of 0x0C43. The rest map out OK using INT16 but there are clearly errors in the doc.
I also don’t seem to be able to make sense of the values in terms of breaking out the bits for bytes 3, 4 and 5 or even figuring out the high and low bytes for the remainder.