The USB-RS485 bridge lets a PC drive a segment from tools/wiredsensor.py,
which is a bench arrangement: it needs a host awake and attached. A
Waveshare ESP32-S3-Relay-6CH does the same master role permanently and
brings six relays of its own, so one board both reads the node and
switches things in response.
Every pin is fixed by the board and was read off its schematic, so they
are written literally rather than as substitutions — a substitution would
imply a choice that does not exist. Relays sit on GPIO1/2/41/42/45/46,
the WS2812 on GPIO38, the buzzer on GPIO21 and RS485 on GPIO17/18.
Two of those deserve their comments. GPIO45 and GPIO46 are strapping
pins, and GPIO45 selects the flash supply voltage: the internal pulldown
gives 3.3V at reset and the pin is released back to it even with the
relay energised, but anything external holding it high across a reset
selects 1.8V and the module will not boot at all. The strapping warnings
from `esphome config` are left unsuppressed for that reason — channels 5
and 6 can also click during reset, so the warning is not crying wolf.
The `modbus:` component sets no flow_control_pin, unlike the other
configs here. This board derives the SP485EE's driver-enable from the TX
line with a 74HC04D, a 54K/1nF RC and a diode, so there is no DE GPIO to
name; stated in a comment because an absent option reads as an oversight.
flash_size is 16MB, read off the chip with `esptool flash-id` rather than
taken from the schematic, which names an ESP32-S3-WROOM-1U with no memory
suffix. The logger goes to USB_SERIAL_JTAG because the Type-C is wired
straight to native USB with no bridge chip, and the default hardware UART
would log to pins this board does not break out.
The node's entities are inline rather than from wiredsensor-node.yaml,
which creates its own modbus_controller and would leave two of them
polling address 0x01.
Verified on hardware: the gateway reports 23.624 C and 43.35 %RH with
zero bus CRC errors while the node's own USB diagnostics independently
show 23.72 C and 43.04 %RH over the same window, drifting in step.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The README carried a fragment, which is enough to show the shape but not
enough to flash. These are complete configs:
wiredsensor.yaml one node, every measurement and diagnostic register
wiredsensor-node.yaml one node as a reusable package, parameterised by address
bus-of-nodes.yaml three nodes on one segment, via that package
All three validate against ESPHome 2026.7, and the expanded config was
checked register by register rather than only for schema validity — a
wrong address or value_type validates perfectly and then reports a
plausible but wrong temperature, which is the failure mode worth
guarding against.
Two things the fragment in the README was missing and a real config
cannot be:
flow_control_pin on the modbus component. Without it the ESP32 never
asserts DE, so nothing reaches the segment and the node looks dead. The
generated fragment now carries it too.
The read/holding split for diagnostics. ESPHome merges adjacent registers
of one register_type into a single command, and a read overlapping
0x0000..0x0004 is refused when the sensor has never produced a reading —
so diagnostics merged into the measurement command go unavailable exactly
when they are needed. Asking for them as `holding` puts them in their own
command.
Serials are text_sensors with raw_encode: HEXBYTES rather than numeric
sensors, because Home Assistant stores states as float32 and 24 bits of
mantissa cannot hold a 32-bit serial. Uptime has the same limit and is
left numeric with a note; quantising past 194 days does not matter for
spotting a reboot.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>