Pierwsze kroki w automatyce DIY wykonałem z wykorzystaniem protokołu HTTP. Jest mi lepiej znany, potrafiłem łatwo sprawdzić czy urządzenie działa np. wchodząc na stronę arduino czy czegoś opartego na esp8266, które serwowało mi stronę z napisem „wszystko działa”. Jednak obróbka requestów http w tym obsługa API Domoticza przez http nastręczyła mi sporo trudności.
Z czasem obiło mi się o uszy, że takie home DIY może się komunikować z wykorzystaniem protokołu MQTT, który ma następujące właściwości:
- jest szybszy,
- bardziej niezawodny,
- potrafi kolejkować requesty,
- nie nawiązuje od nowa połączenia przy każdej komunikacji
Zapoznajmy się z definicją za wikipedia.pl:
MQ Telemetry Transport (MQTT) – oparty o wzorzec publikacja/subskrypcja, ekstremalnie prosty, lekki protokół transmisji danych. Przeznaczony jest do transmisji dla urządzeń niewymagających dużej przepustowości. Poprzez ograniczenie prędkości transmisji, protokół zapewnia większą niezawodność. Protokół ten idealnie sprawdza się przy połączeniach maszyna-maszyna, w internecie rzeczy (IoT), w urządzeniach mobilnych, oraz tam, gdzie wymagana jest oszczędność przepustowości, oraz energii.
Jak widzimy – brzmi to genialnie, prawda?
POPRZEDNIE ROZWIĄZANIE OPARTE O HTTP
U mnie standardowa komunikacja po HTTP wyglądała mniej więcej tak:
[SERWER DOMOTICZ] —<http>–> [ARDUINO]
[SERWER DOMOTICZ] < —<http>— [ARDUINO].
A po przejściu na MQTT wygląda następująco:
[SERWER DOMOTICZ] —<mqtt> –> [BROKER MQTT] <—–<mqtt>— [ ARDUINO ]
Jak widzimy doszedł element pośredni – broker komunikatów mqtt. Urządzenia podłączone do niego subskrybują lub publikują wiadomości z tematów. Tematy wymyślamy sobie sami lub są zdefiniowane przez jakieś urządzenie / system.
MQTT – TEMATY I HIERARCHIA W DRZEWIE
Na przykład Domoticz nasłuchuje na zmiany przełączników/urządzeń w temacie: DOMOTICZ/IN
zaś publikuje zmiany stanów przełączników w temacie DOMOTICZ/OUT.
Tematy możemy sobie publikować i subskrybować dowolne, zaś znak slash / mowi nam o hierarchi w drzewie tematów. Np. drzewo tematu: MOJDOM / PARTER / KUCHNIA / TEMPERATURA wygląda tak:
–MOJDOM
— PARTER
— JADALNIA
— KUCHNIA
—-TEMPERATURA
—- SWIATLO
— PIĘTRO
Komunikat MQTT składa się z tematu i wiadomości. Przykład:
/domoticz/in { „idx”: 3 , „switchcmd”: „On” }
Istnieją także znaki typu wildcard : + plus i # hash.
Znak plus zastępuje dowolną nazwę w obrębie jednego poziomu, znak hash na wielu poziomach – dotyczy tylko SUBSKRYPCJI.
Przykład: jeśli chcemy subskrybować temat związany z zapalaniem światła na całym parterze. Zamiast odczytywać komunikaty na tematach: MÓJDOM / PARTER / KUCHNIA / SWIATLO, MÓJDOM / PARTER / POKOJ / SWIATLO, MÓJDOM / PARTER / KORYTARZ / SWIATLO itd.. możemy zasubksrybować jeden temat: MÓJDOM / PARTER / + / SWIATLO
Instalacja brokera Moquitto na Raspberry Pi
Przejdźmy do instalacji brokera na Raspberry:
sudo apt-get install mosquitto mosquitto-clients
I już.
Wyedytuj plik konfiguracyjny:
nano /etc/mosquitto/mosquitto.conf
i wklej:
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example
port 1883
pid_file /var/run/mosquitto.pidpersistence true
persistence_location /var/lib/mosquitto/log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
Skrypt programu
Co będzie potrzebne? Przede wszystkim biblioteka PubSubClient.
#include <PubSubClient.h>
Powołanie obiektu klasy PubSubClient
WiFiClient espClient;
PubSubClient client(espClient);
Zmienna wskazująca na adres ip brokera MQTT
const char* mqtt_server = „XXX.XXX.XXX.XXX”;
Funkcja wysyłająca wiadomość na zadany kanał ( w tym przypadku obsługująca tylko komendę switchlight)
void publikuj(int idx){
Serial.println(„Publikuje toggle przelacznika”);String message;
// message format {„command”: „switchlight”, „idx”: 2450, „switchcmd”: „On” }
message+=”{\”command\”: \”switchlight\”, \”idx\”: „;
message+=String(idx);
message+=”, \”switchcmd\” : \”Toggle\”}”;
if ( client.publish(domoticz_in, (char*) message.c_str())) {Serial.println(„Opublikowano: ” + message);
}
}
Funkcja subskrybująca wybrany kanał, parsująca jsona i szukająca wystąpień okreslonego IDX. U mnie IDX 85 to światło w kuchni.
void callback(char* topic, byte* payload, unsigned int length) {
StaticJsonBuffer<200> jsonBuffer;
char receivedChar[length];
//Serial.print(„Message arrived [„);
//Serial.print(topic);
//Serial.print(„] „);
for (int i=0;i<length;i++) {
receivedChar[i] = (char)payload[i];
//Serial.print(receivedChar);
}
JsonObject& root = jsonBuffer.parseObject(receivedChar);
int idx = root[„idx”];
int nvalue = root[„nvalue”];
String svalue = root[„svalue1”];obsluga(idx,nvalue,svalue);
}void obsluga(int idx, int nvalue, String svalue)
{
Serial.println(„IDX: ” + String(idx) + ” nval.: „);
//Serial.print(nvalue + ” svalue: „);
// Serial.println(svalue);if (idx == 85) {
Serial.println(„IDX 85 – sprawdzam nvalue: ” + String(nvalue) + ” / ” + svalue);
if (nvalue==1) { digitalWrite(D7,LOW); Serial.println(„zalaczam d7”); }
if (nvalue==0) { digitalWrite(D7,HIGH); Serial.println(„wylaczam d7”); }}
}
Oraz wywołanie naszej funkcji subskrybującej w obrębie funkcji reconnect wywoływana w głównej pętli:
void reconnect() {
// Loop until we’re reconnected
while (!client.connected()) {
Serial.print(„Attempting MQTT connection…”);
// Attempt to connect
if (client.connect(„ESP8266 Client”)) {
Serial.println(„connected”);
// … and subscribe to topic
client.subscribe(„domoticz/out”);
} else {
Serial.print(„failed, rc=”);
Serial.print(client.state());
Serial.println(” try again in 5 seconds”);
// Wait 5 seconds before retrying
delay(5000);
}
}
}
Link do kompletnego pliku programu na githubie:
https://github.com/marcinprzybysz86/arduino/blob/master/esp8266_wemosd1_kuchnia.ino
Program steruje pinem D7 w momencie otrzymania komunikatu MQTT oraz jako wejście (przycisk fizyczny) używa pinu D2 ; wejście obsługiwane przez bibliotekę debounce2. Zadaniem programu jest zapalenie i gaszenie światła.
Jeśli pobierzesz cały program, ustaw następujące parametry wg swojej konfiguracji:
- linia 15: BUTTON_PIN (przycisk fizyczny na ścianie)
- linie 19,20,21: parametry wifi oraz adres brokera mqtt
- linie 26,27,28: adresacja IP
- linie 66,67: który PIN przełączasz w stan wysoki/niski (pod przekaźnik)