[104] Arduino i sieć cz. 1

[104] Arduino i sieć cz. 1

Nowe Arduino nie ma już nic wspólnego z ośmiobitowcem klasy Atari, którym było gdy powstawało. Sieć i moc (bo do sieci trzeba mocy) towarzyszy mu od jakiegoś czasu, a nowa wersja Uno ma na pokładzie dwa kontrolery – „arduinowy”, ale już trzydziestodwubitowy ARM Cortex M4 i wspierający go głównie sieciowo, jeszcze potężniejszy ESP32-S3. O nowym Arduino pisałem jakiś czas temu i dziś zajmiemy się siecią właśnie, zaledwie tytułem wstępu, ale – już w kolejnych artykułach – w tworząc jak najbardziej użyteczne, choć nadal proste urządzenie.


Korzystaliśmy już z usług WiFi, budując kilka projektów chmurowych. Jednak wszystko co związane z siecią, było robione poza naszą świadomością. Tymczasem Arduino możemy potraktować także bardziej świadomie, tworząc… właściwie wszystko to, co można zrobić z komputerem mającym na pokładzie kartę sieciową. Zbudujmy więc sobie watchdoga do pilnowania urządzenia mającego zapewnić działanie WiFi w lokalnej sieci. Wielu użytkowników posiada infrastrukturę inteligentnego domu, jakiś serwer czy cokolwiek, co wymaga zdalnego dostępu. I właśnie wtedy, gdy ten dostęp jest potrzeby, okazuje się, że połączenia nie ma. Często jednak – jak w najsłynniejszym kawale informatyków – wystarczy „wyłączyć i włączyć” – i po chwili wszystko działa. Tylko kto to zrobi, jeśli w domu nie ma nawet Kevina?

Oczywiście urządzenia same powinny to robić i robią. Stąd te braki sieci przez kilka sekund czy w ogóle chwilowe cisze w eterze. Ale bywa, że się zawiesi i amen. Projekt ten zresztą może przydać się do innych rzeczy, przede wszystkim związanych testami sieci WiFi. A więc do dzieła: co tak konkretnie będziemy robić? Będziemy cyklicznie wysyłać pingi pod wybrany adres. Jeśli przez jakiś czas nie dostaniemy odpowiedzi, włączymy przekaźnik, który odłączy zasilanie urządzeń związanych z siecią. Wszystkie czasy, ilości pingów jak i adresy będzie można ustawić wedle własnych potrzeb i upodobań. I jak to zwykle, będziemy tworzyć projekt etapami, korzystając tym razem z monitora, na który będziemy wysyłać informacje. Docelowo jednak urządzenie będzie mogło pracować niezależnie, korzystając tylko z dwukolorowej diody świecącej i przekaźnika. Wiadomo – zielone – dobrze, żółte – testujemy i czekamy – czerwone – awaria. Kto jednak będzie potrzebował wyświetlacza – nie ma problemu, by go dołożyć do projektu.

Współczesna elektronika cierpi na chorobę braku dokumentacji. Niby wszystko można znaleźć, ale porozrzucane, często w formie komentarzy albo niedomówień. Podstawą naszej dzisiejszej zabawy jest biblioteka WiFiS3 i po próbie znalezienia spisu komend trafiłem na coś takiego.

Porada, bym sobie poszukał opisu podobnej biblioteki, nie do końca się sprawdziła, bo podobne to nie identyczne. W końcu jednak z pomocą tej dokumentacji i przykładów udało mi się jakoś okiełznać WiFi na płytce Uno R4.

A zaczęło się od tego, że nic nie działało. Gdzieś tam w komentarzu znalazłem uwagę o wymaganej minimalnej wersji firmware, więc na wszelki wypadek postanowiłem zaktualizować płytkę poleceniem dostępnym z menu Arduino IDE.

Znak czasów – aktualizacja trwała kilka minut, a na ekranie działy się rzeczy straszne, płytka chwilowo zmieniała nazwy i pozostała na końcu płytką EPS o jakimś strasznie długim imieniu. Przewidując najgorsze, odłączyłem ją i podłączyłem z powrotem i – znowu miałem zwyczajne Arduino, już zaktualizowane, bo teraz wszystko działało. Tak więc mając płytkę z wcześniejszej serii nie obędziemy się bez aktualizacji. Czas na szkic.

#include "WiFiS3.h"              // Biblioteka obsługująca WiFi na Arduino R4
char ssid[] = "Smialek";         // Nazwa sieci WiFi.
char pass[] = "1234";            // Hasło do sieci WiFi.
int modulWiFi = WL_IDLE_STATUS;  // Zmienna stanu WiFi.

