W artykule o podłączeniu ESP8266 do internetu wspomniałem opisałem rozwiązanie, w którym urządzenie w kółko odpytywało serwer o porządany stan.
Rozwiązanie to, które nazywa się polingiem, jest proste ale powoduje pewne problemy. Alternatywą jest technologia WebSockets.
Po pierwsze każde wywołanie http jest na tyle powolne, że jest dostrzegalne i denerwujące w użytkowaniu. Dzieje się tak ponieważ wiąże się nawiązaniem połączenia na nowo.
Po drugie moja aplikacja serwerowa jest uruchomiona w chmurze Google i jest chroniona przez mechanizmy powiązane z jej load-balancerem. Mechanizmy te dość szybko odcięły moje ESP8266 od aplikacji, ponieważ uznały je za próbę ataku DoS (Denial of Service) Wydłużenie czasu pomiędzy wywołaniami do 1.5 sekundy, sprawiało że mój domowy adres IP otrzymywał bana raz tydzień, a nie kilka razy dziennie.
Ban sprawiał że albo płytka odbierająca sygnał z pilota nie mogła go dostarczyć do aplikacji w chmurze, albo płytka sterująca diodami LED nie była w stanie odebrać oczekiwanego stanu.
Technologia WebSockets zamiast wielu krótkich połączeń, nawiązywane jest jedno połączenie długo-żyjące, umożliwiające komunikację dwustronną dzięki temu
- praca routerów związana z całym stosem TCP wykonywana jest rzadziej
- brama ogniowa jest odpytywana znacznie rzadziej o pozwolenie na wejście, więc nie traktuje tych zapytań jako ataku.
Obsługa webSockets nie jest może super-skomplikowana ale po co to robić jak istnieje kilka bibliotek pomagających obsłużyć tą technologię. Pierwszą, która mi zadziałała i miała fajne API, była WebSockets2_Generic.
Podobnie jak inne biblioteki, instaluje się ją klikając w Arduino studio Sketch -> Include library -> Manage libraries.
Na wyświetlonej liście powinien znajdować się element WebSockets2_Generic
Aby wykorzystać tą bibliotekę należy zaimportować biblioteki związane z konfiguracją WiFi oraz bibliotekę WebSockets2_Generic.
Biblioteka zawiera przestrzeń nazw websockets2_generic, a ta klasę WebsocketsClient.
#include <WebSockets2_Generic.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClient.h>
ESP8266WiFiMulti WiFiMulti;
using namespace websockets2_generic;
WebsocketsClient client;
void setup() {
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("<SSID>", "<Password>"
);
pinMode(3, OUTPUT);
client.onMessage(onClientMessage);
}
void onClientMessage(WebsocketsMessage message) {
if(message.data() == "true") {
digitalWrite(3, HIGH);
} else {
digitalWrite(3, LOW);
}
}
void loop() {
if (WiFiMulti.run() != WL_CONNECTED) {
return;
}
if (!client.available())
{
if(!client.connect("<server-dns-name-or-ip>", 80, "<path>")) {
return;
}
}
client.poll();
}
Klasa posiada 5 metod:
- available – sprawdza czy połączenie z serwerem jest nawiązane
- connect – otwiera połączenie z serwerem, niestety metoda nie przyjmuje url tylko 3 argumenty: adres serwera, port na którym nasłuchuje serwer, ścieżka na serwerze
- send – wysyła wiadomość do serwera – w tym kodzie nie używana
- onMessage – przyjmuje jako parametr metodę wywołaną gdy serwer nada wiadomość
- poll – wywoływana w metodzie loop – zawiera komunikację z serwerem
To w zasadzie wszystkie zmiany po stronie urządzenia, pozostaje tylko tak zmienić kod serwera.
Po zastosowaniu tych zmian odbiornik reaguje praktycznie natychmiastowo.
Inne artykuły związane z Internetem rzeczy