Contents — 26 sections
Project Overview
SOS buttons across a campus or society that route a located, acknowledged alarm to a control room in seconds — engineered so that when it is pressed, it works.
A panic button has exactly one job, and it must never fail at it: when someone in trouble presses it, a located alarm has to reach whoever can help, fast, and the person who sent it should know help is coming. That single-mindedness drives the whole design. Scattered across a campus, a housing society, a hospital or a school — in stairwells, car parks, corridors, hostel rooms — the buttons form a network that turns a press into an instant, located alert at a staffed control room, with acknowledgement flowing back so the sender is not left wondering whether anyone saw it.
The engineering challenge is reliability under the worst conditions, because a panic system is judged only by the moments it is used, which are emergencies. So every part is built to keep working when things are going wrong: each button reports its location so responders go straight to the right place; the alert is acknowledged end-to-end so both the control room and the sender have confirmation; the network is supervised so a button with a flat battery or a broken link is detected and fixed before an emergency, not discovered during one; and the communication path is chosen for coverage and resilience (a LoRa mesh or wired bus across a site, with redundancy) rather than a single fragile link. Buttons run on mains with battery backup so a power cut does not disarm them.
The behaviours around the core press are what make it dependable in practice: a button press is unmistakable and hard to trigger accidentally yet easy in a panic; an alert latches until a human acknowledges it, so it cannot be missed by a glance away; the control room sees a clear, prioritised, located alarm with the button's ID and place; and periodic self-tests and battery/link supervision keep the whole network provably healthy. It is honest that a DIY system is not a substitute for a monitored, certified life-safety installation where regulations demand one — but as a responsive, located, supervised SOS network for a campus or community, it does the thing that matters most: when the button is pressed, the alarm gets through, someone knows, and help is dispatched to the right place.
What this project does
- Sends an instant, located alarm to a control room when a button is pressed
- Acknowledges end-to-end so the sender knows help is coming
- Supervises every button (battery, link) so faults are found before emergencies
- Latches alarms until a human acknowledges — never missed by a glance away
- Uses a resilient path (LoRa mesh / wired bus) with redundancy
- Runs on mains with battery backup so a power cut does not disarm it
- Prioritises and locates alarms clearly at the control room
Real-World Applications
| Setting | How it is used |
|---|---|
| Campus / university safety | Emergency SOS points across grounds, car parks and buildings routing to campus security with location. |
| Residential society / gated community | Panic buttons in common areas and homes alerting a guard control room instantly. |
| Hospitals / care facilities | Staff-assist and patient SOS points with located, acknowledged alerts. |
| Schools / workplaces | Lockdown/assistance buttons in classrooms and offices routing to a coordinator. |
Deployment contexts where a build of this kind earns its keep.
Features & Capabilities
- Single-purpose reliability: when pressed, it works
- Located alarms so responders go straight to the place
- End-to-end acknowledgement to the sender
- Network supervision (battery/link) — faults found in advance
- Latched, prioritised alarms at a staffed control room
- Resilient comms with backup power
- Honest scope vs certified life-safety systems
Difficulty, Time & Required Skills
| Attribute | Value |
|---|---|
| Difficulty level | Intermediate |
| Estimated completion time | 12–18 hours |
| Indicative build cost | ₹2,800 – ₹4,500 per button (+ shared gateway/console) |
| Primary discipline | Security |
| Reference platform | ESP32 DevKit V1 (ESP-WROOM-32) |
Skills you should have (or will pick up)
- Designing single-purpose reliable alerting
- Located alarms and end-to-end acknowledgement
- Network supervision (battery/link heartbeats)
- Resilient comms (LoRa mesh / wired bus) with backup power
- Control-room prioritisation and latching
Bill of Materials
Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.
| Component | Key specification | Qty | Approx. cost |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 1 | ₹450 |
| Active piezo buzzer 5 V Active buzzers make tone on DC; passive ones need a PWM carrier. | 85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter | 1 | ₹25 |
| 0.96″ SSD1306 OLED display Static images burn in — invert or scroll the screen periodically. | 128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C | 1 | ₹250 |
| SX1278 LoRa 433 MHz module (Ra-02) Never power the radio without an antenna — the PA will destroy itself. | −148 dBm sensitivity, +20 dBm output, up to 10 km line of sight, SF7–SF12 | 1 | ₹480 |
| Reed switch + magnet pair (door contact) Wire it normally-closed so a cut cable reads the same as an open door — fail-safe by construction. | NO contact, 10–15 mm operating gap, 100 V / 0.5 A, > 10⁷ operations | 1 | ₹55 |
| DS3231 precision RTC + CR2032 backup Vastly better than DS1307; some boards trickle-charge a non-rechargeable cell — cut that resistor. | ±2 ppm (±1 min/year), temperature-compensated crystal, alarms, 32 kHz out | 1 | ₹180 |
| 5 V 3 A regulated SMPS adapter Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 1 | ₹350 |
| 18650 Li-ion cell 3400 mAh + holder Never charge below 0 °C; always use a protected cell or a BMS. | 3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge | 1 | ₹450 |
| Robust panic button + housing Optionally protected/latching to prevent casual presses | Large, tamper-resistant, hard-to-trigger-accidentally, easy-in-panic button | 1 | ₹350 |
| LoRa mesh gateway (control room) | Gateway with backhaul to the control-room console | 1 | ₹2,500 |
| Backup battery + charger per button | Battery + charger so a mains cut does not disarm the button | 1 | ₹300 |
| Control-room console/annunciator | Screen/panel showing located, prioritised, latched alarms with ack | 1 | ₹1,500 |
Estimated total: ₹6,890, excluding tools, shipping and consumables.
Tools and consumables
- Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
- Digital multimeter — continuity, DC volts and current ranges
- Wire strippers, flush cutters and a small set of precision screwdrivers
- Heat-shrink tubing and a heat gun (or a lighter, carefully)
- A laptop with a USB port and the toolchain listed above
Hardware Specifications
| Part | Specification | Supply | Interface | Reference |
|---|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 3.3 V logic / 5 V USB | UART, SPI, I²C, I²S, CAN, PWM | Datasheet |
| Active piezo buzzer 5 V | 85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter | 3–5 V | Digital / PWM | Datasheet |
| 0.96″ SSD1306 OLED display | 128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C | 3.3–5 V | I²C (0x3C) | Datasheet |
| SX1278 LoRa 433 MHz module (Ra-02) | −148 dBm sensitivity, +20 dBm output, up to 10 km line of sight, SF7–SF12 | 3.3 V | SPI | Datasheet |
| Reed switch + magnet pair (door contact) | NO contact, 10–15 mm operating gap, 100 V / 0.5 A, > 10⁷ operations | passive | Digital with pull-up | Datasheet |
| DS3231 precision RTC + CR2032 backup | ±2 ppm (±1 min/year), temperature-compensated crystal, alarms, 32 kHz out | 2.3–5.5 V | I²C (0x68) | Datasheet |
| 5 V 3 A regulated SMPS adapter | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 5 V | DC barrel / USB | Datasheet |
| 18650 Li-ion cell 3400 mAh + holder | 3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge | 3.0–4.2 V | Holder / spot-welded tabs | Datasheet |
Consolidated electrical and interface specifications for every active part in the build.
Power Budget & Supply Sizing
Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.
| Load | Supply rail | Typical current (mA) | Notes |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | 3.3 V logic / 5 V USB | 160 | Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. |
| Active piezo buzzer 5 V | 3–5 V | 30 | Active buzzers make tone on DC; passive ones need a PWM carrier. |
| 0.96″ SSD1306 OLED display | 3.3–5 V | 20 | Static images burn in — invert or scroll the screen periodically. |
| SX1278 LoRa 433 MHz module (Ra-02) | 3.3 V | 120 | Never power the radio without an antenna — the PA will destroy itself. |
| DS3231 precision RTC + CR2032 backup | 2.3–5.5 V | 0.2 | Vastly better than DS1307; some boards trickle-charge a non-rechargeable cell — cut that resistor. |
| 5 V 3 A regulated SMPS adapter | 5 V | 3000 | Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. |
Summed typical draw is 3330.2 mA. With a 1.5× design margin the supply should deliver at least 5000 mA continuously at the stated rail voltage.
Software Requirements & Development Environment
Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.
- Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
- Add
https://espressif.github.io/arduino-esp32/package_esp32_index.jsonunder File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager. - Set the correct port under Tools → Port. On Linux add yourself to the
dialoutgroup:sudo usermod -aG dialout $USERand log out and back in. - Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
- Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.
Required libraries
| Library | Why it is needed | Install |
|---|---|---|
| WiFi (ESP32 core) bundled | Station/AP connection management for the ESP32. | Bundled with the ESP32 Arduino core |
| PubSubClient 2.8 | Lightweight MQTT 3.1.1 client for constrained devices. | Library Manager → "PubSubClient" by Nick O'Leary |
| Adafruit SSD1306 + GFX 2.5.x | Framebuffer and text/graphics primitives for the OLED. | Library Manager → "Adafruit SSD1306" |
| LoRa (sandeepmistry) 0.8.0 | SX127x radio configuration, packet TX/RX and callbacks. | Library Manager → "LoRa" by Sandeep Mistry |
| NTPClient / configTime bundled | Wall-clock time from an NTP server for timestamping. | Bundled (`configTime()` on ESP32) |
| ArduinoJson 7.x | Zero-allocation JSON serialisation and parsing. | Library Manager → "ArduinoJson" by Benoit Blanchon |
| Preferences (NVS) bundled | Wear-levelled key/value storage in ESP32 flash for settings. | Bundled with the ESP32 core |
Block Diagram
The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.
Circuit Diagram & Wiring
Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.
| Peripheral | Peripheral pin | Controller pin | Signal |
|---|---|---|---|
| Panic button | NO/NC | GPIO 27 | SOS press |
| Tamper switch | NC | GPIO 14 | Enclosure tamper |
| DS3231 RTC | SDA/SCL | GPIO 21/22 | Event timestamps |
| LoRa SX1276 | SPI+CTRL | GPIO 18/19/23/5/14/2 | Resilient alert path |
| OLED + buzzer | I²C / IN | GPIO 21-22 / 26 | Local ack + status |
| Backup battery | sense | ADC | Battery supervision |
| Mains 5V + charger | OUT | 3V3 reg | Powered + backup |
Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.
Wiring explanation
- Wire the button so a press is unambiguous and debounced; consider a protected/latching actuator to prevent casual/accidental presses while staying easy in a real emergency.
- Power from mains with automatic battery backup, and sense the battery so low-power is supervised and reported.
- Use a resilient comms path — a LoRa mesh (each button relaying) or a supervised wired bus — with redundancy where possible.
- Add a tamper switch and give the RTC a coin-cell backup for accurate event times.
- Provide clear local feedback (buzzer/OLED) that the alert was sent and acknowledged.
System Architecture
Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.
Working Principle
A panic button is a life-safety alerting device, and life-safety design is dominated by one idea: the system must work in the rare, adverse moment it is needed, so everything is engineered for that moment rather than for the common case where nothing happens. That inverts normal priorities. Convenience, features, and efficiency are secondary; reliability, supervision, and confirmation are paramount. The measure of the system is not how it behaves on an ordinary Tuesday but whether, at 3 a.m. during a power cut when someone is in danger, a press still produces a located alarm at a staffed console and a confirmation back to the sender.
Three properties turn a button-and-buzzer into a dependable SOS system. First, location: an alarm that just says "someone pressed a button somewhere" wastes the seconds that matter, so every button carries its identity and place, and the control room sees exactly where help is needed. Second, acknowledgement: the alert is confirmed end-to-end — the control room's console shows and latches it, and a confirmation flows back to the button so the person who pressed it knows their call was received, which is both reassurance and evidence the path worked. A one-way send that might have been lost is not good enough when a life may depend on it. Third, latching and prioritisation: an alarm holds until a human explicitly acknowledges it, so it cannot be missed by a glance away, and it is presented prominently above routine information.
The property that separates a real system from a hopeful one is supervision. A panic network sits idle almost all the time, and the danger is that a button quietly dies — flat backup battery, broken antenna, severed wire — and nobody notices until the emergency reveals it, too late. So every button periodically sends a heartbeat reporting that it is alive and healthy (battery level, link quality), and the control room tracks these and raises a maintenance alarm the moment a button goes silent or reports a low battery. This turns "is the system working?" from an assumption into a continuously-verified fact. Combined with backup power (so a mains cut does not silently disarm the network) and a resilient comms path (a LoRa mesh where each button relays for others, or a supervised wired bus, ideally with redundancy so one failure does not create a dead zone), supervision is what lets you trust the system on the day it is used.
The design is finally about honest scope and human factors. The button must be unmistakable and hard to trigger by accident yet effortless to press in a panic; the alarm must reach a place where a human will actually act; and the whole thing must be regularly self-tested. It is candid that a DIY panic network, however well-built, is not a substitute for a professionally-monitored, certified life-safety installation where regulations or duty of care require one — a certified system carries guarantees and monitoring a homebrew cannot. But within its scope — a responsive, located, acknowledged, supervised SOS network for a campus or community — it delivers exactly what a panic button must: pressed in trouble, it gets through, someone knows, and help is sent to the right place.
The maths behind it
Reliable delivery (retry + ack)
On press:
repeat up to N times:
send SOS(button_id, location, seq)
wait for ACK(seq) up to T
if ACK received → confirm to sender, stop
if no ACK after N → escalate (alt path / audible / SMS)
One-way sends are not enough; require and surface the ACK.
Supervision heartbeat
Each button, every H minutes:
send HEARTBEAT(button_id, battery, rssi)
Control room:
if no heartbeat within k·H → button UNHEALTHY (maintenance)
if battery < B_min → low-battery maintenance alarm
Silence is itself an alarm — a dead button must be noticed.
Mesh relay for coverage/resilience
SOS packets flood the LoRa mesh with dedup + hop limit:
each button relays neighbours' unseen SOS (hops < HOP_MAX)
→ reaches the control-room gateway even if one path fails
Redundant paths mean a single broken link is not a dead zone.
Program Flowchart
The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.
Assembly Instructions
Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.
Build a reliable, supervised button
Fit a robust, unmistakable panic button (protected against casual/accidental presses but effortless in an emergency), power it from mains with automatic battery backup, and sense the battery for supervision. Add a tamper switch and a backed-up RTC.
Set up the resilient comms
Use a LoRa mesh (each button relaying) or a supervised wired bus to reach the control-room gateway, with redundancy so a single failure is not a dead zone. Encode each button's location/ID.
Set up the control-room console
Provide a console/annunciator that shows located, prioritised, latched alarms and lets an operator acknowledge them, plus a maintenance view of button health.
Step-by-Step Implementation Guide
Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.
Send with retry and require acknowledgement
On a press, send the located SOS and wait for an acknowledgement, retrying and escalating if none arrives, and confirm to the sender when the control room acknowledges.
cpppanic-send.ino#define N_RETRY 5 #define ACK_TIMEOUT_MS 1500 bool sendSOS(uint32_t seq) { for (int attempt = 0; attempt < N_RETRY; attempt++) { txSOS(BUTTON_ID, LOCATION, seq); // located alert into the mesh localFeedback("sending..."); if (waitForAck(seq, ACK_TIMEOUT_MS)) { // control room received it localFeedback("HELP COMING"); // confirm to the sender return true; } } escalate(); // alt path / audible / SMS localFeedback("escalating"); return false; } void onButtonPress() { static uint32_t seq = 0; latchLocalAlarm(); // local sounder on sendSOS(++seq); // deliver, confirm or escalate }for (int attempt = 0; attempt < N_RETRY; attempt++)The SOS is retried several times, because a single transmission can be lost and a life-safety alert cannot depend on one lucky packet.if (waitForAck(seq, ACK_TIMEOUT_MS))Delivery is confirmed by an acknowledgement from the control room, not assumed — the difference between hoping the alert arrived and knowing it did.localFeedback("HELP COMING")The sender is told their call was received, which both reassures the person in danger and proves the path worked end-to-end.escalate(); // alt path / audible / SMSIf no acknowledgement arrives after all retries, the button escalates to an alternate path rather than failing silently.Heartbeat and supervise
Send periodic heartbeats with battery and link status; at the control room, flag any button that goes silent or reports low battery as a maintenance alarm so faults are fixed before an emergency.
Complete Source Code
The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.
/* ═══════════════════════════════════════════════════════════════
Panic Button Network — ESP32 node, LoRa mesh, supervised
Single-purpose reliable SOS: on press, sends a located alert with
retry until acknowledged (confirming to the sender), escalates if
not, and periodically heartbeats battery/link so a dead button is
noticed before an emergency. Mains + battery backup.
══════════════════════════════════════════════════════════════════ */
#include <SPI.h>
#include <LoRa.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Preferences.h>
#define PIN_BTN 27
#define PIN_TAMPER 14
#define PIN_BUZZER 26
#define PIN_VBAT 34
#define LORA_CS 5
#define LORA_RST 14
#define LORA_DIO0 2
#define N_RETRY 5
#define ACK_MS 1500
#define HEARTBEAT_MS 300000UL // 5 min health beat
const uint16_t BUTTON_ID = 12;
const char *LOCATION = "Block C stairwell";
Adafruit_SSD1306 oled(128,64,&Wire);
Preferences prefs;
uint32_t seq = 0, lastBeat = 0;
volatile bool pressed = false;
void IRAM_ATTR onPress() { pressed = true; }
float batteryV() { return analogRead(PIN_VBAT)/4095.0f*3.3f*2.0f; }
void showLocal(const char *msg) {
oled.clearDisplay(); oled.setCursor(0,0);
oled.printf("Btn %d\n%s\n%s", BUTTON_ID, LOCATION, msg); oled.display();
}
void txSOS(uint32_t s) {
LoRa.beginPacket();
LoRa.printf("{\"t\":\"SOS\",\"id\":%u,\"loc\":\"%s\",\"seq\":%lu}",
BUTTON_ID, LOCATION, (unsigned long)s);
LoRa.endPacket();
}
bool waitForAck(uint32_t s, uint32_t timeout) {
uint32_t t0 = millis();
while (millis() - t0 < timeout) {
if (LoRa.parsePacket()) {
String p; while (LoRa.available()) p += (char)LoRa.read();
if (p.indexOf("\"ACK\"") >= 0 && p.indexOf(String(s)) >= 0) return true;
}
}
return false;
}
bool sendSOS() {
digitalWrite(PIN_BUZZER, HIGH); // local sounder latches on
uint32_t s = ++seq;
for (int a = 0; a < N_RETRY; a++) {
showLocal("sending...");
txSOS(s);
if (waitForAck(s, ACK_MS)) { showLocal("HELP COMING"); return true; }
}
escalate(); // alt path / audible / SMS
showLocal("escalating");
return false;
}
void heartbeat() {
LoRa.beginPacket();
LoRa.printf("{\"t\":\"HB\",\"id\":%u,\"vbat\":%.2f}",
BUTTON_ID, batteryV());
LoRa.endPacket();
}
void setup() {
Serial.begin(115200);
pinMode(PIN_BTN, INPUT_PULLUP);
pinMode(PIN_TAMPER, INPUT_PULLUP);
pinMode(PIN_BUZZER, OUTPUT);
attachInterrupt(PIN_BTN, onPress, FALLING);
Wire.begin(21,22); oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
SPI.begin();
LoRa.setPins(LORA_CS, LORA_RST, LORA_DIO0);
LoRa.begin(433E6); LoRa.setSpreadingFactor(10);
showLocal("ready");
}
void loop() {
if (pressed) { pressed = false; sendSOS(); }
if (millis() - lastBeat > HEARTBEAT_MS) { // supervision heartbeat
heartbeat();
lastBeat = millis();
}
// relay neighbours' SOS packets (dedup + hop limit) for mesh resilience
relayMeshIfNeeded();
}
Configuration & Calibration
Configuration steps
- Set each button's ID and human-readable location; configure the control-room gateway/console.
- Set retry count/timeout, heartbeat interval, and low-battery/silence thresholds for supervision.
- Choose the resilient comms (LoRa mesh / wired bus) and any escalation path (audible, SMS).
- Configure alarm latching/acknowledgement and prioritisation at the console.
Calibration procedure
An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.
Delivery reliability
Verify that a press is acknowledged within the timeout across the whole site, including the farthest/most-shadowed buttons; add relays where needed.
Supervision thresholds
Set the heartbeat interval and the silence/low-battery thresholds so a genuinely dead or dying button is flagged promptly without nuisance alarms.
Backup power
Confirm each button keeps working on battery through a simulated mains cut for the required duration.
Network Architecture & Connectivity
Communication protocol
SOS packets are delivered with retry and acknowledgement and flood the mesh with dedup for resilience; heartbeats supervise health. The local sounder and delivery are independent of any single link.
| Topic / endpoint | Direction | Payload |
|---|---|---|
panic/sos | button → console | located SOS (id, location, seq) |
panic/ack | console → button | acknowledgement (seq) → confirms to sender |
panic/heartbeat | button → console | battery, link — supervision |
Message contract between the device and the broker.
Cloud platform configuration
A control-room console presents located, prioritised, latched alarms and lets operators acknowledge them, and maintains a health map that flags any silent or low-battery button for maintenance.
Dashboard setup
A site map of buttons with instant located alarms, an alarm queue with acknowledge, and a supervision view of battery/link health per button.
Mobile app integration
Located SOS alerts and maintenance alerts (silent/low-battery button) to responders and facilities staff.
Security considerations
- Authenticate buttons and acknowledgements so alarms cannot be spoofed or falsely acknowledged.
- Keep the local sounder and delivery independent of any single link; supervise continuously.
- Protect against tamper and ensure backup power so the network cannot be silently disarmed.
Testing Procedure & Expected Output
Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.
| Test | What you should see |
|---|---|
| Press a button | Located alarm at the console within seconds; sender sees "HELP COMING" |
| Block the primary path | Mesh relays / escalation still delivers; sender still acknowledged |
| Remove a button's battery/mains | On battery it still works; total loss is flagged by missing heartbeat |
| Let a button go silent | Control room raises a maintenance alarm for that button |
| Low battery | Heartbeat reports it; maintenance alarm before it fails |
| Acknowledge at the console | Alarm de-latches; sender confirmation stands |
Bench-test checklist. If a row fails, stop and fix it before moving on.
Expected output
The control-room console shows located, prioritised, latched alarms with button ID/place and time, plus a health view of every button's battery and link.
{
"type": "SOS",
"button": 12,
"location": "Block C stairwell",
"seq": 41,
"time": "2026-07-27T02:14:55",
"acknowledged": true
}
A located SOS from button 12 reaches the console and is acknowledged — the sender is told help is coming, and the event is recorded; a silent or low-battery button would instead appear as a maintenance alarm before any emergency.
Troubleshooting: Common Errors & Fixes
Performance Optimisation
- Prioritise latency and delivery certainty over everything — retry with acknowledgement, not fire-and-forget.
- Keep the mesh quiet except for heartbeats and alarms so an SOS propagates instantly.
- Supervise continuously so the network's health is a known fact, not an assumption.
- Debounce presses but never delay the alert.
- Replace every
delay()with amillis()comparison — blocking delays are the single most common cause of dropped readings. - Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
- Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
- Use
uint8_t/uint16_twhere the range allows; on an 8-bit AVR a 32-bit add costs four times as much. - Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
- Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
- For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.
Safety Precautions
- A panic system is life-safety: engineer for the emergency, supervise so faults are found first, and provide backup power and resilient comms.
- Require and surface acknowledgement so the sender knows help is coming.
- A DIY network is not a certified, professionally-monitored life-safety system; use a certified installation where regulations or duty of care require one.
- Test regularly (drills and self-tests) so the system is provably ready.
- Lithium cells vent and burn when abused. Only use protected cells or a proper BMS, never charge below 0 °C, and never leave a charging pack unattended on a wooden desk.
- Never power an RF module without its antenna fitted — the reflected power destroys the output stage. Check your local licence-free band and duty-cycle limits before transmitting.
- Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
- Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
- Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.
Maintenance
- Act on every supervision alarm — replace flat batteries and fix silent buttons promptly.
- Run periodic end-to-end drills and self-tests across all buttons.
- Verify backup-power run-time and comms resilience after any site change.
- Keep button locations and the console map accurate as the site evolves.
- Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
- Log pack voltage. When resting voltage after a full charge drops below about 4.0 V, the cell is near end of life — replace it.
- Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
- Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
- Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.
Future Improvements & Upgrades
A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.
- Add two-way voice/intercom at the button for the control room to talk to the sender.
- Add wearable/mobile panic triggers linked into the same network.
- Integrate with door locks/lighting/CCTV to guide responders to the location.
- Add automatic escalation to external emergency services where appropriate.
- Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
- Add over-the-air firmware updates so you never have to physically reach a deployed node again.
- Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
- Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
- Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
- Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.
Frequently Asked Questions
References & Learning Resources
These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.