Автоматическое отключение воды при протечке

Я купил это двухканальное радиореле из списка совместимых контроллеров на ebay для питания привода. Тип YKT-02XX-433

Как не переплатить за умный дом. Защита от наводнений (антизатопление)

В этой статье представлен прагматичный подход к созданию одного из компонентов "умного дома" – экономичной защиты от наводнений (антизатопления) на базе универсального контроллера домашней автоматизации.

Основное отличие от предыдущих решений этой проблемы, представленных на хабах – простота реализации, относительная дешевизна + не нужно быть программистом, чтобы это воспроизвести. Правда, паять все равно придется, но только 2 раза.

Введение

Много статей по умному дому публикуется на хабах – ресурсе для технически активных людей, где люди ищут советы и решения проблем.
И в комментариях часто звучит сетование на то, что никто еще не придумал мощного, простого в освоении и экономически эффективного способа реализовать умный дом для обычных людей одновременно. Нужно паять, нужно кодить, часто на разных языках: для микроконтроллера, для сети и так далее.
Но купить дешевый кубик с деталями и запустить его самому – это редкость.

Вот я и решил вставить свои 5 копеек, потому что, похоже, только что попался один из вариантов умного дома, который может подойти многим прагматично настроенным потребителям.

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

Итак, согласно моей "Пирамиде потребностей Маслоу для умного дома" (с) – важность сигнализации и предотвращения наводнений находится на том же уровне, что и важность сигнализации от взлома или дыма.

Пирамида потребностей Маслоу для умного дома

Действительно, масштабы трагедии могут быть пугающими:

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

Краны

Вот два крана (TK12):
изображение
На каждом из них есть плотный бумажный след 🙂
изображение
Разбираем кран на две части:
изображение
Сторона крана:
изображение
Серьезная металлическая шестеренка, которая закрывает шаровой кран. В первых версиях она была пластиковой, но они исправили этот недостаток. Со стороны двигателя:
изображение
Также металлическая шестерня для выходного вала редуктора (устройство, которое уменьшает скорость и увеличивает мощность). Все выглядит серьезно. Клапаны тоже специальные – с низким коэффициентом трения, чтобы маленькому моторчику было легче поворачивать клапан. Его очень легко закрыть – вы можете повернуть его пальцем без особых усилий. В других системах есть краны с двигателем на 220 вольт, но тут возникает другая проблема – безопасность и невозможность отключить кран в случае перебоев с электричеством. А закон Мерфи гласит, что электричество отключится в самый неподходящий момент. Поэтому я предпочитаю переплатить за низковольтный моторизованный кран.

Проводной датчик затопления (TK24) так же прост, как сборка часов:
изображение
Провод, корпус и стекловолоконная пластина с двумя контактами. Когда контакты намокают, сопротивление падает, контроллер определяет это и перекрывает подачу воды. Ничего не ломается – контакты покрыты погружным золотом, что означает, что они не окисляются и не гниют.
Контактные площадки:
изображение
Это датчик "премиум-класса", или, проще говоря, с защитой от обрыва провода. Проблема в том, что для контроллера неисправный "нормальный" датчик и датчик с оборванным проводом – это одно и то же. Защитой от этого является простой конденсатор:
изображение
Он проводит переменный ток, и по его наличию контроллер уже может определить три состояния – короткое замыкание (затопление), отсутствие короткого замыкания (датчик на месте) и отсутствие контакта (оборванный провод).
Датчик очень прост и, если у вас есть умелые руки, вы можете сделать любое их количество в соответствии с вашими потребностями – хоть из ЛУТ текстолита, хоть из двух полосок олова и проволоки. Нужно только позаботиться о защите от брызг – иначе однажды, принимая душ, вам придется вылезать из ванны и объяснять контроллеру, что это был не потоп, а упала капля 🙂 Но я имел в виду самодельный датчик – у "фирменных" датчиков конструкция корпуса защищает их от случайных брызг. Кроме того, они будут работать, только если уровень воды достигнет 1 мм по всему датчику – это примерно 10-15 мл воды.

