MODBUS RS485 - not reading correctly

I think i posted this in the wrong channel

In short,
Using a ESP32-ROVER-kit and can’t seem to get the MAX483 to read this device

And If i start reading ex: temperature like so I want to say its the correct reading if i convert to F vs Celsius.

uart:
  id: mod_bus
  tx_pin: 1
  rx_pin: 3
  baud_rate: 9600
  stop_bits: 1
  parity: NONE
  data_bits: 8
  debug:
    direction: BOTH
    dummy_receiver: false
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);

modbus:
  id: modbus1
  # flow_control_pin: 4
 
modbus_controller:
  - id: reader1
    address: 0x01
    modbus_id: modbus1
    setup_priority: -10
    update_interval: 2s

sensor:
  - platform: modbus_controller
    modbus_controller_id: reader1
    name: "soil_meter_temp"
    id: soil_meter_temp
    register_type: read
    register_count: 6
    address: 0x0000
    # response_size: 2
    # bitmask: 0xFF00
    # accuracy_decimals: 3
    value_type: S_WORD
    unit_of_measurement: "°C"
    # accuracy_decimals: 1
    filters:
      - multiply: .01
    
  - platform: template
    name: Temperature_F
    id: temperature_f
    lambda: return id(soil_meter_temp).state * 9/5+32;
    update_interval: 5s

But the minute I start adding more readings everything seems out of wack. I also cant seem to “set” or switch a register ex: change soil type.

Currently its commented out but i have tried as many times as I could before i start to just pull my hairs out and go bald.

# text_sensor:
#   - platform: modbus_controller
#     modbus_controller_id: reader1
#     name: "Reset command"
#     id: reset_partial
#     # custom_command to reset all partial energy readings just before midnight
#     # Sensor value can't be used as result value. That has to be checked via command_result sensor
#     # device slave address: 0x01
#     # modbus command 16: 0x10
#     # commmand register 5250 decimal: 0x1481 
#     # number of registers to write: 0x0002 (write both command and command parameters registers)
#     # number of bytes: 0x04 (2 parameters x 2 bytes)
#     # command 2020 in register 5250: 0x07E4
#     # command parameters in register 5252: 0x000 (this command has no parameters)
#     custom_command: [ 0x01, 0x06, 0x0021, 0x01, 0x00 ]
# #     register_type: coil
#     # device_class: energy
    # value_type: FP32

# switch:
#   - platform: modbus_controller
#     modbus_controller_id: reader1
#     id: sensor_soil_type
#     name: "Soil Type"
#     address: 32
#     register_type: coil
#     bitmask: 3
#     # write_lambda: |-
#     #   payload.push_back(0x01);  // device address
#     #   payload.push_back(0x06);  // force single coil
#     #   payload.push_back(0x00); // high byte address of the coil
#     #   payload.push_back(0x01); // ON = 0xFF00 OFF=0000
#     #   payload.push_back(0xB8D);
#     #   return {};

# switch:
#   - platform: modbus_controller
#     modbus_controller_id: reader1
#     id: nilan_on_off_state
#     register_type: holding
#     # force_new_range: true
#     address: 0x0020
#     name: "Soil Type"

# number:
#   - platform: modbus_controller
#     modbus_controller_id: reader1
#     name: "soil_type"
#     address: 0x0020
#     value_type: U_WORD
#     min_value: 0
#     max_value: 3

Try using command_throttle in the modbus_controller section to give time to the device to answer.
Also try force_new_range on the sensor def to force separate queries via modbus

@bgug777 thats giving me much better and promising data back.

Here is the new code

uart:
  id: mod_bus
  tx_pin: 1
  rx_pin: 3
  baud_rate: 9600
  stop_bits: 1
  parity: NONE
  # data_bits: 8
  debug:
    direction: BOTH
    dummy_receiver: false
    # after:
    #   delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);

modbus:
  id: modbus1
  # flow_control_pin: 4
 
modbus_controller:
  - id: reader1
    address: 0x01
    modbus_id: modbus1
    setup_priority: -10
    update_interval: 2s
    command_throttle: 2ms
