Modbus485 SHT30 RH and temp sensor or other rs485 hexadecimal sensors and WiFi

I am trying to connect a rs485 temp and humidty sensor using the SHT30 chip with a rs485 modbus. This is connected to rs485 base with atom S3 lite. The sensor data is retrieved by hexadecimal and the address can be changed. I have tried to wrap my brain around the modbus components but unfortunately I do not know how to convert the hexadecimal command into what the components need in order to retrieve what I want. My current yaml is below.

The hexadecimal address to request data is 01 03 00 00 00 02 C4 0B. Address is 01, function code is 03, address for temp would be 00 00, data length is 00 02, and check code is C4 0B. After sending that query it should return with 01 03 04 00 00 79 00 7A AA 09 where 01 is address, 03 is function, 04 is length, 00 79 is data 1, 00 7A is data2 and check code is AA 09. That data is converted to decimal and then divided by 100 to get celsius. If I query the RH address, I am assuming that the RH data point would just be used as the percent directly.

So I have a few questions:

  1. In order to get humidity data it would be 01 03 00 01 00 02 (but not sure what check code to use because it doesn’t have that as an example for the device specs). How do I determine check code?
  2. Why does it return 2 data points?
  3. How do I write my yaml below to query properly?
  4. Is my lamba going to accurately convert the query to Celsius and then to F?
  5. If I change the device to 02, 03, 04, 05, 06, 07, 08, 09, 10 etc, how would I modify the address so it returns properly?
substitutions:
  name: Modbus
  friendly_name: rs485 Modbus hub
  tx_pin: GPIO6
  rx_pin: GPIO5
  board: esp32-s3-devkitc-1
  platform: esp32
  variant: esp32s3

uart:
  id: Temp Sensor
  tx_pin: GPIO6
  rx_pin: GPIO5
  baud_rate: 9600
  stop_bits: 1

modbus:
  #flow_control_pin: GPIO6
  send_wait_time: 200ms
  id: mod_bus_TempSensor1

modbus_controller:
  - id: modbus_controller_Temp_Sensor_1
    address: 0x1
    modbus_id: mod_bus_TempSensor1
    command_throttle: 0ms
    setup_priority: -10
    update_interval: ${updates}

sensor:
  - platform: modbus_controller
    modbus_controller_id: modbus_controller_Temp_Sensor_1
    id: Temp_Sensor_1
    name: "Temp Sensor 1"
    address: 0x3000
    unit_of_measurement: "F"
    register_type: read
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
      - lambda: return ((x * 0.01) * (9.0/5.0)) + 32.0;


Also, forgot to ask, how do I get data 1 and data 2 to report properly as “xx.xF” and “xx%” in HA?

This isnt working. The device needs the command in hexadecimal, no matter what I do (modbus components, uart components, and even doing my best trying lamba) I cannot get a hexadecimal command sent to rx/tx for the device to respond back with data bits.

I deleted a post to reduce confusion because I had a yaml set up for custom commands that worked, but I literally just found a yaml for this sensor from a separate manufacturer buried in their own forum that was only found when I was trying to figure out how to get data from a different address (since mine is reading properly from a device other than 1). In order to change the device address you need to follow the sensor documents and can only be done when that one device is connected by itself. I used a wall panel tablet that has rs485 and an API that allows you to send direct hexadecimal commands to change each individual sensor address before adding to my esphome setup. All of these sensors are attached to a single port on the atoms3-rs485 base. It works that way because each device has it’s own address and I put enough of a delay in the yaml below to allow time for each sensor to respond before it goes on to the next.

In order for this sensor to work it needs Hexadecimal codes sent. The command to get temp for device 1 is 01 03 00 00 00 02 C4 0B. Below you will see that you set the modbus_controller address to the address of your device. If my hex above 01 is the device address so my modbus_controller is 0x01. By setting the register type to holding then it automatically sends 03. The 00 00 (temp address) is sent under the temp section of the actual sensor with address 0x0000 (humidity in my case is 00 01 or 0x0001 in yaml). The U_word returns the data from the returned decimal (in my case 00 02 is the data requested) and it converts it to decimal. Lamba converts it how you need it per sensor documentation. In my case if the decimal was too high it needed to subtract a number to convert to the actual negative values. I also added a line to convert form C to F. The C4 and 0B in the above hexadecimal are check codes…no idea what they do but this yaml works for me so it must determine that automatically. The rest of the configuration just makes it easier to display in HA entity/dashboard and it make it accessible for automations.

