Blynk: контроль підключеннями до серверу Blynk та мережі WiFi
Передмова
Помітив, що багато початківців, які хочуть створити для себе IoT пристрій на базі WiFi мікроконтролера ESP8266 або ESP32 з системою Blynk, стикаються з такою проблемою як:
- не виконання коду, поки пристрій не підключиться до точки WiFi;
- відсутность спроб відновити з'єднання у разі втрати зв'язку з мережею;
- блокування коду при втраті зв'язку з сервером Blynk.
Проблематика
Ми можемо взяти за основу будь який приклад Blynk і вже навколо нього "наростити" свій функціонал. Але це буде не зовсім вірно. Тому пишемо в першу чергу код, який буде, наш модуль WiFi, завжди тримати на зв'язку з точкою WiFi. Та при втраті підключення до Blynk зробити логіку, яка дозволить не блокувати основний код, та періодично намагатись під'єднатись до серверу Blynk.
Поширений приклад для підключення до WiFi нам пропонують в такому вигляді:
#include <ESP8266WiFi.h> void setup() { Serial.begin(115200); Serial.println(); WiFi.begin("network-name", "pass-to-network"); Serial.print("Connecting"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.print("Connected, IP address: "); Serial.println(WiFi.localIP()); } void loop() {}
В цьому прикладі далі циклу while (WiFi.status() != WL_CONNECTED), поки не буде з'єднання з точкою WiFi, програма не виконається. Нам потрібно, щоб спроби приєднатись до точки WiFi були постійними, а код в циклі loop() виконувався та контролював стан з'єднання з точкою WiFi.
А поширений приклад для підключення до Blynk нам пропонують в такому вигляді:
#include <ESP8266WiFi.h> #include <BlynkSimpleEsp8266.h> // You should get Auth Token in the Blynk App. // Go to the Project Settings (nut icon). char auth[] = "YourAuthToken"; // Your WiFi credentials. // Set password to "" for open networks. char ssid[] = "YourNetworkName"; char pass[] = "YourPassword"; void setup() { // Debug console Serial.begin(9600); Blynk.begin(auth, ssid, pass); // You can also specify server: //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80); //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080); } void loop() { Blynk.run(); // You can inject your own code or combine it with other sketches. // Check other examples on how to communicate with Blynk. Remember // to avoid delay() function! }
В цьому випадку, при відсутності WiFi ваш пристрій так і буде "мертвою залізякою", а у разі наявності WiFi і втрати зв'язку з сервером Blynk, ваш код блокуватиметься функцією Blynk.run() яка викликається з циклу loop() і користуватись пристроєм буде не можливо.
Приклад рішення для ESP8266
Я пропоную такий варіант коду для підтримки зв'язку з точкою WiFi та сервером Blynk без блокування основного коду:
#include <Arduino.h> #include <ESP8266WiFi.h> #include "BlynkSimpleEsp8266.h" const char* ssid = "MY_SSID"; const char* password = "MY_PASS"; const char* blynkToken = "MY_TOKEN"; bool isWiFiConnected = false; int numTimerReconnect = 0; WiFiEventHandler gotIpEventHandler; WiFiEventHandler disconnectedEventHandler; BlynkTimer timer; void WiFiStationConnected(const WiFiEventStationModeGotIP& event); void WiFiStationDisconnected(const WiFiEventStationModeDisconnected& event); void ReconnectBlynk(void); void BlynkRun(void); void setup() { Serial.begin(115200); gotIpEventHandler = WiFi.onStationModeGotIP(&WiFiStationConnected); disconnectedEventHandler = WiFi.onStationModeDisconnected(&WiFiStationDisconnected); WiFi.begin(ssid, password); Blynk.config(blynkToken); if(Blynk.connect()) { Serial.printf("[%8lu] setup: Blynk connected\r\n", millis()); } else { Serial.printf("[%8lu] setup: Blynk no connected\r\n", millis()); } Serial.printf("[%8lu] Setup: Start timer reconnected\r\n", millis()); numTimerReconnect = timer.setInterval(60000, ReconnectBlynk); } void loop() { BlynkRun(); timer.run(); } void WiFiStationConnected(const WiFiEventStationModeGotIP& event) { isWiFiConnected = true; Serial.printf("[%8lu] Interrupt: Connected to AP, Ip: ", millis()); Serial.println(WiFi.localIP()); } void WiFiStationDisconnected(const WiFiEventStationModeDisconnected& event) { isWiFiConnected = false; Serial.printf("[%8lu] Interrupt: Disconnected to AP!\r\n", millis()); } void BlynkRun(void) { if (isWiFiConnected) { if(Blynk.connected()) { if (timer.isEnabled(numTimerReconnect)) { timer.disable(numTimerReconnect); Serial.printf("[%8lu] BlynkRun: Stop timer reconnected\r\n", millis()); } Blynk.run(); } else { if (!timer.isEnabled(numTimerReconnect)) { timer.enable(numTimerReconnect); Serial.printf("[%8lu] BlynkRun: Start timer reconnected\r\n", millis()); } } } } void ReconnectBlynk(void) { if (!Blynk.connected()) { if (Blynk.connect()) { Serial.printf("[%8lu] ReconnectBlynk: Blynk reconnected\r\n", millis()); } else { Serial.printf("[%8lu] ReconnectBlynk: Blynk not reconnected\r\n", millis()); } } else { Serial.printf("[%8lu] ReconnectBlynk: Blynk connected\r\n", millis()); } }
Приклад рішення для ESP32
Приклад для ESP32 дещо відрізняється з попереднім для ESP8266, але логіка роботи залишається такою самою:
#include <Arduino.h> #include <WiFi.h> #include "BlynkSimpleEsp32.h" const char* ssid = "MY_SSID"; const char* password = "MY_PASS"; const char* blynkToken = "MY_TOKEN"; bool isWiFiConnected = false; int numTimerReconnect = 0; BlynkTimer timer; void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info); void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); void ReconnectBlynk(void); void BlynkRun(void); void setup() { Serial.begin(115200); WiFi.onEvent(WiFiStationConnected, SYSTEM_EVENT_STA_GOT_IP); WiFi.onEvent(WiFiStationDisconnected, SYSTEM_EVENT_STA_DISCONNECTED); WiFi.begin(ssid, password); Blynk.config(blynkToken); if(Blynk.connect()) { Serial.printf("[%8lu] setup: Blynk connected\r\n", millis()); } else { Serial.printf("[%8lu] setup: Blynk no connected\r\n", millis()); } Serial.printf("[%8lu] Setup: Start timer reconnected\r\n", millis()); numTimerReconnect = timer.setInterval(60000, ReconnectBlynk); } void loop() { BlynkRun(); timer.run(); } void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info) { isWiFiConnected = true; Serial.printf("[%8lu] Interrupt: Connected to AP, IP: ", millis()); Serial.println(WiFi.localIP()); } void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { isWiFiConnected = false; Serial.printf("[%8lu] Interrupt: Disconnected to AP!\r\n", millis()); } void ReconnectBlynk(void) { if (!Blynk.connected()) { if (Blynk.connect()) { Serial.printf("[%8lu] ReconnectBlynk: Blynk reconnected\r\n", millis()); } else { Serial.printf("[%8lu] ReconnectBlynk: Blynk not reconnected\r\n", millis()); } } else { Serial.printf("[%8lu] ReconnectBlynk: Blynk connected\r\n", millis()); } } void BlynkRun(void) { if (isWiFiConnected) { if(Blynk.connected()) { if (timer.isEnabled(numTimerReconnect)) { timer.disable(numTimerReconnect); Serial.printf("[%8lu] BlynkRun: Stop timer reconnected\r\n", millis()); } Blynk.run(); } else { if (!timer.isEnabled(numTimerReconnect)) { timer.enable(numTimerReconnect); Serial.printf("[%8lu] BlynkRun: Start timer reconnected\r\n", millis()); } } } }
Розумію, що для початківця це доволі складний код і потребує детальних пояснень. Тому я підготував відео з поясненням і демонстрацією роботи з кнопкою, світлодіодом і таймером. А також демонстраційний код доступний і для завантаження і для ESP8266 , і для ESP32. Приємного перегляду.