Jak dodać mqtt do sterownika rolet z ESP ?
Zakupiłem moduł WiFi WF1 do sterowania roletami (pasmo 434MHz). Moduł ten łączy się do domowego routera i posiada dedykowaną aplikację na system Android. Posiada jeszcze jedną ciekawą cechę - ESP-01 (8266), który można wyjąć z płytki. Postanowiłem więc go trochę przerobić i dodać obsługę protokołu MQTT.
Jak ESP komunikuje się z płytką WF1 ?
W więszkości przypadków moduły ESP-01 komunikują się z resztą elektroniki przy pomocy portu szeregowego. Ponieważ moduł można wyjąć, to bardzo łatwo to sprawdzić. Podłączę do niego tylko zasilanie, masę i nóżkę TX. Jeżeli zadziała to znaczy, że w tym przypadku również tak jest.
Po podłączeniu wszystko dalej działa. Mogę teraz podłączyć ESP-01 do komputera. Użyję starej chińskiej przejściówki USB<->Serial.
Po podłączeniu do komputera widzę jakie komendy ESP wysyła do płytki WF1. Ta informacja przyda się później.
Program dla ESP-01 do obsługi MQTT
Napisłem kod, który obsłuży MQTT i serial port w ESP. Wgrywam go za pomocą gotowego programatora. Można oczywiście zbudować własny programator (instrukcje się w internecie) ale cena gotowego wynosi około 12zł.
Teraz wysyłając do brokera Mosquitto wiadomość z tematem "home/blind/remote" i payloadem zawierającym w treści komendę do wykonania przez moduł wszystko działa poprawnie.
Kod programu
Pełny kod znajduje się na githubie: https://github.com/blogwebpl/wf1
Tu wstawię fragmenty z opisem. Program zaczynamy od procedury setup, która wywołuje procedury konfigurujące port szeregowy i mqtt:
void setup() {
setup_serial_port();
setup_mqtt();
}
Konfiguracja portu. Tu należy wpisać prędkość z jaką ESP komunikuje się z procesorem na płytce.
void setup_serial_port() {
Serial.begin(19200);
}
W MQTT ustawiamy serwer i port oraz procedurę callback wywoływaną po przyjściu wiadomości.
void setup_mqtt() {
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqtt_callback);
}
Procedura callback sprawdza czy temat wiadomości to 'home/blind/remote'. Tak naprawdę nie musi tego sprawdzać, ponieważ subskrybujemy tylko ten temat. Ale w przyszłości może się to przydać, gdyby trzeba było obsłużyć inne tematy. Po otrzymaniu wiadomości z odpowiednim tematem, payload tej wiadomości jest wysyłany przez port szeregowy.
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
if (strcmp(topic,"home/blind/remote") == 0) {
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
}
W głównej pętli programu sprawdzamy czy wifi ma połączenie i jeżeli nie to wywołujemy procedurę łączącą się z wifi. Tak samo robimy z połączeniem do serwera Mosquitto.
void loop() {
unsigned long current_millis = millis();
if ((WiFi.status() != WL_CONNECTED) && (current_millis - last_wifi_reconnect > 30000)) {
wifi_connect();
last_wifi_reconnect = current_millis;
}
if ((!client.connected()) && (WiFi.status() == WL_CONNECTED) && (current_millis - last_mqtt_reconnect > 5000)) {
mqtt_connect();
last_mqtt_reconnect = current_millis;
}
client.loop();
}
Należy jeszcze wspomnieć o jednym. Program podczas połączenia do brokera mosquitto wysyła wiadomość z właściwością retained ustawioną na true (broker ma przechowywać tylko jej ostatnią wartość) oraz informacją, że jest online. Samo połączenie ma zdefiniowaną tzw. ostatnią wolę (last will) czyli wiadomość, która jest wysyłana przez brokera, gdy połączenie z danym klientem zostanie zerwane. Wiadomość ta ma wartość "offline" oraz retain także ustawiony na true. Dzięki temu broker przechowuje informację o tym czy dany klient jest online.
void mqtt_connect() {
Serial.println("Attempting MQTT connection");
if (client.connect(mqtt_client_id, mqtt_user, mqtt_password, mqtt_will_topic, mqtt_will_qos, mqtt_will_retain, mqtt_will_message, mqtt_clean_session)) {
Serial.println("MQTT connected");
client.publish("wf1/status", "online", true);
client.subscribe("home/blind/remote");
} else {
Serial.print("MQTT failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
}
}
Wartości konfiguracyjne są zapisane w oddzielnym pliku config.h
#define SSID "NazwaWiFi"
#define WIFI_PASSWORD "tajnehaslo"
#define MQTT_SERVER "192.168.1.200"
#define MQTT_PORT 1883
#define MQTT_CLIENT_ID "WF1"
#define MQTT_USER "usermqtt"
#define MQTT_PASSWORD "passwordmqtt"
#define MQTT_WILL_QOS 1
#define MQTT_WILL_TOPIC "wf1/status"
#define MQTT_WILL_MESSAGE "offline"
#define MQTT_WILL_RETAIN true
#define MQTT_CLEAN_SESSION true