ESP32 — налаштовуємо сповіщення про зникнення живлення

Цей приклад показує, як зробити просту систему на базі ESP32, яка може визначати, коли пропадає або з’являється живлення, і передавати цю інформацію до Home Assistant. Усе це реалізується через прошивку ESPHome, яка спрощує роботу з ESP-пристроями й не вимагає складного програмування.

У прикладі використовується плата Lolin D32, тому що вона має зручний USB-порт для живлення й роз’єм для акумулятора. Завдяки цьому ESP може продовжувати працювати навіть тоді, коли зникає напруга в розетці

Крім відстеження стану живлення, через Home Assistant система може надсилати сповіщення різними каналами, включно з email, мобільними додатками або вбудованими повідомленнями Home Assistant, що дозволяє миттєво дізнаватися про відключення електрики або повернення живлення.

Коротка версія

Я налаштував ESP32, щоб отримувати сповіщення, якщо зникає живлення. Ідеально, якщо ESP має і USB-порт, і роз’єм для батареї, а також пін, на якому з’являється напруга лише тоді, коли живлення подається через USB. Хоча, ймовірно, те саме можна реалізувати за допомогою дрібки вправного паяння і на інших платах ESP, які не мають усіх цих елементів.

Довга версія

У мене вдома кілька пристроїв на базі ESP, деякі з яких я вважаю критичними. Наприклад, ті, що вимірюють температуру у морозильнику. Проблема в тому, що якщо холодильник/морозильник знеструмлюється, той ESP-пристрій перестає його контролювати.

Мені важливо знати, до якої температури нагрівся морозильник до того, як живлення відновилося — щоб зрозуміти, чи потрібно викидати продукти. Також я хочу отримувати сповіщення, якщо хтось випадково вимкне холодильник/морозильник і сам ESP-пристрій (що вже траплялося) — щоб швидко відреагувати.

Це лише один приклад сценарію використання. Наприклад, у мене розставлені ESP-пристрої по будинку для BLE-відстеження присутності. Вони теж могли б сигналізувати, якщо якась конкретна лінія живлення знеструмлюється через вибитий запобіжник.

Примітка: усе мережеве обладнання живиться від UPS, тож якщо зникає живлення, мережа певний час ще працює, а отже — сповіщення продовжують надходити.

Раніше я фактично давав деяким ESP «міні-UPS»: просто підключав ESP до USB-павербанка, який був під’єднаний до зарядного пристрою в розетці. Це працювало добре й дозволяло використати старі елементи 18650. Але контролювати можливі проблеми було складно.

Як я це реалізував

Я переглянув форуми — не знайшов готових прикладів такої схеми. Люди радили зовнішні AC-реле чи інші дорожчі варіанти (на кшталт використання Ring Extenders), але все виглядало занадто складним і дорогим. Можливо, я просто пропустив чийсь кейс, але вирішив зробити власну реалізацію.

Моя ідея:

  • ESP живиться від USB, але має резервну батарею.
  • Якщо живлення зникає, пристрій переходить на батарею й фіксує, що на лінії 5В немає напруги, після чого надсилає сповіщення.
  • Коли живлення повертається — надсилається ще одне сповіщення.

Обладнання

Я обрав Lolin D32 — це перевірена, дешева плата з USB та роз’ємом для батареї. Як бонус — у мене була запасна. Вона має пін «USB», на який подається напруга, коли плата живиться від USB.
Я просто підключив цей пін до одного з GPIO, щоб відстежувати, коли живлення з’являється або зникає.

Код виявився нескладним. Тестування пройшло з першого разу. Я використовую Bermuda для BLE-відстеження, тож приклад коду був саме для цього сценарію, але базовий принцип можна адаптувати для будь-якого іншого ESP-пристрою, просто змінивши GPIO.

# Compiled and tested on esphome 2025.2.2 and HA 2025.3.0
# Notes:
#  * need to jumper between USB pin and pin 16 - when USB power is connected, power goes to the USB pin and sets pin 16 high
#  * Using a Lolin D32 as cheap and has built in battery socket
#  * Note that need to check polarity on battery - in my case frequently they are reversed.

substitutions:
  name: ble03
  friendly_name: ble03
  devicename: ble03
  location: master

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  min_version: 2024.6.0
  name_add_mac_suffix: false
  project:
    name: ninkasi.ble
    version: '1.1'
  comment: BLE Sensor LOLIN D32 $location
  platformio_options:
    build_flags:
      - "-D CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=1" # Putting this in temporarily to remove warning “legacy adc calibration driver is deprecated" message during compilation - https://github.com/esphome/issues/issues/5153#issuecomment-1847547482

esp32:
  board: esp32dev
  framework:
    type: esp-idf
    version: recommended
    # Custom sdkconfig options
    sdkconfig_options:
      COMPILER_OPTIMIZATION_SIZE: y
    # Advanced tweaking options
    advanced:
      ignore_efuse_mac_crc: false

