// ------------------------------------------------------------------------------------------------------------ // // --- D a r k N e t S e r v e r & M e s h & B T B Y T O M A S Z M A J C H E R --------- // // ------------------------------------------------------------------------------------------------------------ // // // by Tomasz Majcher (TLG) Trans Line Group, Lubin POLSKA // NIP: 692-201-09-78 // TEL: 667-08-21-21 // mail: transline.majcher@gmail.com // // // // // // // ------------------------------------------------------------------------------------------------------------ // // --- HISTORIA WERSJI ---------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // // // DarkNet Server v0.02 - rozbudowa usług MESH // DarkNet Server v0.01 - budowa pod serwer WEATHER // // ------------------------------------------------------------------------------------------------------------ // // --- DOŁĄCZONE NAGŁÓWKI BIBLIOTEK --------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // #include #include #include #include #include // NTP klient (czas) #include // parser #include // UDP Wi-Fi #include #include #include #include // zegar RTC ESP32 #include "tools.h" // dołącz moje narzędzia // ------------------------------------------------------------------------------------------------------------ // // --- D E F I N I C J E -------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // #define MESH_PREFIX "ESP_Root" // nazwa sieci MESH #define MESH_PASSWORD "ESP_Root" // hasło sieci MESH #define MESH_PORT 5555 // port sieci MESH #define STATION_SSID "XXXXXXXXXX" // nazwa sieci Wi-Fi (router podłączony do sieci) #define STATION_PASSWORD "XXXXXXXXXX" // hasło sieci Wi-Fi (router podłączony do sieci) #define HOSTNAME "DarkNet" // nazwa hosta (bridge) most sieci MESH i INTERNET #define SERIAL 1 // włącz terminal SERIAL.MONITOR #define SPEED 115200 // prędkość terminala SERIAL #define THREAD_INFO 0 #define CORE0_TASK1 1 // ------------------------------------------------------------------------------------------------------------ // // --- P R O T O T Y P Y -------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // void receivedCallback( const uint32_t &from, const String &msg ); void mqttCallback(char* topic, byte* payload, unsigned int length); // ------------------------------------------------------------------------------------------------------------ // // --- O B I E K T Y ------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // WiFiUDP ntpUDP; // dla NTP (pobieranie czasu z internetu) NTPClient timeClient(ntpUDP, "pool.ntp.org", 7200); // dla NTP (pobieranie czasu z internetu) IPAddress getlocalIP(); // pobierz adres lokalny IP IPAddress myIP(0,0,0,0); // mój adres IP IPAddress mqttBroker(192, 168, 1, 1); // mój adres IP painlessMesh mesh; // obiekt mesh WiFiClient wifiClient; // obiekt WiFi HTTPClient http; // obiekt HTTP PubSubClient mqttClient(mqttBroker, 1883, mqttCallback, wifiClient); ESP32Time rtc; JSONVar JSON_Astronomy; // obiekt Astronomia JSONVar JSON_Weather; // obiekt Pogoda JSONVar JSON_Forecast; // obiekt Forecast JSONVar JSON_Air; // obiekt Powietrze JSONVar JSON_Mesh; // obiekt Mesh Incoming void Core0_Task1( void * pvParameters ); // funkcja Task1 dla rdzenia nr. 0 CPU void Core0_Task2( void * pvParameters ); // funkcja Task2 dla rdzenia nr. 0 CPU void Core1_Task1( void * pvParameters ); // funkcja Task1 dla rdzenia nr. 1 CPU void Core1_Task2( void * pvParameters ); // funkcja Tasl2 dla rdzenia nr. 1 CPU TaskHandle_t CPU_Core_0; // rdzeń nr. 0 CPU - ESP32 TaskHandle_t CPU_Core_1; // rdzeń nr. 1 CPU - ESP32 // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- M I E S I Ą C E P L ---------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // const char MONTH_00 [] = "Error"; const char MONTH_01 [] = "Styczeń"; const char MONTH_02 [] = "Luty"; const char MONTH_03 [] = "Marzec"; const char MONTH_04 [] = "Kwiecień"; const char MONTH_05 [] = "Maj"; const char MONTH_06 [] = "Czerwiec"; const char MONTH_07 [] = "Lipiec"; const char MONTH_08 [] = "Sierpień"; const char MONTH_09 [] = "Wrzesień"; const char MONTH_10 [] = "Pazdziernik"; const char MONTH_11 [] = "Listopad"; const char MONTH_12 [] = "Grudzień"; const char* const MONTH [] = { MONTH_00, MONTH_01, MONTH_02, MONTH_03, MONTH_04, MONTH_05, MONTH_06, MONTH_07, MONTH_08, MONTH_09, MONTH_10, MONTH_11, MONTH_12 }; // ------------------------------------------------------------------------------------------------------------ // // --- Z E G A R N T P ------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // struct NTP_TIME { String SformatowanaData; String SformatowanaDataPL; int DzienTygodnia; int DzienMiesiaca; int Miesiac; int Rok; String SformatowanyCzas; String SformatowanyCzasHM; int Godzina; int Minuta; int Sekunda; } zegar; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- A S T R O N O M I A ------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // struct ASTRONOMY { String miejscowosc = ""; String kraj = ""; double szerokosc_geograficzna = 0; double dlugosc_geograficzna = 0; long czas_epoch = 0; String czas_lokalny = ""; String wschod_slonca = ""; String zachod_slonca = ""; String wschod_ksiezyca = ""; String zachod_ksiezyca = ""; String faza_ksiezyca = ""; String oswietlenie_ksiezyca = ""; } astronomia; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- P O G O D A -------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // struct Weather { String miejscowosc = ""; String kraj = ""; double szerokosc_geograficzna = 0; double dlugosc_geograficzna = 0; String id = ""; long czas_epoch = 0; String czas_lokalny = ""; String ostatnia_aktualizacja = ""; double temperatura_C = 0; double temperatura_C_odczuwalna = 0; String kondycja = ""; double predkosc_wiatru_kph = 0; double podmuchy_wiatru = 0; int kierunek_wiatru_stopnie = 0; String kierunek_wiatru_kompas = ""; int cisnienie = 0; double opady = 0; int wilgotnosc = 0; int zachmurzenie = 0; int widzialnosc = 0; int index_uv = 0; } pogoda; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- P O W I E T R Z E -------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // struct Air { double co = 0; // Carbon Monoxide (μg/m3) - Tlenek węgla (μg / m3) double o3 = 0; // Ozone (μg/m3) - Ozon (μg / m3) double no2 = 0; // Nitrogen dioxide (μg/m3) - Dwutlenek azotu (μg / m3) double so2 = 0; // Sulphur dioxide (μg/m3) - Dwutlenek siarki (μg / m3) double pm25 = 0; // PM2.5 (μg/m3) - aerozole atmosferyczne o średnicy nie większej niż 2,5 μm double pm10 = 0; // PM10 (μg/m3) - mieszanina zawieszonych w powietrzu cząsteczek o średnicy nie większej niż 10 μm int Defra = 0; // Air Quality Index - index jakości powietrza } powietrze; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- P A R S E R M S G S E N D ------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // struct JSON_MSG { String czas; // JSON czas HH:MM:SS String czasHM; // JSON czas HH:MM String data; // JSON data DD.MM.YYYY String dataPL; // JSON data DD miesiac YYYY } jmsg; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- F L A G I ---------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // bool F_Astronomia = false; bool F_Pogoda = false; bool F_Prognoza = false; bool F_Powietrze = false; bool F_Zegar = false; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- M I L L I S -------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // unsigned long timeZERO = 0; unsigned long task01m = 0; unsigned long task05m = 0; unsigned long task10m = 0; unsigned long task15m = 0; unsigned long timeout_task01m = 0; unsigned long timeout_task05m = 0; unsigned long timeout_task10m = 0; unsigned long timeout_task15m = 0; String root = "{\"ID\":\"ROOT\",\"CODE\":0000,\"ROOT\":\"Ja tu rządze [DarkNet] mesh serwer\"}"; // ------------------------------------------------------------------------------------------------------------ // // --- Z M I E N N E G L O B A L N E ------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // --- P A R S E R M E S H ---------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // struct MeshParser { long Id; int Code; } meshParser; // ------------------------------------------------------------------------------------------------------------ // // --- p a r s e r m s g ------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // void parserMsg(const String &msg) { JSON_Mesh = JSON.parse(msg); meshParser.Id = JSON_Mesh["ID"]; // ID urządzenia ESP w sieci MESH meshParser.Code = JSON_Mesh["CODE"]; // KOD rządania z ESP w sieci MESH } // ------------------------------------------------------------------------------------------------------------ // // --- o d b i o r n i k b r o a d c a s t ------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // void receivedCallback( const uint32_t &from, const String &msg ) { Serial.printf("\n[ESP Bridge] [otrzymałem od] %u [wiadomosc JSON] %s", from, msg.c_str()); parserMsg(msg); switch(meshParser.Code) { case 0000 : mesh.sendSingle ( from, root.c_str()); break; case 1001 : mesh.sendSingle ( from, jmsg.czas.c_str() ); // jeśli nadawca wysłał kod 1001 wyślij mu aktualny czas Serial.printf("\n[ESP Bridge] [wysyłam do] %u [wiadomosc JSON] %s", from, jmsg.czas.c_str()); break; case 1002 : mesh.sendSingle ( from, jmsg.czasHM.c_str() ); // jeśli nadawca wysłał kod 1002 wyślij mu aktualny czas Serial.printf("\n[ESP Bridge] [wysyłam do] %u [wiadomosc JSON] %s", from, jmsg.czasHM.c_str()); break; case 1011 : mesh.sendSingle ( from, jmsg.data.c_str() ); // jeśli nadawca wysłał kod 1011 wyślij mu aktualną datę - format: DD.MM.RRRR Serial.printf("\n[ESP Bridge] [wysyłam do] %u [wiadomosc JSON] %s", from, jmsg.data.c_str()); break; case 1012 : mesh.sendSingle ( from, jmsg.dataPL.c_str() ); // jeśli nadawca wysłał kod 1012 wyślij mu aktualną datę - format: DD miesiac RRRR Serial.printf("\n[ESP Bridge] [wysyłam do] %u [wiadomosc JSON] %s", from, jmsg.dataPL.c_str()); break; default : mesh.sendSingle ( from, "nieznany kod mesh" ); break; } } // ------------------------------------------------------------------------------------------------------------ // // --- m q t t C a l l b a c k ----------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // void mqttCallback(char* topic, uint8_t* payload, unsigned int length) { char* cleanPayload = (char*)malloc(length+1); memcpy(cleanPayload, payload, length); cleanPayload[length] = '\0'; String msg = String(cleanPayload); free(cleanPayload); String targetStr = String(topic).substring(16); if(targetStr == "gateway") { if(msg == "getNodes") { auto nodes = mesh.getNodeList(true); String str; for (auto &&id : nodes) str += String(id) + String(" "); mqttClient.publish("painlessMesh/from/gateway", str.c_str()); } } else if(targetStr == "broadcast") { mesh.sendBroadcast(msg); } else { uint32_t target = strtoul(targetStr.c_str(), NULL, 10); if(mesh.isConnected(target)) { mesh.sendSingle(target, msg); } else { mqttClient.publish("painlessMesh/from/gateway", "Klient nie podłaczony!"); } } } // // ------------------------------------------------------------------------------------------------------------ // // --- M U L T I - C O R E T A S K --- // // ------------------------------------------------------------------------------------------------------------ // // // // // // ------------------------------------------------------------------------------------------------------------ // // --- CORE0 TASK1 POBIERANIE CZASU i DATY Z SERWERA NTP i AKTUALIZACJA ZEGARA ESP32 RTC --- // // ------------------------------------------------------------------------------------------------------------ // // void Core0_Task1( void * pvParameters ) { for(;;) { #if THREAD_INFO PrintLine(60); PrintMSG("ESP32","CORE", "Wykonuje watek TASK1 na CORE0"); #endif timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); struct tm *ptm = gmtime ((time_t *)&epochTime); zegar.Godzina = timeClient.getHours(); zegar.Minuta = timeClient.getMinutes(); zegar.Sekunda = timeClient.getSeconds(); zegar.SformatowanyCzas = timeClient.getFormattedTime(); zegar.DzienTygodnia = timeClient.getDay(); zegar.DzienMiesiaca = ptm->tm_mday; zegar.Miesiac = ptm->tm_mon+1; zegar.Rok = ptm->tm_year+1900; if (zegar.Godzina < 10) { zegar.SformatowanyCzasHM = "0" + String (zegar.Godzina) + ":"; } else zegar.SformatowanyCzasHM = String(zegar.Godzina) + ":"; if (zegar.Minuta < 10) { zegar.SformatowanyCzasHM += "0" + String (zegar.Minuta) + ":"; } else zegar.SformatowanyCzasHM += String(zegar.Minuta); if (zegar.Rok !=1970) { if(zegar.DzienMiesiaca < 10) { zegar.SformatowanaData = "0" + String(zegar.DzienMiesiaca) + "."; zegar.SformatowanaDataPL = "0" + String(zegar.DzienMiesiaca) + " "; } else { zegar.SformatowanaData = String(zegar.DzienMiesiaca) + "."; zegar.SformatowanaDataPL = String(zegar.DzienMiesiaca) + " "; } if(zegar.Miesiac < 10) { zegar.SformatowanaData += "0" + String(zegar.Miesiac) + "."; zegar.SformatowanaDataPL += String(MONTH[zegar.Miesiac]) + " "; } else { zegar.SformatowanaData += String(zegar.Miesiac) + "."; zegar.SformatowanaDataPL += String(MONTH[zegar.Miesiac]) + " "; } zegar.SformatowanaData += String(zegar.Rok); zegar.SformatowanaDataPL += String(zegar.Rok); // --- zapisz aktualny czas pobrany z serwera NTP do zegara RTC --------------------------------------- // rtc.setTime(zegar.Sekunda, zegar.Minuta, zegar.Godzina, zegar.DzienMiesiaca, zegar.Miesiac, zegar.Rok); // --- zbuduj obiekty typu (JSON STRING) do odesłania na żadanie do innego ESP w sieci MESH jmsg.czas = "{\"ID\":\"ROOT\",\"CODE\":1001,\"CZAS\":\"" + zegar.SformatowanyCzas + "\"}"; jmsg.czasHM = "{\"ID\":\"ROOT\",\"CODE\":1002,\"CZAS\":\"" + zegar.SformatowanyCzasHM + "\"}"; jmsg.data = "{\"ID\":\"ROOT\",\"CODE\":1011,\"DATA\":\"" + zegar.SformatowanaData + "\"}"; jmsg.dataPL = "{\"ID\":\"ROOT\",\"CODE\":1012,\"DATA\":\"" + zegar.SformatowanaDataPL + "\"}"; #if CORE0_TASK1 PrintLine(60); PrintMSG("CORE0_TASK1", "NTP Time", zegar.SformatowanyCzas.c_str()); PrintMSG("CORE0_TASK1", "NTP Date", zegar.SformatowanaData.c_str()); Serial.printf("\n[CORE0_TASK1] [RTC Time] "); Serial.print(rtc.getTime()); Serial.printf("\n[CORE0_TASK1] [RTC Date] "); Serial.print(rtc.getDate()); Serial.printf("\n[CORE0_TASK1] [FREE RAM] "); Serial.print(ESP.getFreeHeap()); PrintLine(60); PrintEND(); #endif F_Zegar = true; // dane OK, flaga na true } else F_Zegar = false; // dane złe, flaga na false vTaskDelay(60000 / portTICK_PERIOD_MS); // wykonuj 1 minutę } } // // ------------------------------------------------------------------------------------------------------------ // // --- CORE0 TASK2 POBIERANIE ASTRONOMII --- // // ------------------------------------------------------------------------------------------------------------ // // void Core0_Task2( void * pvParameters ) // Rdzeń 0 Zadanie 1 { // początek for(;;) // nieskończona pętla { // początek FOR delay(3600000); // sprawdzaj co 1 godzinę } } // // ------------------------------------------------------------------------------------------------------------ // // --- CORE1 TASK1 // ------------------------------------------------------------------------------------------------------------ // void Core1_Task1( void * pvParameters ) // Rdzeń 0 Zadanie 1 { // początek for(;;) // nieskończona pętla { // początek FOR #if SERIAL PrintLine(60); PrintMSG("ESP32","CORE", "Wykonuje watek Task1 na CORE-1"); #endif delay(1800000); // wykonuj co 30 minut } } // ------------------------------------------------------------------------------------------------------------ // // --- CORE1 TASK2 // ------------------------------------------------------------------------------------------------------------ // void Core1_Task2( void * pvParameters ) // Rdzeń 0 Zadanie 1 { // początek for(;;) // nieskończona pętla { // początek FOR #if SERIAL PrintLine(60); PrintMSG("ESP32","CORE", "Wykonuje watek Task2 na CORE-1"); #endif mesh.sendBroadcast( root.c_str() ); // roześlij Broadcast co wszystkich w sieci MESH delay(900000); // wykonuj co 15 minut } } // ------------------------------------------------------------------------------------------------------------ // // --- p o b i e r z a d r e s I P ----------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // IPAddress getlocalIP() { return IPAddress(mesh.getStationIP()); } // ------------------------------------------------------------------------------------------------------------ // // --- Aktualizacja Pogody z Serwera ------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // // String httpGETRequest(const char* serverName) { HTTPClient http; http.begin(serverName); int httpResponseCode = http.GET(); String bufor = "{}"; if ( httpResponseCode > 0 ) { #if SERIAL //Serial.print("\nHTTP Response code: "); //Serial.print(httpResponseCode); #endif bufor = http.getString(); } else { #if SERIAL //Serial.print("Error code: "); //Serial.println(httpResponseCode); #endif } http.end(); return bufor; } // // ------------------------------------------------------------------------------------------------------------ // // --- A K T U A L I Z A C J A P O G O D Y --- // // ------------------------------------------------------------------------------------------------------------ // // void PogodaAktualizuj() { PrintLine(60); PrintMSG("ESP32","MyTask", "Aktualizję pogodę z serwera : api.weatherapi.com"); String path = "http://api.weatherapi.com/v1/current.json?key=d27d7ab450e84466822133129211704&q=Mieroszow&aqi=no"; String jsonBuffer = httpGETRequest(path.c_str()); JSON_Weather = JSON.parse(jsonBuffer); if (JSON.typeof(JSON_Weather) == "undefined") { PrintLine(60); PrintMSG("DarkNet", "POGODA PARSER", "BŁĄD, BRAK DANYCH" ); } pogoda.miejscowosc = JSON_Weather["location"]["name"]; pogoda.kraj = JSON_Weather["location"]["country"]; pogoda.szerokosc_geograficzna = JSON_Weather["location"]["lat"]; pogoda.dlugosc_geograficzna = JSON_Weather["location"]["lon"]; pogoda.id = JSON_Weather["location"]["tz_id"]; pogoda.czas_epoch = JSON_Weather["location"]["localtime_epoch"]; pogoda.czas_lokalny = JSON_Weather["location"]["localtime"]; pogoda.ostatnia_aktualizacja = JSON_Weather["current"]["last_updated"]; pogoda.temperatura_C = JSON_Weather["current"]["temp_c"]; pogoda.temperatura_C_odczuwalna = JSON_Weather["current"]["feelslike_c"]; pogoda.kondycja = JSON_Weather["current"]["condition"]["text"]; pogoda.predkosc_wiatru_kph = JSON_Weather["current"]["wind_kph"]; pogoda.kierunek_wiatru_stopnie = JSON_Weather["current"]["wind_degree"]; pogoda.kierunek_wiatru_kompas = JSON_Weather["current"]["wind_dir"]; pogoda.podmuchy_wiatru = JSON_Weather["current"]["gust_kph"]; pogoda.cisnienie = JSON_Weather["current"]["pressure_mb"]; pogoda.opady = JSON_Weather["current"]["precip_mm"]; pogoda.wilgotnosc = JSON_Weather["current"]["humidity"]; pogoda.zachmurzenie = JSON_Weather["current"]["cloud"]; pogoda.widzialnosc = JSON_Weather["current"]["vis_km"]; pogoda.index_uv = JSON_Weather["current"]["uv"]; if(pogoda.miejscowosc == "Lubin") { PrintLine(60); Serial.printf("\n[DarkNet] [Pogoda] Miejscowość \t\t: "); Serial.print(pogoda.miejscowosc); Serial.printf("\n[DarkNet] [Pogoda] Kraj \t\t: "); Serial.print(pogoda.kraj); Serial.printf("\n[DarkNet] [Pogoda] Szer.Geograficzna \t: %2.2f",pogoda.szerokosc_geograficzna); Serial.printf("\n[DarkNet] [Pogoda] Dług.Geograficzna \t: %2.2f",pogoda.dlugosc_geograficzna); Serial.printf("\n[DarkNet] [Pogoda] Czas Epoch \t\t: %u",pogoda.czas_epoch ); Serial.printf("\n[DarkNet] [Pogoda] Serwer ID \t\t: "); Serial.print( pogoda.id ); Serial.printf("\n[DarkNet] [Pogoda] Czas Epoch \t\t: %u",pogoda.czas_epoch ); Serial.printf("\n[DarkNet] [Pogoda] Czas Lokalny \t: "); Serial.print( pogoda.czas_lokalny ); Serial.printf("\n[DarkNet] [Pogoda] Aktualizacja \t: "); Serial.print( pogoda.ostatnia_aktualizacja ); Serial.printf("\n[DarkNet] [Pogoda] Temperatura \t\t: %2.2f",pogoda.temperatura_C); Serial.printf("\n[DarkNet] [Pogoda] Temp.Odczuwalna \t: %2.2f",pogoda.temperatura_C_odczuwalna); Serial.printf("\n[DarkNet] [Pogoda] Opis pogody \t\t: "); Serial.print(pogoda.kondycja); Serial.printf("\n[DarkNet] [Pogoda] Predkosc wiatru \t: %2.2f",pogoda.predkosc_wiatru_kph); Serial.printf("\n[DarkNet] [Pogoda] Podmuchy wiatru \t: %2.2f",pogoda.podmuchy_wiatru); Serial.printf("\n[DarkNet] [Pogoda] Kierunek wiatru \t: %2.2f",pogoda.kierunek_wiatru_stopnie); Serial.printf("\n[DarkNet] [Pogoda] Kierunek wiatru \t: "); Serial.print(pogoda.kierunek_wiatru_kompas); Serial.printf("\n[DarkNet] [Pogoda] Cisnienie \t\t: %d",pogoda.cisnienie); Serial.printf("\n[DarkNet] [Pogoda] Opady deszczu \t: %2.2f",pogoda.opady); Serial.printf("\n[DarkNet] [Pogoda] Wilgotnosc \t\t: %d",pogoda.wilgotnosc); Serial.printf("\n[DarkNet] [Pogoda] Zachmurzenie \t: %d",pogoda.zachmurzenie); Serial.printf("\n[DarkNet] [Pogoda] Widzialnosc \t\t: %d",pogoda.widzialnosc); Serial.printf("\n[DarkNet] [Pogoda] Index UV \t\t: %d",pogoda.index_uv); PrintLine(60); PrintEND(); F_Pogoda = true; // dane OK, ustaw flagę na true } else F_Pogoda = false; // dane ZŁE, ustaw flagę na false } // // ------------------------------------------------------------------------------------------------------------ // // --- A K T U A L I Z A C J A A S T R O N O M I I --- // // ------------------------------------------------------------------------------------------------------------ // // void AstronomiaAktualizuj() { PrintLine(60); PrintMSG("ESP32","MyTask", "Aktualizję astronomię z serwera : api.weatherapi.com"); // pobierz dane astronomiczne z serwera dla miasta LUBIN String path = "http://api.weatherapi.com/v1/astronomy.json?key=d27d7ab450e84466822133129211704&q=Mieroszow&dt=2021-04-17"; String jsonBuffer = httpGETRequest(path.c_str()); JSON_Astronomy = JSON.parse(jsonBuffer); if (JSON.typeof(JSON_Astronomy) == "undefined") { PrintLine(60); PrintMSG("DarkNet", "ASTRONOMIA PARSER", "BŁĄD, BRAK DANYCH" ); } astronomia.miejscowosc = JSON_Astronomy["location"]["name"]; astronomia.kraj = JSON_Astronomy["location"]["country"]; astronomia.szerokosc_geograficzna = JSON_Astronomy["location"]["lat"]; astronomia.dlugosc_geograficzna = JSON_Astronomy["location"]["lon"]; astronomia.czas_epoch = JSON_Astronomy["location"]["localtime_epoch"]; astronomia.czas_lokalny = JSON_Astronomy["location"]["localtime"]; astronomia.wschod_slonca = JSON_Astronomy["astronomy"]["astro"]["sunrise"]; astronomia.zachod_slonca = JSON_Astronomy["astronomy"]["astro"]["sunset"]; astronomia.wschod_ksiezyca = JSON_Astronomy["astronomy"]["astro"]["moonrise"]; astronomia.zachod_ksiezyca = JSON_Astronomy["astronomy"]["astro"]["moonset"]; astronomia.faza_ksiezyca = JSON_Astronomy["astronomy"]["astro"]["moon_phase"]; astronomia.oswietlenie_ksiezyca = JSON_Astronomy["astronomy"]["astro"]["moon_illumination"]; if(astronomia.miejscowosc == "Lubin") { PrintLine(60); Serial.printf("\n[DarkNet] [Astronomia] Miejscowość \t\t: "); Serial.print(astronomia.miejscowosc); Serial.printf("\n[DarkNet] [Astronomia] Kraj \t\t\t: "); Serial.print(astronomia.kraj); Serial.printf("\n[DarkNet] [Astronomia] Szer.Geograficzna \t: %2.2f",astronomia.szerokosc_geograficzna); Serial.printf("\n[DarkNet] [Astronomia] Dług.Geograficzna \t: %2.2f",astronomia.dlugosc_geograficzna); Serial.printf("\n[DarkNet] [Astronomia] Czas Epoch \t\t: %u",astronomia.czas_epoch ); Serial.printf("\n[DarkNet] [Astronomia] Czas Lokalny \t\t: "); Serial.print( astronomia.czas_lokalny ); Serial.printf("\n[DarkNet] [Astronomia] Wschód Słońca \t\t: "); Serial.print(astronomia.wschod_slonca ); Serial.printf("\n[DarkNet] [Astronomia] Zachód Słońca \t\t: "); Serial.print(astronomia.zachod_slonca ); Serial.printf("\n[DarkNet] [Astronomia] Wschód Księżyca \t\t: "); Serial.print(astronomia.wschod_ksiezyca ); Serial.printf("\n[DarkNet] [Astronomia] Zachód Księżyca \t\t: "); Serial.print(astronomia.zachod_ksiezyca ); Serial.printf("\n[DarkNet] [Astronomia] Faza Księżyca \t\t: "); Serial.print(astronomia.faza_ksiezyca); Serial.printf("\n[DarkNet] [Astronomia] Oświetlenie Księżyca \t: "); Serial.print(astronomia.oswietlenie_ksiezyca ); PrintLine(60); PrintEND(); F_Astronomia = true; // dane OK, ustaw flagę na true } else F_Astronomia = false; // dane ZŁE, ustaw flagę na false } // // ------------------------------------------------------------------------------------------------------------ // // --- A K T U A L I Z A C J A J A K O Ś C I P O W I E T R Z A --- // // ------------------------------------------------------------------------------------------------------------ // // void PowietrzeAktualizuj() { PrintLine(60); PrintMSG("ESP32","MyTask", "Aktualizję jakość powietrza z serwera : api.weatherapi.com"); // pobierz dane jakości powietrza z serwera dla miasta LUBIN String path = "http://api.weatherapi.com/v1/current.json?key=d27d7ab450e84466822133129211704&q=Mieroszow&aqi=yes"; String jsonBuffer = httpGETRequest(path.c_str()); JSON_Air = JSON.parse(jsonBuffer); if (JSON.typeof(JSON_Air) == "undefined") { PrintLine(60); PrintMSG("DarkNet", "AIR PARSER", "BŁĄD, BRAK DANYCH" ); } powietrze.co = JSON_Air["current"]["air_quality"]["co"]; powietrze.o3 = JSON_Air["current"]["air_quality"]["o3"]; powietrze.no2 = JSON_Air["current"]["air_quality"]["no2"]; powietrze.so2 = JSON_Air["current"]["air_quality"]["so2"]; powietrze.pm25 = JSON_Air["current"]["air_quality"]["pm2_5"]; powietrze.pm10 = JSON_Air["current"]["air_quality"]["pm10"]; powietrze.Defra = JSON_Air["current"]["air_quality"]["gb-defra-index"]; if (powietrze.co != 0) { PrintLine(60); Serial.printf("\n[DarkNet] [Jakość Powietrza] Tlenek węgla \t\t: %2.8f [μg/ m3]", powietrze.co); Serial.printf("\n[DarkNet] [Jakość Powietrza] Dwutlenek azotu \t\t: %2.8f [μg/ m3]", powietrze.no2); Serial.printf("\n[DarkNet] [Jakość Powietrza] Ozon \t\t\t: %2.8f [μg/m3]", powietrze.o3); Serial.printf("\n[DarkNet] [Jakość Powietrza] Pyły i aerozole PM2.5 \t: %2.8f [μm]", powietrze.pm25); Serial.printf("\n[DarkNet] [Jakość Powietrza] Pyły i aerozole PM10 \t: %2.8f [μm]", powietrze.pm10); Serial.printf("\n[DarkNet] [Jakość Powietrza] Index jakości \t\t: %d IND", powietrze.Defra); PrintLine(60); PrintEND(); F_Powietrze = true; } else F_Powietrze = false; } // // ------------------------------------------------------------------------------------------------------------ // // --- A K T U A L I Z A C J A P R O G N O Z Ę --- // // ------------------------------------------------------------------------------------------------------------ // // void PrognozaAktualizuj() { PrintLine(60); PrintMSG("ESP32","MyTask", "Aktualizję prognozę z serwera : api.weatherapi.com"); // pobierz dane astronomiczne z serwera dla miasta LUBIN String path = "http://api.weatherapi.com/v1/forecast.json?key=d27d7ab450e84466822133129211704&q=Mieroszow&days=1&aqi=no&alerts=no"; String jsonBuffer = httpGETRequest(path.c_str()); JSON_Forecast = JSON.parse(jsonBuffer); if (JSON.typeof(JSON_Forecast) == "undefined") { PrintLine(60); PrintMSG("DarkNet", "AIR PARSER", "BŁĄD, BRAK DANYCH" ); } } // // ------------------------------------------------------------------------------------------------------------ // // --- MyTask ------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // // void MyTask() { timeZERO = millis(); // zapisz czas 0 task01m = timeZERO - timeout_task01m; // wyznacz nowy task05m = timeZERO - timeout_task05m; // wyznacz nowy task10m = timeZERO - timeout_task10m; // wyznacz nowy task15m = timeZERO - timeout_task15m; // wyznacz nowy // --- ZADANIE co 1 minutę ------------------------------------------------------------------------------- // if(task01m >= 60000UL) // wykonuj co 1 minutę { if (!F_Astronomia) AstronomiaAktualizuj(); // jeśli BRAK DANYCH wykonuj co minutę if (!F_Pogoda) PogodaAktualizuj(); // jeśli BRAK DANYCH wykonuj co minutę if (!F_Powietrze) PowietrzeAktualizuj(); // jeśli BRAK DANYCH wykonuj co minutę //if (!F_Prognoza) PrognozaAktualizuj(); // jeśli BRAK DANYCH wykonuj co minutę timeout_task01m = timeZERO; } // --- ZADANIE co 5 minut -------------------------------------------------------------------------------- // if(task05m >= 300000UL) // wykonuj co 5 minut { timeout_task05m = timeZERO; } // --- ZADANIE co 10 minut ------------------------------------------------------------------------------- // if(task10m >= 600000UL) // wykonuj co 10 minut { timeout_task10m = timeZERO; } // --- ZADANIE co 15 minut ------------------------------------------------------------------------------- // if(task15m >= 900000UL) // wykonuj co 15 minut { if (F_Astronomia) AstronomiaAktualizuj(); // jeśli DANE OK co 15 minut if (F_Pogoda) PogodaAktualizuj(); // jeśli DANE OK co 15 minut if (F_Powietrze) PowietrzeAktualizuj(); // jeśli DANE OK co 15 minut //if (F_Prognoza) PrognozaAktualizuj(); // jeśli BRAK DANYCH wykonuj co minutę timeout_task15m = timeZERO; } } // // ------------------------------------------------------------------------------------------------------------ // // --- S E T U P ---------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ // // void setup() { #if SERIAL Serial.begin(SPEED); // ustaw prędkość terminala SERIAL #endif mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION ); // ustaw przed init (), abyś mógł zobaczyć komunikaty startowe mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA, 6 ); mesh.onReceive(&receivedCallback); mesh.stationManual(STATION_SSID, STATION_PASSWORD); mesh.setHostname(HOSTNAME); mesh.setRoot(true); // sieć MESH na tym urządzeniu jako ROOT mesh.setContainsRoot(true); // sieć MESH na tym urządzeniu jako ROOT timeClient.begin(); // włącz klienta NTP (pobieranie czasu z internetu) // --- CPU_Core_0 ---------------------------------------------------------------------------------- xTaskCreatePinnedToCore(Core0_Task1, "CPU_Core_0", 5000, NULL, 1, &CPU_Core_0, 0); vTaskDelay(500 / portTICK_PERIOD_MS); xTaskCreatePinnedToCore(Core0_Task2, "CPU_Core_0", 5000, NULL, 1, &CPU_Core_0, 0); vTaskDelay(500 / portTICK_PERIOD_MS); // --- CPU_Core_1 ---------------------------------------------------------------------------------- xTaskCreatePinnedToCore(Core1_Task1, "CPU_Core_1", 5000, NULL, 1, &CPU_Core_1, 1); vTaskDelay(500 / portTICK_PERIOD_MS); xTaskCreatePinnedToCore(Core1_Task2, "CPU_Core_1", 5000, NULL, 1, &CPU_Core_1, 1); vTaskDelay(500 / portTICK_PERIOD_MS); } // ------------------------------------------------------------------------------------------------------------ // // --- L O O P ------------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------ // // void loop() { mesh.update(); // aktulizuj MESH mqttClient.loop(); // pętla dla klienta mqtt if(myIP != getlocalIP()) // jeśli moje IP różne od lokalnego IP { myIP = getlocalIP(); // zapisz lokalne IP #if SERIAL Serial.println("Adres lokalny IP: " + myIP.toString()); #endif if (mqttClient.connect("painlessMeshClient")) // jeśli client { mqttClient.publish("painlessMesh/from/gateway","Gotowe!"); mqttClient.subscribe("painlessMesh/to/#"); } } MyTask(); } // // ------------------------------------------------------------------------------------------------------------ // // --- E N D ------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------ //