Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.
Shutter Alarm: the finished build
UnoIndia utility

Shop shutter burglar alarm with SMS and call (Arduino Uno + SIM800L)

Shutter forced or motion inside at night → siren, SMS and a ringing phone.

Difficulty
Medium
Build time
3 h
Parts cost
₹2,990 · $35
Verified — core avr 1.8.8, 3 Nov 2026Compile-only

Community draft — report a mistake

Parts list

PartQtyApprox.Buy
Arduino Uno R3 (CH340 clone)1₹450Buy Arduino Uno R3 (CH340 clone)
Rolling-shutter magnetic contact (heavy-duty reed switch + magnet)1₹250Buy Rolling-shutter magnetic contact (heavy-duty reed switch + magnet)
PIR motion sensor HC-SR5011₹80Buy PIR motion sensor HC-SR501
SIM800L GSM module + 2G-capable SIM1₹350Buy SIM800L GSM module + 2G-capable SIM
LM2596 buck module set to 4.0 V + 1000 µF capacitor1₹100Buy LM2596 buck module set to 4.0 V + 1000 µF capacitor
1-channel relay module, 5 V1₹60Buy 1-channel relay module, 5 V
12 V piezo siren (110 dB)1₹250Buy 12 V piezo siren (110 dB)
Active buzzer module1₹25Buy Active buzzer module
Push button (hidden)1₹20Buy Push button (hidden)
Resistors 10 kΩ + 20 kΩ (RX divider)1₹5Buy Resistors 10 kΩ + 20 kΩ (RX divider)
12 V 7 Ah battery + 12 V charger/SMPS (alarm power through cuts)1₹1,400Buy 12 V 7 Ah battery + 12 V charger/SMPS (alarm power through cuts)
Total₹2,990

Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logicLM2596 buck set to 4.0 V12 V battery (on its charger) + 12 V sirenReed switch / MC-38 magnetic door sensorHC-SR501 PIR motion sensorPush button (6 mm tactile switch)1-channel relay module (5 V coil)Active buzzer module (high-level trigger)SIM800L GSM/GPRS module (2G)10k│20k+-+12VSiren +−5VGNDVIND2D3D4D5D6D7D8WIRE 1WIRE 2VCCOUTGND12DC+DC−INCOMNONC (not connected)I/OVCCGNDNET (not connected)VCCRST (not connected)RXDTXDGND
Every connection
Arduino Uno R3Part · pinWireNotes
D4Reed switch / MC-38 magnetic door sensor · WIRE 1blueShutter switch, INPUT_PULLUP — closed while the shutter is down
GNDReed switch / MC-38 magnetic door sensor · WIRE 2black
5VHC-SR501 PIR motion sensor · VCCred
D5HC-SR501 PIR motion sensor · OUTyellow
GNDHC-SR501 PIR motion sensor · GNDblack
D6Push button (6 mm tactile switch) · 1purpleHidden arm / disarm button
GNDPush button (6 mm tactile switch) · 2black
D71-channel relay module (5 V coil) · INorangeActive-LOW; HIGH before it becomes an output
5V1-channel relay module (5 V coil) · DC+red
GND1-channel relay module (5 V coil) · DC−black
12 V battery (on its charger) + 12 V siren · +12V1-channel relay module (5 V coil) · COMred12 V + to COM
12 V battery (on its charger) + 12 V siren · Siren +1-channel relay module (5 V coil) · NOredNO to the siren +; siren − to the battery −
D8Active buzzer module (high-level trigger) · I/OorangeExit / entry beeps inside
5VActive buzzer module (high-level trigger) · VCCred
GNDActive buzzer module (high-level trigger) · GNDblack
D2SIM800L GSM/GPRS module (2G) · TXDblue
D3SIM800L GSM/GPRS module (2G) · RXDyellowVia 10 kΩ / 20 kΩ divider — Protects the SIM800L’s 2.8 V serial input
VIN12 V battery (on its charger) + 12 V siren · +12VredThe Uno runs from the 12 V battery (VIN = the barrel-jack rail, 7–12 V)
GND12 V battery (on its charger) + 12 V siren · −blackBattery − to Uno GND; the buck’s input − goes here too
LM2596 buck set to 4.0 V · +SIM800L GSM/GPRS module (2G) · VCCred4.0 V / 2 A buck fed from the 12 V supply; 1000 µF across VCC/GND at the module
LM2596 buck set to 4.0 V · -SIM800L GSM/GPRS module (2G) · GNDblack
GNDSIM800L GSM/GPRS module (2G) · GNDblackCommon ground: Uno GND and buck − both to SIM800L GND

