Esphome Chinese modbus io relay board

Hello there, bought a Chinese io modbus relay with 8 input and 8 relays.

EDIT: this is the board Modbus-RTU 1/2/4/8 canais módulo de relé swtich DC7-24V ac220v rs485/rs232/ttl saída de relé de comunicação 3 modos anti-reverso

I have made a small python script to test the communication and use a usb to rs485. all data works ok.

These are the packets I send via rs485

r1on = "FF050000FF00"
r1of = "FF0500000000"
rin = "FF0200000008"

I start and reading inputs, use “FF0200000008”
As I read, the FF is the board modbus address, the 02 is the input read code and next 00 00. is the register address of the inputs and the 00 08 is the number of bits.

for the input number 3 I receive:
b'\xff\x02\x01\x04\x91\xa3'

witch I know FFis the modbus address slave, 02 is the reading code, I don’t know what is the 01, but the 04 is the last byte contains the input 3 ON.

So I start my yaml on esphome like this:

uart:
  tx_pin: GPIO04
  rx_pin: GPIO03
  baud_rate: 9600  

modbus_controller:
- id: modbus_device
  address: 0xFF   ## address of the Modbus slave device on the bus
  modbus_id: modbus1
  setup_priority: -10


binary_sensor:
- platform: modbus_controller
  modbus_controller_id: modbus_device
  name: "I1"
  register_type: discrete_input
  address: 0x00
  bitmask: 0x1 #(bit 8)
- platform: modbus_controller
  modbus_controller_id: modbus_device
  name: "I2"
  register_type: discrete_input
  address: 0x00
  bitmask: 0x2 #(bit 8)  
- platform: modbus_controller
  modbus_controller_id: modbus_device
  name: "I3"
  register_type: discrete_input
  address: 0x00
  bitmask: 0x4 #(bit 8)

Has many different approaches I try, always get

"[D][modbus_controller:040]: Modbus command to device=255 register=0x00 no response received - removed from send queue"

What I’m suppose doing wrong here?

Thanks :slight_smile:

08 is number of inputs you request.

01 is byte count.
04 is your input values 0000 0100 (1 is the third input from right to left)
91 A3 is the CRC

Turn on uart-debug to see what esphome is really sending.

Dear Karosm,

I have activated the debug uart and I’m reading this:

