Wi-Fi
Wi-Fi jest zestawem standardów sieci bezprzewodowych. Obecne jest właściwie wszędzie. W IoT również stosuje się je coraz częściej, ze względu na rozwijające się mechanizmy oszczędzania energii.
Więcej na temat sieci Wi-Fi, można przeczytać np. w wikipedii.
W poniższym ćwiczeniu, poznamy podstawy łączenia się z istniejącą siecią Wi-Fi oraz komunikacji przy użyciu MQTT.
Blinky dla Wi-Fi
Jak zawsze, pisanie kodu należy zacząć od blinky
. W tym celu:
-
Do pustego projektu zaincluduj bibliotekę
<ESP8266WiFi.h>
-
Zdefiniuj
WIFI_SSID "workshop_h3x"
-
Zdefiniuj
WIFI_PASSWORD "workshop_h3x"
-
Dodaj funkcję:
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
- Zainicjalizuj port szeregowy z prędkością
115200
- Wywołaj funkcję
setup_wifi()
Uruchom kod i obserwuj port szeregowy. Twoje urządzenie powinno połączyć się z siecią i otrzymać adres ip 172.30.0.xx
.
MQTT - odczyt wiadomości w chmurze
MQTT jest lekkim protokołem IoT działającym w formacie subskrybcji. Urządzenia wysyłają oraz odbierają wiadomości w konkretnym wątku (Topic).
Instalacja
Zainstaluj bibliotekę PubSubClient
Implementacja klienta
Rozbuduj kod blinky w następujący sposób:
- Dodaj bibliotekę
<PubSubClient.h>
- Zdefiniuj
MQTT_SERVER "broker.emqx.io"
- Zdefiniuj
SENSOR_NAME "workshop/test1"
- test1 zmień na dowolną, wymyśloną przez siebie nazwę - Stwórz globalne zmienne
WiFiClient espClient
orazPubSubClient client(espClient)
- Dodaj do kodu funkcję
callback()
- Będzie ona wywoływana gdy urządzenie odbierze wiadomość
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
}
- Dodaj do kodu funkcję
reconnect()
- będzie ona łączyć urządzenie z brokerem (serwerem)
void reconnect()
{
while (!client.connected())
{
Serial.print("Attempting MQTT connection...");
String clientId = "client-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str()))
{
Serial.println("connected");
client.publish(SENSOR_NAME, "hello world");
client.subscribe(SENSOR_NAME);
}
else
{
delay(5000);
}
}
}
- Po połączeniu z Wi-Fi wywołaj funkcje
client.setServer(MQTT_SERVER, 1883)
orazclient.setCallback(callback);
- W funkcji loop wywołaj funkcję reconnect jeśli
!client.connected()
- W funkcji loop wywołaj
client.loop()
- Jest to niezbędne dla obsłużenia przychodzących wiadomości
Skompiluj i uruchom swój kod. Obserwuj port szeregowy. Twoje urządzenie powinno połączyć się z wifi oraz
brokerem: (Attempting MQTT connection...connected
).
Konfiguracja brokera
Aby odbierać wiadomości musimy mieć brokera. Czyli serwer, przekazujący wiadomości.
Wykorzystamy do tego narzędzie online http://tools.emqx.io/
W pierwszym kroku, należy stworzyć nowe połączenie. Wykorzystamy domyślne ustawienia, zmieniając jedynie nazwę. W pole Name
wpisz dowolną, wybraną przez siebie nazwę połączenia.
Po dodaniu połączenia, po lewej stronie zobaczymy nasze połączenie wraz z zieloną kropką, sygnalizującą stan połączenia.
Przyciskiem New subscription
należy stworzyć nową subskrubcję. W polu Topic
wpisujemy zdefiniowane w kodzie TOPIC
. Możemy również zmienić kolor, który będzie wyświetlany przy danym temacie.
Na koniec, zresetuj swoją płytkę (lub wgraj kod od nowa). W przeglądarce, zobaczysz wiadomość, którą wysyła Twoje ESP.
Możesz również wysłać wiadomość do swojej płytki. W tym celu na dole panelu:
- Ustaw
Payload
naplaintext
- Wpisz temat który subskrybuje w kodzie Twoje urządzenie (funkcja
client.subscribe()
) - Wpisz dowolną wiadomość
Subskrubcja kilku tematów - zadanie dodatkowe
Zwróć uwagę, że za to czy odbierzemy wiadomość w jakimś temacie odpowiada funkcja client.subscribe()
. Może być ona wywołana wielokrotnie, z różnymi argumentami, Podobnie, jak funkcja client.publish()
. Dzięki temu, Twoje urządzenie może:
- Wysyłać konkretne informacje (temperatura, stan przycisku, wartość z czujnika) pod różne tematy
- Odbierać wiadomości i reagować w różny sposób w zależności od tematu wiadomości
Spróbuj przerobić kod w taki sposób aby:
- Subskrybował dwa różne tematy:
- Temat A Będzie włączać lub wyłączać
LED_BUILTIN
w zależności czy otrzyma wartość1
czy0
- Temat B Będzie wypisywać otrzymaną wiadomość na port szeregowy
- Temat A Będzie włączać lub wyłączać
- Wysyłał wiadomość pod dwa różne tematy:
- Temat A wyśle wiadomość
button pressed
gdy naciśniemy przycisk - Temat B wyśle wiadomość wpisaną na port szeregowy
- Temat A wyśle wiadomość
Wskazówki:
- Wykorzystaj funkcję
void serialEvent()
z rozdziału UART. UWAGA! Funkcjaclient.publish()
przyjmuje argumenty typuchar *
, czyli tablicę znaków. Wspomniany przykład używa obiektuString
. Podając go jako argument, wywołaj na nim funkcję.c_str()
:
client.publish(TOPIC_B_PUBLISH, inputString.c_str());
Przekonwertuje ona typ String, na char *. - Zdefiniuj osobne stałe dla kolejnych tematów np.
#define TOPIC_A_SUBSCRIBE "workshop/suba"
. Pamiętaj, że broker (przeglądarka) powinna publikować pod tematem, który urządzenie subskrybuje. - Stwórz dwie zmienne globalne typu
bool
: button_pressed oraz button_previously_pressed. Przy ich użyciu stwórz w funkcjiloop()
warunek który sprawi, że będziesz wysyłać tylko jedną wiadomość, w momencie naciskania przycisku. - Skorzystaj z funkcji
strcmp(char *, char *)
aby sprawdzić pod jakim tematem otrzymałeś wiadomość. Zwróci ona 0 gdy oba teksty(tablice znaków, char*) są identyczne. - Pamiętaj o odwróconej logice
LED_BUILTIN
- Pamiętaj o konfiguracji pinów, w funkcji
setup()