const char* adresWWW = "www.google.com";  // Adres stromy do badania dostępności internetu.
const int opoznienie = 3000;              // Opóźnienie dla ustabilizowania połączeń z WiFi.
int czas;                                 // Czas w milisekundach dla funkcji ping.

void setup() {
  Serial.begin(115200);  // Inicjuj monitor.
  while (!Serial) {}     // Czekaj dopóki nie będzie połączenia z portem szeregowym.

  Serial.print("Dzień dobry. Jestem aplikacją nadzorującą punkt dostępu WiFi. Czekaj...");
  if (WiFi.status() == WL_NO_MODULE) {  // Sprawdź połączenie z modułem WiFi na płytce.
    Serial.println(" Niestety moduł WiFi na płytce Arduino nie odzywa się. Spróbuj zaktualizować firmware.");
    while (true) {}  // Brak połączenia z modułem WiFi, zakończ pracę.
  }
  Serial.println(" Inicjacja przebiegła prawidłowo.");
  Serial.print("Spróbuję teraz połączyć się z punktem dostępu WiFi o nazwie \"");
  Serial.print(ssid);  // SSID
  Serial.print("\". Czekaj...");
  while (modulWiFi != WL_CONNECTED) {    // Czekaj, dopóki nie połączysz się z punktem dostępu WiFi.
    modulWiFi = WiFi.begin(ssid, pass);  // Procedura łączenia WiFi z punktem dostępu.
    delay(opoznienie);                   // Opóźnienie niezbędne do ustabilizowania się połączenia.
  }
  Serial.println(" Połączenie powiodło się.");
  Serial.print("Adres bramy: ");
  Serial.println(WiFi.gatewayIP());  // IP bramy.
  Serial.print("Przydzielony adres: ");
  Serial.println(WiFi.localIP());  // Przydzielone IP
  Serial.print("Siła sygnału WiFi (RSSI): ");
  Serial.print(WiFi.RSSI());  // RSSI
  Serial.println(" dBm");
  Serial.println("");
}
void loop() {

  Serial.println("Wysyłam ping na adres bramy. Czekaj...");  // Badamy lokalne połączenie z bramą.
  czas = WiFi.ping(WiFi.gatewayIP());                        // Ping adresu bramy.
  if (czas >; 0) {
    Serial.print("Czas odpowiedzi: ");
    Serial.print(czas);
    Serial.println(" ms");
  } else {  // Brak odpowiedzi z bramy.
    Serial.println("Połączenie z bramą zostało zerwane. Będę próbował połączyć się ponownie.");

    modulWiFi = WiFi.disconnect();         // Odłącz się od sieci WiFi
    delay(opoznienie);                     // Opóźnienie niezbędne do ustabilizowania się połączenia.
    while (modulWiFi != WL_CONNECTED) {    // Czekaj, dopóki nie połączysz się z punktem dostępu WiFi.
      modulWiFi = WiFi.begin(ssid, pass);  // Procedura łączenia WiFi z punktem dostępu.
      delay(opoznienie);                   // Opóźnienie niezbędne do ustabilizowania się połączenia.
    }
  }
  Serial.print("Siła sygnału WiFi (RSSI): ");  // Badamy poziom sygnału WiFi
  Serial.print(WiFi.RSSI());                   // RSSI
  Serial.println(" dBm");

  Serial.print("Wysyłam ping na adres \"");  // Badamy połączenie z wybraną stroną internetową.
  Serial.print(adresWWW);
  Serial.println("\". Czekaj...");
  czas = WiFi.ping(adresWWW);  // Ping wybranej strony internetowej.
  if (czas > 0) {
    Serial.print("Czas odpowiedzi: ");
    Serial.print(czas);
    Serial.println(" ms");
  } else {  // Brak odpowiedzi z wybranej strony internetowej.
    Serial.println("Internet jest niedostępny.");
  }
  Serial.println("");
  delay(opoznienie);
}

Podstawą jest biblioteka WiFiS3. Importujemy ją oczywiście, a szczegółami będziemy zajmować się niżej. I teraz kontrowersja: jak przekazać do Arduino nazwę sieci WiFi (ssid) i hasło do niej? (pass) Czyni się to zwyczajowo w osobnym pliku, a jeśli projekt ma być tajny, trzeba je podawać przy inicjalizacji. Jednak urządzenie, które tu tworzę i tak ma siedzieć obok routera, więc po prostu jawnie wpiszemy tu jedno i drugie. Tak na marginesie, naprawdę mam taką sieć, ale udostępnianą awaryjnie – ze smartfona. Tylko hasło jest inne ;)

Poniżej definiujemy sobie tak zwaną zmienną statusu modułu WiFi. Będzie przyjmować wartości zgodne ze stanem tego modułu, co pozwoli się dowiedzieć na przykład dlaczego nie ma połączenia.