Радиобаза и датчики

изображение
Дополнительный блок (TK17), который добавляет несколько беспроводных датчиков к обычным датчикам. В комплект входят два датчика, но можно приобрести и добавить еще 6 – они подключаются к этому блоку. Еще 12 датчиков подключаются к блоку расширения (TK19). Итого, общее количество беспроводных датчиков – 20. Не знаю, зачем столько, разве что для какого-нибудь большого коттеджа.
Базовая плата радиоприемника имеет свой ионистор, чтобы не тратить энергию основной платы на поддержку радиодатчиков.
изображение
Контроллер, и еще одна пищалка:
изображение

А вот и радиодатчики:
изображение
Правый – просто датчик (TK16), а левый – датчик дистанционного управления (TK18). Кнопки можно использовать для закрытия и открытия кранов в любое время.
На обратной стороне обоих датчиков находится печатная плата с контактами, с которыми мы уже знакомы:
изображение
Демонтаж датчика довольно прост – нужно поддеть плоской отверткой среднюю часть по очереди со всех сторон. Она очень прочно удерживается на месте – как я понимаю, это сделано для предотвращения попадания воды.
изображение
Кстати, сенсор с кнопкой – это то же самое, что и сенсор без кнопки, только с кнопкой:
изображение
Так что если руки чешутся, а паяльник горячий, то кнопка вполне возможна – я проверил, контакты работают.
На обратной стороне платы находятся контакты для подключения батареек (2xAAA):
изображение
контроллер, жгут проводов и пищалка:
изображение

Датчики протечки

Датчики я купил от того же контроллера ВСУ – универсальные. У них два выхода "открытый коллектор", один притягивается к земле только когда есть вода, другой, если вода попадает внутрь, притягивается к земле все время, пока не отключится питание. Я использую только первый выход, остальная логика в контроллере, но похоже, что этот выход может быть полезен в некоторых более условных системах диспетчеризации.

Провода в комплекте имеют длину около трех метров. Цвет проводов – Hell_and_Israel. Контрольная цитата:

Красный (коричневый) провод (Vcc) питание от +5 до +30 В.
Черный (белый) провод (OUT2)
зеленый провод (OUT1)
желтый провод (GND)

Из-за этого белый/черный провод не был заземлен? Также на батарейном приводе провода имеют цветовую кодировку, а логика отключена. Первый датчик находится на кухне, под раковиной рядом с посудомоечной машиной.

Второй находится в ванной комнате в специальной дренажной канаве. Когда я делал излив, он не доходил до самой стены. Есть своего рода отстойник для сбора воды из ванной и туалета.

По опыту, у посудомоечной машины уже было одно ложное срабатывание датчика. Согласно логу для одного цикла (500 мс) это было короткое замыкание, я изменил код – теперь изменение состояния происходит при 10 последовательных одинаковых значениях с датчика.

Контакты датчика позолочены. У моего друга подобные датчики стоят уже несколько лет, окисления не замечено.

Счетчики

Самый обычный Itelma, через каждые 10 литров контакты замыкаются. Со стороны водителя выход подтянут к + 3,3в, счетчик подтягивается к земле.

Внутри


Основан на Particle Photon, подробнее здесь. У них есть версия с модулем 2G или 3G (Electron). Первая прошивка была полным отстоем, мигающие светодиоды были в порядке, но как только вы начинаете делать сложные вещи, играть с i2c и прерываниями, вы можете потерять wifi. Теперь я могу с этим жить. В принципе, вы можете убрать датчики давления из схемы и подключить ее к ESP8266. Прежде всего, необходимо привязать photon к учетной записи particle (это можно сделать через мобильное приложение или консоль Particle CLI – я использую только второй способ) и зарегистрировать сеть wifi. После привязки контроллер и статус его подключения к облаку появятся в разделе устройств здесь.

