Translate:
Informacje
WWW
PLIKI
-
Najnowsze wpisy
Najnowsze komentarze
- Andrzej o Czarne chmury nad BLYNK 1.0
- Marek Marczuk o Czarne chmury nad BLYNK 1.0
- Krzycho o Czarne chmury nad BLYNK 1.0
- Marek Marczuk o Czarne chmury nad BLYNK 1.0
- Marek Marczuk o Czarne chmury nad BLYNK 1.0
Archiwa
- Grudzień 2021 (1)
- Listopad 2021 (1)
- Październik 2019 (1)
- Czerwiec 2019 (1)
- Marzec 2019 (1)
- Styczeń 2019 (1)
- Listopad 2018 (2)
- Październik 2018 (1)
- Sierpień 2018 (1)
- Czerwiec 2018 (1)
- Maj 2018 (2)
- Kwiecień 2018 (4)
- Luty 2018 (4)
- Styczeń 2018 (5)
- Grudzień 2017 (2)
- Listopad 2017 (8)
- Październik 2017 (4)
- Wrzesień 2017 (7)
- Sierpień 2017 (4)
- Lipiec 2017 (1)
Kategorie
- Serwer Lokalny BLYNK (8)
- Zaczynamy (1)
- Ciekawostki (1)
- Aplikacja tel/tablet (15)
- Sterowanie z pulpitu (2)
- 5. Widgety (13)
- EVENTOR (2)
- Znalezione w sieci (1)
- Układy wieloprocesorowe (2)
- Na warsztacie u innych (2)
- komunikaty (2)
- Problemy (1)
- Uncategorized (5)
- 1. Ogólne (5)
- 2. Piny (3)
- 3. Komunikacja (11)
- API WEBHOOK (4)
- kontrola komunikacji (3)
- Nie blokujący BLYNK (3)
- 4. Biblioteki (3)
BLYNK blokuje program przy braku połączenia – co robić? cz. II
Rozwiązanie I – Łatanie dziur
Rozważmy najtrudniejszy przypadek – połączenie z serwerem BLYNK siecią WiFi. Złożoność problemu polega na tym, że biblioteka BLYNK oprócz połączenia z serwerem musi wcześniej zestawić połączenie WiFi. Ten problem nie występuje przy dostępie do sieci via Ethernet – tam połączenie dokonuje się sprzętowo bez udziału bibliotek BLYNKa.
Rozwiązanie jest jedno – należy w jakikolwiek sposób „ominąć” powyższe procedury jeśli nie dochodzi do połączenia w określonym czasie ale jednocześnie umożliwić połączenie gdy ustąpią przyczyny jego przerwania.Nie jest to proste zadanie.
Wiemy że program może zawiesić się na dwu procedurach BLYNK
- Blynk.begin(………)
- Blynk.run()
Blynk.begin(………)
zawiera w sobie kilka ważnych funkcji
- Ustawienie podstawowych parametrów dostępu do serwera BLYNK – AUTCH i adres serwera (publiczny – domyślny lub lokalny)
- Nawiązanie połączenia WiFi (ssid i pass) lub powtarzanie prób nawiązania połączenia WiFi – do skutku
- Nawiązanie połączenia z serwerem BLYNK lub powtarzanie prób nawiązania połączenia z serwerem – do skutku
Są więc dwa przypadki mogące zawiesić program na procedurze Blynk.begin – niemożność nawiązania połączenia WiFi i brak połączenia z serwerem. Oba te zdarzenia trzeba rozpatrywać osobno.
Po pierwsze musimy zamienić procedurę Blynk.begin kilkoma podprocedurami w sumie realizującymi całość funkcji. Dokumentacja BLYNKa zaleca następujący ciąg procedur:
Blynk.config(auth, server, port);
ustalającą parametry dostępu do serwera BLYNK
Blynk.connectWiFi(ssid, pass);
nawiązującą połączenie WiFi
Blynk.connect();
nawiązującą połączenie z serwerem BLYNK.
Po rozdzieleniu funkcji i sprawdzeniu w działaniu wiemy że:
- Pierwsza procedura nie wstrzymuje nigdy przebiegu programu
- Druga staje murem aż do nawiązania połączenia WiFi (niestety)
- Trzecia zatrzymuje program na około 5 sek przy braku połączenia z serwerem (choć powinna na 30 sek)
Z nawiązaniem połączenia WiFi jest więc problem – ale został on już szczęśliwie rozwiązany na forum BLYNKa. Należy użyć innej procedury, która jest „przelotowa” a dodatkowo sama odtwarza połączenie w tle działania programu głównego.
WiFi.begin(ssid, pass);
Pierwsza część problemu za nami.
Blynk.run()
To podstawowa procedura odpowiedzialna za wszystkie zdarzenia pomiędzy modułem, serwerem i aplikacją mobilną w czasie normalnej pracy systemu. Dodatkowo zawiera funkcję odtwarzania połączenia z serwerem w przypadku jego zaniku. Umieszczona w pętli głównej wywoływana jest setki a może tysiące razy w ciągu sekundy. Przy braku łączności praktycznie blokuje dostęp innych części programu do procesora. Rozwiązaniem jest sprawdzanie stanu łącza. Przy prawidłowym połączeniu Blynk.run() wywoływana jest z maksymalną częstotliwością. W razie awarii sieci lub serwera należy ją (lub Blynk.connect) uruchamiać w dużo dłuższych odstępach (sekundowych, minutowych). Dobór czasu zależy już od konkretnej aplikacji. Rozsądnym przedziałem jest 0,5 – 10 minut.
Szkielet instrukcji umożliwiający w miarę płynne działanie programu podstawowego przy problemach z łącznością wygląda mniej więcej tak.
#include <ESP8266WiFi.h> #include <BlynkSimpleEsp8266.h> #include <Timers.h> Timers <3> akcja; #define treconnect 30 //czasy wywoływania Blynk.run przy braku łączności w sek int liczreconnect = 10; void setup() { akcja.attach(0, 1000, testconnect); // timer 1 sek ....... WiFi.begin(ssid, pass); Blynk.config(auth, IPAddress(192, 168, 2, 19)); Blynk.connect(); ............. } void loop() { akcja.process(); // timer Timers.h if (Blynk.connected()) { Blynk.run(); } } void testconnect() //procedura wywoływana co 1 sek { if (Blynk.connected()) { liczreconnect = treconnect; } else { liczreconnect--; if (liczreconnect==0) { Blynk.connect(); liczreconnect = treconnect; } } }
Podsumowanie
Programowe ominięcie problemu zawieszania programu przez bibliotekę BLYNKa wymaga nieco zachodu i pewnej znajomości specyfiki systemu. Powyższy przykład jest maksymalnie złożony – w modułach z kablowym łączem do sieci problemy związane z WiFi nie występują. Nie jest to niestety uniwersalna recepta dla wszystkich obsługiwnych przez BLYNKa modułów i platform. To raczej wskazówka jak rozwiązać problem w swoim projekcie gdy program główny jest priorytetowy w stosunku do aplikacji BLYNK.
W kolejnym odcinku o optymalnym moim zdaniem rozwiązaniu tego problemu opartym na strukturze dwuprocesorowej.
12
Witam, twój sposób na działanie programu przy braku połączenia działa u mnie bardzo dobrze jednak w momencie gdy ESP32 połączy się ponownie, resetuje mi EPS32 i program zaczyna działać od nowa. W programie wykonują się różne rzeczy czasowo i jeśli już została wykonana pewna część programu to reconnect daje taki efekt że wykonuję się wszystko od nowa. Czy jest jakiś sposób by program został w tym samym miejscu w którym był przed ponownym połączeniem do sieci ?
opis dotyczy ESP8266
nie sprawdzałem tego w ESP32
Mam jeszcze jeden problem. Otóż teraz co pewien czas blynk się rozłącza i łączy podownie. Tak musi być?
na jakim procesorze pracujesz?
Próbowałem przez port 80 i nie udawało mi się połączyć – możliwe, że to wina biblioteki sprawdzę później jakiej używam.
Dziękuję Ci bardzo. Wszystko już działa jednak musiałem zrobić inaczej – nie korzystam z serwera lokalnego:
void setup()
{
akcja.attach(0, 1000, testconnect); // timer 1 sek
WiFi.begin(ssid, pass);
Blynk.config(auth, „blynk-cloud.com”, 8442); // dla serwera lokalnego
// Blynk.config(auth); /// dla Cloud server
// You can also specify server:
//Blynk.begin(auth, ssid, pass, „blynk-cloud.com”, 8442);
//Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);
//WiFi.begin(auth,ssid, pass);
Blynk.connect();
if (Blynk.connected()) Blynk.run(); else Blynk.connect();
// Debug console
Serial.begin(9600);
lcd.backlight();
lcd.begin(16,2);
lcd.init();
Serial.println(LED);
sensors.begin();
sensors.requestTemperatures();
timer.setInterval(1000L, temp);
// The begin call takes the width and height. This
// Should match the number provided to the constructor.
}
Cała funkcja setup – jakby ktoś potrzebował kiedyś
Pozdrawiam
Świetnie
co prawda trochę dziwne że udaje ci się łączyć z serwerem na porcie 8442. Od jakiegoś czasu domyślnym portem dla cloud servera jest port 80 i do łączenia powinna wystarczyć procedura Blynk.config(auth) chyba że używasz biblioteki poniżej 0.5.1
tu szczegóły
https://blynk.pl/blynk-zmiana-portow-czyli-male-trzesienie-ziemi/
https://pastebin.com/81bzv6GL
Tutaj mój kod. Problem jest taki, że jak jestem podłączony do wifi to wszystko fajnie lata. blynk pokazuje temperatury na smartfonie a wyświetlacz na ekranie. Problem gdy nie ma połączenia. Potrzebuję aby wyświetlacz prezentował temperatury bez połączenia wifi – miał być jako zabezpieczenie w razie gdyby połączenie zawiodło a nie działą wogóle.
Proszę rzuć okiem – może coś zauważysz. Kod z modyfikacjami podanymi przez Ciebie – niestety nie działa, pewnie coś robię nie tak ale nie jestem doświadczonym użytkownikiem arduino:)
Pozdrawiam !!
1. W setup() dodałeś procedurę Blynk.begin(auth, ssid, pass); i na niej wszystko staje. W moim przykładzie tego nie ma.
2. Nie wiem z jakim serwerem pracujesz ale kod wskazuje na serwer lokalny. Jesli tak to procedura Blynk.config(auth, IPAddress(192, 168, 2, 19)); nie połączy się z serwerem bo jego port został zmieniony na 8080
wstaw taki fragment kodu w setup()
————-
akcja.attach(0, 1000, testconnect); // timer 1 sek
WiFi.begin(ssid, password);
Blynk.config(auth, IPAddress(x, x, x, x), 8080); // dla serwera lokalnego
// Blynk.config(auth); /// dla Cloud server
Blynk.connect();
if (Blynk.connected()) Blynk.run(); else Blynk.connect();
……….
reszta wygląda ok
no to teraz wyrzuca mi: „‚WiFi’ was not declared in this scope”
problem jest chyba jeszcze w tym że zamiast bibliotek:
#include
#include
ja muszę przecież używać:
#include
#include
jeszcze raz pod linkiem wrzucam: https://pastebin.com/4G0jenwh
nie znam Yun ale w przykładzie dla tej płytki nie widzę obsługi wifi – przykład jest niby w podgrupie WiFi ale w środku nie ma żadnych danych do logowania w sieci
………….
#define BLYNK_PRINT Serial
#include
#include
// You should get Auth Token in the Blynk App.
char auth[] = „YourAuthToken”;
void setup()
{
Serial.begin(9600);
Blynk.begin(auth);
// You can also specify server:
//Blynk.begin(auth, „blynk-cloud.com”, 8442);
//Blynk.begin(auth, IPAddress(192,168,1,100), 8442);
}
void loop()
{
Blynk.run();
}
No przecież to Twój kod podany wyżej w artykule.
mea culpa
poprawiłem
masz u mnie nalewkę
https://pastebin.com/L58E4x1V
nie widzę definicji „akcja” po dołączeniu biblioteki Timers.h //
coś takiego
#include
Timers <7> akcja; // gdzie 7 do liczba potrzebnych w programie timerów
Kurczę coś nie mogę dać rady, bibliotekę Timers.h mam wrzuconą a po kompilacji i tak dostaje: „‚akcja’ was not declared in this scope” o co chodzi ??
Gdzie może być problem ?? dodam że korzystam z Arduino Yun
wrzuć kod na https://pastebin.com/ i wyślij link
popatrzę co tam się haczy
a skąd pobrać bibliotekę timers ??
np tutaj http://blynk.pl/pliki/Timers.zip
a tu oryginał ze strony autora
http://forum.arduinopolska.pl/attachment.php?aid=77 ale trzeba być zalogowanym na forum by go ściągnąć
Blynk nie będzie działał bo kierujesz połączenie na serwer lokalny
Blynk.config(auth, IPAddress(192, 168, 2, 19));
ma być tak jak w działającym ci programie z Blynk.begin(auth);
czyli Blynk.config(auth);
tu domyślnie kierujesz BLYNKa na serwer w chmurze
to nauczka dla mnie by pisać jaśniej w komentarzach
biblioteka timers.h MUSI działać 🙂
Cześć, niestety u mnie nie działa, mam podpięte po kablu(ethernet), mógłbyś napisać czy wtedy kod jest taki sam?
Dodatkowo u mnie nie działa biblioteka Timers.h(nie wiem czemu), więc zrobiłem to „ręcznie” na millisach.
Czy w linijce: Blynk.config(auth, IPAddress(192, 168, 2, 19)); mam podać adres IP który był przypisany mojemu arduino(mój 192.168.254.105)?
Mój kod już znasz dostawiłem tylko twoje linijki:
#include // standardowa biblioteka Arduino
#include // dolaczenie pobranej biblioteki I2C dla LCD
#include „RTClib.h”
#include „Adafruit_HTU21DF.h”
#include „i2c.h”
#include „i2c_BMP280.h”
#include
#include
#include „Timers.h”
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Ustawienie adresu ukladu na 0x27
RTC_DS1307 czas;
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
BMP280 bmp280;
#define led_blue 50
#define treconnect 30 //czasy wywoływania Blynk.run przy braku łączności w sek
int liczreconnect = 10;
enum{STAN1=1, STAN2};
int stan = STAN1;
int wilg;
int temp;
unsigned long cMillis1;
unsigned long pMillis1= 0;
unsigned long cMillis;
unsigned long pMillis = 0;
const long interval = 6000;
char auth[] = „4fc87431c0ec4c1e90778d8c5765b1c8”;
void setup() {
Serial.begin(9600);
// akcja.attach(0, 1000, testconnect); // timer 1 sek
// Blynk.begin(auth);
Blynk.config(auth, IPAddress(192, 168, 2, 19));
Blynk.connect();
pinMode(led_blue, OUTPUT);
htu.begin();
Wire.begin();
czas.begin();
lcd.begin(20,4); // Inicjalizacja LCD 2×16
lcd.backlight(); // zalaczenie podwietlenia
wilg = htu.readHumidity();
temp = htu.readTemperature();
}
void loop() {
cMillis1= millis();
if(cMillis1 – pMillis1>1000){
test_connect();
pMillis1 = cMillis1;
}
if (Blynk.connected()) {
Blynk.run();
}
cMillis = millis();
switch(stan){
case STAN1:
ZEGAR_HTU();
if(cMillis – pMillis > interval){
pMillis = cMillis;
lcd.clear();
stan=STAN2;
}
break;
case STAN2:
BMP_280();
if(cMillis – pMillis > interval){
pMillis = cMillis;
lcd.clear();
stan=STAN1;
}
break;
}
}
void ZEGAR_HTU(){
DateTime now = czas.now();
lcd.setCursor(5,0); // Ustawienie kursora w pozycji 0,0 (pierwszy wiersz, pierwsza kolumna)
lcd.print(„Temp: „);
lcd.print(temp);
lcd.print(„*C”);
lcd.setCursor(1,1); //Ustawienie kursora w pozycji 0,0 (drugi wiersz, pierwsza kolumna)
lcd.print(„Wilgotnosc: „);
lcd.print(wilg);
lcd.print(„%RH”);
lcd.setCursor(5,2);
lcd.print(now.day(), DEC);
lcd.print(‚.’);
lcd.print(now.month(), DEC);
lcd.print(‚.’);
lcd.print(now.year(), DEC);
lcd.setCursor(6,3);
lcd.print(now.hour(), DEC);
if(now.minute()<10){
lcd.print(':0');
}
else{
lcd.print(":");
}
lcd.print(now.minute(), DEC);
lcd.print(':');
lcd.print(now.second(), DEC);
}
void BMP_280(){
bmp280.initialize();
bmp280.setEnabled(0);
bmp280.triggerMeasurement();
bmp280.awaitMeasurement();
float temperature;
bmp280.getTemperature(temperature);
float pascal;
int hPascal = pascal/100;
bmp280.getPressure(pascal);
static float meters, metersold;
int metry = meters;
bmp280.getAltitude(meters);
metersold = (metersold * 10 + meters)/11;
bmp280.triggerMeasurement();
lcd.setCursor(2,0);
lcd.print(" Wys npm.: ");
lcd.print(metry);
lcd.print(" m");
lcd.setCursor(2,1);
lcd.print(" Temp: ");
lcd.print(temperature);
lcd.print(" *C");
lcd.setCursor(1,2);
lcd.print("Cisnienie atmosf.:");
lcd.setCursor(6,3);
lcd.print(hPascal);
lcd.print(" hPa");
}
void testconnect()
{
if (Blynk.connected()) {
digitalWrite(led_blue, HIGH); //wskaźnik łączności z serwerem stan wysoki- wyłączenie LEDa
} else {
digitalWrite(led_blue, LOW);
}
}
void test_connect(){ //procedura wywoływana co 1 sek
if (Blynk.connected()) {
liczreconnect = treconnect;
} else {
liczreconnect–;
if (liczreconnect==0) {
Blynk.connect();
liczreconnect = treconnect;
}
}
}
akcja.process() to cykliczne wywołanie timera odliczającego czasy w programie
a co to jest ‚akcja’ ??????