#include "network.h" #include "WiFi.h" #include "display.h" #include "options.h" #include "config.h" #include "telnet.h" #include "netserver.h" #include "player.h" Network network; TaskHandle_t syncTaskHandle; bool getWeather(char *wstr); void doSync(void * pvParameters); void ticks() { static const uint16_t weatherSyncInterval=1800; //static const uint16_t weatherSyncIntervalFail=10; static const uint16_t timeSyncInterval=3600; static uint16_t timeSyncTicks = 0; static uint16_t weatherSyncTicks = 0; static bool divrssi; timeSyncTicks++; weatherSyncTicks++; divrssi = !divrssi; if(network.forceTimeSync || network.forceWeather){ xTaskCreatePinnedToCore(doSync, "doSync", 1024 * 4, NULL, 0, &syncTaskHandle, 0); } if(timeSyncTicks >= timeSyncInterval){ timeSyncTicks=0; network.forceTimeSync = true; } if(weatherSyncTicks >= weatherSyncInterval){ weatherSyncTicks=0; network.forceWeather = true; } if(network.timeinfo.tm_year>100) { network.timeinfo.tm_sec++; mktime(&network.timeinfo); display.putRequest(CLOCK); } if(player.isRunning() && config.store.play_mode==PM_SDCARD) netserver.requestOnChange(SDPOS, 0); if(divrssi) { int rs = WiFi.RSSI(); netserver.setRSSI(rs); display.putRequest(DSPRSSI, rs); } } #define DBGAP false void Network::begin() { BOOTLOG("network.begin"); config.initNetwork(); ctimer.detach(); forceTimeSync = forceWeather = true; if (config.ssidsCount == 0 || DBGAP) { raiseSoftAP(); return; } byte ls = (config.store.lastSSID == 0 || config.store.lastSSID > config.ssidsCount) ? 0 : config.store.lastSSID - 1; byte startedls = ls; byte errcnt = 0; WiFi.mode(WIFI_STA); while (true) { Serial.printf("##[BOOT]#\tAttempt to connect to %s\n", config.ssids[ls].ssid); Serial.print("##[BOOT]#\t"); display.putRequest(BOOTSTRING, ls); WiFi.begin(config.ssids[ls].ssid, config.ssids[ls].password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); if(LED_BUILTIN!=255) digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); errcnt++; if (errcnt > 16) { errcnt = 0; ls++; if (ls > config.ssidsCount - 1) ls = 0; Serial.println(); break; } } if (WiFi.status() != WL_CONNECTED && ls == startedls) { raiseSoftAP(); Serial.println("##[BOOT]#\tdone"); return; } if (WiFi.status() == WL_CONNECTED) { config.setLastSSID(ls + 1); break; // отстрелялись } } Serial.println("."); Serial.println("##[BOOT]#\tdone"); if(LED_BUILTIN!=255) digitalWrite(LED_BUILTIN, LOW); status = CONNECTED; WiFi.setSleep(false); weatherBuf=NULL; trueWeather = false; #if (DSP_MODEL!=DSP_DUMMY || defined(USE_NEXTION)) && !defined(HIDE_WEATHER) weatherBuf = (char *) malloc(sizeof(char) * WEATHER_STRING_L); memset(weatherBuf, 0, WEATHER_STRING_L); #endif if(strlen(config.store.sntp1)>0 && strlen(config.store.sntp2)>0){ configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2); }else if(strlen(config.store.sntp1)>0){ configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1); } ctimer.attach(1, ticks); if (network_on_connect) network_on_connect(); } void Network::requestTimeSync(bool withTelnetOutput, uint8_t clientId) { if (withTelnetOutput) { char timeStringBuff[50]; strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &timeinfo); if (config.store.tzHour < 0) { telnet.printf(clientId, "##SYS.DATE#: %s%03d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin); } else { telnet.printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin); } } } void rebootTime() { ESP.restart(); } void Network::raiseSoftAP() { WiFi.mode(WIFI_AP); WiFi.softAP(apSsid, apPassword); Serial.println("##[BOOT]#"); BOOTLOG("************************************************"); BOOTLOG("Running in AP mode"); BOOTLOG("Connect to AP %s with password %s", apSsid, apPassword); BOOTLOG("and go to http:/192.168.4.1/ to configure"); BOOTLOG("************************************************"); status = SOFT_AP; if(config.store.softapdelay>0) rtimer.once(config.store.softapdelay*60, rebootTime); } void Network::requestWeatherSync(){ display.putRequest(NEWWEATHER); } void doSync( void * pvParameters ) { static uint8_t tsFailCnt = 0; //static uint8_t wsFailCnt = 0; if(network.forceTimeSync){ network.forceTimeSync = false; if(getLocalTime(&network.timeinfo)){ tsFailCnt = 0; network.forceTimeSync = false; mktime(&network.timeinfo); display.putRequest(CLOCK); network.requestTimeSync(true); }else{ if(tsFailCnt<4){ network.forceTimeSync = true; tsFailCnt++; }else{ network.forceTimeSync = false; tsFailCnt=0; } } } if(network.weatherBuf && (strlen(config.store.weatherkey)!=0 && config.store.showweather) && network.forceWeather){ network.forceWeather = false; network.trueWeather=getWeather(network.weatherBuf); } vTaskDelete( NULL ); } bool getWeather(char *wstr) { #if (DSP_MODEL!=DSP_DUMMY || defined(USE_NEXTION)) && !defined(HIDE_WEATHER) WiFiClient client; const char* host = "api.openweathermap.org"; if (!client.connect(host, 80)) { Serial.println("## OPENWEATHERMAP ###: connection failed"); return false; } char httpget[250] = {0}; sprintf(httpget, "GET /data/2.5/weather?lat=%s&lon=%s&units=%s&lang=%s&appid=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", config.store.weatherlat, config.store.weatherlon, weatherUnits, weatherLang, config.store.weatherkey, host); client.print(httpget); unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 2000UL) { Serial.println("## OPENWEATHERMAP ###: client available timeout !"); client.stop(); return false; } } timeout = millis(); String line = ""; if (client.connected()) { while (client.available()) { line = client.readStringUntil('\n'); if (strstr(line.c_str(), "\"temp\"") != NULL) { client.stop(); break; } if ((millis() - timeout) > 500) { client.stop(); Serial.println("## OPENWEATHERMAP ###: client read timeout !"); return false; } } } if (strstr(line.c_str(), "\"temp\"") == NULL) { Serial.println("## OPENWEATHERMAP ###: weather not found !"); return false; } char *tmpe; char *tmps; char *tmpc; const char* cursor = line.c_str(); char desc[120], temp[20], hum[20], press[20], icon[5]; tmps = strstr(cursor, "\"description\":\""); if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;} tmps += 15; tmpe = strstr(tmps, "\",\""); if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;} strlcpy(desc, tmps, tmpe - tmps + 1); cursor = tmpe + 2; // "ясно","icon":"01d"}], tmps = strstr(cursor, "\"icon\":\""); if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: icon not found !"); return false;} tmps += 8; tmpe = strstr(tmps, "\"}"); if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: icon not found !"); return false;} strlcpy(icon, tmps, tmpe - tmps + 1); cursor = tmpe + 2; tmps = strstr(cursor, "\"temp\":"); if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;} tmps += 7; tmpe = strstr(tmps, ",\""); if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;} strlcpy(temp, tmps, tmpe - tmps + 1); cursor = tmpe + 2; float tempf = atof(temp); tmps = strstr(cursor, "\"pressure\":"); if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;} tmps += 11; tmpe = strstr(tmps, ",\""); if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;} strlcpy(press, tmps, tmpe - tmps + 1); cursor = tmpe + 2; int pressi = (float)atoi(press) / 1.333; tmps = strstr(cursor, "humidity\":"); if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;} tmps += 10; tmpe = strstr(tmps, ",\""); tmpc = strstr(tmps, "}"); if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;} strlcpy(hum, tmps, tmpe - tmps + (tmpc>tmpe?1:0)); #ifdef USE_NEXTION nextion.putcmdf("press_txt.txt=\"%dmm\"", pressi); nextion.putcmdf("hum_txt.txt=\"%d%%\"", atoi(hum)); char cmd[30]; snprintf(cmd, sizeof(cmd)-1,"temp_txt.txt=\"%.1f\"", tempf); nextion.putcmd(cmd); int iconofset; if(strstr(icon,"01")!=NULL) iconofset = 0; else if(strstr(icon,"02")!=NULL) iconofset = 1; else if(strstr(icon,"03")!=NULL) iconofset = 2; else if(strstr(icon,"04")!=NULL) iconofset = 3; else if(strstr(icon,"09")!=NULL) iconofset = 4; else if(strstr(icon,"10")!=NULL) iconofset = 5; else if(strstr(icon,"11")!=NULL) iconofset = 6; else if(strstr(icon,"13")!=NULL) iconofset = 7; else if(strstr(icon,"50")!=NULL) iconofset = 8; else iconofset = 9; nextion.putcmd("cond_img.pic", 50+iconofset); nextion.weatherVisible(1); #endif Serial.printf("## OPENWEATHERMAP ###: description: %s, temp:%.1f C, pressure:%dmmHg, humidity:%s%%\n", desc, tempf, pressi, hum); #ifdef WEATHER_FMT_SHORT sprintf(wstr, weatherFmt, tempf, pressi, hum); #else sprintf(wstr, weatherFmt, desc, tempf, pressi, hum); #endif network.requestWeatherSync(); return true; #endif // if (DSP_MODEL!=DSP_DUMMY || defined(USE_NEXTION)) && !defined(HIDE_WEATHER) return false; }