Community project

Zoned Building Alarm System

ESP32
Photo of Zoned Building Alarm System
Generated with AI

Santos Flores Peralta

Published October 19, 2026

This zoned building alarm system uses an ESP32 microcontroller to monitor multiple entry points and motion detection, with armed/disarmed states controlled via a 4×4 keypad. The system communicates over WiFi and MQTT, allowing remote monitoring and control while providing real-time feedback through status LEDs and an audible siren.

The guide includes a complete wiring diagram showing connections for door and window sensors, motion detector, RGB status indicators, sensitivity adjustment potentiometer, and buzzer alarm. Assembly steps walk through power setup, keypad integration, zone sensor wiring, LED mounting, and firmware configuration—everything needed to deploy a networked multi-zone alarm system.

Wiring diagram

Gather all the parts

QtyComponent
1

Teclado matricial 4×4

Teclado de dieciséis teclas para ingresar el código de seis dígitos de la alarma.

1

Pulsador de puerta o ventana

Pulsador que simula que una puerta o ventana se abre o se cierra.

1

Pulsador de movimiento

Pulsador que simula la detección de movimiento en una zona.

1

LED verde

Verde

Luz que indica que la alarma está desarmada.

1

LED amarillo

Amarillo

Luz que indica que la alarma está armada.

1

LED rojo

Rojo

Luz que indica que la alarma fue disparada.

1

Resistencia para LED verde

220 Ω

Resistencia de 220 Ω que limita la corriente y protege el LED verde.

1

Resistencia para LED amarillo

220 Ω

Resistencia de 220 Ω que limita la corriente y protege el LED amarillo.

1

Resistencia para LED rojo

220 Ω

Resistencia de 220 Ω que limita la corriente y protege el LED rojo.

1

Potenciómetro lineal de 10 kΩ

La perilla que ajusta la sensibilidad simulada del detector de movimiento.

1

Zumbador de sirena

Zumbador que emite el aviso sonoro cuando se dispara la alarma.

Assemble it in 7 steps

1. Prepara el ESP32 y la alimentación

Coloca el ESP32 DevKit v1 sobre la protoboard dejando espacio a ambos lados. Conecta el riel positivo de la protoboard al pin 3V3 del ESP32 y el riel negativo a un pin GND; todos los demás componentes usarán estos dos rieles.

  • El ESP32 se alimentará por su conector USB durante las pruebas.
  • No conectes 5 V a las filas de señales, al potenciómetro ni al teclado: las entradas del ESP32 trabajan a 3,3 V y 5 V puede dañarlas.

2. Conecta el teclado

Une las cuatro filas del teclado a GPIO13, GPIO14, GPIO16 y GPIO17, en ese orden. Une sus cuatro columnas a GPIO18, GPIO19, GPIO21 y GPIO22, en ese orden; estos ocho cables llevan las teclas al ESP32.

  • Mira las etiquetas impresas en tu teclado: algunos modelos enumeran las ocho patillas como R1–R4 y C1–C4.

3. Cablea los pulsadores de zona

Conecta una pata del pulsador de puerta al riel GND y la otra a GPIO32. Conecta una pata del pulsador de movimiento al riel GND y la otra a GPIO33; al pulsarlos simulan puerta abierta y movimiento.

  • No hace falta añadir resistencias a estos pulsadores: el ESP32 activa una resistencia interna para leerlos de forma estable.

4. Monta las tres luces de estado

Para cada LED, conecta la pata corta al riel GND. Conecta la pata larga del LED verde a una resistencia de 220 Ω y el otro extremo de esa resistencia a GPIO25; repite con el LED amarillo hacia GPIO26 y el LED rojo hacia GPIO27. Las resistencias limitan la corriente y protegen los LEDs y el ESP32.

  • La pata larga es el lado positivo; la pata corta y el borde plano del LED indican el lado que va a GND.
  • No conectes un LED directamente a un GPIO: sin su resistencia de 220 Ω se puede dañar el LED o el pin del ESP32.

5. Conecta la perilla de sensibilidad

Conecta un terminal exterior del potenciómetro a 3V3, el otro terminal exterior a GND y el terminal central a GPIO34. La perilla envía al ESP32 el valor de sensibilidad.

  • Asegúrate de usar 3V3, no 5 V: una señal superior a 3,3 V en GPIO34 puede dañar el ESP32.