I am providing a link to the yaml code I found which ignores custom commands and sends the query appropriately to the sensor to retrieve correct data. This is a much cleaner and more reliable than the custom command yaml that I deleted above. My comments (#comments) are included next to relevant lines.

A32 Pro ESPHome yaml include RS485 modbus temperature humidity sensor

my yaml is

substitutions:
  names: modbustempsense
  friendly_name: rs485_modbus_hub
esphome:
  name: testa3modbus
esp32:
 board: esp32-s3-devkitc-1 #your board here
external_components:
 - source: github://nielsnl68/esphome-components #this is for the relays below
i2c:
  - sda: GPIO2 #determined by your board/pinmap
    scl: GPIO1 #determined by your board/pinmap
    scan: True
    id: i2c0
uart:
  id: uart_sensor
  tx_pin: GPIO6 #determined by your board/pinmap, if your sensor doesn't work trying switching rx and tx pin numbers here
  rx_pin: GPIO5 #determined by your board/pinmap, if your sensor doesn't work trying switching rx and tx pin numbers here
  baud_rate: 9600 #your sensor paperwork should tell you baud rate
  stop_bits: 1

modbus:
- uart_id: uart_sensor
  id: modbus1
  send_wait_time: 500ms #this needs to be high enough that it gives your sensor time to respond before sending new query commands

modbus_controller:
- id: modbus_uartsensor1
  address: 0x01 #address of first device
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor2
  address: 0x02 #address of second device
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor3
  address: 0x03 #address of third device, and so on
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor4
  address: 0x04
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor5
  address: 0x05
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor6
  address: 0x06
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor7
  address: 0x07
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor8
  address: 0x08
  modbus_id: modbus1
  update_interval: 5s
- id: modbus_uartsensor9
  address: 0x09
  modbus_id: modbus1
  update_interval: 5s
sensor:
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor1 #change this to whatever address you are using for the device you need data from
  id: Temp_Sensor_1 #this is the unique entity ID
  address: 0x0000 #this address is listed by your sensor paperwork, it will be the same for all sensors of the same type. Your device number above will determine which device it pulls this from.
  register_type: holding #this is to determine how to get the data
  name: "Living Area Temp" #this makes your unique entity ID display as your common name so it is easier for you to find
  icon: "mdi:temperature-fahrenheit" #this changes the default icon in Home Assistant
  device_class: "temperature" #this is to help you set automations after it adds the entity
  state_class: "measurement" #this is to help you set automations after it adds the entity
  unit_of_measurement: "°F" #you can set this to whatever measurement you need, mine is F but this sensor defaults as Celsius
  value_type: U_WORD #this is to determine how the data is reported back
  accuracy_decimals: 1 #this makes it display as ##.#
  filters:
   - lambda: if (x < 32768) return x * 0.01; else return -1 * (x - 65535) * 0.01; #this is how you have to process your data, sensor paperwork tells you what it needs to do. In order for the sensor I am using to work it takes the data in decimal form and has to be divided by 100. If it is over 32768 then it is supposed to report as a negative number, to do that you need to subtract 65535 and then divide by 100. Then your negative temperature will display correctly.
   - lambda: return x * (9.0/5.0) + 32.0; #this is because I am from a stupid country that doesn't use C so it converts the above value and displays as F in Home Assistant

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor1
  id: Humidty_Sensor_1
  name: "Living Area Humidity"
  address: 0x0001 #this address is listed by your sensor paperwork, it will be the same for all sensors of the same type. Your device number above will determine which device it pulls this from.
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0 #I used 0 because I only wanted whole numbers
  filters:
   - lambda: return x * 0.01; #since the humidity is 0 to 100% it only needs to be divided by 100
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor2
  id: Temp_Sensor_2
  address: 0x0000
  register_type: holding
  name: "Master Suite Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor2
  id: Humidty_Sensor_2
  name: "Master Suite Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor3
  id: Temp_Sensor_3
  address: 0x0000
  register_type: holding
  name: "Far Bedroom Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor3
  id: Humidty_Sensor_3
  name: "Far Bedroom Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor4
  id: Temp_Sensor_4
  address: 0x0000
  register_type: holding
  name: "Near Bedroom Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor4
  id: Humidty_Sensor_4
  name: "Near Bedroom Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor5
  id: Temp_Sensor_5
  address: 0x0000
  register_type: holding
  name: "Upstairs Common Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor5
  id: Humidty_Sensor_5
  name: "Upstairs Common Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor6
  id: Temp_Sensor_6
  address: 0x0000
  register_type: holding
  name: "School Room Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor6
  id: Humidty_Sensor_6
  name: "School Room Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor7
  id: Temp_Sensor_7
  address: 0x0000
  register_type: holding
  name: "Playroom Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor7
  id: Humidty_Sensor_7
  name: "Playroom Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor8
  id: Temp_Sensor_8
  address: 0x0000
  register_type: holding
  name: "Guest Room Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor8
  id: Humidty_Sensor_8
  name: "Guest Room Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;
- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor9
  id: Temp_Sensor_9
  address: 0x0000
  register_type: holding
  name: "Upstairs Bedroom Temp"
  icon: "mdi:temperature-fahrenheit"
  device_class: "temperature"
  state_class: "measurement"
  unit_of_measurement: "°F"
  value_type: U_WORD
  accuracy_decimals: 1
  filters:
   - lambda: if (x < 10000) return x * 0.01; else return -1 * (x - 10000) * 0.01;
   - lambda: return x * (9.0/5.0) + 32.0;

- platform: modbus_controller
  modbus_controller_id: modbus_uartsensor9
  id: Humidty_Sensor_9
  name: "Upstairs Bedroom Humidity"
  address: 0x0001
  register_type: holding
  icon: "mdi:water-percent"
  device_class: "humidity"
  state_class: "measurement"
  unit_of_measurement: "%"
  value_type: U_WORD
  accuracy_decimals: 0
  filters:
   - lambda: return x * 0.01;

tca9548a: #this is a multiplexer that allows you to plug in multiple i2c devices to a single port on your controller, you could also call this device an i2c hub
  - address: 0x70 #this is given by manufacturer, many of these addresses can be changed so you could have multiple hubs if your controller had multiple ports
    id: multiplex0
    i2c_id: i2c0 #ties to your i2c above, this will determine which port on your controller you plugged into
    channels: #these are the channels, each of these multiplexers have 6 ports to plug into. You use this as your new i2c address for any device connected to the hub (even if your device has the same address as the other one (like 2 bme temps sensors with 0x76 addresses, it doesn't matter because the address is by the channel below)
      - bus_id: multiplex0channel0
        channel: 0
      - bus_id: multiplex0channel1
        channel: 1
      - bus_id: multiplex0channel2
        channel: 2
      - bus_id: multiplex0channel3
        channel: 3
      - bus_id: multiplex0channel4
        channel: 4
      - bus_id: multiplex0channel5
        channel: 5

switch:
  - platform: m5stack4relay
    i2c_id: multiplex0channel0 #this is the exact port
    address: 0x26 #this is the address of the device
    sync_mode: true
    id: Relay_25 #all of these names and IDs make it easier to link the relay and led on the device to the same spot so you know which one is turned on or off just by looking at it, I kept the names the same so that it was easier to find in Home Assistant
    relay1: relay 25 #note this is for relay1 on the device as this device has 4 relays
    led1:
      name: led 25
      assumed_state: true #not sure what this does, but it works!
      id: led_25
  - platform: m5stack4relay
    i2c_id: multiplex0channel0 #each relay device has 4 relays, this has to be the same ID to control all relays on that same device
    address: 0x26
    sync_mode: true
    id: Relay_26
    relay2: relay 26
    led2:
      name: led 26
      assumed_state: true
      id: led_26
  - platform: m5stack4relay
    i2c_id: multiplex0channel0
    address: 0x26
    sync_mode: true
    id: Relay_27
    relay3: relay 27
    led3:
      name: led 27
      assumed_state: true
      id: led_27
  - platform: m5stack4relay
    i2c_id: multiplex0channel0
    address: 0x26
    sync_mode: true
    id: Relay_28
    relay4: relay 28
    led4:
      name: led 28
      assumed_state: true
      id: led_28
  - platform: m5stack4relay
    i2c_id: multiplex0channel1 #note that the first 4 relays were for the other device, since those are all named this is the next relay device on the hub so it starts back to relay1 through relay4
    address: 0x26
    sync_mode: true
    id: Relay_29
    relay1: relay 29
    led1:
      name: led 29
      assumed_state: true
      id: led_29
  - platform: m5stack4relay
    i2c_id: multiplex0channel1
    address: 0x26
    sync_mode: true
    id: Relay_30
    relay2: relay 30
    led2:
      name: led 30
      assumed_state: true
      id: led_30
  - platform: m5stack4relay
    i2c_id: multiplex0channel1
    address: 0x26
    sync_mode: true
    id: Relay_31
    relay3: relay 31
    led3:
      name: led 31
      assumed_state: true
      id: led_31
  - platform: m5stack4relay
    i2c_id: multiplex0channel1
    address: 0x26
    sync_mode: true
    id: Relay_32
    relay4: relay 32
    led4:
      name: led 32
      assumed_state: true
      id: led_32
  - platform: m5stack4relay
    i2c_id: multiplex0channel2
    address: 0x26
    sync_mode: true
    id: Relay_33
    relay1: relay 33
    led1:
      name: led 33
      assumed_state: true
      id: led_33
  - platform: m5stack4relay
    i2c_id: multiplex0channel2
    address: 0x26
    sync_mode: true
    id: Relay_34
    relay2: relay 34
    led2:
      name: led 34
      assumed_state: true
      id: led_34
  - platform: m5stack4relay
    i2c_id: multiplex0channel2
    address: 0x26
    sync_mode: true
    id: Relay_35
    relay3: relay 35
    led3:
      name: led 35
      assumed_state: true
      id: led_35
  - platform: m5stack4relay
    i2c_id: multiplex0channel2
    address: 0x26
    sync_mode: true
    id: Relay_36
    relay4: relay 36
    led4:
      name: led 36
      assumed_state: true
      id: led_36
  - platform: m5stack4relay
    i2c_id: multiplex0channel3
    address: 0x26
    sync_mode: true
    id: Relay_37
    relay1: relay 37
    led1:
      name: led 37
      assumed_state: true
      id: led_37
  - platform: m5stack4relay
    i2c_id: multiplex0channel3
    address: 0x26
    sync_mode: true
    id: Relay_38
    relay2: relay 38
    led2:
      name: led 38
      assumed_state: true
      id: led_38
  - platform: m5stack4relay
    i2c_id: multiplex0channel3
    address: 0x26
    sync_mode: true
    id: Relay_39
    relay3: relay 39
    led3:
      name: led 39
      assumed_state: true
      id: led_39
  - platform: m5stack4relay
    i2c_id: multiplex0channel3
    address: 0x26
    sync_mode: true
    id: Relay_40
    relay4: relay 40
    led4:
      name: led 40
      assumed_state: true
      id: led_40
  - platform: m5stack4relay
    i2c_id: multiplex0channel4
    address: 0x26
    sync_mode: true
    id: Relay_41
    relay1: relay 41
    led1:
      name: led 41
      assumed_state: true
      id: led_41
  - platform: m5stack4relay
    i2c_id: multiplex0channel4
    address: 0x26
    sync_mode: true
    id: Relay_42
    relay2: relay 42
    led2:
      name: led 42
      assumed_state: true
      id: led_42
  - platform: m5stack4relay
    i2c_id: multiplex0channel4
    address: 0x26
    sync_mode: true
    id: Relay_43
    relay3: relay 43
    led3:
      name: led 43
      assumed_state: true
      id: led_43
  - platform: m5stack4relay
    i2c_id: multiplex0channel4
    address: 0x26
    sync_mode: true
    id: Relay_44
    relay4: relay 44
    led4:
      name: led 44
      assumed_state: true
      id: led_44
  - platform: m5stack4relay
    i2c_id: multiplex0channel5
    address: 0x26
    sync_mode: true
    id: Relay_45
    relay1: relay 45
    led1:
      name: led 45
      assumed_state: true
      id: led_45
  - platform: m5stack4relay
    i2c_id: multiplex0channel5
    address: 0x26
    sync_mode: true
    id: Relay_46
    relay2: relay 46
    led2:
      name: led 46
      assumed_state: true
      id: led_46
  - platform: m5stack4relay
    i2c_id: multiplex0channel5
    address: 0x26
    sync_mode: true
    id: Relay_47
    relay3: relay 47
    led3:
      name: led 47
      assumed_state: true
      id: led_47
  - platform: m5stack4relay
    i2c_id: multiplex0channel5
    address: 0x26
    sync_mode: true
    id: Relay_48
    relay4: relay 48
    led4:
      name: led 48
      assumed_state: true
      id: led_48

logger: #this is to track your commands if esplogs, baud should match your device and the level verbose gives you more details
  baud_rate: 9600
  level: verbose


api:
  encryption:
    key: your key here


wifi:
  ssid: "your wifi here"
  password: "your wifi password here"

One thing I notice is that if a sensor is still connected but loses power (I removed the 12v power source) that it just perpetually shows the last reading. How do I make it show unavailable in HA if the sensor stops responding?

search my other posts for making this work on ethernet with w5500 chip