Board quirks: Power everything from a 12 V battery kept charged by a 12 V supply: the Uno through its barrel jack (VIN), the SIM800L through the 4.0 V buck, the siren directly. A thief who cuts the shop’s power — or an ordinary power cut — must not silence the alarm. Fix the reed switch to the floor or frame and the magnet to the shutter’s bottom slat, about 1 cm apart when it’s down. Floor-mount shutter contacts are made for this and survive being stepped on. Hide the arm/disarm button somewhere only you know (behind the counter, inside a cupboard). After pressing it to arm, you have 60 s to step out and pull the shutter down; when you open up, you have 30 s to reach it. SIM800L is a 2G module. Check that your operator still runs 2G in your area — many Indian circles still do for basic phones, but this is changing; a 4G module (A7670 family) uses similar AT commands.

Code

shop-shutter-burglar-alarm.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// Shop shutter burglar alarm with SMS and call — Arduino Uno + reed switch + PIR + SIM800L
// Shutter reed switch D4 to GND (closed = shutter down). PIR HC-SR501 OUT on D5.
// Hidden arm/disarm push button D6 to GND. Relay module IN on D7 (active-LOW) switches a 12 V siren.
// Buzzer module on D8 for the exit/entry beeps. SIM800L: TXD -> D2, RXD <- D3 through a divider.
#include <SoftwareSerial.h>
#include "fr_settings.h"

const char* ALERT_TO = "+91XXXXXXXXXX";
// Filled in from the FlashReady flasher over USB (kept in EEPROM), or type the value above.
FrSetting SETTINGS[] = {{"alert_to", &ALERT_TO, true}};

constexpr uint8_t SHUTTER_PIN = 4;
constexpr uint8_t PIR_PIN = 5;
constexpr uint8_t BUTTON_PIN = 6;
constexpr uint8_t RELAY_PIN = 7;
constexpr uint8_t BUZZER_PIN = 8;
constexpr bool RELAY_ACTIVE_LOW = true;
constexpr unsigned long EXIT_MS = 60000UL;    // time to step out and pull the shutter down
constexpr unsigned long ENTRY_MS = 30000UL;   // time to reach the hidden button after opening
constexpr unsigned long SIREN_MS = 180000UL;  // siren limit per alarm (3 minutes)
constexpr uint8_t MAX_ALARMS = 3;             // per arming: no endless SMS if a sensor fails

enum State { DISARMED, EXIT_DELAY, ARMED, ENTRY_DELAY, ALARM };
const char* const NAMES[] = {"DISARMED", "EXIT", "ARMED", "ENTRY", "ALARM"};
State state = DISARMED;
unsigned long since = 0;
uint8_t alarms = 0;
SoftwareSerial sim(2, 3);  // RX <- SIM800L TXD, TX -> divider -> SIM800L RXD

bool shutterOpen() { return digitalRead(SHUTTER_PIN) == HIGH; }  // magnet away = switch open
bool motion() { return digitalRead(PIR_PIN) == HIGH; }

void siren(bool on) { digitalWrite(RELAY_PIN, (on != RELAY_ACTIVE_LOW) ? HIGH : LOW); }

void enter(State s) {
  state = s;
  since = millis();
  siren(s == ALARM);
  digitalWrite(BUZZER_PIN, LOW);
  Serial.print(F("-> "));
  Serial.println(NAMES[s]);
}

void smsAndCall(const __FlashStringHelper* why) {
  if (!*ALERT_TO) {
    Serial.println(F("SMS off — no phone number set."));
    return;
  }
  sim.println(F("AT+CMGF=1"));
  delay(300);
  sim.print(F("AT+CMGS=\""));
  sim.print(ALERT_TO);
  sim.println('"');
  delay(500);
  sim.print(F("SHOP ALARM: "));
  sim.print(why);
  sim.write(26);
  delay(5000);
  sim.print(F("ATD"));  // ring the phone for 20 s so it isn't missed at night
  sim.print(ALERT_TO);
  sim.println(';');
  delay(20000);
  sim.println(F("ATH"));
}

void trigger(const __FlashStringHelper* why) {
  if (alarms >= MAX_ALARMS) return;
  alarms++;
  enter(ALARM);
  Serial.print(F("ALARM: "));
  Serial.println(why);
  smsAndCall(why);  // the siren is already sounding while this runs
}

