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:
- 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?
- Why does it return 2 data points?
- How do I write my yaml below to query properly?
- Is my lamba going to accurately convert the query to Celsius and then to F?
- 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