door sensor/Using it/09. A door that nags
Using it · 09 of 10

A door that nags

A door sensor that counts openings and complains when one stays open. The change has to hold for 50 ms before it counts, so a rattling door or a bouncing contact counts once; after that the sketch prints a reminder every 10 seconds until the door closes. The pull-down in setup() is the same as in the first read.

One opening, several edges

A door does not open in one clean step. The contacts in the sensor can flicker as the magnet leaves, a door in a loose frame rattles, and a wire that is not quite tight makes and breaks. A loop that acts on every change counts all of them.

A door that nags
Debounce
50 ms
Nags after
10 s open
Openings counted
0
Press Run. The door is shut, SIGNAL is HIGH and nothing is printed. The sketch counts openings, and nags once a door has been open more than 10 s.

The sketch waits until a new reading has stayed the same for 50 ms, believes it, and only then counts. A real door changes state and stays changed for far longer than that.

How the sketch debounces

raw is the last thing read, and rawSince is when it last changed. Every bounce resets rawSince. steady changes only when raw has been different from it for DEBOUNCE_MS, which a bounce never is. So one real change is one change of steady, and the count and the timing hang off that.

There is no delay() in loop(). The debounce is a comparison with millis(), so the loop keeps reading thousands of times a second and nothing is missed while it waits.

How it nags

When steady goes LOW the sketch notes the time: the opening and its count. Each pass of loop() then asks whether the door is still open and OPEN_TOO_LONG_S has gone by since the last reminder. If so it prints how long the door has been open, and starts counting again from that moment. So a door left open for a minute prints about six reminders, ten seconds apart.

Ten seconds is short on purpose, so it can be tried at a desk. For a real door, raise OPEN_TOO_LONG_S to what that door needs.

What you should see

At 115200 the serial monitor prints the state once at the start, then door opened (opening 1) when the magnet leaves. Ten seconds later it prints door has been open for 10 s, and again every ten seconds until the magnet comes back, when it prints door closed. Each opening counts once, however fast you move the magnet.

What it does not do

It nags into the serial monitor, which is the nearest thing a bare board has to a voice. A buzzer on another pin, a push to your phone and a message are each another block, and each starts with this condition: the door has been open for more than so many seconds.

The counter lives in RAM, so a restart resets it to zero. On a battery project, a closed sensor draws its small current all day, and deep sleep and the pins that wake it is the place to start.

The code

Reads SIGNAL on every pass of loop(), believes a change only once it has held for DEBOUNCE_MS, then counts openings and nags when one has lasted OPEN_TOO_LONG_S. No delay() anywhere, so nothing is missed while it waits.

door_open_alarm.ino
/*
  Door Sensor - a door that nags                        TK107 / /p/tk107

  Wiring, the same as the first read. Count from the square pad on
  the TinkerBlock board, parts up, header at the bottom:

    GND    -> GND
    3V3    -> 3V3 on an ESP32, ESP32-S3 or Pico; 5V on an Uno.
              Your board's logic voltage: this pin powers nothing,
              it is the level a closed sensor puts on SIGNAL.
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> GPIO 4 on an ESP32-S3, GPIO 25 on an ESP32,
              D2 on an Uno, GP15 on a Raspberry Pi Pico

  The sensor: its two wires go under the two screws of the terminal
  block. Either way round; the sensor is a plain switch.

  What it does: counts openings, and once the door has been open
  longer than OPEN_TOO_LONG_S it prints a reminder every
  OPEN_TOO_LONG_S seconds until the door closes. No delay(), so
  nothing else is blocked while it waits.

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The pin SIGNAL is wired to.
// Uno: 2. ESP32: 25. ESP32-S3: 4. Pico: 15.
const int DOOR_PIN = 4;

// A change counts once it has held this long: longer than a contact
// bounces, shorter than a real door.
const unsigned long DEBOUNCE_MS = 50;

// Open for longer than this and it nags, then nags again this often.
const unsigned long OPEN_TOO_LONG_S = 10;

int raw;                       // the latest reading
int steady;                    // the debounced state: HIGH = closed
unsigned long rawSince;        // when raw last changed
unsigned long openedAt;        // when the door was last seen to open
unsigned long lastNag;         // when it last nagged
unsigned int openings = 0;

void setup() {
  Serial.begin(115200);

  // The board has no pull-down and no pull-up. While the sensor is
  // open, SIGNAL is connected to nothing and floats; a closed sensor
  // puts VCC on it. So the pin must pull itself LOW: INPUT_PULLDOWN.
  // INPUT_PULLUP would be wrong: open would read HIGH, closed would
  // read HIGH, and the two could never be told apart.
#ifdef INPUT_PULLDOWN
  pinMode(DOOR_PIN, INPUT_PULLDOWN);
#else
  // An Uno or Nano has no internal pull-down. Fit a 10 kOhm resistor
  // from SIGNAL to GND, or this pin will read noise while open.
  pinMode(DOOR_PIN, INPUT);
#endif

  // Report the state at power-up, so the first line is never a change.
  raw = digitalRead(DOOR_PIN);
  steady = raw;
  rawSince = millis();
  openedAt = millis();
  lastNag = millis();
  Serial.println(steady == HIGH ? "door closed (magnet near)"
                                : "door open");
}

void loop() {
  unsigned long now = millis();

  int level = digitalRead(DOOR_PIN);
  if (level != raw) {          // a bounce, or a real change starting
    raw = level;
    rawSince = now;
  }

  // Believe a change only once it has held for DEBOUNCE_MS.
  if (raw != steady && now - rawSince >= DEBOUNCE_MS) {
    steady = raw;
    if (steady == HIGH) {
      Serial.println("door closed");
    } else {
      openings++;
      openedAt = now;
      lastNag = now;
      Serial.print("door opened (opening ");
      Serial.print(openings);
      Serial.println(")");
    }
  }

  // Still open after OPEN_TOO_LONG_S: say so, then again every
  // OPEN_TOO_LONG_S seconds.
  if (steady == LOW && now - lastNag >= OPEN_TOO_LONG_S * 1000UL) {
    lastNag = now;
    Serial.print("door has been open for ");
    Serial.print((now - openedAt) / 1000UL);
    Serial.println(" s");
  }
}

The pull-down is the same as the first read's. With the magnet on the door the sensor is closed, HIGH, while the door is shut, so an opening is a change to LOW. Mounted the other way round, swap the two branches.

View on GitHub · blocks/tk107-door-sensor/arduino/door_open_alarm/door_open_alarm.ino @ v1.13

When it does not work

It counts two or three openings for one.

The sketch is counting bounces, or the door is rattling in its frame. A loop that counts every change sees each flicker. Keep the 50 ms debounce, and do not add a delay() that makes the loop miss the settled level.

It nags the moment I open the door.

OPEN_TOO_LONG_S is 10 seconds so it can be tried at a desk. Raise it to the time that suits the door. The first reminder comes that long after the opening, then again every OPEN_TOO_LONG_S.

It never nags, even left open for a minute.

Check the monitor prints door opened first. If it never does, the pin still reads HIGH with the door open: the magnet may be too near, or the pull-down missing so the pin floats. The nag only starts once the opening is recorded.

The count goes up with the door shut.

The magnet sits near the edge of its range and the door moves a little in its frame, or a wire is loose. Bring the magnet closer to the sensor's face, and check the wires are firm under both screws.

Where this goes next

The LED, then the wires: what to check, in order.

When it does not switch →

Edit this page — content/books/door-sensor/a-door-that-nags.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Door Sensor

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum →