dontsovcmc / waterius

Передача показаний воды по Wi-Fi. Watermeter Wi-Fi transmitter.
https://waterius.ru
GNU Lesser General Public License v3.0
564 stars 108 forks source link

Обнаружение протечки по потреблению #202

Open dontsovcmc opened 2 years ago

dontsovcmc commented 2 years ago

Идея реализовать детектирование равномерного расхода воды в течении некоторого времени. Пример реализации: https://www.saures.ru/resheniya/kvartira/kontrol-protechek/

В чём вижу проблему: счетчики воды бывают 3-х классов. Обычно класс В - он обязан крутиться от 30л/час. класс А - от 60л/час. Класс С почти нет - 15л/час. Поэтому протечку сложно будет детектировать.

Алгоритм:

  1. Запоминаем через сколько циклов пришёл новый импульс.
  2. Если число циклов отличается от предыдущего числа на +- Х шт (гистерезис), то увеличиваем Y на единицу. Иначе Y=0.
  3. Если Y превысил порог - тревога.

Пример: Пусть тревога - 50 литров за 30мин. Счетчик на 10л/имп. Значит вода должна литься с одинаковой скоростью каждые 50л/30мин = 10л/3мин Т.е. 1 импульс через каждые 180сек или 180*4 = 720 итераций пробуждения.

Те протечка - это если 5 раз подряд пришёл импульс через интервал не больше 720 итераций. И эти интервалы близки.

Примерный ход разработки:

  1. добавить CounterState - LEAK
  2. добавить переменные leak_wdt_limit0, leak_wdt_limit1;

define LEAK_WDT_LIMIT_DEFAULT 720

define LEAK_COUNT_DEFAULT 5

uint16_t wdt_prev; uint16_t leak_wdt_limit0 = LEAK_WDT_LIMIT_DEFAULT; uint16_t leak_wdt_limit1 = LEAK_WDT_LIMIT_DEFAULT; uint16_t leak_count0 = 0; uint16_t leak_count1 = 0;

.... bool is_leak(uint16_t &limit, uint16_t &count) { if (wdt_prev > 0) {

uint16_t diff = wdt_count - wdt_prev; if (wdt_count < wdt_prev) //перешли через wakeup_period { diff = wakeup_period - wdt_prev + wdt_count; }

if (abs(limit - diff) < LEAK_WDT_HISTERESIS) { count++; if (count >= LEAK_COUNT_DEFAULT) { return true; } } } else { count = 0; } } else { wdt_prev = wdt_count; } return false; }

.... if (counter0.is_impuls()) {

if (is_leak(leak_wdt_limit0, leak_count0)) { info.state.states0 = LEAK; wdt_count = wakeup_period; //пробуждаемся } }