

Если вы живёте в частном доме и к вам не приходят свои без предупреждения или созвона, то установив обычный звонок в него могут звонить все кому не лень, а это обычно совершенно посторонние люди, которых не хотелось бы видеть. А если звонка или домофона нет - ну постучат в дверь немного и уходят не видя обратной связи. Что бы такие стуки фиксировать, я сделал на ESP8266 и датчике вибрации SW-420 небольшой приборчик, который реагирует на стук в дверь.
Сделал не сложную автоматизацию:
В итоге, даже если дома ни кого нет - вы всегда будете знать во сколько и кто приходил. Если дома, то всегда можно пойти и открыть дверь, если вдруг кто-то пришёл например из соседей. Но соседи у нас все дружные - обычно проще позвонить или написать в ТГ, если есть вопросы.
Рядом с дверью у меня есть питание для камер 12V, что бы не городить огород, новое устройство я запитал обычной витой парой через понижайку типа LM2596S.

Всё уместилось в небольшом напечатанном на 3D принтере корпусе. Крышка корпуса проклеена герметиком от влаги - второй год стоит и прекрасно работает. Сам корпус закреплён на двухстороннем скотче.
Для начала уровень чувствительности датчика SW-420 нужно настроить вручную. Летом, в обеденное время, когда солнце сильно палило прямыми лучами были ложные срабатывания, в том числе от больших проезжающих машин но добавив в прошивку дополнительные фильтры я от этого избавился. Плюс можно в автоматизации дополнительно добавить условие если есть вибрация в течении 0,2 или 0,3 сек, только тогда срабатывает. И мне это помогло.
Прошивка под ESPHome:
# Датчик вибрации SW-420 и ESP8266
esphome:
name: esp8266-0
friendly_name: ESP8266-0
esp8266:
board: esp01_1m
logger:
level: DEBUG
# Enable Home Assistant API
api:
encryption:
key: "ВАШ КЛЮЧ"
ota:
- platform: esphome
password: "ВАШ ПАРОЛЬ"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Esp8266-0 Fallback Hotspot"
password: "ВАШ ПАРОЛЬ"
captive_portal:
web_server:
port: 80
binary_sensor:
- platform: gpio
pin: GPIO14 # D5
name: "Датчик вибрации без фильтра"
id: knock_raw
device_class: vibration
internal: true
- platform: template
name: "Датчик вибрации с фильтром"
id: knock_filtered
device_class: vibration
lambda: |-
static bool last_state = false;
static unsigned long last_knock = 0;
static int knock_count = 0;
static unsigned long first_knock_time = 0;
const unsigned long DEBOUNCE_MS = 50; // Антидребезг между импульсами
const unsigned long WINDOW_MS = 500; // За это время должно быть N срабатываний
const int REQUIRED_KNOCKS = 2; // Сколько срабатываний нужно для включения
const unsigned long HOLD_MS = 1000; // Держим выход в ON столько времени
bool current_state = id(knock_raw).state;
unsigned long now = millis();
// Обработка фронта: сработало ли новое включение (с антидребезгом)
if (current_state && !last_state) {
if (now - last_knock > DEBOUNCE_MS) {
last_knock = now;
// Если это первое срабатывание в серии
if (knock_count == 0) {
first_knock_time = now;
knock_count = 1;
ESP_LOGD("knock_filtered", "Первый стук зафиксирован");
} else {
// Проверяем, укладываемся ли в окно времени
if (now - first_knock_time <= WINDOW_MS) {
knock_count++;
ESP_LOGD("knock_filtered", "Счётчик стуков: %d", knock_count);
} else {
// Окно истекло — начинаем счёт заново
knock_count = 1;
first_knock_time = now;
ESP_LOGD("knock_filtered", "Окно истекло, начинаем счёт заново");
}
}
// Если достигнуто нужное количество стуков
if (knock_count >= REQUIRED_KNOCKS) {
last_knock = now; // Обновляем время последнего валидного события
knock_count = 0; // Сбрасываем счётчик
first_knock_time = 0;
ESP_LOGD("knock_filtered", "Достаточно стуков! Включаем выход.");
}
}
}
last_state = current_state;
// Держим состояние ON в течение HOLD_MS после валидного события
if (last_knock != 0 && now - last_knock < HOLD_MS) {
return true;
} else {
return false;
}
Примерная автоматизация:
alias: Долбятся в дверь
description: ""
triggers:
- type: vibration
device_id: ЗАМЕНИТЕ НА СВОЙ
entity_id: ЗАМЕНИТЕ НА СВОЙ
domain: binary_sensor
trigger: device
for:
hours: 0
minutes: 0
seconds: 2
conditions: []
actions:
- data:
filename: /config/www/snapshots/door_knock.jpg
target:
entity_id: camera.ВАША
action: camera.snapshot
- action: telegram_bot.send_photo
data:
config_entry_id: ЗАМЕНИТЕ НА СВОЙ
parse_mode: html
caption: Стук в дверь
file: /config/www/snapshots/door_knock.jpg
target:
- ЗАМЕНИТЕ НА СВОЙ
- action: media_player.volume_set
target:
entity_id:
- media_player.esp32_s3_esphome_pcm5102a_media_player
- media_player.esp32_s3_3_esphome_pcm5102a_media_player_3
data:
volume_level: 0.4
- action: tts.google_translate_say
metadata: {}
data:
cache: true
entity_id: media_player.esp32_s3_esphome_pcm5102a_media_player
message: Внимание! Кто-то стучится в дверь
- action: tts.google_translate_say
metadata: {}
data:
cache: true
entity_id: media_player.esp32_s3_3_esphome_pcm5102a_media_player_3
message: Внимание! Кто-то стучится в дверь
- action: tts.google_translate_say
metadata: {}
data:
cache: false
entity_id: media_player.yandex_station_ЗАМЕНИТЕ НА СВОЙ
message: Внимание! Кто-то стучится в дверь
- data:
filename: >-
/config/www/snapshots/door_knock_{{ now().strftime('%Y-%m-%d_%H-%M-%S')
}}.jpg
target:
entity_id: camera.ЗАМЕНИТЕ НА СВОЙ
action: camera.snapshot
enabled: false
mode: single
Тут, если сработал датчик - делаем снимок с камеры, отправляем его Телеграм-боту, потом устанавливаем предпочтительную громкость для WiFi колонок и отправляем TTS оповещение, в том числе и на Яндекс колонку.
Да не сразу идеально заработало, но после добавления фильтров - работает без ложных срабатываний. По стоимости - все детали очень бюджетные.