跪拜 Guibai
← All articles
Embedded · Serverless · Frontend

A $5 ESP32 Pager That Provisions Itself and Receives Cloud Messages

By sRect ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The project demonstrates a practical, low-cost pattern for getting a headless IoT device onto Wi-Fi without a screen or keyboard, then controlling it from anywhere through a serverless relay. The "verify first, persist later" approach to credential storage and the separation of local provisioning secrets from cloud API tokens are directly reusable design decisions for any connected-hardware prototype.

Summary

A complete prototype chains together an ESP32-S3, an Android app, a Cloudflare Worker, and EMQX Cloud to build a device that receives short text messages from anywhere. The hardware costs under $5, and the cloud services run on free tiers. The provisioning flow is the standout piece: the ESP32 boots an open SoftAP with a one-time random token, the Android app hands over 2.4 GHz credentials through a local HTTP API, and the firmware writes them to NVS only after successfully obtaining a DHCP lease — a single mistyped password never bricks the device. Once online, the ESP32 connects to EMQX over TLS on port 8883, subscribes to a device-specific command topic, and acknowledges every message. The Cloudflare Worker sits between the phone and the broker, validating a Bearer token, enforcing payload limits, and publishing commands with QoS 1 and retain set to false so stale messages don't replay on reconnect. The repository ships with Arduino firmware, a Kotlin/Jetpack Compose app, and a test-covered Worker; OLED and buzzer drivers are stubbed out but the cloud-to-device path is fully closed-loop.

Takeaways
Long-pressing the BOOT button for 5 seconds starts a SoftAP with a random 16-byte provisioning token that expires on reboot.
Wi-Fi credentials are held in RAM and written to NVS only after the ESP32 successfully obtains a non-zero IP address from the router.
The Android app binds HTTP calls to the temporary hotspot's Network object so requests to 192.168.4.1 don't leak over cellular data.
A Cloudflare Worker validates a Bearer token, enforces a 1–120 character text limit, and publishes MQTT commands with QoS 1 and retain=false.
The ESP32 verifies the EMQX broker certificate against the DigiCert Global Root G2 CA after syncing time via NTP.
Firmware re-checks the messageId, target deviceId, and command type on every incoming MQTT message rather than trusting topic-level isolation alone.
Total hardware cost stays under 40 RMB (about $5), and both EMQX Cloud and Cloudflare Workers run on free tiers.
Conclusions

Making credential persistence conditional on a successful DHCP lease is a simple state-machine decision that eliminates the most common provisioning failure mode: a device that has Wi-Fi credentials but can't connect and can't be reached to fix them.

Binding HTTP traffic to the Wi-Fi network handle returned by Android's ConnectivityManager, rather than relying on the OS to route correctly, is a detail that most provisioning tutorials skip but that determines whether the flow works reliably on real devices with active cellular data.

Publishing with retain=false and re-validating the command payload on the device side, even though the broker already enforces topic ACLs, treats the MQTT broker as an untrusted pipe — a sensible posture when the publish endpoint is a public-facing Worker.

The project's security section is unusually honest for a prototype: it lists seven specific risks and maps each to a current mitigation and a production recommendation, making it a useful checklist rather than a hand-waving disclaimer.

Concepts & terms
NVS (Non-Volatile Storage)
A key-value storage partition in ESP32 flash memory that survives power cycles. Used here to persist Wi-Fi credentials and a flag indicating whether the device has been provisioned before.
SoftAP
A mode where the ESP32 acts as a Wi-Fi access point while also maintaining a station connection to a router. The prototype uses WIFI_AP_STA mode to keep the provisioning hotspot available while attempting to connect to the home network.
QoS 1 (MQTT)
A delivery guarantee level where the broker ensures a message reaches the subscriber at least once, potentially causing duplicates. The project pairs QoS 1 with a retain=false flag so offline devices don't receive stale commands on reconnect.
WifiNetworkSpecifier
An Android API (10+) that lets an app request a connection to a specific Wi-Fi network through a system-managed dialog, replacing the deprecated enableNetwork approach that silently switched networks.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