Verze Arduino UNO, která místo procesoru využívá mikrokontroler a wifi modul ESP8266. Výrazným rozdílem je logika která místo 5V je 3,3V.
Wemos D1 je Wifi vývojová deska, založená na ESP8266EX.
WeMos D1 obsahuje rozložení pinů skoro identické s Arduino UNO. Všechny I/O piny mají přerušení, PWM, I2C a 1-Wire , mimo pin D0.
Deska má USB Micro konektor a USB pro sériový (UART) převodník, takže je jednoduché tuto desku připojit ke svému počítači pomocí USB Micro kabelu.
Destičku jsem koupil zde: https://www.laskakit.cz/wemos-d1-r2-uno-esp8266/
Warning
Pozor - destička používá 3,3 V logiku.
Při zprovozňování destičky mi pomohly tyto návody:
Na této adrese jsem stáhnul vývojové prostředí Arduino IDE 2.2.1. Zvolil jsem ZIP file pro Linux.
Uživatel, který spouští Arduino IDE musí být ve skupině dialout. Po rozbalení stačí spustit
./arduino-ide
Nejprve zvolit menu Soubor → vlastnosti
V nastavení přidat správce dalších desek tuto URL: http://arduino.esp8266.com/stable/package_esp8266com_index.json
Skrze odkaz umožníme do prostředí IDE přidat podporu pro ESP8266.
Skrze menu Tools → Board → Board Manager přidat destičky ESP8266. Napsat esp8266 a nainstalovat.
Jakmile je destička nainstalovaná, tak vybrat destičku skrze menu Tools → Board → esp8266 → LOLIN(WEMOS) D1 R2 & mini.
Pak je možné připojit přes USB kabel zařízení, psát kód a odesílat kód skrze tlačítko do zařízení.
Jako první ukázkový program je připraveno blikání dvěma dostupnými LED diodami. První LED dioda je přímo na modulu, ke které máme přístup v Arduino IDE přes klíčové slovo LED_BUILTIN. Tato LED dioda je zvláštní v tom, že má obrácenou logiku řízení, tedy pokud jí chceme zapnout, je nutné na ní přivést logickou nulu. Druhá LED dioda je připojena na pin 14 a je řízena klasickým způsobem. Po nastavení obou LED diod jako výstupních v podprogramu setup se přesuneme rovnou na nekonečnou smyčku loop, kde jako první blikneme rychleji vestavěnou LED diodou a následně blikneme pomaleji LED diodou na pinu 14.
// ESP8266 blikání dvou LED diod // nastavení propojovacího pinu LED diody #define LEDka 14 void setup() { // nastavení obou LED diod jako výstupních pinMode(LED_BUILTIN, OUTPUT); pinMode(LEDka, OUTPUT); } void loop() { // blikání vestavěnou diodou na ESP, // pro zapnutí musíme přivést logickou 0 - LOW digitalWrite(LED_BUILTIN, LOW); delay(500); digitalWrite(LED_BUILTIN, HIGH); delay(500); // blikání LED diodou na desce, // pro zapnutí musíme přivést logickou 1 - HIGH digitalWrite(LEDka, HIGH); delay(1000); digitalWrite(LEDka, LOW); delay(1000); }
Druhý ukázkový program už je praktičtější a obsahuje skener WiFi sítí v okolí modulu ESP8266. Program na začátku obsahuje připojení potřebné knihovny a poté v podprogramu setup jako první nastavení komunikace po sériové lince. Pro úspěšné vyhledávání WiFi sítí je nutné jako další krok nastavit WiFi modul do módu stanice a pro jistotu provést odpojení od jakékoliv sítě. V nekonečné smyčce loop vytiskneme informaci o zahájení skenování po sériové lince a následně načteme do vytvořené proměnné počet sítí v okolí včetně všech dostupných informací o těchto sítích. Poté zkontrolujeme počet načtených sítí a v případě nuly pouze vypíšeme informaci o nedostupnosti viditelných sítí. Pokud ale máme nějaké sítě v dosahu, provedeme v následujících řádcích vytištění informací o nich. Jako první tedy vytiskneme celkový počet načtených sítí a následně pomocí for smyčky vytiskneme pro každou WiFi síť její název, sílu signálu a druh zabezpečení. Na konci celého programu pak už jen vyčkáme pět vteřin před novým načtením seznamu sítí.
// ESP8266 WiFi skener // připojení potřebné knihovny #include "ESP8266WiFi.h" void setup() { // zahájení komunikace po sériové lince Serial.begin(9600); // nastavení WiFi do módu stanice a odpojení od předchozí sítě WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); } void loop() { Serial.println("Zahajeni skenovani.."); // načtení WiFi sítí v okolí a uložení jejich počtu do proměnné int n = WiFi.scanNetworks(); // v případě nulového počtu sítí vypíšeme informaci // po sériové lince if (n == 0) { Serial.println("Zadne viditelne WiFi site v okoli."); } // pokud byly nalezeny WiFi sítě v okolí, // vypíšeme jejich počet a další informace else { Serial.print(n); Serial.println(" WiFi siti v okoli. Seznam:"); // výpis všech WiFi sítí v okolí, // vypíšeme název, sílu signálu a způsob zabezpečení for (int i = 0; i < n; ++i) { Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(")"); Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*"); delay(10); } } // ukončení výpisu Serial.println(""); // pauza po dobu pěti vteřin před novým skenováním delay(5000); }
Po nahrání druhého ukázkového kódu do Arduino ESP8266 desky dostaneme například tento výsledek:
Zahajeni skenovani.. 3 WiFi siti v okoli. Seznam: 1: SilentB (-25)* 2: ** (-69)* 3: *** (-74)*
Třetí ukázkový kód obsahuje jednoduchý příklad využití ESP jako webserveru v domácí síti. Na začátku programu se nachází připojení všech potřebných knihoven a vytvoření proměnných s uloženým nastavením názvu a hesla pro WiFi síť, do které se budeme připojovat. Jako další je provedena inicializace webserveru na portu 80 a nastaven propojovací pin indikační LED diody. Podprogram zpravaHlavni obsahuje kód, který se provede při přístupu na hlavní stránku. Jako první tedy zapneme LED diodu a poté vytvoříme proměnné s načtením informací o analogové hodnotě z pinu A0 společně s časem od spuštění Arduina. Následně vytvoříme proměnnou se zprávou, do které postupně přidáme všechny chtěné informace. Na konci provedeme příkazem send vytištění zprávy se statusem 200, tedy OK, a vypneme LED diodu. Podprogram zpravaNeznamy funguje obdobným způsobem, jen slouží pro informování o přístupu na neexistující odkaz webserveru. Opět tedy blikneme LED diodou a vypíšeme kompletní informace o neexistujícím odkazu včetně metody a argumentů, s kterými bylo přistupováno. Podprogram setup na svém začátku obsahuje nastavení LED diody jako výstupní společně s jejím vypnutím. Následně zahájíme komunikaci po sériové lince a zahájíme komunikace s WiFi routerem pomocí našich uložených přihlašovacích údajů. Po zahájení následuje while smyčka, která vyčkává na potvrzení připojení a v mezičase tiskne tečky po sériové lince. Jakmile jsme úspěšné připojení, vytiskneme informace o připojení po sériové lince včetně názvu připojené sítě a přidělené IP adrese z routeru. Poté proběhne kontrola MDNS responderu. Jako další je nutné přidělit tištění zpráv k jednotlivým adresám. Pro přístup na IP adresu samotnou tedy například přidělíme volání podprogramu zpravaHlavni. Avšak není nutné pro každou zprávu vytvářet podprogram, proto tedy následuje ukázka s odkazem /ukázka, který obsahuje vytištění krátké zprávy. Pro přístup na jakoukoli jinou nedefinovanou stránku slouží nastavení onNotFound, ke kterému přidělíme náš podprogram zpravaNeznamy. Po veškerém nastavení pak stačí už jen zahájit aktivitu webserveru. Nekonečná smyčka loop v tomto případě obsahuje pouze kontrolování připojených klientů, kdy při detekci klienta už sám program provede veškerou práci skrze nastavení provedená v podprogramu setup.
// ESP8266 Web Server // připojení potřebných knihoven #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> // vytvoření proměnných s názvem WiFi sítě a heslem const char* nazevWifi = "nazev"; const char* hesloWifi = "12345"; // incializace webserveru na portu 80 ESP8266WebServer server(80); // propojovací pin indikační LED diody #define LEDka 14 // podprogram s hlavní zprávou, která je vytištěna // při zadání IP adresy do prohlížeče void zpravaHlavni() { // zapnutí LED diody digitalWrite(LEDka, HIGH); // načtení hodnoty analogového pinu a času // od spuštění Arduina ve formátu String String analog = String(analogRead(A0)); String cas = String(millis()/1000); // vytvoření zprávy, která bude vytištěna // v prohlížeči (\n znamená nový řádek) String zprava = "Ahoj Arduino svete!\n"; zprava += "Analogovy pin A0: "; zprava += analog; zprava += "\nCas od spusteni Arduina je "; zprava += cas; zprava += " vterin."; // vytištění zprávy se statusem 200 - OK server.send(200, "text/plain", zprava); // vypnutí LED diody digitalWrite(LEDka, LOW); } // podprogram s chybovou zprávou, která je vytištěna // při zadání IP adresy s neexistující podstránkou void zpravaNeznamy() { // zapnutí LED diody digitalWrite(LEDka, HIGH); // vytvoření zprávy s informací o neexistujícím odkazu // včetně metody a zadaného argumentu String zprava = "Neexistujici odkaz\n\n"; zprava += "URI: "; zprava += server.uri(); zprava += "\nMetoda: "; zprava += (server.method() == HTTP_GET)?"GET":"POST"; zprava += "\nArgumenty: "; zprava += server.args(); zprava += "\n"; for (uint8_t i=0; i<server.args(); i++){ zprava += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } // vytištění zprávy se statusem 404 - Nenalezeno server.send(404, "text/plain", zprava); // vypnutí LED diody digitalWrite(LEDka, LOW); } void setup(void) { // nastavení LED diody jako výstupní a její vypnutí pinMode(LEDka, OUTPUT); digitalWrite(LEDka, LOW); // zahájení komunikace po sériové lince Serial.begin(9600); // zahájení komunikace po WiFi s připojením // na router skrze zadané přihl. údaje WiFi.begin(nazevWifi, hesloWifi); // čekání na úspěšné připojení k routeru, // v průběhu čekání se vytiskne každých // 500 milisekund tečka po sériové lince while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // odřádkování a výpis informací o úspěšném připojení // včetně přidelené IP adresy od routeru Serial.println(""); Serial.print("Pripojeno k WiFi siti "); Serial.println(nazevWifi); Serial.print("IP adresa: "); Serial.println(WiFi.localIP()); // kontrola funkčnosti MDNS if (MDNS.begin("esp8266")) { Serial.println("MDNS responder je zapnuty."); } // nastavení vytištění hlavní zprávy po přístupu // na samotnou IP adresu server.on("/", zpravaHlavni); // pokud chceme vytisknout pouze menší zprávy, není // nutné je vytvářet v podprogramech jako zpravaHlavni, // viz. ukázka níže // nastavení vytištění jiné zprávy po přístupu na // podstránku ukazka, tedy např. 10.0.0.31/ukazka server.on("/ukazka", []() { String zprava = "Ukazka odkazu pro vice stranek."; server.send(200, "text/plain", zprava); }); // nastavení vytištění informací o neznámém // odkazu pomocí podprogramu zpravaNeznamy server.onNotFound(zpravaNeznamy); // zahájení aktivity HTTP serveru server.begin(); Serial.println("HTTP server je zapnuty."); } void loop(void) { // pravidelné volání detekce klienta, // v případě otevření stránky se provedou // funkce nastavené výše server.handleClient(); delay(10); }
Po nahrání třetího ukázkového kódu do Arduino ESP8266 desky dostaneme například tento výsledek v Sériovém monitoru a v prohlížeči při přístupu na samotnou IP adresu:
Pripojeno k WiFi siti SilentB IP adresa: 10.0.0.31 MDNS responder je zapnuty. HTTP server je zapnuty. Ahoj Arduino svete! Analogovy pin A0: 3 Cas od spusteni Arduina je 54 vterin.
Toto už jsem připravoval vlastní kód. Je to základní kód pro připojení k MQTT serveru. Tady je chování:
Program řeší základní problematiku navázání a obnovení síťových spojení.
#include <ESP8266WiFi.h> #include <WiFiClientSecure.h> #include <PubSubClient.h> #include "client_crt.h" // client certificate #include "client_key.h" // client key #include "ca_crt.h" // CA const char* WiFiName = "Wifi_IoT"; const char* WiFiPassword = "supersecurepassword"; // MQTT connection const char* clientName = "wemos"; const char* mqttBroker = "192.168.0.50"; const int mqttPort = 8883; const char* mqttUser = "user"; const char* mqttPassword = "users_password"; const char* mqttTopic = "building/room/wemos"; #define LED_SCK 14 WiFiClientSecure espClient; PubSubClient mqttClient(espClient); void setupWiFi() { WiFi.mode(WIFI_STA); WiFi.begin(WiFiName, WiFiPassword); // connect to WiFi Serial.print("Connecting to WiFi..."); // wait for connecting to the server // during this waiting it will write dot to serial link while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // write new line, Wi-Fi network and IP address of connection Serial.println(""); Serial.print("Connected to WiFi "); Serial.println(WiFiName); Serial.print("IP address: "); Serial.println(WiFi.localIP()); WiFi.setAutoReconnect(true); WiFi.persistent(true); } void reconnectMQTT() { int retryCount = 0; while (!mqttClient.connected()) { Serial.println("Attempting to connect to MQTT server..."); // SSL/TLS certificate and key settings // The BearSSL::X509List and BearSSL::PrivateKey objects must be in scope (alive) // for the duration of their usage by espClient. If these objects are defined // within a separate function and used here, they will be destroyed when that // function exits, leading to undefined behavior and potential device resets. // A solution to this is to declare them as global variables if they need to // be used across multiple functions. BearSSL::X509List cert(cert_der, cert_der_len); BearSSL::PrivateKey key(key_der, key_der_len); BearSSL::X509List caCert(ca_der, ca_der_len); espClient.setInsecure(); //espClient.setTrustAnchors(&caCert); // Setting the CA certification espClient.setClientRSACert(&cert, &key); // Setting the client's cert and key mqttClient.setServer(mqttBroker, mqttPort); if (mqttClient.connect(clientName, mqttUser, mqttPassword)) { Serial.println("Connected"); // Subscribe to topics here if necessary // mqttClient.subscribe("some/topic"); } else { Serial.print("Failed, rc="); Serial.print(mqttClient.state()); Serial.println(" trying again in 5 seconds"); delay(5000); // 5-second delay between attempts retryCount++; if (retryCount > 5) { // Restart the ESP if it fails to connect 5 times //ESP.restart(); } } } } void setup() { // put your setup code here, to run once: // set LED diode as OUTPUT a turn on the diode pinMode(LED_SCK, HIGH); // start communication on serial line Serial.begin(9600); setupWiFi(); reconnectMQTT(); } void loop() { // put your main code here, to run repeatedly: if (!mqttClient.connected()) { reconnectMQTT(); } mqttClient.loop(); // Odesílání zprávy každou vteřinu static unsigned long lastMsg = 0; unsigned long now = millis(); if (now - lastMsg > 1000) { lastMsg = now; // Tvořte zde svou zprávu const char* message = "Hello MQTT"; mqttClient.publish(mqttTopic, message); } }