Learning Lab
A NodeMCU panic button with Telegram alerts and RF fallback — circuit, code, lessons
I wanted a single tactile button that, when pressed, delivers a short message to a small group of people on Telegram — and keeps working when the office Wi-Fi quietly stops working, which it does. What follows is the build I settled on after three weekends of false starts.
Why bother
A friend asked. The counter at her clinic gets the occasional aggressive visitor, and the existing “solution” was “shout for help.” I’ve had a tray of NodeMCUs1 gathering dust since 2022, so this seemed like a useful excuse to use them.
note 1 — what’s a NodeMCU
The circuit
Two boards, talking by radio, with one on Wi-Fi as the primary path. Receiver lives near the back-office router; transmitter sits under the counter on its own 5V adapter.
Component list, for the curious or for future-me when I rebuild this on a Sunday and can’t remember which radio module worked:
| Part | Notes | Cost (₹) |
|---|---|---|
| NodeMCU v3 (ESP8266) | Either CH340 or CP2102 driver works | 220 |
| FS1000A 433 MHz pair | Cheap, lo-fi, surprisingly enough range with a 17 cm wire antenna | 90 |
| 12 mm tactile button | Recess-mounted; pull-up on D2 | 35 |
| 5V/1A USB adaptor + cable | One per board | 160 |
| Hammond-style enclosure | Matte black; the button should look intentional | 240 |
| Total per unit | ~745 |
The firmware
The transmitter does almost nothing on purpose. Debounce the button, fire the radio, fire Wi-Fi, sleep. The hardest part of writing this was resisting the urge to add features.2
// transmitter.ino — keep this file boring on purpose.
#include <ESP8266WiFi.h>
#include <RCSwitch.h>
#include "secrets.h" // SSID, PSK, BOT_TOKEN, CHAT_ID
constexpr uint8_t PIN_BTN = D2;
constexpr uint8_t PIN_RF = D5;
constexpr uint32_t RF_CODE = 0xA17C0DE;
RCSwitch rf;
void setup() {
pinMode(PIN_BTN, INPUT_PULLUP);
rf.enableTransmit(PIN_RF);
rf.setRepeatTransmit(15);
WiFi.begin(WIFI_SSID, WIFI_PSK);
}
void loop() {
if (digitalRead(PIN_BTN) == LOW) {
rf.send(RF_CODE, 32); // fallback first
notifyTelegram("PANIC at counter"); // then primary
delay(2500); // crude debounce
}
}
On the receiver, the only addition is that an RF packet with the matching code triggers the same Telegram path, which means a Wi-Fi outage on the transmitter side still gets a message out, as long as the receiver itself can reach the router.3
The hardest part of writing reliable hardware code is admitting that most of the failures are not interesting. They are wires, solder joints, and adapters from a market two years ago.
Lessons
I will probably rebuild the receiver on an ESP32 the next time I touch it — not because the ESP8266 is bad, but because the ESP32 has dual-core scheduling that lets the radio task and the Wi-Fi task stop fighting each other for the radio bus. That fight is invisible until it isn’t.