adresWWW to adres strony, której będziemy wysyłać pingi. Użyłem google.com, bo jak on zniknie, będzie koniec świata. Ale można tu wpisać cokolwiek, co komu pasuje. W ten sposób można także kontrolować własną stronę, zwłaszcza jeśli jej dostawca nie za bardzo wywiązuje się ze swoich zadań.

opoznienie jest zwłoką między różnymi etapami nawiązywania połączeń i stabilizowania się pracy modułu WiFi. Zaleca się zadeklarowanie 10 sekund, ale na potrzeby szkicu skróciłem je do trzech, a w eksperymentach używałem sekundy i też wystarczyło.

W końcu czas jest parametrem, o który wszyscy walczymy: to opóźnienie między nami, a odwiedzonymi stronami i im jest mniejsze, tym lepiej.

Będziemy używać tutaj monitora w Arduino IDE, choć po zaprogramowaniu układu można użyć jakiegokolwiek terminala, dzięki czemu poznamy wybrane parametry i będziemy wiedzieć co się dzieje w świecie WiFi. Stąd deklaracja monitora i linia poniżej, zwyczajowo dodawana w nowych Arduino.

if (WiFi.status() == WL_NO_MODULE) {  // Sprawdź połączenie z modułem WiFi na płytce.
  Serial.println(" Niestety moduł WiFi na płytce Arduino nie odzywa się. Spróbuj zaktualizować firmware.");
  while (true) {}  // Brak połączenia z modułem WiFi, zakończ pracę.
}

Obrzędy wstępne rozpoczynają się od nawiązania dialogu z modułem. Jeśli to będzie monolog, zabawy nie będzie i program zakończy działanie. Tak na marginesie, to jest pętla bez końca.

while (modulWiFi != WL_CONNECTED) {    // Czekaj, dopóki nie połączysz się z punktem dostępu WiFi.
  modulWiFi = WiFi.begin(ssid, pass);  // Procedura łączenia WiFi z punktem dostępu.
  delay(opoznienie);                   // Opóźnienie niezbędne do ustabilizowania się połączenia.
}

Tutaj nastąpi próba połączenia się modułu z punktem dostępu. Jak widać, przekazujemy nazwę sieci oraz hasło. Trzeba pamiętać, że Uno toleruje sieci w paśmie 2,4 GHz, więc taką musi być udostępniona. Gdy moduł połączy się, za pomocą standardowych komend biblioteki będziemy mogli wyssać kilka interesujących informacji.

Serial.println(" Połączenie powiodło się.");
Serial.print("Adres bramy: ");

Na początek – adres bramy. To tam następuje zarządzanie adresami lokalnymi i przy ręcznej konfiguracji sieci rzecz tę musimy znać. A skoro o zarządzaniu mowa, dostaliśmy własny adres w sieci lokalnej i ten poznamy za pomocą tej komendy.

Serial.print("Przydzielony adres: ");
Serial.println(WiFi.localIP());  // Przydzielone IP

Interesująca będzie moc sygnału WiFi. Wyraża się ją w jednostkach zwanych decybelami na miliwat (dBm), czy poprawniej – odniesionych do miliwata mocy. W praktyce sięga poziomu od -30, dla urządzeń wręcz ocierających się od siebie, do -80, gdy już połączenie się rwie.

Serial.print("Siła sygnału WiFi (RSSI): ");
Serial.print(WiFi.RSSI());  // RSSI
Serial.println(" dBm");

Wszystkie te informacje dostaniemy jednorazowo, ponieważ siedzą w części wstępnej programu. W pętli zaś w nieskończoność będziemy testować połączenie zarówno lokalne jak i z wybraną stroną. Zaczynamy od pierwszego.

Serial.println("Wysyłam ping na adres bramy. Czekaj...");  // Badamy lokalne połączenie z bramą.
czas = WiFi.ping(WiFi.gatewayIP());                        // Ping adresu bramy.

Ta komenda wysyła tak zwany ping. Co to jest ping? To polecenie diagnostyczne, które wysyła pod wybrany adres specjalny pakiet i oczekuje odpowiedzi. Jeśli tylko usługa taka nie jest blokowana, odpowiedź przychodzi po pewnym czasie i czas ten świadczy o jakości połączenia.

Serial.print("Czas odpowiedzi: ");
Serial.print(czas);
Serial.println(" ms");

Pojedyncze milisekundy są idealne, kilkanaście – to bardzo dobry praktyczny wynik, kilkadziesiąt – ujdzie, kilkaset – nie da się pracować. Niestety żadne Arduino nie poprawi wyników i od tego są inne narzędzia, łącznie z wymianą dostawcy internetu. Na razie jednak dostawcą jest nasz router i tutaj wymaga się opóźnień rzędu pojedynczych milisekund. Tak na marginesie, ping potrafi więcej, ale ja tu się ograniczyłem tylko do czasu.

