The Great IoT Hype Cycle
Somewhere around 2014, the consumer electronics industry collectively decided that every object in your house needed an IP address. Thermostats were first. Then light bulbs. Then door locks, refrigerators, washing machines, and — inevitably, tragically — toilets. We now live in a world where a toilet can have a firmware update. Let that sink in. Or rather, let that flush in.
The promise was seductive: a connected home where everything talks to everything else, where your refrigerator orders milk before you run out, where your lights dim automatically when you start a movie. The reality is a graveyard of dead apps, bricked devices, and subscription fees for things that used to just work.
Every appliance manufacturer is now a “tech company.” Your microwave vendor has a cloud team. Your garage door company has a Kubernetes cluster. Your thermostat requires Terms of Service acceptance. This is not progress. This is an industry that has confused connectivity with value and complexity with sophistication.
The gap between IoT marketing and IoT reality could swallow a continent. Marketing says: “seamless, intelligent, always connected.” Reality says: “please wait while your light switch downloads a 200MB update.” Marketing says: “the future of smart living.” Reality says: “your smart lock’s certificate expired and you are locked out of your own house on a Tuesday evening in January.”
Here is the uncomfortable truth that no one at CES wants to hear: most IoT products would be better off without the “I.” A thermostat with a well-designed dial, a light switch with a physical toggle, a lock with a key — these are technologies perfected over decades. They are reliable. They are fast. They do not require a cloud account. And critically, they still work when your WiFi goes down.
But here we are. So let us talk about how to do IoT properly, for those of us who actually care about building things that work.
The Constraints That Set You Free
There is a particular kind of freedom that comes from working within severe constraints. When you have 32KB of RAM, a 72MHz ARM Cortex-M0 processor, and a coin cell battery that needs to last three years, you cannot afford to be sloppy. Every byte matters. Every clock cycle matters. Every milliamp matters.
This is the opposite of modern web development, where the answer to every performance problem is “throw more hardware at it” or “just spin up another container.” In embedded systems, there is no more hardware. There is what is on the board, and that is what you get. Deal with it.
And honestly? It is liberating.
When you cannot hide behind layers of abstraction, you are forced to understand what your code actually does. Not what your framework does. Not what your runtime does. What your code does, instruction by instruction, register by register. You know exactly how long a function takes because you counted the cycles. You know exactly how much memory you use because you allocated it yourself.
C is not a popular language in 2026. It is not trendy. It does not have a package manager with 2 million packages of varying quality. It does not have a “state of the C ecosystem” survey with colorful charts. What it has is predictability. When you write C for a microcontroller, you are one thin layer of abstraction above the hardware. You can read the generated assembly. You can predict the stack usage. You can reason about timing down to the nanosecond.
Bare-metal programming — writing code that runs directly on hardware without an operating system — is the ultimate exercise in intentional engineering. There is no scheduler deciding when your code runs. There is no garbage collector pausing your execution at inconvenient moments. There is no virtual memory giving you the illusion of infinite RAM. There is just your code, the hardware, and the laws of physics.
This is not nostalgia. This is pragmatism. When your device needs to wake up from deep sleep, sample a sensor, transmit a 20-byte packet, and go back to sleep in under 50 milliseconds to hit its power budget, you do not reach for Python. You do not reach for JavaScript. You reach for the tool that gives you control.
That said, MicroPython and CircuitPython have earned a legitimate place in prototyping and in applications where the constraints are less brutal. A sensor hub running on an ESP32 with 520KB of RAM and wall power is a perfectly reasonable MicroPython target. Know your constraints. Choose your tools accordingly.
The Protocol Wars
Choosing a communication protocol for an IoT project is like choosing a religion: everyone has strong opinions, nobody is entirely wrong, and the wrong choice will cause you years of suffering.
Here is a pragmatic guide, free of vendor allegiance.
The Contenders
| Protocol | Transport | Power | Bandwidth | Range | Best For |
|---|---|---|---|---|---|
| MQTT | TCP/IP (WiFi, Ethernet) | Medium | Medium-High | LAN/WAN | Cloud-connected devices with reliable power |
| CoAP | UDP/IP | Low-Medium | Low-Medium | LAN/WAN | Resource-constrained devices needing REST-like semantics |
| HTTP/REST | TCP/IP | High | High | LAN/WAN | Absolutely nothing in embedded (fight me) |
| LoRaWAN | LoRa PHY | Very Low | Very Low (0.3-50 kbps) | 2-15 km | Long-range sensor networks, agriculture, utilities |
| Zigbee | IEEE 802.15.4 | Low | Low (250 kbps) | 10-100 m (mesh) | Home automation mesh networks |
| Thread | IEEE 802.15.4 | Low | Low (250 kbps) | 10-100 m (mesh) | Modern home automation (Matter-compatible) |
| BLE | Bluetooth 5.x | Very Low | Low-Medium | 10-50 m | Wearables, beacons, phone-connected peripherals |
| Matter | Thread, WiFi, Ethernet | Varies | Varies | Varies | Interoperable smart home (the great unifier, allegedly) |
The Common Mistakes
Mistake 1: Using HTTP for everything. If your battery-powered sensor is making HTTP requests to a REST API, you have already lost. HTTP’s verbose headers, TCP handshake overhead, and TLS negotiation cost real power on constrained devices. MQTT’s persistent connections and tiny packet headers exist for a reason.
Mistake 2: Choosing LoRaWAN when you have WiFi. LoRaWAN is extraordinary for what it does — long-range, low-power communication for devices that send small amounts of data infrequently. It is terrible for anything that needs low latency or high throughput. If your device is indoors with access to a WiFi network and wall power, LoRaWAN is not the answer.
Mistake 3: Ignoring Thread/Matter. The smart home protocol fragmentation has been a disaster for a decade. Matter is an imperfect but genuine attempt to fix it. If you are building a consumer home automation product in 2026 and you are not at least evaluating Matter, you are betting against the industry’s direction.
Mistake 4: Rolling your own protocol. Unless you are doing something genuinely novel at the physical layer, do not invent a new application protocol. You will get security wrong. You will get reliability wrong. You will spend years debugging edge cases that existing protocols solved in 2015.
Here is a minimal MQTT publish example in MicroPython, because every IoT blog post is legally required to include one:
from umqtt.simple import MQTTClient
import machine
import json
def publish_sensor_reading():
adc = machine.ADC(machine.Pin(34))
temperature = adc.read_u16() * 0.00125 # crude conversion
client = MQTTClient(
client_id="sensor-node-017",
server="192.168.1.50",
port=1883,
keepalive=60
)
client.connect()
payload = json.dumps({
"node": "sensor-017",
"temp_c": round(temperature, 2),
"battery_mv": get_battery_voltage()
})
client.publish(b"home/basement/temperature", payload.encode())
client.disconnect()
Short. Simple. Does what it needs to do. No framework. No dependency tree. No build step that takes four minutes.
Edge vs Cloud: The False Dichotomy
The IoT industry has developed an unhealthy obsession with the cloud. Somewhere along the way, “IoT” became synonymous with “devices that send all their data to AWS so you can run analytics on it and display a dashboard that nobody looks at.”
Here is a radical idea: maybe the data should stay where it is.
The Latency Problem
When you flip a light switch, you expect the light to turn on. Not in 200 milliseconds after a round trip to a data center in us-east-1. Not in 2 seconds because the cloud function had a cold start. Now. Immediately. With the mechanical certainty of an electrical contact closing a circuit.
If your IoT device needs cloud connectivity to perform its primary function, you have made an architectural mistake. The cloud should enhance, not enable. Your smart light should work without the internet. Your door lock should work without the internet. Your thermostat should maintain temperature without the internet. If the cloud is down, the device should degrade gracefully, not become a paperweight.
Local-First IoT
The best IoT architectures are local-first. The device does its job independently. It makes decisions at the edge. It stores data locally when it cannot reach the network. It syncs when connectivity is available. The cloud provides remote access, long-term analytics, and firmware updates — nice-to-have features, not core functionality.
This is not a new idea. Industrial control systems have worked this way for decades. A PLC on a factory floor does not phone home to Azure before actuating a valve. It runs its control loop locally, deterministically, every single scan cycle. Consumer IoT could learn a lot from industrial automation.
When the Cloud Makes Sense
To be fair, there are legitimate cloud use cases. Machine learning inference on aggregated data from thousands of sensors. Cross-device coordination that spans geographic regions. Long-term trend analysis. Remote firmware deployment. These are real problems that benefit from centralized compute.
The key question is: what happens when the cloud is unreachable? If the answer is “the device stops working,” go back to the drawing board.
Security: The IoT Industry’s Shame
Let us talk about the elephant in the room. Or rather, the botnet in the room.
In 2016, the Mirai botnet took down a significant portion of the internet by exploiting IoT devices with default credentials. That was a decade ago. The industry’s response has been… let us charitably call it “inadequate.”
Default passwords are still shipping on devices. Firmware update mechanisms still use unencrypted HTTP. Devices still run ancient Linux kernels with known vulnerabilities. Debug interfaces still ship enabled in production. Telnet. In 2026. On devices connected to the internet. It would be funny if it were not actively dangerous.
Why IoT Security Is Hard
Embedded devices have real constraints that make security genuinely difficult. Cryptographic operations are computationally expensive on low-power processors. Secure boot requires hardware support that adds cost. OTA update mechanisms need flash space for dual images. Certificate management requires persistent, secure storage.
These are real engineering challenges. They are not excuses. They are problems to solve.
What You Can Actually Do
Secure boot. Verify the integrity of your firmware before executing it. Modern microcontrollers from vendors like STM32, Nordic, and ESP32 support hardware-backed secure boot. Use it. The cost is measured in pennies and boot-time milliseconds. The alternative is devices that run whatever code an attacker flashes onto them.
Encrypted OTA updates. Sign your firmware images. Verify signatures before applying updates. Use TLS for the transport. Store the signing public key in one-time-programmable (OTP) memory if your hardware supports it. Never, under any circumstances, accept unsigned firmware.
Certificate pinning. Do not just validate that a TLS certificate is signed by a CA. Validate that it is signed by your CA, or pin the specific certificate. Supply chain attacks on certificate authorities are real.
Eliminate default credentials. Force unique credential generation during manufacturing or first setup. If your device ships with admin/admin, you have personally contributed to the next botnet.
Minimize attack surface. Disable every interface you do not need. No debug UART in production. No JTAG without authentication. No open ports. No unnecessary services. Every enabled interface is a potential entry point.
Assume breach. Design your system so that a compromised device cannot pivot to other devices on the network. Use unique per-device credentials. Segment your network. Apply the principle of least privilege to every communication channel.
Security is not a feature you add at the end. It is a property of the design, or it is absent.
Building IoT That Lasts
The best IoT device is the one you forget about. You install it, it works, and you do not think about it again for a decade. No app updates. No subscription renewals. No “this device is no longer supported” emails. It just works, quietly, reliably, in the background of your life.
This is the standard we should aspire to. It is also the standard that the industry consistently fails to meet, because “device that works forever” is a terrible business model for quarterly revenue targets.
Here is how to build for longevity anyway.
Low Power Design
Power management is not an optimization. It is a core architectural decision that affects every layer of your system, from hardware design to communication protocol to firmware architecture.
A well-designed battery-powered sensor should spend 99.9% of its time in deep sleep, drawing microamps. It wakes up, does its job, and goes back to sleep as fast as possible. Every millisecond spent awake is energy spent.
Here is a minimal hardware watchdog timer in C for an STM32 — because the other thing your device needs to do is recover from its own bugs:
#include "stm32f1xx_hal.h"
static IWDG_HandleTypeDef hiwdg;
void watchdog_init(uint32_t timeout_ms) {
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_64;
// LSI oscillator ~40kHz, prescaler 64 -> 625 Hz tick
hiwdg.Init.Reload = (timeout_ms * 625) / 1000;
if (hiwdg.Init.Reload > 0xFFF) {
hiwdg.Init.Reload = 0xFFF; // cap at max
}
HAL_IWDG_Init(&hiwdg);
}
void watchdog_feed(void) {
HAL_IWDG_Refresh(&hiwdg);
}
// In your main loop:
// watchdog_init(5000); // 5 second timeout
// while (1) {
// do_sensor_reading();
// transmit_data();
// watchdog_feed(); // pet the dog
// enter_low_power();
// }
If your firmware hangs — and eventually, in the field, it will — the watchdog resets the processor and your device comes back to life. No human intervention required. No support ticket filed. The device simply recovers and continues doing its job. This is what reliability looks like in the real world: not the absence of failure, but graceful recovery from it.
OTA Updates Done Right
Your device will ship with bugs. This is not a moral failing; it is a statistical certainty. The question is whether you can fix those bugs after deployment.
A robust OTA update system needs: dual image slots (so a failed update does not brick the device), rollback capability (so a bad firmware reverts to the last known good version), incremental updates (so you are not pushing 1MB images over a 250 kbps link), and cryptographic verification (so an attacker cannot push malicious firmware).
This is not optional. If your device cannot be updated in the field, its security posture degrades monotonically from the day it ships. Every newly discovered vulnerability becomes permanent. This is how botnets are born.
Graceful Degradation
Design for failure. Not because you are a pessimist, but because you are a realist.
Your WiFi will drop. Your cloud service will have an outage. Your sensor will return garbage data. Your flash memory will eventually wear out. Your battery will die. Plan for all of it.
A well-designed IoT device degrades gracefully. When it loses connectivity, it buffers data locally and syncs later. When it gets garbage sensor readings, it applies sanity checks and discards outliers. When its battery is critically low, it increases sleep intervals and reduces transmission frequency. When its flash is wearing out, it rotates write locations and monitors error counts.
The device should always do something useful, even when conditions are far from ideal.
Design for a Decade
Ten years is an eternity in technology. It is also a reasonable lifespan for a thermostat, a smoke detector, or an industrial sensor. Building hardware that lasts that long requires thinking about things that software engineers rarely consider.
Electrolytic capacitors dry out. Flash memory has limited write cycles. Battery chemistry degrades. Connectors corrode. Solder joints fatigue under thermal cycling. These are not software bugs you can patch. These are physics, and they are unforgiving.
Choose components rated for your expected lifetime. Derate generously. Use conformal coating in harsh environments. Test at temperature extremes. Design your PCB with generous clearances. Use automotive or industrial grade components where it matters, even if they cost a few cents more.
And for the love of all that is reliable, put a hardware watchdog on your processor. Software hangs. It is what software does. Plan for it.
Closing Thoughts
The IoT industry does not have a technology problem. The protocols work. The hardware is extraordinary — you can buy a WiFi-enabled microcontroller with 520KB of RAM for less than the price of a coffee. The toolchains are mature. The knowledge is available.
What we have is a priorities problem. We have optimized for time-to-market over reliability, for feature count over power efficiency, for cloud integration over local functionality, and for subscription revenue over product longevity.
The best embedded engineers I know share a common trait: a deep respect for constraints. They do not fight the limitations of their hardware. They embrace them. They write firmware that is small, fast, and correct. They design systems that recover from failure without human intervention. They build products that just work.
Your toaster does not need Kubernetes. Your light switch does not need a cloud account. Your door lock does not need a subscription.
Build things that work. Build things that last. Build things that respect the humans who use them. The technology is ready. The question is whether the industry is.