Умный дом на Home Assistant и 3D печать.
 
Telegram-канал FoxJoy
Почта: dm@foxfoy.ru
"Звонок" для частного дома

"Звонок" для частного дома

Если вы живёте в частном доме и к вам не приходят свои без предупреждения или созвона, то установив обычный звонок в него могут звонить все кому не лень, а это обычно совершенно посторонние люди, которых не хотелось бы видеть. А если звонка или домофона нет - ну постучат в дверь немного и уходят не видя обратной связи. Что бы такие стуки фиксировать, я сделал на 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 оповещение, в том числе и на Яндекс колонку.

Да не сразу идеально заработало, но после добавления фильтров - работает без ложных срабатываний. По стоимости - все детали очень бюджетные.