6. Conecta el zumbador

Conecta el pin marcado GND o negativo del zumbador al riel GND y su pin de señal o positivo a GPIO23; el ESP32 lo activa cuando recibe la orden de alarma disparada.

  • Si tu zumbador no tiene marcas, revisa su carcasa: el terminal positivo suele llevar un signo +.

7. Revisa y prueba con USB

Revisa que todos los GND estén unidos y que ninguna conexión de señal toque el riel de 5 V. Conecta el ESP32 por USB; después de completar los datos de Wi‑Fi y del servidor MQTT en el firmware, usa Deploy para grabarlo.

  • Desconecta el USB antes de mover cables si notas calor, olor extraño o una conexión suelta.

Review all connections

1. Connections between "keypad_1" and "ESP32"

Functionkeypad_1ESP32
dataROW0GPIO 13
dataROW1GPIO 14
dataROW2GPIO 16
dataROW3GPIO 17
dataCOL0GPIO 18
dataCOL1GPIO 19
dataCOL2GPIO 21
dataCOL3GPIO 22

2. Connections between "door_button" and "ESP32"

Functiondoor_buttonESP32
groundGNDGND
digitalSIGNALGPIO 32

3. Connections between "motion_button" and "ESP32"

Functionmotion_buttonESP32
groundGNDGND
digitalSIGNALGPIO 33

4. Connections between "green_resistor" and "ESP32"

Functiongreen_resistorESP32
digitalP1GPIO 25
digitalP2 → LED verde ANODEEXT

5. Connections between "green_led" and "ESP32"

Functiongreen_ledESP32
groundGNDGND

6. Connections between "yellow_resistor" and "ESP32"

Functionyellow_resistorESP32
digitalP1GPIO 26
digitalP2 → LED amarillo ANODEEXT

7. Connections between "yellow_led" and "ESP32"

Functionyellow_ledESP32
groundGNDGND

8. Connections between "red_resistor" and "ESP32"

Functionred_resistorESP32
digitalP1GPIO 27
digitalP2 → LED rojo ANODEEXT

9. Connections between "red_led" and "ESP32"

Functionred_ledESP32
groundGNDGND

10. Connections between "sensitivity_pot" and "ESP32"

Functionsensitivity_potESP32
powerVCC3V3
adcWIPERGPIO 34
groundGNDGND

11. Connections between "siren_buzzer" and "ESP32"

Functionsiren_buzzerESP32
groundGNDGND
digitalSIGNALGPIO 23

Deploy the firmware

#include <WiFi.h>
#include <PubSubClient.h>
#include <Keypad.h>

const char WIFI_SSID[] = "REEMPLAZAR_WIFI";
const char WIFI_PASSWORD[] = "REEMPLAZAR_CLAVE";
const char MQTT_HOST[] = "192.168.1.100";
const uint16_t MQTT_PORT = 1883;

