Защита от потопа с беспроводными датчиками

Публикация 04.06.2017

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

В качестве беспроводных датчиков воды я взял очень дешевые и эффективные датчики открытия дверей для китайских сигнализаций. Выглядят они вот так:

Датчик двери на 433 mhz

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

Датчик воды на 433 mhz

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

Датчик охраны двери 433 mhz внутри

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

Переделка датчика двери на датчик водыПеределка датчика двери на датчик водыПеределка датчика двери на датчик воды

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

Переделка датчика двери на датчик воды

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

Принимать сигнал будет приемник на 433 mhz - XD-RF-5V.

Приемник 433mhz 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;
    }
  }
}
Файлы для скачивания:
* комментарии публикуются после модерации
Нет комментариев