У меня все узлы подключаются к облаку только для обновления прошивки. Не то чтобы я был параноиком – просто работа с облаком потребляет не самые богатые ресурсы контроллера. IDE поддерживает работу с библиотеками, буквально десяток поддерживается самим контроллером, остальные – сообществом. Еще одна классная вещь, в IDE можно сразу увидеть, сколько проектов используют библиотеки.

Исходный код прошивки
// Этот #include оператор был автоматически добавлен Particle IDE. #include "Adafruit_SSD1306/Adafruit_SSD1306.h" // Эта инструкция #include была автоматически добавлена Particle IDE. #include "MQTT/MQTT.h" // Эта инструкция #include была автоматически добавлена Particle IDE. #include "OneWire/OneWire.h" SYSTEM_THREAD(ENABLED); SYSTEM_MODE(MANUAL); STARTUP(WiFi.selectAntenna(ANT_EXTERNAL)); STARTUP(System. enableFeature(FEATURE_RETAINED_MEMORY)); struct counter_struct < float value; byte state; int pin; >; struct valve_struct < byte state; int pin; >; struct sensor_struct < int timeout; byte state; int pin; >; unsigned long currentMillis = 0; unsigned long previous_conected = 100000; //финт ушами unsigned long previous_wifi_uptime = 100000; //финт ушами unsigned long previous_counter_read = 0; //финт ушами unsigned long wifi_uptime; unsigned long start_temp_timer = 0; unsigned long read_temp_timer = 0; byte display_timeout = 0; //temp onewire OneWire ds0 = OneWire(D2); OneWire ds1 = OneWire(D3); byte addr0[8]; byte addr1[8]; bool presense0 = false; bool presense1 = false; byte data[12]; #define OLED_RESET A7 Adafruit_SSD1306 display(OLED_RESET); // управление клапаном сохраняется valve_struct valve[2] = < , >; // управление счетчиком сохраняется counter_struct counter[2] = < , >; volatile int pressure[2] = ; #define SENSOR_TIMEOUT 10 volatile sensor_struct sensor[2] = < , >; void callback(char* topic, byte* payload, unsigned int length); byte server[] = < 192,168,2,101>; MQTT client(server, 1883, callback); bool publish_message(const char* t, const char* p, bool retain) < return client. publish(t, (uint8_t*)p, sizeof(p), retain); >bool publish_message(const char* t, int p, bool retain) < char buf_d[12]; int n = sprintf(buf_d,"%d",p); return client. publish(t, (uint8_t*)buf_d, n, retain); >bool publish_message(const char* t, float p, bool retain) < //char buf_f[18]; String s(p, 4); // dtostrf(p, 9, 4, buf_f); //int n = sprintf(buf_f,"%f",p); return client. publish(t, (uint8_t*)s.c_str(), s.length(), retain); >// получить сообщение void callback(char* topic, byte* payload, unsigned int length) < char p[length + 1]; memcpy(p, payload, length); p[length] = NULL; String message(p); String t(topic); if (t.equals("home/water_count/spark/set")) < if (message.equalsIgnoreCase("1")) < Particle.connect(); if (waitFor(Particle.connected, 10000)) else > else < Particle.disconnect(); publish_message("home/water_count/spark", 0, false); >> else if (t.startsWith("home/water_count/valve/")) < int m = message.toInt(); int x = t.substring(23,24).toInt(); if (m >-1 && m < 2 && x >-1 && x <2) < set_valve(x, m); >else < publish_message("home/water_count/valve/" + t.substring(23,24), valve[x].state , true); >> else if (t.startsWith("home/water_count/counter/")) < float m = message.toFloat(); int x = t.substring(25,26).toInt(); if (m >-1 && m -1 && x <2) < counter[x].value = m; >publish_message("home/water_count/counter/" + t.substring(25,26), counter[x].value , true); > > > void setup() < //Serial.begin(9600); WiFi. on(); WiFi.connect(); if (waitFor(WiFi.ready, 5000)) for (int i=0; i < 2; i++) < pinMode(valve[i].pin, OUTPUT); digitalWrite(valve[i].pin, valve[i].state); pinMode(counter[i]. pin, INPUT); pinMode(sensor[i].pin, INPUT); counter[i].state = digitalRead(counter[i].pin); pinMode(pressure[i], AN_INPUT); >pinMode(A4, INPUT_PULLUP); display. begin(SSD1306_SWITCHCAPVCC, 0x3C); // инициализируем с I2C addr 0x3C (для 128×64) display.clearDisplay(); // очищаем экран и буфер //Particle. connect(); > void loop() < currentMillis = millis(); // проверяем наличие сети и подключения к MQTT брокеру if (currentMillis – previous_conected >= 30000 || previous_conected > currentMillis) < previous_conected = currentMillis; if (! client.isConnected() & wifi_uptime >60) < mqtt_connect(); >publish_message("home/water_count/rssi", WiFi.RSSI(), true); > if (currentMillis – previous_wifi_uptime >= 1000 || previous_wifi_uptime > currentMillis) < previous_wifi_uptime = currentMillis; WiFi. ready() ? wifi_uptime++ : wifi_uptime = 0; //praca z przyciskiem i wyświetlaczem int fg = digitalRead(A4); if (display_timeout >0) < display_timeout -= 1; if (display_timeout == 0) < display. clearDisplay(); display.display(); >> if (fg == 0) < if (display_timeout == 0) < display.clearDisplay(); // czyści ekran i bufor display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(0,0); display.print("C="); display.println(counter[0].value, 4); display. setCursor(0,16); display.print("H="); display.println(counter[1].value, 4); display.setCursor(0,32); display.print("Valve="); display.print(valve[0].state); display.print("|"); display. println(valve[1].state); display.setCursor(0,48); display. print("Sensor="); display.print(sensor[0].state); display.print("|"); display.println(sensor[1].state); display. display(); >display_timeout = 10; > > //sprawdzenie licznika if (currentMillis – previous_counter_read >= 500 || previous_counter_read > currentMillis) < previous_counter_read = currentMillis; for (int i=0; i < 2; i++) < byte count_state = digitalRead(counter[i]. pin); if (count_state != counter[i]. state) < counter[i].state = count_state; if (count_state == 0) < counter[i].value += 0.01; char buf18[30]; sprintf(buf18, "home/water_count/counter/%d", i); publish_message(buf18 , counter[i]. value, true); >> // // работаем с датчиком протечки byte sensor_state = digitalRead(sensor[i]. pin); if (sensor_state != sensor[i].state) // < sensor[i].state = sensor_state; sensor[i].timeout = SENSOR_TIMEOUT; >if (sensor[i].timeout > 0) < sensor[i]. timeout -= 1; if (sensor[i].timeout == 0) < char buf18[30]; sprintf(buf18, "home/water_count/sensor/%d", i); publish_message(buf18 , sensor[i].state, true); if (sensor[i]. state == 0) < set_valve(0, 1); //zamknij oba zawory set_valve(1, 1); //zamknij oba zawory >> > > // temp onewire if (currentMillis – start_temp_timer >= 299000 || start_temp_timer > currentMillis) < //стартуем расчет start_temp_timer = currentMillis; presense0 = start_temp0(); presense1 = start_temp1(); >if (currentMillis – read_temp_timer >= 300000 || read_temp_timer > currentMillis) > //Particle.process(); client.loop(); > void mqtt_connect() < if (client.connect("water_count")) < //подписываемся на spark и публикуем последнее состояние client.subscribe("home/water_count/spark/set"); publish_message("home/water_count/spark", Particle.connected() ? 1 : 0, true); client.subscribe("home/water_count/valve/+/set"); client.subscribe("home/water_count/counter/+/set"); >> bool start_temp0() < if ( ! search(addr0)) < ds0.reset_search(); return false;>ds0.reset_search(); if (OneWire::crc8(addr0, 7) != addr0[7]) < return false;>ds0.reset(); ds0.select(addr0); ds0. write(0x44, 0); return true; > bool start_temp1() < if ( !ds1.search(addr1)) < ds1.reset_search(); return false;>ds1.reset_search(); if (OneWire::crc8(addr1, 7) != addr1[7]) < return false;>ds1. reset(); ds1.select(addr1); ds1. write(0x44, 0); return true; > bool read_temp0() < //delay(1000); ds0.reset(); ds0.select(addr0); ds0.write(0xBE, 0); for (int i = 0; i < 9; i++) < data[i] = ds0. read(); >int16_t raw = (data[1] 100) return false; publish_message("home/water_count/temp/0", celsius, false); //Serial. println(celsius); ds0. reset_search(); return true; > bool read_temp1() < //delay(1000); ds1.reset(); ds1.select(addr1); ds1.write(0xBE, 0); for (int i = 0; i < 9; i++) < data[i] = ds1. read(); >int16_t raw = (data[1] 100) return false; publish_message("home/water_count/temp/1", celsius, false); //Serial.println(celsius); ds1.reset_search(); return true; > void set_valve(int vlv, byte state) < valve[vlv]. state = state; digitalWrite(valve[vlv].pin, state); char buf26[26]; sprintf(buf26, "home/water_count/valve/%d", vlv); publish_message(buf26 , state , true); >