# Enable logging
# Change to avoid "Components should block for at most 20-30ms" warning messages in the log - an issue since 2023.7.0
# Not really a breaking change - it's an issue I suspect due to the device being slow and this error previously
# simply not being reported
logger:
  baud_rate: 0  # disable serial uart logging to maybe save a little ram
  logs:
    component: ERROR

api:
  encryption:
    key: !secret esphome_encryption_key

ota:
  password: !secret ota_password
  platform: esphome

wifi:
  networks:
  - ssid: !secret wifIoT_ssid
    password: !secret wifIoT_password
    priority: 2
# Backup SSID just in case
  - ssid: !secret wifi_ssid
    password: !secret wifi_password
    priority: 1
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "$devicename Fallback Hotspot"
    password: !secret ota_password

esp32_ble_tracker:
  scan_parameters:
#    continuous: True
    active: True
    interval: 211ms # default 320ms
    window: 120ms # default 30ms

bluetooth_proxy:
  active: true
  
sensor:
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: wifisignal
    update_interval: 60s
    unit_of_measurement: dBm
    accuracy_decimals: 0
    device_class: signal_strength
    state_class: measurement
    entity_category: diagnostic
  - platform: copy # Reports the WiFi signal strength in %
    source_id: wifisignal
    id: wifipercent
    name: "WiFi Signal Percent"
    filters:
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "Signal %"
    entity_category: "diagnostic"
  - platform: uptime
    id: uptime_s
    name: "$devicename Uptime"
    update_interval: 60s          
  - platform: template
    name: $devicename free memory
    lambda: return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
    icon: "mdi:memory"
    entity_category: diagnostic
    state_class: measurement
    unit_of_measurement: "b"
    update_interval: 60s
# Define the battery pin (GPIO35) as an ADC sensor
  - platform: adc
    pin: GPIO35
    name: "Battery Capacity"
    id: battery_capacity
    icon: mdi:battery-medium
    unit_of_measurement: "%"
    accuracy_decimals: 0
    attenuation: 12db
    update_interval: 60s  # Update every 60 seconds (adjust as needed)
    filters:
      - multiply: 2.0
      - median:
          window_size: 7
          send_every: 7
          send_first_at: 7
      - throttle: 15min
      - calibrate_polynomial:
         degree: 3
         datapoints:
          - 0.00 -> 0.0
          - 3.30 -> 0.0
          - 3.35 -> 5.0
          - 3.39 -> 10.0
          - 3.44 -> 15.0
          - 3.48 -> 20.0
          - 3.53 -> 25.0
          - 3.57 -> 30.0
          - 3.62 -> 35.0
          - 3.66 -> 40.0
          - 3.71 -> 45.0
          - 3.75 -> 50.0
          - 3.80 -> 55.0
          - 3.84 -> 60.0
          - 3.88 -> 65.0
          - 3.92 -> 70.0
          - 3.96 -> 75.0
          - 4.00 -> 80.0
          - 4.05 -> 85.0
          - 4.09 -> 90.0
          - 4.14 -> 95.0
          - 4.20 -> 100.0
      - lambda: |-
          if (x <= 100) {
            return x;
          } else {
            return 100;
          }

    on_value_range:
      # Trigger an action if the battery voltage goes below a threshold (e.g., 3.3V)
      - above: 30
        then:
          - logger.log: "Battery voltage is above threshold"
      - below: 30
        then:
          - logger.log: "Battery power detected (below threshold)"

# Optional: Set a custom threshold to trigger actions, e.g., battery level below 3.3V
binary_sensor:
  - platform: template
    name: "Low Battery"
    lambda: |-
      if (id(battery_capacity).state < 30) {
        return true;
      } else {
        return false;
      }
    on_press:
      - logger.log: "Battery is low"
    on_release:
      - logger.log: "Battery is back to normal"

# Define the GPIO pin connected to USB power detection
  - platform: gpio
    pin: 16  # GPIO pin connected to USB power
    name: "USB Power Status"
    device_class: power
    filters:
      - delayed_on: 100ms
      - delayed_off: 100ms
    on_press:
      # Action to take when USB power is disconnected (i.e., running on battery)
      then:
        - logger.log: "Running on battery power"
    on_release:
      then:
        - logger.log: "Running on USB power"
        # Optionally, trigger actions for when USB power is present

Щоб повторити це:

  1. Скомпілюйте код (адаптуючи під свій пристрій).
  2. Завантажте його на ESP32.
  3. Підключіть джамперний дріт від USB-піну до GPIO 16 (спочатку я використовував GPIO 5 — теж працює, але на 16 немає попереджень про strap pin).
  4. Під’єднайте батарею та USB-зарядку.

Схема максимально проста — дріт між двома пінами.

