MQTT прошивка сенсорного выключателя Sonoff Touch

Sonoff – это устройства для умного дома от компании ITEAD с поддержкой Wi-Fi, основанные на чипах ESP8266 или ESP8285. Интерес к Sonoff состоит в том, что в одной крошечной и довольно симпатичной коробочке поместились ESP-модуль, блок питания, реле или датчики. И самое главное - его можно довольно легко перепрограммировать и внедрить в свою экосистему "умного дома".

Sonoff Touch - настенный Wifi выключатель с сенсорным управлением. Основан на микросхеме ESP8285 и может управлять одним реле.

Для управления выключателем  в локальной сети по протоколу MQTT необходим  MQTT брокер mosquitto, предустановленный на компьютер или роутер с прошивкой OpenWRT. Также необходим MQTT клиент такой как MQTT Dash для Андроид или же что-то более масштабное такое как умный дом MajorDoMo.


В любом случае без MQTT брокера и клиента нам не обойтись.



Подготовка к прошивке выключателя.

Снимаем крышку, для этого отвёрткой снизу поддеваем Touch панель.


Снимаем плату. Для удобства можно припаять четыре контакта.



Для прошивки чипа нужен  USB-TTL конвертер, к примеру CP2104 CNT-003A работающий с напряжением 3.3В.


Соединяем конвертер и выключатель 4 проводами следующим образом:

GND выключатель  - GND конвертер
RX выключатель     - TX конвертер
TX выключатель     - RX конвертер
3.3В выключатель   - 3.3В конвертер (VCC)


Осторожно напряжение должно быть не более 3.3В.




Чтобы перевести ESP8285 в режим программирования, необходимо соединить контакты GPIO-0 и GND.


В Arduino IDE устанавливаем настройки чипа в меню Инструменты ->


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


В моём случае это 12 порт.


GPIO-13 синий светодиод WiFi
GPIO-12 реле 2A при 230 В переменного тока
GPIO-0 кнопка Touch панель

Простейший скетч для выключателя.

Остаётся только присвоить значения переменным

  1. ssid                - название Wi-Fi сети
  2. password       - пароль от Wifi
  3. mqtt_server   - IP адрес MQTT брокера в локальной сети к примеру 192.168.8.1
  4. NAME          - Имя выключателя к примеру kitchenSwitch значит команды на вкл/выкл будут ходить по пути kitchenSwitch/comand, а подтверждения по пути kitchenSwitch/alive.

Если MQTT брокер защищён логином и паролем необходимо так же присвоить переменным mqtt_user и mqtt_password правильные значения. И не забыть убрать слеш // перед ними.

Вот теперь можно заливать скетч.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

//--------------WIFI---------------------//
const char* ssid = "................";  // SSID Имя Wifi
const char* password = "............";  // Введи пароль от Wifi
const char* mqtt_server = ".........";  // IP адрес MQTT брокера
#define NAME  "..........."           // Имя выключателя

//const char* mqtt_user = "majordomo";
//const char* mqtt_password = "123456";

//--------------MQTT и топики----------------//
const char *comand = NAME "/comand";
const char *topicIP = NAME "/IP";           // отправляет IP
const char *topicInfo = NAME "/info";        // отправляет инфу о подкл. датчиках
const char *lightAlive = NAME "/alive";

//--------------Переменные-----------------//
#define LED_PIN     13
#define RELAY_PIN     12
#define BUTTON_PIN     0
int a, cn;
volatile int desiredRelayState = 0;
volatile int relayState = 0;
unsigned long lastMQTTCheck = -5000; //Это заставит немедленно проверить init.

//--------------Инициализация----------------//
WiFiClient espClient;
PubSubClient client(espClient);

//-------------- Подключение к сети WiFi----------//
void setup_wifi() {
  delay(10);
  cn = 0;
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    cn++;
    delay(1000);
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    if (cn > 200) {
      ESP.restart();
    }
  }
  digitalWrite(LED_PIN, LOW);
}

//--------------- Петля, пока мы не подключимся к WiFi-------------//
void reconnect() {
  digitalWrite(LED_PIN, !digitalRead(LED_PIN));
  while (!client.connected()) {     // Попытка подключения
    a++;
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    if (client.connect(NAME)) {
      client.subscribe(comand);
      String ipInfo = WiFi.localIP().toString();
      client.publish(topicIP, ipInfo.c_str(), true);
      digitalWrite(LED_PIN, HIGH);
      a = 0;
    } else {            // Подождите 5 секунд до повторной попытки
      delay(5000);
    }
    if (a > 10) {
      ESP.restart();
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  // Преобразование входящего массива байтов в строку
  payload[length] = '\0'; // Null terminator используется для завершения массива char
  String message = (char*)payload;
  String top = topic;

  /*-------------Info ESP-----------------*/
  if (top == comand) {
    if (message == NAME) {
      String esp = "Sonoff Выключатель: LED GPIO13, Реле GPIO12, Кнопка GPIO0)";
      client.publish(topicInfo, String(esp).c_str(), true);
    } else if (message == "1" || message == "on") {
      desiredRelayState = 1;
    } else if (message == "0" || message == "off") {
      desiredRelayState = 0;
    }
  }
}

void shortPress() {
  desiredRelayState = !desiredRelayState; //Переключить состояние реле.
}

void longPress() {
  desiredRelayState = !desiredRelayState; //Переключить состояние реле.
}

void buttonChangeCallback() {
  if (digitalRead(0) == 0)
  {
    longPress();
  }
}

void setup() {
  Serial.begin(115200);
  
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  //------------ WIFI-OTA-MQTT---------------//
  setup_wifi();
  ArduinoOTA.setHostname(NAME);                   // Задаем имя сетевого порта
  //ArduinoOTA.setPassword((const char *)"0000"); // Задаем пароль доступа для удаленной прошивки
  ArduinoOTA.begin();                             // Инициализируем OTA
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  
  // Задаем  функцию buttonChangeCallback , которая будет вызвана по внешнему прерыванию.
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonChangeCallback, CHANGE);
}

void loop() { 
  /*------------OTA и подключение к MQTT ----------------*/
  ArduinoOTA.handle();      // Всегда готовы к прошивке

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  delay(100);

  if (millis() - lastMQTTCheck >= 5000) {
    reconnect();
    lastMQTTCheck = millis();
  }


  //Состояние реле обновляется через прерывание или через вызов MQTT.
  if (relayState != desiredRelayState) {
      digitalWrite(RELAY_PIN, desiredRelayState);
      relayState = desiredRelayState;
      analogWrite(LED_PIN, !desiredRelayState);
      client.publish(lightAlive, String(desiredRelayState).c_str(), true);
  }
  delay(50);
}


Более детально о Sonoff выключателях и их прошивках тут, тут, здесь и там

Комментарии

Популярные сообщения из этого блога

Motor Shield L293D + Arduino

Перенос Armbian на SSD

Радиореле 220В 433МГц c кодировкой сигнала eV1527