void setup() {
  siren(false);  // relay off before the pin becomes an output
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(SHUTTER_PIN, INPUT_PULLUP);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(PIR_PIN, INPUT);
  Serial.begin(115200);
  frSettingsBegin(SETTINGS);
  if (!*ALERT_TO) Serial.println(F("SMS off — no phone number set. Flash from flashready.in or type it into the code."));
  sim.begin(9600);
  enter(DISARMED);
}

void loop() {
  unsigned long now = millis();
  unsigned long t = now - since;

  // Hidden button: arm from DISARMED, disarm from anything else.
  if (digitalRead(BUTTON_PIN) == LOW) {
    delay(30);
    if (digitalRead(BUTTON_PIN) == LOW) {
      if (state == DISARMED) {
        alarms = 0;
        enter(EXIT_DELAY);
      } else {
        enter(DISARMED);
      }
      while (digitalRead(BUTTON_PIN) == LOW) delay(10);
      return;
    }
  }

  switch (state) {
    case EXIT_DELAY:
      digitalWrite(BUZZER_PIN, (t % 1000) < 100);  // beep once a second
      if (t > EXIT_MS) {
        if (shutterOpen()) {
          Serial.println(F("Shutter still open - not armed"));
          digitalWrite(BUZZER_PIN, HIGH);
          delay(1500);
          enter(DISARMED);
        } else {
          enter(ARMED);
        }
      }
      break;
    case ARMED:
      if (shutterOpen()) enter(ENTRY_DELAY);
      else if (motion()) trigger(F("motion inside with the shutter down"));
      break;
    case ENTRY_DELAY:
      digitalWrite(BUZZER_PIN, (t % 500) < 100);  // fast beeps: disarm now
      if (t > ENTRY_MS) trigger(F("shutter opened"));
      break;
    case ALARM:
      if (t > SIREN_MS) {
        siren(false);  // silent after 3 minutes, but stays alarmed until the shutter is down
        if (!shutterOpen()) enter(ARMED);
      }
      break;
    default:
      break;
  }

  static unsigned long lastLog = 0;
  if (now - lastLog > 2000) {
    lastLog = now;
    Serial.print(F("state="));
    Serial.print(NAMES[state]);
    Serial.print(F(" shutter="));
    Serial.print(shutterOpen() ? F("open") : F("closed"));
    Serial.print(F(" pir="));
    Serial.println(motion());
  }
}

Arduino IDE: keep fr_settings.h in the same folder as the .ino (tab menu → New Tab, same name). Flashing from this page doesn’t need it.

fr_settings.hArduino C++
// fr_settings.h — FlashReady on-board settings (Wi-Fi name, phone number, ...) over USB.
//
// Why: the pre-built file on flashready.in is the same for everyone, so your own settings
// can't be inside it. Instead the board asks for them over USB serial and keeps them in
// its EEPROM. If you use Arduino IDE you can still type them into the constants in the
// sketch — this file then changes nothing except a 2-second pause at start-up.
//
// The protocol, in plain words (one text line each way, ending in \n, at 115200 baud):
//  1. Right after Serial.begin(115200) the board prints
//       FR?SETTINGS v1 keys=wifi_ssid,wifi_pass missing=wifi_pass
//     "missing" lists the required settings that still have no real value.
//  2. If nothing is missing it listens for 2 seconds and then carries on. If something is
//     missing it keeps listening, printing the line again every 2 seconds, for up to
//     30 seconds; then it carries on anyway and the sketch skips whatever needs the
//     missing value (an alarm still sounds, it just can't send the SMS).
//  3. The flasher answers   FR!SET wifi_ssid=My%20Home&wifi_pass=secret
//     (values URL-encoded). The board stores them and answers FR!OK, then carries on with
//     the new values. Errors: FR!ERR unknown <key>, FR!ERR long <key> (nothing is stored).
//     A key that is left out keeps its stored value; "key=" (empty) removes it.
//     "FR!SET" with nothing after it means "carry on now": FR!OK, nothing is stored.
//  4. FR!CLEAR wipes everything that was stored, answers FR!OK and keeps listening.
//  Other lines are ignored.
//
// A stored value wins over the constant in the sketch. A constant that is still a
// placeholder ("YOUR_SSID", "your-wifi", "+91XXXXXXXXXX") or empty counts as not set.
//
// EEPROM block at FR_SETTINGS_ADDR: 'F' 'R' 0x01, length (uint16, low byte first), then
// "key=value\n" lines. Uses FR_SETTINGS_SIZE bytes; move FR_SETTINGS_ADDR with a #define
// before the #include if your sketch uses EEPROM for something else.
//
// Use in a sketch:
//   const char* WIFI_SSID = "YOUR_SSID";
//   FrSetting SETTINGS[] = { {"wifi_ssid", &WIFI_SSID, true} };   // key, constant, required
//   void setup() { Serial.begin(115200); frSettingsBegin(SETTINGS); ... WiFi.begin(WIFI_SSID, ...); }
// After frSettingsBegin() each constant points at the value to use ("" if none is set).
#pragma once
#include <Arduino.h>
#include <EEPROM.h>
#include <string.h>

