Did someone knock while you had headphones on? Fix the knock sensor to a door or desk, and the ESP32 records every knock with the time and shows the list on your phone. The LED flashes with each knock too.
What you'll learn
- How a knock (vibration) sensor works
- How to keep a list of recent events
- How to get the real time from the internet (NTP)
What you need
- ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
- Knock sensor module (45-in-1 Sensor Kit)
- 1 LED and 1 resistor, 220 Ω
- A 2.4 GHz Wi-Fi network
- Breadboard and jumper wires (ESP32 IoT Starter Kit)
Wiring

| From | To |
|---|---|
| Knock sensor S | ESP32 GPIO 27 |
| Knock sensor + | 3V3 |
| Knock sensor − | GND |
| ESP32 GPIO 26 | 220 Ω resistor, then the LED's long leg |
| LED short leg | GND |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
The sketch
Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details (2.4 GHz only). Open the Serial Monitor at 115200 baud to see the address, then open it on a phone or computer on the same Wi-Fi.
Some versions of this module switch their output to HIGH when they trigger, others to LOW. The sketch reads the output when it starts (keep things quiet and still for a moment) and treats any change from that resting state as a trigger, so it works with both.
#include <WiFi.h>
#include <WebServer.h>
#include <time.h>
const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* TIME_ZONE = "EET-2EEST,M3.5.0/3,M10.5.0/4"; // Estonia; change for your country
const int KNOCK_PIN = 27;
const int LED_PIN = 26;
WebServer server(80);
int restState;
unsigned long lastKnock = 0;
const int LOG_SIZE = 15;
String knocks[LOG_SIZE];
int knockCount = 0;
long total = 0;
String timeNow() {
struct tm t;
if (getLocalTime(&t, 10)) {
char text[20];
strftime(text, sizeof(text), "%H:%M:%S", &t);
return String(text);
}
return String(millis() / 1000) + " s after start";
}
String page() {
String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
html += "<meta http-equiv='refresh' content='3'><title>Knock log</title></head>";
html += "<body style='font-family:sans-serif;padding:16px'><h1>Knock log</h1>";
html += "<p>Total knocks: <b>" + String(total) + "</b></p>";
if (knockCount == 0) html += "<p>No knocks yet.</p>";
for (int i = 0; i < knockCount; i++) html += "<p>" + knocks[i] + "</p>";
html += "</body></html>";
return html;
}
void setup() {
Serial.begin(115200);
pinMode(KNOCK_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
delay(300);
restState = digitalRead(KNOCK_PIN);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.print("Open http://");
Serial.println(WiFi.localIP());
configTzTime(TIME_ZONE, "pool.ntp.org");
server.on("/", []() { server.send(200, "text/html", page()); });
server.begin();
}
void loop() {
server.handleClient();
if (digitalRead(KNOCK_PIN) != restState && millis() - lastKnock > 300) {
lastKnock = millis();
total++;
for (int i = LOG_SIZE - 1; i > 0; i--) knocks[i] = knocks[i - 1]; // newest first
knocks[0] = timeNow();
if (knockCount < LOG_SIZE) knockCount++;
Serial.println("Knock!");
digitalWrite(LED_PIN, HIGH);
}
if (millis() - lastKnock > 150) digitalWrite(LED_PIN, LOW);
}
How it works
The knock sensor contains a tiny spring that touches a contact when it's shaken, so a knock briefly changes the signal. The ESP32 checks the pin thousands of times a second and treats each change as a knock, ignoring anything within 300 ms so that one knock isn't counted twice. The time comes from an internet time server, and the 15 most recent knocks are kept in a list for the web page.
Try this next
- Recognise a secret knock pattern, such as knock-knock … knock.
- Show how many knocks there were in the last hour.
- Sound the buzzer from the ESP32 kit on every knock.
Troubleshooting
- Knocks aren't detected: fix the sensor firmly to the surface with tape; it has to feel the vibration.
- One knock counts several times: increase 300 to 500 ms.
- The time shows "s after start": the ESP32 hasn't reached the time server yet; wait a minute.