TUF-2000M Ultrasonic Water Flowmeter MODBUS integration

UPDATE: Resolution below

I cannot integrate this flow meter into ESPhome via MODBUS. The flow meter is TUF-2000M on aliexpress or Amazon.

Everything is hooked up correctly to my ESP8266. I followed the instructions here:

Using the ESP8266 Arduino code in that blog, I can read various registers such as the Flow, temperature inlet, etc. The TUF-2000M MODBUS registers are here on page 39: https://images-na.ssl-images-amazon.com/images/I/91CvZHsNYBL.pdf.

However, when I try to integrate into ESPhome, I get CRC check errors and “no response received”. I am using uart pins D2/D3 for my RX/TX pins so that it does not interfere with the serial logger. I’ve also tried to play with output data type, register counts, and response sizes.

Here is my ESPhome MODBUS code:

esphome:
  name: tuf-2000m-flowmeter

esp8266:
  board: nodemcuv2

# Enable logging
logger:
  level: VERY_VERBOSE
  #hardware_uart: UART0_SWAP

uart:
   id: mod_bus_uart
   tx_pin:
     number: D3
     #number: GPIO1
   rx_pin:
     number: D2
     #number: GPIO3
   baud_rate: 9600
   stop_bits: 1
   parity: none

modbus:
   id: modbus1
   uart_id: mod_bus_uart
   send_wait_time: 500ms

modbus_controller:
 - id: tuf2000m
   ## the Modbus device addr
   address: 0x1
   modbus_id: modbus1
   setup_priority: -10
   update_interval: 15s

sensor:
 - platform: modbus_controller
   modbus_controller_id: tuf2000m
   name: "Inlet Temp"
   id: inlet_temp
   register_type: holding
   address: 0x21
   register_count: 2
   response_size: 2
   value_type: FP32

Here is the output of the log:

