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

Удивительно то, что существуют аналогичные датчики воды, которые отличаются отсутствием геркона и наличием контактов для воды. Стоимость их в три раза выше, чем у дверных. Видимо, спрос на дверные понизил цену...

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

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



Передатчик кладется нижней крышкой с контактами на кафель (встает как на ножках) и ожидает замыкания контактов водой.

Питается устройство от батарейки на 12 вольт. В спящем режиме практически ничего не расходует и по тому пихаем устройство под ванную и забываем о нем.
Принимать сигнал будет приемник на 433 mhz - XD-RF-5V.

Для обработки сигнала используется библиотека RemoteReceiver.h - прекрасно понимает сигналы устройств: SC5262 / SC5272, HX2262 / HX2272, PT2262 / PT2272, EV1527, RT1527, FP1527 или HS1527. Совместима с Arduino и ESP8266.От данной библиотеки нам нужно только вовремя получать код устройство и больше ничего.
Схема и подключаемые серво-краны никак не изменились. О ней можно узнать в статье о системе защиты от потопа. Отличия в том, что мы подключаем на порт 5 приемник 433mhz и обновляем прошивку. Программа как и раньше работает с аналоговым датчиком. Коды беспроводных датчиков нужно предварительно считать по uart (подключить устройство по usb и выполнить срабатывание датчика на воду) и все их дописать в массив прошивки (скетча).
Обновленная версия скетча для ESP8266:
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <RemoteReceiver.h> const char *ssid = "xxxxxx"; // Имя роутера const char *pass = "xxxxxx"; // Пароль роутера const char *mqtt_server = "m13.cloudmqtt.com"; // Имя сервера MQTT const int mqtt_port = 14483; // Порт для подключения к серверу MQTT const char *mqtt_user = "xxxxxx"; // Логи для подключения к серверу MQTT const char *mqtt_pass = "xxxxxx"; // Пароль для подключения к серверу MQTT unsigned long transmitter_ids[] = {670536, 670537, 670538}; // уникальные коды датчиков потопа на которые будет реагировать устройство const int sensor = 1; // датчик воды const int drive1 = 3; // кран const int led = 5; // диод на плате const int receiver = 2; // пин для приема сигнала #define BUFFER_SIZE 100 int tm = 300; float temp = 0; bool sensor_is_alarm = false; bool drive1_is_close = false; WiFiClient wclient; PubSubClient client(wclient); void setup() { Serial.begin(115200); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); // конфигурация приемника 433 mhz RemoteReceiver::init(false, receiver, readCode); delay(10); Serial.println(); Serial.println(); pinMode(led, OUTPUT); pinMode(sensor, INPUT_PULLUP); pinMode(drive1, OUTPUT); digitalWrite(drive1, LOW); } void loop() { // подключаемся к wi-fi if (WiFi.status() != WL_CONNECTED) { Serial.print("Connecting to "); Serial.print(ssid); Serial.println("..."); WiFi.begin(ssid, pass); if (WiFi.waitForConnectResult() != WL_CONNECTED) return; Serial.println("WiFi connected"); } // подключаемся к MQTT серверу if (WiFi.status() == WL_CONNECTED) { if (!client.connected()) { Serial.print("Connecting to MQTT server "); Serial.print(mqtt_server); Serial.println("..."); if (client.connect("arduinoClient", mqtt_user, mqtt_pass)) { Serial.println("Connected to MQTT server"); // подписываемся по топики client.subscribe("valve/1"); client.subscribe("valve/alarm"); } else { Serial.println("Could not connect to MQTT server"); } } readSensor(); if (client.connected()){ client.loop(); sendCurrentValue(); delay(1); } } } // Функция проверки радио датчика воды (433 mhz) void readCode(unsigned long receivedCode, unsigned int period) { Serial.print("Recived 433mhz code: "); Serial.println(receivedCode); if (sensor_is_alarm == false) { for (int i = 0; i < sizeof(transmitter_ids); i++) { if (transmitter_ids[i] == receivedCode) { // сработал датчик потопа sensor_is_alarm = true; drive1_is_close = true; Serial.println("Alarm on"); } } } } // Функция проверки аналогового датчика воды void readSensor() { int sensorValue = analogRead(sensor); if (sensorValue < 1023 && sensor_is_alarm == false) { // сработал датчик потопа sensor_is_alarm = true; drive1_is_close = true; Serial.println("Alarm on"); } if (drive1_is_close == true) digitalWrite(drive1, HIGH); else digitalWrite(drive1, LOW); digitalWrite(led, sensor_is_alarm); } // Функция отправки показаний void sendCurrentValue() { if (tm == 0) { // отсылаем текущий статус client.publish("valve/alarm", String(sensor_is_alarm)); client.publish("valve/1", String(!drive1_is_close)); tm = 3000; // пауза меду отправками 3 секунды } tm--; } // Функция получения данных от сервера void callback(char* topic, byte* bpayload, unsigned int length) { // конвертируем byte в sting String payload = ""; for (int i = 0; i < length; i++) { payload = payload + (char)bpayload[i]; } Serial.print(topic); // выводим в сериал порт название топика Serial.print(" => "); Serial.println(payload); // выводим в сериал порт значение полученных данных // проверяем из нужного ли нам топика пришли данные if(topic == "valve/1" && sensor_is_alarm == false) { int value = payload.toInt(); if (value == 0) drive1_is_close = true; else drive1_is_close = false; } if(topic == "valve/alarm") { int value = payload.toInt(); if (value == 0) { sensor_is_alarm = false; } else { sensor_is_alarm = true; drive1_is_close = true; } } }