33 Reference: IoT Code Pattern Library
More
Depth: Practitioner
Progress saves as you read. Mark sections complete as you go; your progress appears in the sidebar.
33.1 Start With the Behavior to Prove
This section: Start With the Behavior to Prove — Picture a learner copying a sensor example that works once on a desk.
Treat Every Snippet as an Unproved Starting Point
Picture a learner copying a sensor example that works once on a desk. In the project, the pin differs, the reply arrives late, and a missing field causes a restart. Code that runs is not yet code that fits the new boundary.
Turn the desk-ready sensor snippet into a tested starting point.
-
A copied sensor example works once on a desk.
-
A new pin, late reply, or missing field can make it restart.
-
State the snippet's limits, then change one boundary and test it.
-
Reuse it only when the changed code proves the intended behavior.
A protocol is an agreed set of message and timing rules. Bluetooth Low Energy (BLE) is a short-range radio system. General purpose input output (GPIO) pins connect software to simple hardware signals. Hypertext Transfer Protocol (HTTP) carries web requests and replies. JavaScript Object Notation (JSON) is a text shape for named data. Message Queuing Telemetry Transport (MQTT) carries named messages through a service.
Choose one snippet and state its input, output, timing, resource, error, and safety assumptions. Run it unchanged and keep the result. Then alter one boundary, such as the pin, message field, delay, disconnect, or restart. Record the changed code and evidence that the intended behaviour still holds. Reject secret values or unsafe defaults before reuse.
This process does not make a snippet production-ready. Hardware, libraries, and field conditions differ. The deeper sections group patterns by task and show how to adapt, test, and review each boundary without mistaking copied code for proof.
A snippet should prove one behavior before it becomes project code. Run the original, change one boundary, and keep the output that shows the adaptation worked so the learner can separate reusable pattern from project-specific risk.
33.2 Learning Objectives
This section: Learning Objectives
- Implement common IoT code patterns for sensor reading, MQTT messaging, and HTTP communication on ESP32
- Apply power management techniques including deep sleep with timer and GPIO wakeup
- Use JSON serialization and ring buffers for efficient IoT data handling
- Configure BLE beacons and LoRa point-to-point communication for wireless IoT projects
33.3 Snippets Are Starting Points
This section: Snippets Are Starting Points — In Figure 33.1, A code snippet is useful when it shortens the first working path without hiding the engineering assumptions.
In Figure 33.1, A code snippet is useful when it shortens the first working path without hiding the engineering assumptions. The ESP32, Arduino core, PubSubClient, ArduinoJson, HTTPClient, Wire, Wi-Fi, BLE, and LoRa examples in this hub should be read as patterns: each one shows a small behavior, the library calls involved, and the checks a learner must repeat in their own circuit or network. A snippet is not a finished design record. It is a compact example of one boundary, such as a sensor read, a publish attempt, a JSON conversion, a sleep cycle, or a wireless advertisement.
In Figure 33.1, The right question is not "can I paste this?" The right question is "which assumptions must I confirm before this becomes project code?" Pins, voltage levels, I2C addresses, MQTT broker settings, JSON buffer sizes, sleep intervals, Wi-Fi reconnect behavior, and battery current all depend on the final hardware and deployment context. Even a short DHT22 example carries assumptions about sampling interval and invalid reads. A PubSubClient example carries assumptions about broker reachability, keepalive timing, topic policy, client identity, and payload length. A deep-sleep example carries assumptions about wake source, boot reason, sensor warm-up, and whether the active current pulse is acceptable for the battery.
- Use the snippet for shape: control flow, library setup, error handling, and common API calls.
- Verify the local context: board revision, pins, sensor supply, payload size, broker policy, firmware version, and library version.
- Promote only after testing: run the snippet on target hardware, record assumptions, and add a regression check or bench note before reusing it.
The library is therefore organized for transfer, not blind copying. Start with the smallest snippet that matches the behavior you need, then keep the acceptance check visible: serial output, a broker message, an HTTP status, an I2C scan, a wake reason, a measured current trace, or a repeatable host test. When that proof is missing, the snippet is still a learning aid, but it has not yet become project code.
33.4 Adapt One Boundary at a Time
This section: Adapt One Boundary at a Time — The safest way to reuse snippets is to change one boundary, run it, and inspect the result before moving to the next boundary.
The safest way to reuse snippets is to change one boundary, run it, and inspect the result before moving to the next boundary. For a DHT22 or analog sensor snippet, first confirm wiring, sensor power, sampling interval, ADC range, and invalid-read behavior. For I2C scanner code, confirm pullups, SDA/SCL pins, bus speed, address conflicts, and whether Wi-Fi is using ESP32 ADC or bus resources. For MQTT or HTTP snippets, confirm client ID, topic policy, QoS choice, timeout, retry delay, TLS need, and payload size. If several of those change at once, a failure no longer tells you where the real mismatch lives.
Use concrete tooling around the copy step. PlatformIO or Arduino IDE can pin board and library versions, which keeps a working example reproducible after the next library update. Serial Monitor output catches boot loops, missing credentials, bad pins, and sensor read failures quickly. Logic-analyzer traces can prove an I2C or SPI transaction is actually leaving the board. Broker logs and Wireshark captures show whether MQTT, HTTP, DNS, TCP, and TLS are failing in the firmware, the network, or the server. Measured current traces are the only reliable way to check whether a sleep snippet saves the power it claims to save.
- Run the original snippet first. Confirm it compiles and produces the expected serial, packet, or sensor output.
- Change one project parameter. Adjust pin, interval, endpoint, topic, credential, payload, or power mode separately.
- Capture the acceptance check. Save the serial log, broker message, current trace, bus scan, or API response that proves the adaptation worked.
As the snippet grows, move magic values out of the example body and into a visible configuration boundary: pins, topics, endpoints, thresholds, retry limits, and sleep intervals should be easy to review. ArduinoJson Assistant can size JSON documents before heap pressure appears on the board. PubSubClient buffer settings should be checked before a payload is blamed on the broker. ESP32 deep-sleep wake reasons should be logged before a wakeup path is trusted. FreeRTOS task timing should be inspected when the example moves from a single loop into concurrent sensor, radio, and display work.
A good reuse record is short but specific: source snippet, hardware revision, library versions, changed parameters, observed output, and the remaining risk. That record lets another learner decide whether the snippet still fits their board or whether it needs a fresh adaptation pass.
33.5 Snippets Hide State Boundaries
This section: Snippets Hide State Boundaries — Small snippets look linear, but IoT behavior is stateful.
Small snippets look linear, but IoT behavior is stateful. A reconnect loop crosses Wi-Fi association, DNS, TCP, MQTT session state, broker policy, keepalive timing, and payload retry behavior. A deep-sleep example crosses wake source configuration, RTC memory, boot reason, sensor warm-up, radio startup, and battery pulse current. A JSON parser crosses buffer sizing, message schema, missing fields, numeric range, and heap pressure. Each boundary can succeed in isolation while the whole device still fails under timing, network, or power pressure.
The hidden boundary is ownership. The snippet owns a tiny behavior. The learner owns hardware limits, credentials, timing, error handling, security, logging, and maintainability. A production path must replace placeholder credentials, public brokers, blocking loops, unbounded retries, and demo delays with project-specific configuration, timeouts, observability, and failure handling. It must also make security decisions explicit: credentials should not be hard-coded into examples that become repository code, TLS settings should not be copied without understanding certificate and endpoint policy, and diagnostic logs should not leak secrets while trying to explain a connection failure.
The state-machine view helps explain why. A reliable device is usually not "read sensor, publish, delay" forever. It has boot, configure, sample, validate, publish, backoff, sleep, fault, and recovery states. Interrupts, timers, queues, and network callbacks may enter that state machine at awkward times. Without bounded retries, a radio outage can turn into a battery drain. Without input validation, one malformed payload can poison downstream logic. Without an evidence record, a later maintainer cannot tell whether a value came from a tested requirement, a copied demo, or a temporary experiment.
This is why the library is a learning hub, not a certification source. The snippet gets a learner to a measurable behavior; the project tests decide whether that behavior is reliable, secure, and efficient enough to keep. The best under-the-hood outcome is not more code. It is a clear separation between reusable pattern, project-specific configuration, measured acceptance check, and the failure paths that still need design attention.
This section:
A code snippet is a small piece of programming code that demonstrates a specific task, such as reading a temperature sensor or sending data over Wi-Fi. This library contains 15 searchable example snippets for Arduino or ESP32 projects; choose one as a starting pattern, adapt it, and test it on the selected board.
This section:
This section:
This section:
This section:
This section:
Context: ESP32 deep sleep with 5-minute timer wakeup for battery-powered sensor. Comparing active vs sleep power.
Formula: Battery life =
Worked example: 2,000 mAh battery. Without sleep: Active 100 mA continuously = hours. With deep sleep: Active 100 mA for 10 s every 5 min (96.7% sleep at 10 µA). Average: mA. Battery life: hours = 25 days (30× improvement).
33.6 Code Snippet Library
This section: Code Snippet Library — Treat the library as a set of controlled starting states, not finished firmware.
Treat the library as a set of controlled starting states, not finished firmware. Begin with the snippet whose hardware, protocol, and expected output most closely match the current test. Run it unchanged to establish a baseline; then alter one boundary such as a pin, interval, endpoint, or power mode and repeat the observation. This sequence keeps a failed build attributable to one change and turns adaptation into evidence the next developer can replay.
Browse or search these 15 example IoT code snippets. Each includes an explanation of key concepts and assumptions to verify.
- Start from a relevant example snippet and check its board and library assumptions.
- Adapt one parameter at a time (pin, interval, endpoint, power mode).
- Validate behavior on hardware before adding complexity.
33.7 Snippet Browser
This section: Snippet Browser
33.8 Quick Reference Tables
This section: Quick Reference Tables
33.8.1 Common Pin Configurations
| Module | SPI (SCK/MISO/MOSI/SS) | I2C (SDA/SCL) | UART (TX/RX) |
|---|---|---|---|
| ESP32 DevKit | 18/19/23/5 | 21/22 | 1/3 |
| ESP32-S3 | 12/13/11/10 | 8/9 | 43/44 |
| ESP8266 | 14/12/13/15 | 4/5 | 1/3 |
| Arduino Uno | 13/12/11/10 | A4/A5 | 0/1 |
33.8.2 Library Quick Reference
| Task | Library | Install Command |
|---|---|---|
| MQTT | PubSubClient | pio lib install "PubSubClient" |
| JSON | ArduinoJson | pio lib install "ArduinoJson" |
| HTTP | HTTPClient | Built-in (ESP32) |
| LoRa | LoRa | pio lib install "LoRa" |
| BLE | ESP32 BLE | Built-in (ESP32) |
| Wi-Fi | Wi-Fi | Built-in |
33.9 Common Reference Patterns
This section: Common Reference Patterns — These short reference patterns complement the snippet library above with compact, print-friendly code idioms.
These short reference patterns complement the snippet library above with compact, print-friendly code idioms.
33.9.1 Sensor Reading Pattern
# Pseudo-code for robust sensor reading
def read_sensor_with_retry(sensor, max_retries=3):
for attempt in range(max_retries):
try:
value = sensor.read()
if is_valid(value):
return value
except SensorError:
time.sleep(0.1 * (2 ** attempt)) # Exponential backoff
return None # Or raise exception
# Moving average filter
class MovingAverage:
def __init__(self, window=10):
self.window = window
self.values = []
def add(self, value):
self.values.append(value)
if len(self.values) > self.window:
self.values.pop(0)
return sum(self.values) / len(self.values)
33.9.2 MQTT Connection Pattern
# Robust MQTT connection with reconnection
def connect_mqtt(client, broker, port=1883):
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.subscribe("device/+/command")
else:
print(f"Connection failed: {rc}")
def on_disconnect(client, userdata, rc):
while True:
try:
client.reconnect()
break
except:
time.sleep(5)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.connect(broker, port, keepalive=60)
33.9.3 Deep Sleep Pattern
# ESP32 deep sleep with wake sources
import machine
import esp32
def enter_deep_sleep(seconds):
# Configure wake sources
# For a classic ESP32 board that exposes GPIO33, connect a normally-open button from GPIO33 to GND; provide a board-verified pull-up that remains effective during deep sleep.
esp32.wake_on_ext0(pin=machine.Pin(33, machine.Pin.IN, machine.Pin.PULL_UP), level=esp32.WAKEUP_ALL_LOW)
# Set timer wake
machine.deepsleep(seconds * 1000)
# Check wake reason
wake_reason = machine.wake_reason()
if wake_reason == machine.PIN_WAKE:
handle_button_press()
elif wake_reason == machine.RTC_WAKE:
send_sensor_data()
33.10 Contributing Snippets
This section: Contributing Snippets — Have a useful code snippet?
Have a useful code snippet? Follow this format:
**Title**: Brief descriptive title
**Category**: Sensors/Actuators/MQTT/HTTP/BLE/LoRa/Power/Data/Security
**Platform**: Arduino/ESP32/ESP8266/Raspberry Pi
**Difficulty**: Beginner/Intermediate/Advanced
**Tags**: relevant, searchable, keywords
**Description**: What this snippet does
**Code**: Working, tested code
**Explanation**: Key concepts and gotchas
The Mistake (illustrative scenario): A developer copied an ESP32 MQTT example directly from this library, deployed to 50 devices, and found 30% failed to connect. The code worked perfectly in testing.
What Went Wrong:
// Snippet showed generic ESP32 pins
#define DHT_PIN 4 // Works on ESP32 DevKit V1
#define LED_PIN 2 // Built-in LED on most boards
The Problem: Developer used ESP32-S2 boards where: First, ESP32-S2 boot strapping uses GPIO0, GPIO45, and GPIO46; GPIO2 is not a boot-mode strap. Next, GPIO 4 has an ADC channel assignment that must be checked against the sensor and exact board. Then, the built-in LED pin depends on the exact board model.
Impact:
First, pin behavior and boot symptoms must be verified against the exact board documentation and measured on the affected hardware. Next, Debugging took 6 hours to identify a hardware variant mismatch.
How to Avoid:
First, Check your exact board model before copying pins:.
// Example only: define a verified board identifier and pin map for your exact board.
#if defined(ESP32_DEV_KIT_V1)
#define DHT_PIN 4
#define LED_PIN 2
#elif defined(ESP32_S2_MINI)
#define DHT_PIN 1
#define LED_PIN 15 // Verify for the exact ESP32-S2 board model
#else
#error "Select and verify the exact board pin map"
#endif
First, Test on one device first: Never deploy untested code to multiple devices.
First, Read the datasheet: Verify every GPIO pin for your specific board (not “ESP32 in general”).
First, Document hardware dependencies: Add comments like // Tested on ESP32 DevKit V1 only.
Cost of this mistake: 6 hours debugging + 30 device replacements (wrong board ordered) + project delay = ~$2,000 in wasted time and materials.
Lesson: Code snippets are starting points, not copy-paste solutions. Hardware matters.
This section:
This section:
This section:
This section:
This section:
Fifteen example code snippets provide starting patterns for common IoT tasks; verify pin assignments and library versions for your specific board before deploying.
This section:
Common Pitfalls
This section: Common Pitfalls
Code snippets use hardcoded values (broker address, port, QoS level, topic names) that must be customized for each deployment. Copying and running without adapting these parameters causes connection failures, incorrect behavior, or unintended data routing. Always read each snippet’s comments to understand which values require customization.
Library snippets prioritize clarity over security — they often use plaintext connections, hardcoded credentials, or skip certificate verification. Never deploy library code directly to production. Treat snippets as starting points requiring TLS configuration, secure credential storage, and input validation before deployment.
A snippet using paho-mqtt==1.x APIs may fail with paho-mqtt==2.x which introduced breaking changes. Always check the library version requirements documented in each snippet and test in an isolated environment before integrating into your project.
33.12 Summary
This section: Summary — This chapter collects reusable code snippets for IoT learning tasks.
This chapter collects reusable code snippets for IoT learning tasks. Use snippets as starting points for experiments, then adapt, test, and document the assumptions before using them in a project.
Find help
3 reviewed answers.
Where should I start in a module?
Open the module page from the sidebar to see its chapters in order. Use the module map to return to a topic you need.
Modules and pathsReviewed
What can I try when a project does not work?
Check the symptom, then work through the diagnostic steps. Keep the error message and the smallest example that reproduces it.
When you are stuckReviewed
How do interactive examples work?
Use the interactive guide to check how examples and simulations work before changing your project.
Interactive examples guideReviewed
