Wi-Fi розетка. Часть первая: железо и немного ПО

В связи с чрезвычайной распространенностью и популярностью разного рода «умных» жопожужжателей, решил закупить себе на пробу Wi-Fi розетку. Само устройство выполнено довольно неплохо (если не считать одного монтажного косяка, который будет показан ниже), корпус из качественного пластика. Внутри корпуса на печатной плате расположен честный AC/DC преобразователь (а не конденсаторное барахло), силовое реле, кнопка и два светодиода для ее подсветки. Разрыв нагрузки однополюсный (т.е. разрывается только один провод), что нехорошо, т.к. мы можем легко получить ситуацию, когда на нагрузку в выключенном состоянии подведена фаза.

Внутренности Wi-Fi розетки

С обратной стороны расположена сама микросхема ESP8266, линейный стабилизатор и внешняя flash память, подключенная по SPI. Не обошлось и без монтажных косяков — наши дорогие китайские друзья так и не научились откусывать лишнюю длину выводов у выводных элементов, поэтому один из электролитических конденсаторов оказался практически замкнут загнутыми выводами с обратной стороны платы. Также был замечен криво установленный керамический SMD конденсатор. Такое часто бывает после печки, но то, что он остался в таком положении означает, что либо контроля после печки совсем нет (даже визуального), либо это считается допустимым.

Схема работы с заводской прошивкой

В штатном варианте работает это все следующим образом: при включении в розетку устройство ищет у себя в памяти настройки для подключения к wifi сети (SSID и ключ), если находит — подключается, если нет — создает свою точку доступа (скорее всего скрытую, т.к. обнаружить ее не штатными средствами винды не удалось) и ждет когда его сконфигурируют. Конфигурация происходит при помощи смартфона с установленным приложением производителя. После конфигурации и нехитрой процедуры регистрации устройства начинается собственно работа. Управление устройством происходит по следующей схеме: при нажатии кнопки «включить» в приложении отправляется команда на сервер, далее сервер отправляет команду устройству и наша розетка замыкает контакты реле, после чего отправляет обратно свое состояние.

Ущербность данной схемы видна невооруженным глазом — она не работает без интернета. Нет, включить розетку вручную вы сможете — для этого на ней есть кнопка. Но вот дистанционное управление и какие-то сценарии автоматизации работать не будут, несмотря на то, что вы с розеткой находитесь в одной локальной сети. Еще один существенный минус подобной схемы — она не позволяет встроить эту розетку в существующую систему автоматизации (отличную от того убогого суррогата, который предлагает производитель).

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

Исправляем адрес MQTT сервера (брокера), а также названия топиков (тем), в которые мы будем отдавать данные о состоянии (pubTopic) и на которые мы будем подписаны (controlTopic), с тем чтобы получать оттуда команды управления:

// Библиотеки для WiFi manager

#include <DNSServer.h>;

#include <ESP8266WebServer.h>;

#include <WiFiManager.h>;

//https://github.com/tzapu/WiFiManager

//

WiFiClient espClient;

IPAddress MQTTserver(192, 168, 0, 101); // mosquitto address

PubSubClient client(espClient, MQTTserver);

char* pubTopic = "/ESP8266/STATUS/GPIO12";

char* controlTopic = "/ESP8266/CONTROL/#";

Далее переписываем Callback — это функция, которая вызывается при получении данных. Нас (пока что) интересует только команда управления выводом GPIO12, который управляет реле. Соответственно, обрабатывать будем только его — при получении команды «ON» или «OFF» переводим GPIO12 в соответствующее состояние. Никаких данных мы в топик статуса здесь не посылаем — это удобнее делать в другом месте кода.

//Начало блока обработки полученных данных

void callback(const MQTT::Publish& sub) {

if (sub.topic() == "/ESP8266/CONTROL/GPIO12") {

if (sub.payload_string() == "ON") {

//Serial.println("Control request to GPIO12 [ON]");

digitalWrite(12, HIGH);

}

if (sub.payload_string() == "OFF") {

//Serial.println("Control request to GPIO12 [OFF]");

digitalWrite(12, LOW);

}

}

}