#ifndef FR_SETTINGS_ADDR
#define FR_SETTINGS_ADDR 0
#endif
#ifndef FR_SETTINGS_SIZE
#if defined(__AVR__)
#define FR_SETTINGS_SIZE 96  // 2 KB of RAM on an Uno: a phone number fits easily
#else
#define FR_SETTINGS_SIZE 512
#endif
#endif
#ifndef FR_LINE_MAX
#if defined(__AVR__)
#define FR_LINE_MAX 128
#else
#define FR_LINE_MAX 1024
#endif
#endif
#define FR_MAX_KEYS 8
#define FR_WAIT_MAX_MS 30000UL  // never wait longer than this for missing settings
#define FR_DATA_MAX (FR_SETTINGS_SIZE - 5)

struct FrSetting {
  const char* key;     // [a-z0-9_], as in settings.json
  const char** value;  // the sketch's constant; replaced by the value to use
  bool required;
};

// Stored settings in RAM as "key=value\0key=value\0" (only non-empty values).
static char frData[FR_DATA_MAX + 1];
static uint16_t frLen = 0;

static inline void frEepromBegin() {
#if defined(ESP32) || defined(ESP8266)
  static bool started = false;
  if (!started) EEPROM.begin(FR_SETTINGS_ADDR + FR_SETTINGS_SIZE);
  started = true;
#endif
}

static inline void frLoad() {
  frEepromBegin();
  frLen = 0;
  frData[0] = 0;
  if (EEPROM.read(FR_SETTINGS_ADDR) != 'F' || EEPROM.read(FR_SETTINGS_ADDR + 1) != 'R' || EEPROM.read(FR_SETTINGS_ADDR + 2) != 1) return;
  uint16_t n = EEPROM.read(FR_SETTINGS_ADDR + 3) | (EEPROM.read(FR_SETTINGS_ADDR + 4) << 8);
  if (n > FR_DATA_MAX) return;
  for (uint16_t i = 0; i < n; i++) {
    char c = EEPROM.read(FR_SETTINGS_ADDR + 5 + i);
    frData[i] = c == '\n' ? '\0' : c;
  }
  frData[n] = 0;
  frLen = n;
}

static inline void frPut(int addr, uint8_t b) {
#if defined(__AVR__)
  EEPROM.update(addr, b);
#else
  EEPROM.write(addr, b);
#endif
}

static inline void frSave() {
  frEepromBegin();
  frPut(FR_SETTINGS_ADDR, 'F');
  frPut(FR_SETTINGS_ADDR + 1, 'R');
  frPut(FR_SETTINGS_ADDR + 2, 1);
  frPut(FR_SETTINGS_ADDR + 3, frLen & 0xFF);
  frPut(FR_SETTINGS_ADDR + 4, frLen >> 8);
  for (uint16_t i = 0; i < frLen; i++) frPut(FR_SETTINGS_ADDR + 5 + i, frData[i] ? frData[i] : '\n');
#if defined(ESP32) || defined(ESP8266)
  EEPROM.commit();
#endif
}

// The stored value for key, or nullptr.
static inline const char* frStored(const char* key) {
  size_t kl = strlen(key);
  for (uint16_t i = 0; i < frLen; i += strlen(frData + i) + 1) {
    if (strncmp(frData + i, key, kl) == 0 && frData[i + kl] == '=') return frData + i + kl + 1;
  }
  return nullptr;
}

// Empty, "your_…" / "YOUR-…" / "your …", or a "+91XXXX…" phone number.
static inline bool frIsPlaceholder(const char* v) {
  if (!v || !*v) return true;
  if (strncasecmp(v, "your", 4) == 0 && (v[4] == '_' || v[4] == '-' || v[4] == ' ')) return true;
  return v[0] == '+' && strstr(v, "XXXX") != nullptr;
}