[15:40:54][C][logger:275]: Logger:
[15:40:54][C][logger:276]:   Level: VERY_VERBOSE
[15:40:54][C][logger:277]:   Log Baud Rate: 115200
[15:40:54][C][logger:278]:   Hardware UART: UART0
[15:40:54][C][uart.arduino_esp8266:102]: UART Bus:
[15:40:54][C][uart.arduino_esp8266:103]:   TX Pin: GPIO0
[15:40:54][C][uart.arduino_esp8266:104]:   RX Pin: GPIO4
[15:40:54][C][uart.arduino_esp8266:106]:   RX Buffer Size: 256
[15:40:54][C][uart.arduino_esp8266:108]:   Baud Rate: 9600 baud
[15:40:54][C][uart.arduino_esp8266:109]:   Data Bits: 8
[15:40:54][C][uart.arduino_esp8266:110]:   Parity: NONE
[15:40:54][C][uart.arduino_esp8266:111]:   Stop bits: 1
[15:40:54][C][uart.arduino_esp8266:115]:   Using software serial
[15:40:54][C][modbus:150]: Modbus:
[15:40:54][C][modbus:152]:   Send Wait Time: 500 ms
[15:40:54][C][modbus_controller.sensor:010]: modbus_controller.sensorModbus Controller Sensor 'Inlet Temp'
[15:40:54][C][modbus_controller.sensor:010]: modbus_controller.sensor  State Class: ''
[15:40:54][C][modbus_controller.sensor:010]: modbus_controller.sensor  Unit of Measurement: ''
[15:40:54][C][modbus_controller.sensor:010]: modbus_controller.sensor  Accuracy Decimals: 0
[15:40:54][V][modbus_controller:035]: Sending next modbus command to device 1 register 0x21 count 2
[15:40:54][VV][uart.arduino_esp8266:180]:     Flushing...
[15:40:54][V][modbus:205]: Modbus write: 01.03.00.21.00.02.94.01 (8)
[15:40:54][V][modbus_controller:487]: Command sent 3 0x21 2
[15:40:54][C][modbus_controller:276]: ModbusController:
[15:40:54][C][modbus_controller:277]:   Address: 0x01
[15:40:54][C][modbus_controller:279]: sensormap
[15:40:54][C][modbus_controller:281]:  Sensor type=3 start=0x21 offset=0x0 count=2 size=2
[15:40:54][C][modbus_controller:285]: ranges
[15:40:54][C][modbus_controller:287]:   Range type=3 start=0x21 count=2 skip_updates=0
[15:40:54][V][modbus:058]: Modbus received Byte  1 (0X1)
[15:40:54][V][modbus:058]: Modbus received Byte  2 (0X2)
[15:40:54][V][modbus:058]: Modbus received Byte  0 (0X0)
[15:40:54][V][modbus:058]: Modbus received Byte  0 (0X0)
[15:40:54][V][modbus:058]: Modbus received Byte  128 (0X80)
[15:40:54][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[15:40:54][V][modbus:058]: Modbus received Byte  132 (0X84)
[15:40:54][V][modbus:058]: Modbus received Byte  224 (0Xe0)
[15:40:54][V][modbus:058]: Modbus received Byte  152 (0X98)
[15:40:54][V][modbus:058]: Modbus received Byte  0 (0X0)
[15:40:54][V][modbus_controller:035]: Sending next modbus command to device 1 register 0x21 count 2
[15:40:54][VV][uart.arduino_esp8266:180]:     Flushing...
[15:40:54][V][modbus:205]: Modbus write: 01.03.00.21.00.02.94.01 (8)
[15:40:54][V][modbus_controller:487]: Command sent 3 0x21 2
[15:40:54][V][modbus:058]: Modbus received Byte  1 (0X1)
[15:40:54][V][modbus:058]: Modbus received Byte  2 (0X2)
[15:40:54][V][modbus:058]: Modbus received Byte  0 (0X0)
[15:40:54][V][modbus:058]: Modbus received Byte  0 (0X0)
[15:40:54][V][modbus:058]: Modbus received Byte  128 (0X80)
[15:40:54][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[15:40:54][V][modbus:058]: Modbus received Byte  136 (0X88)
[15:40:54][V][modbus:058]: Modbus received Byte  136 (0X88)
[15:40:54][V][modbus:058]: Modbus received Byte  146 (0X92)
[15:40:54][V][modbus:058]: Modbus received Byte  16 (0X10)
[15:40:55][D][modbus_controller:029]: Modbus command to device=1 register=0x21 countdown=0 no response received - removed from send queue

I have also tried using Custom Commands instead:

uart:
   id: mod_bus_uart
   tx_pin:
     number: D3
     #number: GPIO1
   rx_pin:
     number: D2
     #number: GPIO3
   baud_rate: 9600
   stop_bits: 1
   parity: none

modbus:
   id: modbus1
   uart_id: mod_bus_uart
   send_wait_time: 500ms

modbus_controller:
 - id: tuf2000m
   ## the Modbus device addr
   address: 0x1
   modbus_id: modbus1
   setup_priority: -10
   update_interval: 15s

sensor:
 - platform: modbus_controller
   modbus_controller_id: tuf2000m
   name: "Inlet Temp"
   id: inlet_temp
   value_type: FP32
   custom_command: [ 0x01, 0x03, 0x00, 0x21, 0x00, 0x02]

However. for some reason the register states “register=0xDC0”, which is not correct, but the Modbus write raw is correct “Modbus write raw: 01.03.00.21.00.02 (6)”:

[16:03:43][C][modbus_controller:276]: ModbusController:
[16:03:43][C][modbus_controller:277]:   Address: 0x01
[16:03:43][C][modbus_controller:279]: sensormap
[16:03:43][C][modbus_controller:281]:  Sensor type=0 start=0xDCD offset=0x0 count=2 size=4
[16:03:43][C][modbus_controller:285]: ranges
[16:03:43][C][modbus_controller:287]:   Range type=0 start=0xDCD count=2 skip_updates=0
[16:03:43][D][modbus_controller:029]: Modbus command to device=1 register=0xDCD countdown=0 no response received - removed from send queue
[16:03:48][VV][scheduler:195]: Running interval 'update' with interval=15000 last_execution=10277 (now=25277)
[16:03:48][V][modbus_controller:159]: Updating modbus component
[16:03:48][VV][modbus_controller:163]: Updating range 0xDCD
[16:03:48][V][modbus_controller:125]: Range : DCD Size: 2 (0) skip: 0
[16:03:48][V][modbus_controller:035]: Sending next modbus command to device 1 register 0xDCD count 2
[16:03:48][VV][uart.arduino_esp8266:180]:     Flushing...
[16:03:48][V][modbus:226]: Modbus write raw: 01.03.00.21.00.02 (6)
[16:03:48][V][modbus_controller:487]: Command sent 0 0xDCD 2
[16:03:48][V][modbus:058]: Modbus received Byte  1 (0X1)
[16:03:48][V][modbus:058]: Modbus received Byte  2 (0X2)
[16:03:48][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:48][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:48][V][modbus:058]: Modbus received Byte  128 (0X80)
[16:03:48][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[16:03:48][V][modbus:058]: Modbus received Byte  192 (0Xc0)
[16:03:48][V][modbus:058]: Modbus received Byte  176 (0Xb0)
[16:03:48][V][modbus:058]: Modbus received Byte  224 (0Xe0)
[16:03:48][V][modbus:058]: Modbus received Byte  248 (0Xf8)
[16:03:48][V][modbus_controller:035]: Sending next modbus command to device 1 register 0xDCD count 2
[16:03:48][VV][uart.arduino_esp8266:180]:     Flushing...
[16:03:48][V][modbus:226]: Modbus write raw: 01.03.00.21.00.02 (6)
[16:03:48][V][modbus_controller:487]: Command sent 0 0xDCD 2
[16:03:48][V][modbus:058]: Modbus received Byte  1 (0X1)
[16:03:48][V][modbus:058]: Modbus received Byte  2 (0X2)
[16:03:48][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:48][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:48][V][modbus:058]: Modbus received Byte  128 (0X80)
[16:03:48][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[16:03:48][V][modbus:058]: Modbus received Byte  196 (0Xc4)
[16:03:48][V][modbus:058]: Modbus received Byte  208 (0Xd0)
[16:03:48][V][modbus:058]: Modbus received Byte  184 (0Xb8)
[16:03:48][V][modbus:058]: Modbus received Byte  192 (0Xc0)
[16:03:49][V][modbus_controller:035]: Sending next modbus command to device 1 register 0xDCD count 2
[16:03:49][VV][uart.arduino_esp8266:180]:     Flushing...
[16:03:49][V][modbus:226]: Modbus write raw: 01.03.00.21.00.02 (6)
[16:03:49][V][modbus_controller:487]: Command sent 0 0xDCD 2
[16:03:49][V][modbus:058]: Modbus received Byte  1 (0X1)
[16:03:49][V][modbus:058]: Modbus received Byte  2 (0X2)
[16:03:49][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:49][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:49][V][modbus:058]: Modbus received Byte  128 (0X80)
[16:03:49][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[16:03:49][V][modbus:058]: Modbus received Byte  210 (0Xd2)
[16:03:49][V][modbus:058]: Modbus received Byte  228 (0Xe4)
[16:03:49][V][modbus:058]: Modbus received Byte  160 (0Xa0)
[16:03:49][V][modbus:058]: Modbus received Byte  128 (0X80)
[16:03:49][V][modbus_controller:035]: Sending next modbus command to device 1 register 0xDCD count 2
[16:03:49][VV][uart.arduino_esp8266:180]:     Flushing...
[16:03:49][V][modbus:226]: Modbus write raw: 01.03.00.21.00.02 (6)
[16:03:49][V][modbus_controller:487]: Command sent 0 0xDCD 2
[16:03:49][V][modbus:058]: Modbus received Byte  1 (0X1)
[16:03:49][V][modbus:058]: Modbus received Byte  2 (0X2)
[16:03:49][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:49][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:49][V][modbus:058]: Modbus received Byte  128 (0X80)
[16:03:49][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[16:03:49][V][modbus:058]: Modbus received Byte  208 (0Xd0)
[16:03:49][V][modbus:058]: Modbus received Byte  66 (0X42)
[16:03:49][V][modbus:058]: Modbus received Byte  116 (0X74)
[16:03:49][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:50][V][modbus_controller:035]: Sending next modbus command to device 1 register 0xDCD count 2
[16:03:50][VV][uart.arduino_esp8266:180]:     Flushing...
[16:03:50][V][modbus:226]: Modbus write raw: 01.03.00.21.00.02 (6)
[16:03:50][V][modbus_controller:487]: Command sent 0 0xDCD 2
[16:03:50][V][modbus:058]: Modbus received Byte  1 (0X1)
[16:03:50][V][modbus:058]: Modbus received Byte  2 (0X2)
[16:03:50][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:50][V][modbus:058]: Modbus received Byte  0 (0X0)
[16:03:50][V][modbus:058]: Modbus received Byte  128 (0X80)
[16:03:50][W][modbus:116]: Modbus CRC Check failed! 6021!=8000
[16:03:50][V][modbus:058]: Modbus received Byte  192 (0Xc0)
[16:03:50][V][modbus:058]: Modbus received Byte  6 (0X6)
[16:03:50][V][modbus:058]: Modbus received Byte  64 (0X40)
[16:03:50][V][modbus:058]: Modbus received Byte  96 (0X60)
1 Like

@newnub, any success yet? I am about to do the same with the very same device.

You surely have read Modbus Controller — ESPHome . Have you tried logger: baud_rate: 0, or an ESP32?

No luck yet. I ordered an ESP32 few days ago because I understand that it has more hardware serial GPIO pins unlike the ESP8266. I doubt it will work since even the ESP8266 will work on D2/D3 using Arduino MODbus library in the blog, but just not with ESPHome. I will give it a shot anyways.

I did try changing the logger component to “hardware_uart: UART0_SWAP” so that it does not use the normal GPIO1 and GPIO3 pins just in case it interferes, but it did not work. I doubt this is the issue because I moved my RX and TX pins to D2 and D3, so it should not interfere. I know for the Arduino Modbus library in the blog, if I used GPIO1/GPIO3 instead of D2 and D3, I could not get it working like in the blog. This is because the serial monitor is interfering.

@newnub, I am now as far as you are, with an ESP32, a DSD TECH SH-U12, and unfortunately no clue whatsoever how modbus works. If there is any testing I could do in my setup, I am happy to try and I will let you know what happened.

Been busy and haven’t had a chance to get this working. I ended up using the Arduino code from the blog for now. Hoping someone can figure out how to integrate this in ESPhome. It seems rather straight forward with ESPhome MODBUS, but the data sent isn’t correct. I don’t have a oscilloscope to see what corresponding data is being sent on the bus vs. the Arduino code from the blog.

I finally got it working with some extra debug time over the Thanksgiving holidays. Below is the full instruction:

Hardware:
I used the same parts (same TTL to RS485) as the TUF-2000M blog linked above except for the ESP controller. The connections were the same. For completeness, I’ll list out everything below:

Parts:

  1. TUF-2000M Flow Meter
  2. TTL to RS485 Converter (https://www.amazon.com/gp/product/B08XLT21S6/) - This is the one I used, but I’m sure similar brands may work.
  3. HiLetgo ESP-WROOM-32 (https://www.amazon.com/HiLetgo-ESP-WROOM-32-Development-Microcontroller-Integrated/dp/B0718T232Z/) - This part is important because you need the serial HW logger. The blog used ESP8266. I am using ESP32 because I could not get it working with ESP8266. I believe the ESPhome MODBUS library may either have bugs with ESP8266 or it may require HW serial logger. You cannot use the default GPIO1 and GPIO3 because it interferes with the logger/serial console. ESP32 has additional HW RX/TX pins vs. ESP8266.

How to hook up the HW:

ESP32 to TTL-to-RS485 board:

  1. Connect P17 (RX) from ESP32 to RXD on TTL-to-RS485 board.
  2. Connect P16 (TX) from ESP32 to TXD on TTL-to-RS485 board.
  3. Connect 3V3 (power) from ESP32 to VCC on TTL-to-RS485 board.
  4. Connect GND (ground) from ESP32 to GND on TTL-to-RS485 board.

TTL-to-RS485 board to TUF-2000M:

  1. Connect A+ from TTL-to-RS485 board to 485+ on TUF-2000M.
  2. Connect B- from TTL-to-RS485 board to 485- on TUF-2000M.
  3. Connect GND (Chinese characters on my board) from TTL-to-RS485 board to GND on TUF-2000M.

TUF-2000M to 12V DC Power supply Adapter:

  1. Connect 24+ from TUF-2000M to 12V positive on DC power supply adapter.
  2. Connect 24- from TUF-2000M to 12V negative on DC power supply adapter.

Software:

esphome:
  name: tuf-2000m-flowmeter

esp32:
  board: nodemcu-32s

# Enable logging
logger:
  level: VERY_VERBOSE

wifi:
  ssid: YOUR_WIFI_SSID
  password: YOUR_WIFI_PASSWORD

uart:
   id: mod_bus_uart
   tx_pin:
     number: GPIO16
   rx_pin:
     number: GPIO17
   baud_rate: 9600
   stop_bits: 1
   parity: none
   debug:
     direction: BOTH

modbus:
   id: modbus1
   uart_id: mod_bus_uart
   send_wait_time: 500ms

modbus_controller:
 - id: tuf2000m
   ## the Modbus device addr
   address: 0x1
   modbus_id: modbus1
   setup_priority: -10
   update_interval: 3s

sensor:
 - platform: modbus_controller
   modbus_controller_id: tuf2000m
   name: "Temperature #1/inlet"
   id: inlet_temp1
   register_type: holding
   address: 0x21 # Register 33
   register_count: 2
   response_size: 2
   value_type: FP32
 - platform: modbus_controller
   modbus_controller_id: tuf2000m
   name: "Analog input AI3"
   id: analog_ai3
   register_type: holding
   address: 0x25 # Register 37
   register_count: 2
   response_size: 2
   value_type: FP32
 - platform: modbus_controller
   modbus_controller_id: tuf2000m
   name: "Pipe Inner Diameter"
   id: pipe_inner_diameter
   register_type: holding
   address: 0xDD # Register 221
   register_count: 2
   response_size: 2
   value_type: FP32
 - platform: modbus_controller
   modbus_controller_id: tuf2000m
   name: "Flow rate"
   id: flow_rate
   register_type: holding
   address: 0x1 # Register 1
   register_count: 2
   response_size: 2
   value_type: FP32

I included extra registers because it is easy to use those instead of flow register to verify it is working and that the values match. The TUF-2000M pdf manual above lists all of the MODBUS registers. You may have to change value_type, register_count, and response_size depending on which register you are trying to access.

Debugging:
The “level: VERY_VERBOSE” for the logger definitely helped me figure out any communication errors, along with “direction: BOTH” for uart debug. If you incorrectly swapped your RX/TX pins, you will get MODBUS CRC errors in the logger. Try swapping the pins around. Also, I had an instance where no matter how I hooked up the RX/TX pins, I kept getting MODBUS CRC errors. The issue cleared up once I unplugged the 12V power to TUF-2000M and then unplug USB power to ESP32, and then re-plug 12V TUF-2000M power and re-plug USB power to ESP32. It may help to do that each time you run into errors and recompile the code. One last thing, I could not use GPIO9/10 for HW RX/TX because they were reserved for flash on this board, which leaves only GPIO16/17 since GPIO1/3 were used for serial monitor/logging.

Hope this helps anyone who may be looking for a non-invasive way to detect water supply leak or flow using existing plumbing.

4 Likes

Hi newnub!

I’m also trying to get a water flow measurement but still thinking about the options. How is it working yours? How about the accuracy?

Thanks a lot for your work and for sharing it!!

Jordi

I haven’t had a chance to install it on my pipes. I will need to remove drywall to do that but haven’t had time to do that and replace my water valve (my water valve is a gate valve, and I’m trying to use a ball valve with Dome Automation Shutoff Valve). From what I’ve read online, the accuracy really depends on installation and material of the pipe, but can be up to 1%.

2 Likes

Tried the above (code) solution without any luck. Bunches of errors, no valid values at all. Wonder if it got to do with modbus settings of the device itself?

Well, first I tried to mount it on my pipe and I didn’t figure out how to improve its Q value and the ratio between measured time and calculated time. And as I have seen, the TUF-2000M its a copy almost literal of other well known equip.

Do you have any update on the device esphome integration

In my case, I have returned to China the TUF-2000M. It didn’t worked at all for me.

I think I will leave it for now, but I’m sure that the next step will be to use a traditional water meter installed interspersed in the pipe, and with a reed sensor that detects the motion of the counting disk.

Sorry for necroing this thread, but I believe this information will be useful for anybody looking to do something like this in the future.

The reason ESPHome does not work easily here is because the TUF-2000M echoes back what it receives over its RS485 pins. ESP-IDF has options specifically to deal with this case, in particular the UART_RS485_CONF_REG.UART_RS485TX_RX_EN flag. As far as I can tel ESPHome is entirely oblivious to any RS485 specifics and will not allow setting this sort of mode up.

IOW, you can probably make ESP connected directly to TUF-2000M work (I’m about to find out how), but its not going to be ESPHome in that ESP.

3 Likes

Hi all,

My Modbus/TUF-2000M/RS486 TO ETH(B) setup worked nicely until the 2023.10 update after which this code:

modbus:

  - name: Waveshare

    type: tcp

    host: 192.168.2.80

    port: 502

    delay: 1

    timeout: 5

    retries: 5

    retry_on_empty: true

    message_wait_milliseconds: 500

    close_comm_on_error: false

    sensors:

      - name: Warmwasserzuflussrate

        unique_id: "warmwasserzuflussrate"

        unit_of_measurement: "mÂł/h"

        state_class: measurement

        slave: 1

        count: 2 # 1 for one register integer like 158

        address: 1 # 158 as example for one register integer

        input_type: holding

        data_type: float32 # uint16 for one register integer like 158

        precision: 3

        scan_interval: 5

      - name: Warmwasserzufluss_total

        unique_id: "warmwasserzufluss_total"

        unit_of_measurement: "mÂł"

        state_class: total_increasing

        slave: 1

        count: 2

        address: 115 # 158 as example for one register integer

        input_type: holding

        data_type: float32 # uint16 for one register integer like 158

        precision: 5

        scan_interval: 5

Started giving this error message:

# Home Assistant Core

Modbus Waveshare timeout(5) is adjusted(4) due to scan_interval

14:28:24 – (WARNUNG) modbus - Die Nachricht ist zum ersten Mal am 01:41:35 aufgetreten und erscheint 2 mal

Setup failed for modbus: Invalid config.

01:41:35 – (FEHLER) setup.py

Invalid config for [modbus]: Warmwasserzufluss_total: `count: 2` cannot be combined with `data_type: float32` @ data['modbus'][0]['sensors'][1]. Got {'name': 'Warmwasserzufluss_total', 'unique_id': 'warmwasserzufluss_total', 'unit_of_measurement': 'mÂł', 'state_class': 'total_increasing', 'slave': 1, 'count': 2, 'address': 115, 'input_type': 'holding', 'data_type': 'float32', 'precision': 5, 'scan_interval': 5} Warmwasserzuflussrate: `count: 2` cannot be combined with `data_type: float32` @ data['modbus'][0]['sensors'][0]. Got {'name': 'Warmwasserzuflussrate', 'unique_id': 'warmwasserzuflussrate', 'unit_of_measurement': 'mÂł/h', 'state_class': 'measurement', 'slave': 1, 'count': 2, 'address': 1, 'input_type': 'holding', 'data_type': 'float32', 'precision': 3, 'scan_interval': 5}. (See /config/configuration.yaml, line 256). Please check the docs at https://www.home-assistant.io/integrations/modbus

01:41:35 – (FEHLER) config.py

Anybody any idea how to fix this?

Thanks!

Home Assistant 2023.10.1
Supervisor 2023.10.0
Operating System 10.5
Frontend 20231005.0 - latest