[14:08:58][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:08:58][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:08:59][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:08:59][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:08:59][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"

[D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\x01\xAC\x14"
[D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\x01\xAC\x14"
[D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\x01\xAC\x14"
[D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\x01\xAC\x14"
[D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\x01\xAC\x14"
[D][modbus_controller:040]: Modbus command to device=255 register=0x00 no response received - removed from send queue

That help a lot, the function is not correct, I use “discrete_input”, by docs should have function 2, but instead is using function 1. sometimes it gets right.

left change the last number, the quantity.
the topic “register_count: 8” always gives me error, I try to put near the sensor:

binary_sensor:
- platform: modbus_controller
  modbus_controller_id: modbus_device
  name: "I1"
  register_type: discrete_input
  address: 0x0000
  register_count: 8
  bitmask: 0x1 #(bit 8)

I’l try next the costum command with the bytes I need.

meanwhile the relays are function using lambda


switch:
  - platform: modbus_controller
    modbus_controller_id: modbus_device
    id: R1
    register_type: coil
    address: 0
    name: "Relé 1"
    write_lambda: |-
      ESP_LOGD("main","Modbus Switch incoming state = %f",x);
      // return false ; // use this to just change the value
      if(x) {
      payload.push_back(0xFF);  // device address
      payload.push_back(0x05);  // force single coil
      payload.push_back(0x00); // high byte address of the coil
      payload.push_back(0x00);  // low byte address of the coil
      payload.push_back(0xFF); // ON = 0xFF00 OFF=0000
      payload.push_back(0x00);
      return true; }
      else {
      payload.push_back(0xFF);  // device address
      payload.push_back(0x05);  // force single coil
      payload.push_back(0x00); // high byte address of the coil
      payload.push_back(0x00);  // low byte address of the coil
      payload.push_back(0x00); // ON = 0xFF00 OFF=0000
      payload.push_back(0x00);
      return false;
      }

That’s really weird…

I have delete all sensors, lease just on single sensor, and I got this:

[14:33:42][D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\bl\x12\x00\x00"
[14:33:42][W][modbus_controller:065]: Modbus device=255 back online
[14:33:42][D][uart_debug:158]: <<< "\xFF\x02\x01\x05Pc"
[14:33:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:33:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:33:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:33:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:33:44][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:33:44][W][modbus_controller:027]: Modbus device=255 set offline
[14:33:44][D][modbus_controller:040]: Modbus command to device=255 register=0x00 no response received - removed from send queue
[14:34:42][D][uart_debug:158]: >>> "\xFF\x02\x00\x00\x00\bl\x12\x00\x00"
[14:34:42][W][modbus_controller:065]: Modbus device=255 back online
[14:34:42][D][uart_debug:158]: <<< "\xFF\x02\x01\x05Pc"
[14:34:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:34:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:34:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:34:43][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:34:44][D][uart_debug:158]: >>> "\xFF\x01\x00\x00\x00\x01\xE8\x14"
[14:34:44][W][modbus_controller:027]: Modbus device=255 set offline
[14:34:44][D][modbus_controller:040]: Modbus command to device=255 register=0x00 no response received - removed from send queue

I don’t know wren the 4 requests comes from.

Another thing, I receive
[14:38:42][D][uart_debug:158]: <<< "\xFF\x02\x01\x01Q\xA0"

the last byte if 0x01, and my bit mask is 01, the sensor should’n be 1?

this has wrong function code

but this has wrong everything after correct function code…

By the way, what board do you use? Gpio3 / 4 wouldn’t be my pick for any board I’m familiar with.

this has wrong function code

I agree with you. but every time it sends, and I don’t know why.

By the way, what board do you use? Gpio3 / 4 wouldn’t be my pick for any board I’m familiar with.

Now this:

|15:18:16|[D]|[uart_debug:158]|>>> "\xFF\x02\x00\x00\x00\bl\x12\x00\x00"|
| --- | --- | --- | --- |
|15:18:16|[W]|[modbus_controller:065]|Modbus device=255 back online|
|15:18:16|[D]|[uart_debug:158]|<<< "\xFF\x02\x01\x01Q\xA0"|

this particular code works ok, but is not correctly represented
“\xFF\x02\x00\x00\x00\bl\x12\x00\x00”

the code I’m using is:

binary_sensor:
- platform: modbus_controller
  modbus_controller_id: modbus_device
    #                   FF    02    00    00    00    08    6C    12”
  custom_command: [ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x08, 0x6C, 0x12]
  name: "I1"
  lambda: |-
      ESP_LOGD("main","Modbus e = %s",to_string(x));
      if (data[3] && 0x01) {
        return true;
      }
      else {
        return false;
      }

meaning this “\xFF\x02\x00\x00\x00\bl\x12\x00\x00” is [ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x08, 0x6C, 0x12] and its working.

but I can’t make the sensor true or false.

Hey, I got the inputs working good:

modbus_controller:
- id: modbus_device
  address: 0xFF   ## address of the Modbus slave device on the bus
  modbus_id: modbus1
  setup_priority: -10
  update_interval: 1s


binary_sensor:
- platform: modbus_controller
  modbus_controller_id: modbus_device
  id: inp1
    #                   FF    02    00    00    00    08    6C    12”
  custom_command: [ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x08, 0x6C, 0x12]
  name: "I1"
  lambda: |-
      if (0x02 & data[0]) {
        id(inp2).publish_state(true);
      }
      else {
        id(inp2).publish_state(false);
      }
      return (0x01 & data[0]);

- platform: template
  id: inp2
  name: "I2"

:slight_smile:

I found the solution:

uart:
  tx_pin: GPIO03
  rx_pin: GPIO04
  baud_rate: 9600  
  debug:
    direction: BOTH
    dummy_receiver: false
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);

modbus:
#  flow_control_pin: GPIOXX
  id: modbus1   

modbus_controller:
- id: modbus_device
  address: 0xFF   ## address of the Modbus slave device on the bus
  modbus_id: modbus1
  setup_priority: -10
  update_interval: 10s


binary_sensor:
- platform: modbus_controller
  modbus_controller_id: modbus_device
  id: inp1
    #                   FF    02    00    00    00    08    6C    12”
  custom_command: [ 0xFF, 0x02, 0x00, 0x00, 0x00, 0x08, 0x6C, 0x12]
  name: "I1"
  lambda: |-
      id(inp2).publish_state(0x02 & data[0]);
      id(inp3).publish_state(0x04 & data[0]);
      id(inp4).publish_state(0x08 & data[0]);
      id(inp5).publish_state(0x10 & data[0]);
      id(inp6).publish_state(0x20 & data[0]);
      id(inp7).publish_state(0x40 & data[0]);
      id(inp8).publish_state(0x80 & data[0]);      
      return (0x01 & data[0]);

- platform: template
  id: inp2
  name: "I2"
- platform: template
  id: inp3
  name: "I3" 
- platform: template
  id: inp4
  name: "I4"
- platform: template
  id: inp5
  name: "I5"  
- platform: template
  id: inp6
  name: "I6"   
- platform: template
  id: inp7
  name: "I7"    
- platform: template
  id: inp8
  name: "I8"      

switch:
  - platform: output
    name: "Relé 1"
    output: 'r1o'
    id: r1
  - platform: output
    name: "Relé 2"
    output: 'r2o'
    id: r2   

output:
  - platform: modbus_controller
    modbus_controller_id: modbus_device
    address: 0x0000
    register_type: coil
    bitmask: 0xFF00
    id: r1o
  - platform: modbus_controller
    modbus_controller_id: modbus_device
    address: 0x0001
    register_type: coil
    bitmask: 0xFF00
    id: r2o      

Of course the rest of the 6 relays is just creat the outputs and the switches.
:slight_smile:

Nice that you got solution. I still don’t understand why Esphome was sending invalid code??

Anyway, this is not the worst device I have been “working with”. The most idiotic one I have been scratching my head was responding to slave address x, but with slave address y in response. Invaliding modbus_controller to read response at all, because it was from wrong address.

Nice that you got solution. I still don’t understand why Esphome was sending invalid code??

Because I’m a idiot.

switch:
  - platform: modbus_controller
    modbus_controller_id: modbus_device
    id: R1
    register_type: coil
    address: 0
    name: "Relé 1"
    write_lambda: |-
      ESP_LOGD("main","Modbus Switch incoming state = %f",x);
      // return false ; // use this to just change the value
      if(x) {
      payload.push_back(0xFF);  // device address
      payload.push_back(0x05);  // force single coil
      payload.push_back(0x00); // high byte address of the coil
      payload.push_back(0x00);  // low byte address of the coil
      payload.push_back(0xFF); // ON = 0xFF00 OFF=0000
      payload.push_back(0x00);
      return true; }
      else {
      payload.push_back(0xFF);  // device address
      payload.push_back(0x05);  // force single coil
      payload.push_back(0x00); // high byte address of the coil
      payload.push_back(0x00);  // low byte address of the coil
      payload.push_back(0x00); // ON = 0xFF00 OFF=0000
      payload.push_back(0x00);
      return false;
      }

This block above, send the regular packet (you see 4 times and no answer, because is not correct, and then send the payload by wirite_lambda code.
So this block send 2 complete packets, one for the switch itself, and the other packet created by me in lambda.

ESPhome works ok. i’m not.

the correct solution is this one, as output. esphoem gets all packets corrected.

output:
  - platform: modbus_controller
    modbus_controller_id: modbus_device
    address: 0x0000
    register_type: coil
    bitmask: 0xFF00
    id: r1o