HC-12 vs WiFi for Remote Sensor Nodes: What 433 MHz Actually Buys You
Hardware used in this build
- ESP32-C3 dev board
The shed node MCU. Runs the AI_optimized_shed_TX.ino sketch. Seeed's own board. - HC-12 433 MHz wireless module
HiLetgo HC-12 433 MHz SI4438 module with antenna. Reliable for 100–1 000 m links. - Raspberry Pi 4
Used in the running shed build; works reliably. - Relay module
Every home-monitoring tutorial assumes WiFi reaches your sensor. Mine didn’t — and for my shed node, it fundamentally couldn’t. The shed sits about 100 yards (~90 m) from the house, runs off-grid on a 12 V solar panel, and its only buffer is the tractor battery wired in for charging only. There is no grid power, no ethernet, and no convenient place to put an access point halfway between.
For a node like that, “just use WiFi” collapses immediately: a WiFi board at that distance needs either an outdoor AP and a PoE run (a whole infrastructure project for one sensor), or it simply won’t hold a link. And the power budget is the real killer — a solar panel trickle-charging a tractor battery has no watts to spare for a radio that negotiates, authenticates, and keeps a 2.4 GHz association alive around the clock.
The fix was to stop fighting 2.4 GHz and drop to 433 MHz with a pair of HC-12 modules. Here’s the honest comparison after running both — including why, for the shed, WiFi was never actually on the table.
The tradeoff in one table
| WiFi (ESP32-C3 native) | HC-12 @ 433 MHz | |
|---|---|---|
| Wall penetration | poor | very good |
| Throughput | Mbit/s | ~1–5 kbit/s usable |
| Power per reading | high (assoc + DHCP + TLS) | low (UART burst) |
| Infrastructure needed | AP in range | none, point-to-point |
| Debuggability | excellent | painful |
| Cost per node | €0 (built in) | ~€5 |
The headline: you trade bandwidth you don’t need for range you desperately do. A temperature reading is 20 bytes. Spending a WiFi association on it is absurd.
Why 433 MHz wins through walls
Path loss scales with frequency. Dropping from 2400 MHz to 433 MHz is roughly a 15 dB free-space advantage before you account for material absorption — and building materials absorb 2.4 GHz far more aggressively, because the wavelength (12 cm) is close to the scale of the reinforcement mesh and water content in the structure. At 433 MHz the wavelength is ~69 cm and the wall is electrically “thinner”.
In my install: the WiFi node showed RSSI of -89 dBm and constant reassociation. The HC-12 pair, same positions, delivered packets with zero loss over 24 hours.
Why the shed was never a WiFi problem to solve
The “two masonry walls” case above is a benchmark — a node I could move. The shed is the real one, and WiFi fails it on two independent axes:
Reach. ~100 yards of open air plus a structure between the shed and the house AP is past what an ESP32-C3 with its PCB antenna will hold. You’d need an outdoor access point mounted partway, with a PoE run back to the house — a second infrastructure project just to read one temperature. HC-12 just reaches, point to point, no middleman.
Power. This is the one people miss. The shed is 12 V solar, buffered only by the tractor battery used for charging — there’s no deep-cycle house bank, so the usable stored energy is small and the panel’s input is the constraint. A WiFi radio doesn’t just transmit; it maintains an association: beacons, DHCP leases, re-auth, and a continuous 2.4 GHz frontend drawing current even when idle. That’s a steady tax on a supply that’s already living hand-to-mouth off a solar panel. An HC-12 node sleeps, wakes, UART-bursts 20 bytes, and goes back to sleep — the link’s average draw is a fraction of a WiFi keepalive. Off-grid, that difference is the difference between “runs all summer” and “dead by week two.”
So it isn’t “HC-12 is cheaper than WiFi.” It’s that WiFi, at shed scale, is a power and infrastructure problem you have to solve first — and off-grid, ~90 m away, with no spare watts, you can’t.
The settings that actually mattered
HC-12 modules are configured over AT commands with the SET pin pulled low.
AT+B9600 # UART baud toward the ESP32-C3 / Pi
AT+C001 # channel 1 (each channel is 400 kHz apart)
AT+FU3 # transmission mode 3 — the sane default
AT+P8 # max transmit power (~100 mW)
Three things cost me an evening each:
AT+Bsets the UART baud, not the air rate. In FU3 the over-air rate is fixed at 15 kbps regardless. Setting a high UART baud does not make the link faster and will overflow the module’s buffer if you stream.- Both ends must match on channel and FU mode. Mismatched FU modes fail silently — you get nothing, with no error anywhere.
- The module needs a real antenna. The spring antenna is not optional decoration. Without it, range collapsed to under three metres and I briefly concluded the modules were dead on arrival.
The failure modes nobody warns you about
Power sag on transmit. At AT+P8 the HC-12 pulls ~100 mA in bursts. On an
On an ESP32-C3 running from a marginal LDO, the transmit burst browned out the MCU, which
reset, which retransmitted, which browned out again. A 470 µF electrolytic across the
HC-12 supply pins ended a week of “random” resets.
No addressing, no CRC, no ACK. HC-12 is a dumb serial pipe. Anything on the same channel within range lands in your UART. You must frame your own packets. Mine is deliberately boring:
<NODE_ID>,<SENSOR>,<VALUE>,<CRC8>\n
Without the CRC I was logging temperatures of 8523 °C whenever a neighbouring 433 MHz doorbell fired. I wrote up the retry protocol I ended up using — CRC-16 framing, timeout-based retry, and backoff that actually worked on the live link. The frames land in my asyncio collector, which is why a bad value is a silent corruption rather than an obvious error. The ESP32-C3 that runs the shed node never sleeps between bursts — see ESP32-C3 deep sleep current: what the datasheet doesn’t tell you for why the on-board hardware keeps leaking milliamps even when the sketch is idle. The framed stream from that node lands in the same asyncio collector as the wired sensors.
Duty-cycle rules. In the EU, 433 MHz ISM carries duty-cycle limits. Reading once per 30 seconds with a 20-byte payload is nowhere near the limit; streaming continuously is both illegal and antisocial to everyone else on the band.
Would I do it again?
For the shed — off-grid, ~100 yards out, solar-buffered — HC-12 was not a preference, it was the only option that didn’t require solving power and WiFi infrastructure first. For anything outdoors, through walls, or battery-powered, yes, immediately. For a node sitting two metres from the access point, WiFi is less work and gives you OTA updates, which HC-12 can never do.
The rule I settled on: WiFi where you can, HC-12 where you must, and never argue with a concrete wall — or a solar panel that’s already out of watts.
Related reading
- How to Spot a Fake DS18B20 Temperature Sensor on a Raspberry Pi
Spot a fake DS18B20 on a Raspberry Pi: family-code check, sysfs CRC test, and ice/boil calibration against the datasheet. 3 of 7 probes in one batch were counterfeits, drifting 1.5–3.5 °C.
- ESP32-C3 Deep Sleep Current: What the Datasheet Doesn't Tell You About Your Dev Board
The ESP32-C3 datasheet promises 5–7 µA deep sleep. Your dev board draws thousands of times more. Here is what is actually leaking current in a XIAO ESP32C3 and how to measure it yourself.
- DHT11 vs DHT22: 18 Months of Accuracy Data on a Raspberry Pi
DHT11 accuracy after 18 months of continuous logging on a Raspberry Pi: 26,318 rollup rows, 38% below the datasheet's 20 %RH floor, and where the part stops being usable.