Ну и основной цикл — здесь наша задача определять переключения состояния GPIO12 и отправлять сообщения с фактическим состоянием пина в соответствующий топик. Такой подход позволяет нам отслеживать как включения по команде от MQTT сервера так и ручные включения/выключения, произведенные кнопкой на самом устройстве. Кстати, о кнопке — ее мы тоже должны обрабатывать, опрос кнопки осуществляется каждые 200 мс (на самом деле это несколько многовато, для комфортного использования лучше ставить 150 мс) и при изменении состояния мы переключаем GPIO12.

void loop() {

int ms2;

if ( ( micros() / 1000 ) - ms > 1000 || ms > micros() / 1000 )  {

if ( heap > ESP.getFreeHeap() ) {

Serial.println("Detect mem leak!");

heap = ESP.getFreeHeap();

}

ms = micros() / 1000;

seconds++;

if(seconds > 3599) seconds = 0;

if ( WiFi.status() != WL_CONNECTED ) {

digitalWrite(13, 1);

}

else {

digitalWrite(13, 0);

}

}

ms2 = micros() / 1000;

if ( ms2 % 200 == 0 ) {

pinOldState = pinState; // must be global or static

pinState = digitalRead(12); // must be global or static

if(pinState != pinOldState) {

//Публикуем GPIO в топике

if (client.publish("/ESP8266/STATUS/GPIO12", String(pinState))) {

Serial.println(" Publish status [ok]. PIN [" + String(pinState) + "] OLD [" + String(pinOldState) + "]");

}

else  Serial.println(" Publish status [failed]");

}

ButtonState = digitalRead(0);

//Если нажали кнопку (нашли передний фронт)

if(ButtonState == 0 && ButtonOldState == 1) {

//Переключаем реле

if(digitalRead(12) == 0) digitalWrite(12, 1);

else digitalWrite(12, 0);

}

ButtonOldState = ButtonState;

delay(10);

}

if ( !client.loop() ) { restart();}

yield();

}

Допиленную прошивку можно скачать вот тут (~1 Мб). Кроме самой прошивки в архиве также лежат нужные библиотеки и даташит на ESP8266. В результате, теперь устройство работает по протоколу MQTT в нашей сети и не лезет ни к каким внешним серверам.

Схема работы с допиленной прошивкой

Зашиваем получившееся ПО в устройство, предварительно припаяв 4 штырька на плату.

Соединение с розеткой через USB->UART конвертер

Если в энергонезависимой памяти остались данные для авторизации (SSID и ключ), то устройство автоматически подключится к указанной сети, если по каким-то причинам это не получится, то розетка создаст свою точку доступа с именем, которое мы задали в коде. И по адресу 192.168.4.1 выводит страницу где можно сконфигурировать наш ESP8266. В этой версии точка доступа создается незащищенная! Это косяк (мой) и косяк крайне опасный! В следующий раз расскажу и покажу почему.

Web-морда нашей розетки

Теперь устанавливаем MQTT сервер

Установка на винду описана тут. Также вот тут можно подробнее почитать как пользоваться командами mosquitto_pub и mosquitto_sub чтобы посылать данные в топики и подписываться на интересующие топики с тем, чтобы получать сообщения из них.

Собственно, теперь мы отправляем данные в топик /ESP8266/CONTROL/GPIO12 (запускаем mosquitto_pub c нужными параметрами) и радостно наблюдаем за включение/выключением нагрузки и красивого синего светодиода подсветки кнопки

mosquitto_pub -h localhost -m "ON" -t /ESP8266/CONTROL/GPIO12 -r

mosquitto_pub -h localhost -m "OFF" -t /ESP8266/CONTROL/GPIO12 -r

За сим на сегодня прощаюсь, в следующий раз расскажу как прикрутить все это хозяйство к управляющему ПО и зачем это делать:)

About the Author: admin

Добавить комментарий