// The stored value for key, else the fallback constant; "" if that is a placeholder.
static inline const char* frSettingsGet(const char* key, const char* fallback) {
  const char* v = frStored(key);
  if (!v) v = fallback;
  return frIsPlaceholder(v) ? "" : v;
}

static inline bool frIsMissing(const FrSetting& s) {
  return s.required && !*frSettingsGet(s.key, *s.value);
}

static inline void frRequest(FrSetting* s, uint8_t n) {
  Serial.print(F("FR?SETTINGS v1 keys="));
  for (uint8_t i = 0; i < n; i++) {
    if (i) Serial.print(',');
    Serial.print(s[i].key);
  }
  Serial.print(F(" missing="));
  bool first = true;
  for (uint8_t i = 0; i < n; i++) {
    if (!frIsMissing(s[i])) continue;
    if (!first) Serial.print(',');
    Serial.print(s[i].key);
    first = false;
  }
  Serial.print('\n');
}

static inline void frReply(const __FlashStringHelper* what, const char* key) {
  Serial.print(what);
  Serial.print(key);
  Serial.print('\n');
}

static inline int8_t frHex(char c) {
  if (c >= '0' && c <= '9') return c - '0';
  c |= 0x20;
  return (c >= 'a' && c <= 'f') ? c - 'a' + 10 : -1;
}

// Percent-decodes in place. Drops NUL, CR and LF: they can't be stored.
static inline void frDecode(char* s) {
  char* o = s;
  for (; *s; s++) {
    char c = *s;
    if (c == '%' && frHex(s[1]) >= 0 && frHex(s[2]) >= 0) {
      c = (char)(frHex(s[1]) << 4 | frHex(s[2]));
      s += 2;
    }
    if (c != '\0' && c != '\n' && c != '\r') *o++ = c;
  }
  *o = 0;
}

// "k1=v1&k2=v2" (cut short if the line overflowed). Saves and returns true, or replies with an error.
static inline bool frSet(FrSetting* s, uint8_t n, char* p, bool overflow) {
  const char* upd[FR_MAX_KEYS] = {};
  while (*p) {
    char* amp = strchr(p, '&');
    bool last = !amp;
    if (amp) *amp = 0;
    char* eq = strchr(p, '=');
    if (eq) *eq = 0;
    if (*p) {
      if (last && overflow) {
        frReply(F("FR!ERR long "), p);
        return false;
      }
      uint8_t i = 0;
      while (i < n && strcmp(s[i].key, p) != 0) i++;
      if (i == n) {
        frReply(F("FR!ERR unknown "), p);
        return false;
      }
      char* v = eq ? eq + 1 : p + strlen(p);  // "key" alone = "key="
      frDecode(v);
      upd[i] = v;
    }
    if (last) break;
    p = amp + 1;
  }
  // Build the new block: for each key, the new value or the one already stored.
  char next[FR_DATA_MAX + 1];
  uint16_t len = 0;
  for (uint8_t i = 0; i < n; i++) {
    const char* v = upd[i] ? upd[i] : frStored(s[i].key);
    if (!v || !*v) continue;
    size_t kl = strlen(s[i].key), vl = strlen(v);
    if (len + kl + vl + 2 > FR_DATA_MAX) {
      frReply(F("FR!ERR long "), s[i].key);
      return false;
    }
    memcpy(next + len, s[i].key, kl);
    next[len + kl] = '=';
    memcpy(next + len + kl + 1, v, vl + 1);
    len += kl + vl + 2;
  }
  memcpy(frData, next, len);
  frData[len] = 0;
  frLen = len;
  frSave();
  return true;
}

// Handles one received line. Returns true once settings were saved (boot carries on).
static inline bool frCommand(FrSetting* s, uint8_t n, char* line, bool overflow) {
  if (strcmp(line, "FR!CLEAR") == 0) {
    frLen = 0;
    frData[0] = 0;
    frSave();
    Serial.print(F("FR!OK\n"));
    return false;
  }
  if (strncmp(line, "FR!SET", 6) != 0 || (line[6] != ' ' && line[6] != 0)) return false;  // not for us
  char* p = line + 6;
  while (*p == ' ') p++;
  if (*p && !frSet(s, n, p, overflow)) return false;  // empty FR!SET = carry on, store nothing
  Serial.print(F("FR!OK\n"));
  return true;
}