sensor:
  - platform: modbus_controller
    modbus_controller_id: reader1
    name: "soil_meter_temp"
    id: soil_meter_temp
    register_type: read
    # register_count: 6
    force_new_range: true
    address: 0x0000
    # response_size: 2
    # bitmask: 0xFF00
    # accuracy_decimals: 3
    value_type: S_WORD
    unit_of_measurement: "°C"
    # accuracy_decimals: 1
    filters:
      - multiply: .01
    
  - platform: template
    name: Temperature_F
    id: temperature_f
    lambda: return id(soil_meter_temp).state * 9/5+32;
    update_interval: 5s

  - platform: modbus_controller
    modbus_controller_id: reader1
    name: "soil_meter_moisture"
    # id: flow
    register_type: read
    force_new_range: true
    address: 0x0001
    # response_size: 2
    # accuracy_decimals: 3
    value_type: U_WORD
    unit_of_measurement: "VWC"
    # accuracy_decimals: 1
    # filters:
    #   - multiply: .01

  - platform: modbus_controller
    modbus_controller_id: reader1
    name: "soil_meter_ec"
    # id: flow
    register_type: read
    force_new_range: true
    # register_count: 2
    address: 2
    # response_size: 2
    # accuracy_decimals: 3
    value_type: U_WORD
    unit_of_measurement: "us/cm"
    # accuracy_decimals: 1
    # filters:
    #   - multiply: .55

  # # - platform: modbus_controller
  #   modbus_controller_id: reader1
  #   name: "soil_meter_salinity"
  #   # id: flow
  #   register_type: read
  #   address: 0x0003
  #   # response_size: 2
  #   # accuracy_decimals: 3
  #   value_type: U_WORD
  #   unit_of_measurement: "mg/L"
  #   # accuracy_decimals: 1
  #   # filters:
  #   #   - multiply: .01
  
  - platform: modbus_controller
    modbus_controller_id: reader1
    name: "soil_meter_tds"
    # id: flow
    register_type: read
    force_new_range: true
    address: 0x0004
    # response_size: 2
    # accuracy_decimals: 3
    value_type: U_WORD
    unit_of_measurement: "mg/L"
    # accuracy_decimals: 1
    # filters:
    #   - multiply: .01

here is the new data back. i commented some out and will add more in

[09:19:41][D][sensor:127]: 'soil_meter_ec': Sending state 206.00000 us/cm with 0 decimals of accuracy
[09:19:41][D][uart_debug:158]: <<< "\x01\x04\x02\x00\xCE8\xA4"
[09:19:41][D][uart_debug:158]: >>> "\x01\x04\x00\x04\x00\x01p\v"
[09:19:41][D][modbus_controller.sensor:025]: Sensor new state: 103.00
[09:19:41][D][sensor:127]: 'soil_meter_tds': Sending state 103.00000 mg/L with 0 decimals of accuracy
[09:19:42][D][uart_debug:158]: <<< "\x01\x04\x02\x00g\xF8\xDA"
[09:19:44][D][uart_debug:158]: >>> "\x01\x04\x00\x00\x00\x011\xCA"
[09:19:44][D][modbus_controller.sensor:025]: Sensor new state: 2153.00
[09:19:44][D][sensor:127]: 'soil_meter_temp': Sending state 21.53000 °C with 0 decimals of accuracy
[09:19:44][D][uart_debug:158]: <<< "\x01\x04\x02\bi~\xDE"
[09:19:44][D][uart_debug:158]: >>> "\x01\x04\x00\x01\x00\x01`\n"
[09:19:44][D][modbus_controller.sensor:025]: Sensor new state: 3490.00
[09:19:44][D][sensor:127]: 'soil_meter_moisture': Sending state 3490.00000 VWC with 0 decimals of accuracy
[09:19:44][D][uart_debug:158]: <<< "\x01\x04\x02\r\xA2<\x19"
[09:19:44][D][uart_debug:158]: >>> "\x01\x04\x00\x02\x00\x01\x90\n"
[09:19:44][D][modbus_controller.sensor:025]: Sensor new state: 206.00
[09:19:44][D][sensor:127]: 'soil_meter_ec': Sending state 206.00000 us/cm with 0 decimals of accuracy
[09:19:44][D][uart_debug:158]: <<< "\x01\x04\x02\x00\xCE8\xA4"
[09:19:44][D][uart_debug:158]: >>> "\x01\x04\x00\x04\x00\x01p\v"
[09:19:44][D][modbus_controller.sensor:025]: Sensor new state: 103.00
[09:19:44][D][sensor:127]: 'soil_meter_tds': Sending state 103.00000 mg/L with 0 decimals of accuracy
[09:19:44][D][uart_debug:158]: <<< "\x01\x04\x02\x00g\xF8\xDA"
[09:19:45][D][uart_debug:158]: >>> "\x01\x04\x00\x00\x00\x011\xCA"
[09:19:45][D][modbus_controller.sensor:025]: Sensor new state: 2150.00
[09:19:45][D][sensor:127]: 'soil_meter_temp': Sending state 21.50000 °C with 0 decimals of accuracy
[09:19:45][D][uart_debug:158]: <<< "\x01\x04\x02\bf>\xDA"