constexpr uint8_t ROW0_PIN = 13, ROW1_PIN = 14, ROW2_PIN = 16, ROW3_PIN = 17;
constexpr uint8_t COL0_PIN = 18, COL1_PIN = 19, COL2_PIN = 21, COL3_PIN = 22;
constexpr uint8_t DOOR_PIN = 32, MOTION_PIN = 33;
constexpr uint8_t GREEN_LED_PIN = 25, YELLOW_LED_PIN = 26, RED_LED_PIN = 27;
constexpr uint8_t SENSITIVITY_PIN = 34, BUZZER_PIN = 23;
constexpr byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {{'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'}};
byte rowPins[ROWS] = {ROW0_PIN, ROW1_PIN, ROW2_PIN, ROW3_PIN};
byte colPins[COLS] = {COL0_PIN, COL1_PIN, COL2_PIN, COL3_PIN};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
enum AlarmState { DISARMED, ARMED, TRIGGERED };
AlarmState alarmState = DISARMED;
char enteredCode[7] = "";
uint8_t enteredLength = 0;
int lastSensitivity = -1;
bool lastDoorLevel = HIGH;
unsigned long lastDoorChangeMs = 0, lastMotionMs = 0, lastWifiAttemptMs = 0, lastMqttAttemptMs = 0;
const char *stateName() { return alarmState == ARMED ? "armada" : alarmState == TRIGGERED ? "disparada" : "desarmada"; }
void publishMessage(const char *topic, const String &payload, bool retained = false) { if (mqttClient.connected()) mqttClient.publish(topic, payload.c_str(), retained); }
void showState() { digitalWrite(GREEN_LED_PIN, alarmState == DISARMED); digitalWrite(YELLOW_LED_PIN, alarmState == ARMED); digitalWrite(RED_LED_PIN, alarmState == TRIGGERED); digitalWrite(BUZZER_PIN, alarmState == TRIGGERED); }
void setAlarmState(AlarmState newState) { if (alarmState == newState) return; alarmState = newState; showState(); publishMessage("alarma/estado", String("{\"estado\":\"") + stateName() + "\"}", true); }
void mqttCallback(char *topic, byte *payload, unsigned int length) { if (String(topic) != "alarma/comando") return; String command; for (unsigned int i = 0; i < length; ++i) command += static_cast<char>(payload[i]); command.trim(); command.toUpperCase(); if (command == "ARMAR") setAlarmState(ARMED); else if (command == "DESARMAR") setAlarmState(DISARMED); else if (command == "DISPARAR") setAlarmState(TRIGGERED); else if (command == "SILENCIAR") setAlarmState(ARMED); }
void connectWifiIfNeeded() { if (WiFi.status() == WL_CONNECTED || millis() - lastWifiAttemptMs < 10000UL) return; lastWifiAttemptMs = millis(); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); }
void connectMqttIfNeeded() { if (WiFi.status() != WL_CONNECTED || mqttClient.connected() || millis() - lastMqttAttemptMs < 5000UL) return; lastMqttAttemptMs = millis(); if (mqttClient.connect("alarma-esp32-01")) { mqttClient.subscribe("alarma/comando"); publishMessage("alarma/estado", String("{\"estado\":\"") + stateName() + "\"}", true); } }
void readKeypad() { char key = keypad.getKey(); if (!key) return; if (key == '*') { enteredLength = 0; enteredCode[0] = '\0'; } else if (key == '#') { if (enteredLength == 6) publishMessage("alarma/codigo", String("{\"codigo\":\"") + enteredCode + "\"}"); enteredLength = 0; enteredCode[0] = '\0'; } else if (key >= '0' && key <= '9' && enteredLength < 6) { enteredCode[enteredLength++] = key; enteredCode[enteredLength] = '\0'; } }
void readDoorZone() { bool level = digitalRead(DOOR_PIN); if (level != lastDoorLevel && millis() - lastDoorChangeMs > 35UL) { lastDoorChangeMs = millis(); lastDoorLevel = level; publishMessage("alarma/puerta", level == LOW ? "{\"estado\":\"abierta\"}" : "{\"estado\":\"cerrada\"}"); } }
void readSensitivity() { int sensitivity = map(analogRead(SENSITIVITY_PIN), 0, 4095, 0, 100); if (lastSensitivity < 0 || abs(sensitivity - lastSensitivity) >= 2) { lastSensitivity = sensitivity; publishMessage("alarma/movimiento", String("{\"sensibilidad\":") + sensitivity + "}", true); } }
void readMotionZone() { if (digitalRead(MOTION_PIN) == LOW && millis() - lastMotionMs > 500UL) { lastMotionMs = millis(); publishMessage("alarma/movimiento", String("{\"detectado\":true,\"sensibilidad\":") + lastSensitivity + "}"); } }
void setup() { pinMode(DOOR_PIN, INPUT_PULLUP); pinMode(MOTION_PIN, INPUT_PULLUP); pinMode(GREEN_LED_PIN, OUTPUT); pinMode(YELLOW_LED_PIN, OUTPUT); pinMode(RED_LED_PIN, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); analogReadResolution(12); showState(); lastDoorLevel = digitalRead(DOOR_PIN); mqttClient.setServer(MQTT_HOST, MQTT_PORT); mqttClient.setCallback(mqttCallback); WiFi.mode(WIFI_STA); }
void loop() { connectWifiIfNeeded(); connectMqttIfNeeded(); mqttClient.loop(); readKeypad(); readDoorZone(); readSensitivity(); readMotionZone(); delay(1); }

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik