Skip to content

XY-MD02

A real product: the XY-MD02 "Modbus RTU RS485 SHT20 Temperature Humidity Transmitter", a DIN-rail housing (65 x 46 x 28.5 mm) with a 4-way screw terminal. The twin is a data pack on the uart_device primitive (configs/devices/xy-md02.yaml), so it runs in the browser, in hosted runs, in CI and from Python the same way.

Source

The register map, defaults and frame examples come from the manufacturer manual "XY-MD02" (copy retrieved 2026-10-04):

A second revision of the manual (60 x 30 x 18 mm, same register map) is at https://iot-kmutnb.github.io/blogs/sensors/xy-md02/xy-md02_manual-2.pdf. The terminal order comes from the label on the housing, B- A+ RS485 and - + DC 5~30V, read in the same order as the 4-way terminal.

Status at a glance

Aspect Status
Catalog id xy-md02
Bus UART behind a MAX485 (terminals A+ and B-)
Descriptor configs/devices/xy-md02.yaml
Settings address (1..247, default 1), baud (9600, 14400 or 19200, default 9600), temp_correction, hum_correction
Inputs temperature (C), humidity (%RH)
Power DC 5 to 30 V
Terminal B-, A+, GND, V+, in that order
Example examples/arduino-uno-modbus-rtu
Tier modeled (protocol level)

Register map

Function codes: 03 read holding, 04 read input, 06 write one holding, 10 (16) write several holding.

Address Kind Content Encoding
0x0001 input (04) temperature signed, tenths of a degree C (0x0131 = 30.5, 0xFF33 = -20.5)
0x0002 input (04) humidity tenths of %RH (0x0222 = 54.6)
0x0101 holding (03, 06, 10) device address 1..247, default 1
0x0102 holding baud rate the bit rate itself: 9600 = 0x2580 (default), 14400, 19200
0x0103 holding temperature correction signed tenths, -100..100 (-10.0..10.0 C), default 0
0x0104 holding humidity correction signed tenths, -100..100, default 0

The measured value reads input + correction. Writing 0x0101 changes the address at once; the answer to that request still carries the old address.

Factory defaults: address 1, 9600 baud, 8 data bits, 1 stop bit, no parity.

Every frame example in the manual is a test (rs485_modbus.rs, manual_examples). Two CRCs the manual prints are wrong and are not copied: the humidity response (D1 BA; the CRC of that frame is 38 49) and the function-06 response (D4 0F; a function-06 answer echoes the request, D8 30).

Where the manual is silent or contradicts itself

  • Baud register. The table says 0:9600 1:14400 2:19200; the function-10 example writes 0x2580 into it. The twin stores and reads back the bit rate and accepts 9600, 14400 and 19200. The codes 0 to 2 answer exception 03. A written rate is stored but the line keeps the rate it was placed with; a real part applies it at the next power-up.
  • Exceptions. The manual lists none. The twin answers the standard Modbus ones.
  • Wrong kind of register. A read of 0x0001 with function 03, or of 0x0101 with function 04, answers exception 02.
  • Broadcast. The manual gives addresses 1..247 and says nothing about 0, so address 0 is ignored.
  • Ranges. The manual gives temperature -40..60 C and humidity 0..80 %RH in one revision and humidity 0..100 in the other; the simulation inputs allow -40..60 C and 0..100 %RH.

Behaviour on the wire

  • A frame ends after 3.5 character times of silence at the part's baud (10 bits per character).
  • A bad CRC-16/MODBUS, a frame for another address, a frame split by a longer gap and a frame shorter than address + function + CRC get no answer.
  • Exception 01 for an unsupported function code, 02 for a register or range outside the map or a write to an input register, 03 for a count outside 1..125 (123 for function 10), a byte count that does not match the register count, an address outside 1..247, a baud that is not 9600, 14400 or 19200, or a correction outside -10.0..10.0.

Limits

  • The manual's "ordinary UART protocol" (text commands READ, AUTO, BR:, TC:, HC:, HZ:, PARAM) is not modelled.
  • No parity setting (8N1).
  • A function-10 write checks the range of its first two values only.
  • The fixed 1.75 ms gap Modbus asks for above 19200 baud is not applied.