Now i need to understand how to change the Soil type register. to change the type of soil ONLY bc i want to confirm that my VWC really is

[09:19:44][D][sensor:127]: 'soil_meter_moisture': Sending state 3490.00000 VWC with 0 decimals of accuracy

bc its 100% soaked in water with Rockwool type soil (it should be considered mineral which is default. but shouldnt it read 100000 = 100%? I am still learning how to read the following to calculate its correct.

i corrected the URL issue for the pdf
here

cant see how ex: from data that came back on a 100% saturated soil media,
VWC is reading 3407, * 256 + 2 / 100? 872192.02 ?? lol i must still be doing something wrong

So i commented out just to see the debug from just for VWC register calls

[10:24:46][D][uart_debug:158]: <<< "\x01\x04\x02\r@\xBCP"
[10:24:48][D][uart_debug:158]: >>> "\x01\x04\x00\x01\x00\x01`\n"
[10:24:48][D][modbus_controller.sensor:025]: Sensor new state: 3392.00
[10:24:48][D][sensor:127]: 'soil_meter_moisture': Sending state 3392.00000 VWC with 0 decimals of accuracy
[10:24:48][D][uart_debug:158]: <<< "\x01\x04\x02\r@\xBCP"      = RX??
[10:24:50][D][uart_debug:158]: >>> "\x01\x04\x00\x01\x00\x01`\n"    =TX?

Why is the RX from address x02 r@ \xBCP?
and how does this = 3392?

Ok, I may be jumping to an answer here but I would:

  • Check if a bigger command_throttle: helps. I have mine at 50ms with an SDM230M power meter
  • Regarding your VWC, reading the PDF you sent I believe 3490 stands for 34.90% VWC. You say it should be 100% but I believe that´s what is reading. You mentioned something about soil type? This sensor seems to have a few config registers that may need to be configured for your specific use.
    The unit_of_measurement: config DOES NOT convert units (as you know because of the config you use to change to Faranheit), so you need to do some math to get this value (simple from what I can see on the PDF), just divide by 100 and set units to %
  • Rest of the values sound right to you? Check on the PDF that your sensor can use one of two modes defined by the MEASUREMETHOD register, and default is to only measure when requested. Perhaps set this to continuous reading to give internal values time to stabilize?
  • Try using different pins for UART, either hardware UART or software UART. I had to go with software UART because of issues with logging on UART0 on my ESP8266 (set logging to 0 baud rate but didn´t work either).
  • Can´t figure out your debug values, but addresses seem to be right according to your PDF section 7.4.2, query and answer from address 0x01, function code 0x04 (read).

Just got back to this, i will try the throttle command setting (forgot to test different settings). and report back

Not sure what you meant regarding software / hardware uart but i will google that. im pretty sure i am using software bc the same i had to set logging to 0 due to error when i start with this.

Nothing has changed yet on my end but when i plugged it in and made sure the media was 100% wet and got the following

[14:49:41][D][modbus_controller.sensor:025]: Sensor new state: 5950.00
[14:49:41][D][sensor:127]: 'soil_meter_moisture': Sending state 5950.00000 VWC with 0 decimals of accuracy
[14:49:42][D][uart_debug:158]: <<< "\x01\x04\x04\x17>\x01\x05^o"
[14:49:44][D][modbus_controller.sensor:025]: Sensor new state: 5950.00

So not sure how all of a sudden its 59%?

So judging by some settings I might have to change - MEASUREMETHOD and Soil Type, how would i go about doing that?

OH! forgot to mention so from doing research on this ESP32 Wrover-E , it only have 1 UART tx/rx pins. so i tested another ESP32 and that one has 3. 0/1/2 and I was able to configure - same result as before which was around the 39% reading previously

So bc i switched back and fourth from some boards, i went back to the orig ESP32-WROvER board i was using and i have the MAX485 and the sensor on 3.3V vs 5v. on 3.3 i get 5665 vwc reading and 5v i get 4200 or so - specifically putting sensor VCC on 3.3 vs 5v makes a difference

3.3V is not a valid power voltage for your sensor according to the PDF you linked, so I wouldn´t trust values measured with that input voltage.
Also, if you are using 3.3V on your ESP board (I believe most of them are 3.3V, if not all of them) and 5V on your sensor, try using a TTL logic level converter (I would use it between your ESP and your MAX485 board) so communication to/from the sensor uses 5V differential and communication between ESP and MAX485 board uses 3.3V. I had to use one on my deployment:

Purchased a Logic Level Converter. I will try that out.
If i am using 5V on the MAX485 and Sensor shouldnt that be ok?

I set logger level to VERBOSE and see way more data as well. can confirm incoming data is good, just cant seem to get the switch or number blocks to change the register from 0 → 1 for temp C->F or the MediaType. i tried offset to see if writer_single_register would go through but all i see if 04 not 06

[17:52:00][C][modbus_controller:275]: ModbusController:
[17:52:00][C][modbus_controller:276]:   Address: 0x01
[17:52:00][C][modbus_controller:278]: sensormap
[17:52:00][C][modbus_controller:282]:  Sensor type=4 start=0x21 offset=0x2 count=1 size=2
[17:52:00][C][modbus_controller:284]: ranges
[17:52:00][C][modbus_controller:287]:   Range type=4 start=0x21 count=1 skip_updates=0
[17:52:04][V][modbus_controller:158]: Updating modbus component
[17:52:04][V][modbus_controller:125]: Range : 21 Size: 1 (4) skip: 0
[17:52:04][V][modbus_controller:036]: Sending next modbus command to device 1 register 0x21 count 1
[17:52:04][V][modbus:199]: Modbus write: 01.04.00.21.00.01.61.C0 (8)
[17:52:04][V][modbus_controller:486]: Command sent 4 0x21 1
[17:52:04][D][uart_debug:158]: >>> "\x01\x04\x00!\x00\x01a\xC0"
[17:52:04][V][modbus:042]: Modbus received Byte  1 (0X1)
[17:52:04][V][modbus:042]: Modbus received Byte  4 (0X4)
[17:52:04][V][modbus:042]: Modbus received Byte  2 (0X2)
[17:52:04][V][modbus:042]: Modbus received Byte  0 (0X0)
[17:52:04][V][modbus:042]: Modbus received Byte  0 (0X0)
[17:52:04][V][modbus:042]: Modbus received Byte  185 (0Xb9)
[17:52:04][V][modbus:042]: Modbus received Byte  48 (0X30)
[17:52:04][V][modbus_controller:055]: Modbus response queued
[17:52:04][V][component:200]: Component modbus took a long time for an operation (0.06 s).
[17:52:04][V][component:201]: Components should block for at most 20-30ms.
[17:52:04][V][modbus_controller:063]: Process modbus response for address 0x21 size: 2
[17:52:04][V][modbus_controller:098]: data for register address : 0x21 : 
[17:52:04][V][modbus_controller.switch:047]: Publish 'Temp C or F': new value = OFF type = 4 address = 21 offset = 2
[17:52:04][D][uart_debug:158]: <<< "\x01\x04\x02\x00\x00\xB90"
[17:52:09][V][modbus_controller:158]: Updating modbus component
[17:52:09][V][modbus_controller:125]: Range : 21 Size: 1 (4) skip: 0
[17:52:09][V][modbus_controller:036]: Sending next modbus command to device 1 register 0x21 count 1
[17:52:09][V][modbus:199]: Modbus write: 01.04.00.21.00.01.61.C0 (8)
[17:52:09][V][modbus_controller:486]: Command sent 4 0x21 1
[17:52:09][D][uart_debug:158]: >>> "\x01\x04\x00!\x00\x01a\xC0"
[17:52:09][V][modbus:042]: Modbus received Byte  1 (0X1)
[17:52:09][V][modbus:042]: Modbus received Byte  4 (0X4)
[17:52:09][V][modbus:042]: Modbus received Byte  2 (0X2)
[17:52:09][V][modbus:042]: Modbus received Byte  0 (0X0)
[17:52:09][V][modbus:042]: Modbus received Byte  0 (0X0)
[17:52:09][V][modbus:042]: Modbus received Byte  185 (0Xb9)
[17:52:09][V][modbus:042]: Modbus received Byte  48 (0X30)
[17:52:09][V][modbus_controller:055]: Modbus response queued
[17:52:09][V][component:200]: Component modbus took a long time for an operation (0.06 s).
[17:52:09][V][component:201]: Components should block for at most 20-30ms.
[17:52:10][V][modbus_controller:063]: Process modbus response for address 0x21 size: 2
[17:52:14][V][modbus_controller:158]: Updating modbus component
[17:52:14][V][modbus_controller:125]: Range : 21 Size: 1 (4) skip: 0
[17:52:14][V][modbus_controller:036]: Sending next modbus command to device 1 register 0x21 count 1
[17:52:14][V][modbus:199]: Modbus write: 01.04.00.21.00.01.61.C0 (8)
[17:52:14][V][modbus_controller:486]: Command sent 4 0x21 1
[17:52:14][D][uart_debug:158]: >>> "\x01\x04\x00!\x00\x01a\xC0"
[17:52:14][V][modbus:042]: Modbus received Byte  1 (0X1)
[17:52:14][V][modbus:042]: Modbus received Byte  4 (0X4)
[17:52:14][V][modbus:042]: Modbus received Byte  2 (0X2)
[17:52:14][V][modbus:042]: Modbus received Byte  0 (0X0)
[17:52:14][V][modbus:042]: Modbus received Byte  0 (0X0)
[17:52:14][V][modbus:042]: Modbus received Byte  185 (0Xb9)
[17:52:14][V][modbus:042]: Modbus received Byte  48 (0X30)
[17:52:14][V][modbus_controller:055]: Modbus response queued
[17:52:14][V][component:200]: Component modbus took a long time for an operation (0.05 s).
[17:52:14][V][component:201]: Components should block for at most 20-30ms.
[17:52:14][V][modbus_controller:063]: Process modbus response for address 0x21 size: 2
[17:52:14][V][modbus_controller:098]: data for register address : 0x21 : 
[17:52:14][V][modbus_controller.switch:047]: Publish 'Temp C or F': new value = OFF type = 4 address = 21 offset = 2
[17:52:14][D][uart_debug:158]: <<< "\x01\x04\x02\x00\x00\xB90"

with config

switch:
  - platform: modbus_controller
    modbus_controller_id: reader1
    id: switch_temp_type
    name: "Temp C or F"
    address: 33
    register_type: read
    offset: 2
    bitmask: 1 

It should be OK.
Just to be clear:
ESP <— 3.3V —> TTL Level converter <— 5V —> MAX485 <— 5V differential —> Sensor

TTL Level converter needs to be powered by both 3.3V and 5V (check the datasheet for the converter you purchased)
MAX 485 and Sensor powered by 5V
ESP uses 3.3V (internally, you may be feeding it 5V and it converts it to 3.3V)

Consistent results with reading VWC but reading is should be higher. Def. comes down to, how to i send a write command to change soil type

Also confirmed with a new Logic Analyzer i got and the data coming from the sensor before hitting the MAX485 board is correct. I am trying some new settings to change the soil type, no success yet

I was able to successfully write to the register and change temp C to F.

I also changed soil type BUT even changing that did not change the reading on all except for Organic. Which at fill 100% saturated with water - it only read 6932 which technically is 65%.

I will continue to try and get this at 100% but im also worried that my 5V is really 4.15V - is that normal? my 3.3V reads 3.3v on the Vmeter.

It should be 5V or a little higher with no load connected, perhaps your power supply does not have enough output Amps hence the voltage drops to 4.15V when you try to pull too many Amps.
Try a different power supply for the 5V rail, one with higher output amps/power.

Yeah with no load i get 4.3 on all the USB connected esp32’s that i have. Wonder why its so low? Even when i connect it via USB and an outlet charger that pushes out 5v 1a it still reads 4.3v. am i doing something incorrect? When u say diff PS for the 5V rail, can you give me some details?

Are you measuring the power supply directly or the 5V output pin on the ESP board?
I mean a different power supply for the parts of your deployment that need 5V. One with higher output power (or higher output current which is basically saying the same thing).

Make sure your 5V for powering other devices does not come from the ESP board directly.