Примітки та поради

  • Тепер, коли я переконався, що це працює, планую перевести на таку схему кілька сенсорів. Не всі, але ключові — точно.
  • Можна використовувати й інші ESP-плати — оберіть те, що вам зручно.
  • Я ще не тестував систему довгостроково, але наразі вона стабільна.
  • Батарея з часом деградує, бо постійно перебуває на зарядці. Хоча Lolin періодично відключає зарядку, я досліджую, до якого рівня батарея має розрядитися, щоб процес зарядки знову почався.
  • Є невеликий ризик, що батарея може вийти з ладу із займанням, тому не варто ховати пристрій у важкодоступних місцях (наприклад, на горищі).
  • Я використав батарею 1200 мА·год — цього вистачає, щоб ESP32 працювала як BLE-трекер понад 8 годин. Для інших задач можна використати меншу ємність.
  • Ви можете налаштувати, щоб ESP сама надсилала сигнали чи мигала лампочками, але я вважаю за краще реалізовувати логіку через окрему систему автоматизації. Так легше керувати сценаріями.
alias: Alert - ble03 has detected a power outage!
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.ble03_usb_power_status
    to: "off"
    for:
      hours: 0
      minutes: 0
      seconds: 5
conditions: []
actions:
  - data:
      title: ble03 has detected a power outage!
      message: ble03 has detected a power outage!
    action: persistent_notification.create
  - metadata: {}
    data:
      message: ble03 has detected a power outage!
      title: ble03 has detected a power outage!
      target: [email protected]
    action: notify.example_com
  - action: notify.mobile_app_pixel_9_pro
    data:
      message: ble03 has detected a power outage!
      title: ble03 has detected a power outage!
mode: single

Це простий та дешевий спосіб перетворити звичайну ESP32 на датчик зникнення живлення — без дорогих реле чи складних схем. Ідеальний варіант для моніторингу критичних точок живлення у будинку, особливо якщо ваша мережа підтримується UPS.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось7
До обраногоВ обраному6
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Сама концепция датчика вполне хороша, однако не стоит 5V от USB кидать напрямую на GPIO, который согласно ТТХ производителя чипсета рассчитан на 3.3V. Лучше добавить делитель напряжения. Или купить копеечный TTL конвертор 5V<->3.3V на али.

або шоткі діод з резистором

як зробити просту систему на базі ESP32, яка може визначати, коли пропадає або з’являється живлення, і передавати цю інформацію до Home Assistant.

Тобто у нас цілий пристрій який харчується через UPS тільки для того щоб сказати коли з’явиться основне живлення? А хіба не можна просто дивитися з HA онлайн якийсь пристрій без резервного живлення чи ні і коли він з’являється? Там для цього навіть сенсор є:

binary_sensor:
  - platform: status
    name: "ESP Device Online"
    entity_id: sensor.my_esp_sensor
Варіант що пристрій не в мережі з інших причин виглядає малоімовірним. Пристроєм може бути той же розумний лічильник.

Так достатньо зігбі датчик відкриття дверей під’єднати до копійчаного датчику наявності живлення на базі оптрона. У Квазіса було відео, зробив собі такий самий

Я очень извиняюсь, но у меня с этим функционалом уже несколько лет справляется мобильный клиент для роутера. Ушел роутер со связи — выключили. Вернулся — включили. Правда лаг несколько минут, но не думаю что это критично.

**картинка умного негра** >> pl.aliexpress.com/...​tem/1005004857654505.html
в целом задача типовая и облизана уже десятилетия как, у китайцев есть уйма готового хоть DIN хоть подешевле

Пля, вже до ембеддед зі своїми yaml дорвалися...

Я тебе страшную вещь скажу. До святого Device tree богомерзсеий y’all добрался.

Мені важливо знати, до якої температури нагрівся морозильник до того, як живлення відновилося

Якщо це не якийсь ремоут холодильник, то достатньо просто подивитися на наявність льоду на продуктах, чи спеціально покласти напівзаповнену пляшку з водою, якщо розтало — викидати.
Але нормальний сучасний завантажений морозильник витримає кілька діб без розморозки, якщо туди не заглядати.

Якщо у вас WiFi, то навіщо ще BLE? Зникло світло, кинули в mqtt повідомлення, з’явилося — теж, а далі HA обробить

Мені важливо знати, до якої температури нагрівся морозильник до того, як живлення відновилося — щоб зрозуміти, чи потрібно викидати продукти.

Вирішення неіснуючої проблеми однако.

Для кого як, відключення бувають і не 4 через 2, а аварійно на добу, все залежить приватний сектор чи квартира або куди поцілили в цей раз. Може бути холодильник вдома, може бути морозильна камера на дачі.

Морозилка працює без електрики, ще двоє діб, чисто на залишковому холоді. За 2 дні або з,явиться світло, або увімкнення генератор

це основна проблема всіх diy проектів, немає цілі це все просто для фана.
в самого коробка малинок валяється, з різними машинками або сигналізаторам повітряних тривог і тд.

Не вистачає корпуса, надрукованого на 3д принтері

Підписатись на коментарі