Gdy więc czas przekroczy pewną wartość – którą można zmienić, ale pozostałem przy domyślnych parametrach – uważa się, że strona nie odpowiada, co może znaczyć bardzo wiele, lecz poprzestaniemy na tym, że to źle. W przypadku sieci lokalnej przyczyną zwykle jest zawieszenie się urządzenia już po wcześniejszym nawiązaniu z nim dialogu – inaczej nie połączylibyśmy się na początku. Wówczas wysyłamy na monitor komunikat i spróbujemy się z nim połączyć na nowo.

modulWiFi = WiFi.disconnect();         // Odłącz się od sieci WiFi
delay(opoznienie);                     // Opóźnienie niezbędne do ustabilizowania się połączenia.
while (modulWiFi != WL_CONNECTED) {    // Czekaj, dopóki nie połączysz się z punktem dostępu WiFi.
  modulWiFi = WiFi.begin(ssid, pass);  // Procedura łączenia WiFi z punktem dostępu.
  delay(opoznienie);                   // Opóźnienie niezbędne do ustabilizowania się połączenia.
}

Czasem router sam odzyska władzę nad sobą i operacja zakończy się sukcesem. Kolejno znowu badamy poziom sygnału. Przydatne to bywa przy dobieraniu miejsca obu urządzeń, a czasem też warto zmienić kanał WiFi, co już trzeba robić w routerze, za pomocą oprogramowania systemowego, zwykle mającego format lokalnej strony internetowej.

Czas na powtórkę zabawy z pingiem, ale teraz będziemy atakować prawdziwą stronę internetową. Jak mówiłem, pingi mają prawo błądzić po świecie przez kilkadziesiąt milisekund, choć są szczęśliwcy mieszczący się w niższych przedziałach. Dzisiejszy internet jest mocno związany z pingami i można mieć ogromne transfery, ale czkawka w dostępie do elementów strony stanie się nie do zniesienia. Że o opóźnieniach wśród graczy nie wspomnę.

  Serial.print("Wysyłam ping na adres \"");  // Badamy połączenie z wybraną stroną internetową.
  Serial.print(adresWWW);
  Serial.println("\". Czekaj...");
  czas = WiFi.ping(adresWWW);  // Ping wybranej strony internetowej.
  if (czas > 0) {
    Serial.print("Czas odpowiedzi: ");
    Serial.print(czas);
    Serial.println(" ms");
  } else {  // Brak odpowiedzi z wybranej strony internetowej.
    Serial.println("Internet jest niedostępny.");
  }

W razie niepowodzenia tutaj dostaniemy tylko stosowny komunikat i na tym na razie poprzestaniemy. Skompilujmy program i podziwiajmy co wyszło.

W okienku monitora zobaczymy coś takiego. Po powitaniu i inicjacji Arduino będzie chciało się połączyć z WiFi. Jeśli sieć będzie niedostępna albo pomylimy jej nazwę lub hasło – dalszego ciągu nie będzie. Ale jeśli parametry były prawidłowe, a sieć się pojawi, przejdziemy do dalszych etapów. Na wstępie zobaczymy adres bramy, nasz adres oraz siłę sygnału. Ponieważ udostępniłem internet ze smartfona i telefon leży zaraz obok, poziom sygnału jest bardzo mocny.

Poniżej, już w nieskończonej pętli będziemy najpierw wysyłać pingi na na router, a potem na stronę google. 10 ms nie jest wyjątkowo mocne, jak na nowoczesne urządzenie leżące obok siebie, a pingi z google wracają jak chcą. To typowe dla internetu z komórek w centrach miast, dlatego nie jest to najlepsze źródło tegoż do pracy zawodowej.

Dla porównania przełączyłem się na mój domowy internet. Oranżadowy router oferuje bardzo dobrą odpowiedź, a sama sieć – jak na druty kładzione w epoce pary i węgla – tolerowane pingi. Co ciekawe, zakresy IP – stałe dla routera, w przypadku smartfona zmieniają się czasem po resecie, co tutaj nie ma znaczenia, ale w określonych przypadkach może mieć.

Na koniec: jeśli stracimy połączenie z routerem, program zatrzyma się do czasu, aż połączenie wróci.

Natomiast jeśli router straci połączenie ze światem, pętla będzie pracować, ale pojawi się komunikat o niedostępności. Co z tym zrobić – o tym napiszę w kolejnym artykule.

Powiązane tematy

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2025 arduino.pl