Подключение к брокеру через MQTT. Мониторинг датчиков и отправка событий и значений в соответствующие ветви mqtt. Например, home/water_count/valve/0 – контроль холодной воды. home/water_count/counter/0 – показания счетчика охлажденной воды.

Напишите автоматизацию. Независимо и на ваш вкус

Прямое управление приводами водоснабжения – дополнительная функция комплекта от Aqara и Gidrolock. Комплект предназначен для аварийного перекрытия труб в случае обнаружения утечки и оповещения вас с помощью push-уведомлений и светозвуковой сигнализации на концентраторе M1S. Для этого потребуется настроить автоматику. Для этого вам понадобится датчик, реагирующий на появление воды.

ВАЖНО: Базовый сценарий работает даже без доступа в Интернет (при условии, что реле и датчики подключены к одному концентратору) – все, что нужно, это источник питания 220 В, и вода будет отключена автоматически.

Базовый сценарий, предлагаемый производителем, используется для аварийного отключения воды при обнаружении утечки. Для этого

1. Войдите в приложение Aqara.
2. Перейдите в раздел &#39;Автоматизация&#39; -> «+».
3. В разделе ЕСЛИ добавьте датчик утечки.
4. Установите условие "Обнаружена утечка"..
5. В THEN Добавьте подключенное реле.
6. Установите действие "Включение"..
7. Нажмите кнопку Сохранить . Присвоить имя.
8. Подтвердите создание автоматизации.

Аналогичным образом создаются автоматизации для отправки PUSH-сообщения и задание на регулярное самообслуживание электроприводов для поддержания их в рабочем состоянии (не реже одного раза в квартал).

Gidrolock можно интересно комбинировать с другими устройствами Aqara: например, подача воды может быть прекращена по сигналу умного замка (оставить – закрыть воду) или датчика движения (аналогично).

С чего начинается умный дом?

Сотрудничество между Aqara и Gidrolok, безусловно, является самым полезным проектом для автоматизации дома. С него, пожалуй, стоит начать всем, кто хочет создать по-настоящему умное пространство: предотвращение протечек и отключение критически важных приборов (например, утюгов) действительно помогает экономить деньги и сохранять душевное спокойствие.

Использование стандартных российских компонентов продлевает срок службы комплекта. Именно поэтому я настоятельно рекомендую его, особенно для старых жилых домов.

Затем эту базу можно дополнить датчиками для комплексной автоматизации, набором реле для управления электропитанием и видеоконтролем.

Начните с основ. Умный дом должен начинаться с комплекта Aqara и Gidrolock.

Все изображения в статье:

«Июль в Швейцарии» — издательский дом