// Call right after Serial.begin(115200). Prints the request, waits as described at the top
// (30 s at most), then points every constant in the list at the value to use ("" = not set).
static inline void frSettingsBegin(FrSetting* s, uint8_t n) {
  frLoad();
  char line[FR_LINE_MAX];
  uint16_t len = 0;
  bool overflow = false;
  frRequest(s, n);
  unsigned long start = millis(), quietSince = start;
  while (millis() - start < FR_WAIT_MAX_MS) {
    int c = Serial.read();
    if (c >= 0) {
      quietSince = millis();
      if (c == '\r') continue;
      if (c != '\n') {
        if (len < FR_LINE_MAX - 1) line[len++] = (char)c;
        else overflow = true;
        continue;
      }
      line[len] = 0;
      bool saved = frCommand(s, n, line, overflow);
      len = 0;
      overflow = false;
      if (saved) break;
      continue;
    }
    if (millis() - quietSince < 2000) {
      delay(1);  // also keeps the ESP8266 watchdog fed
      continue;
    }
    len = 0;  // drop half a line
    overflow = false;
    bool missing = false;
    for (uint8_t i = 0; i < n; i++) missing |= frIsMissing(s[i]);
    if (!missing) break;
    frRequest(s, n);
    quietSince = millis();
  }
  for (uint8_t i = 0; i < n; i++) *s[i].value = frSettingsGet(s[i].key, *s[i].value);
}

template <size_t N>
static inline void frSettingsBegin(FrSetting (&s)[N]) {
  static_assert(N <= FR_MAX_KEYS, "fr_settings.h: at most FR_MAX_KEYS settings");
  frSettingsBegin(s, (uint8_t)N);
}

Compiled for uno on avr 1.8.8 · 3 Nov 2026

How it works

Shop break-ins in India usually happen at night by forcing the rolling shutter, often during a power cut. Commercial alarms with monitoring cost a lot; this one costs a few thousand rupees, runs from its own battery, and tells you immediately — with a siren at the shop and an SMS plus a ringing call on your phone.

How it works

Two sensors watch the shop:

  • a reed switch on the shutter. A magnet on the shutter keeps the switch closed while the shutter is down; lifting it opens the switch and D4 reads HIGH through its pull-up;
  • a PIR sensor inside, which sees body heat moving — someone who got in through the roof or a wall.

The sketch runs a small state machine:

  1. DISARMED — press the hidden button to arm.
  2. EXIT — 60 s with a beep every second, to step out and pull the shutter down. If the shutter is still open at the end, it doesn’t arm (and gives a long beep).
  3. ARMED — lifting the shutter starts the ENTRY delay (30 s of fast beeps; press the hidden button to disarm). Motion inside with the shutter down is an immediate alarm.
  4. ALARM — the relay switches the 12 V siren on, and the SIM800L sends an SMS (“SHOP ALARM: shutter opened”) and then calls your phone for 20 seconds so it rings even if you’re asleep. The siren stops after 3 minutes; the alarm can trigger at most three times per arming, so a faulty sensor can’t drain your SIM balance.

Why these parts

  • Reed switch + PIR — the shutter is the usual way in; the PIR covers the rest.
  • SIM800L — works without Wi-Fi or a router, which is usually dead in a power cut anyway.
  • 12 V battery — the alarm’s whole value is working when the power is off.

India notes

Tell your neighbours and the local beat constable about the siren. Test it every month — open the shutter while armed — so you know the SIM still has balance and the battery is still good.

Troubleshooting

It doesn’t arm — beeps for 1.5 s after the exit delay

The shutter was still open (or the reed switch isn’t closing) when the 60 s ended. Check the gap between magnet and switch; the Serial Monitor prints shutter=closed when it’s right.

False alarms at night

The PIR sees a fan, curtains, a pet or sunlight through a vent. Turn its sensitivity trimmer down, point it away from windows, and set its jumper to repeat-trigger. Rats are a real cause in shops — mount it high, pointing down at the floor area near the shutter.

No SMS or call

Check the SIM800L’s LED blinks every 3 s (registered), the SIM has balance, ALERT_TO starts with +91, and the buck gives a steady 4.0 V with the big capacitor fitted.

Upgrades

  • Add a second reed switch for the back door or the godown.
  • Arm and disarm by SMS from your phone (only from your number).
  • Add a small camera module that snaps a photo when the alarm starts.

↑↓ to move · Enter to open