Merge remote-tracking branch 'refs/remotes/origin/master'
[weathermon.git] / weather_screen / weather_screen.ino
index 75448cd2181a6fdce49a3a24d74db368f86d3bcf..aa42be8033c1f46732b116a2558c1bac973d71e7 100644 (file)
@@ -44,12 +44,10 @@ U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;
 #include "fonts.h"
 
 //define your default values here, if there are different values in config.json, they are overwritten.
 #include "fonts.h"
 
 //define your default values here, if there are different values in config.json, they are overwritten.
-char api_key[40]      = "";                      // See: https://openweathermap.org/  // It's free to get an API key, but don't take more than 60 readings/minute!
+//char api_key[40]      = "";                      // See: https://openweathermap.org/  // It's free to get an API key, but don't take more than 60 readings/minute!
 char latitude[8]      = "55.5";
 char longitude[8]     = "37.5";
 char latitude[8]      = "55.5";
 char longitude[8]     = "37.5";
-char language[4]      = "RU";                    // NOTE: Only the weather description is translated by OWM
-                                                 // Examples: Arabic (AR) Czech (CZ) English (EN) Greek (EL) Persian(Farsi) (FA) Galician (GL) Hungarian (HU) Japanese (JA)
-                                                 // Korean (KR) Latvian (LA) Lithuanian (LT) Macedonian (MK) Slovak (SK) Slovenian (SL) Vietnamese (VI)
+char timezone[40]     = "Europe/Moscow";         // Forecast beginning of day
 
 char current_weather_server[255] = "";
 char current_weather_uri[255] = "";
 
 char current_weather_server[255] = "";
 char current_weather_uri[255] = "";
@@ -59,7 +57,7 @@ char current_weather_humidity[40] = "HUMIDITY";
 char current_weather_windspeed[40] = "";
 char current_weather_lux[40] = "LUX";
 
 char current_weather_windspeed[40] = "";
 char current_weather_lux[40] = "LUX";
 
-const char server[] = "api.openweathermap.org";
+const char server[] = "api.open-meteo.com";
 
 int SleepDuration = 10;
 
 
 int SleepDuration = 10;
 
@@ -91,10 +89,9 @@ void WiFiSetup() {
   // The extra parameters to be configured (can be either global or just in the setup)
   // After connecting, parameter.getValue() will get you the configured value
   // id/name placeholder/prompt default length
   // The extra parameters to be configured (can be either global or just in the setup)
   // After connecting, parameter.getValue() will get you the configured value
   // id/name placeholder/prompt default length
-  WiFiManagerParameter custom_api_key("api_key", "OWN API key", api_key, 40);
   WiFiManagerParameter custom_latitude("latitide", "Latitude", latitude, 8);
   WiFiManagerParameter custom_longitude("longitude", "Longitude", longitude, 8);
   WiFiManagerParameter custom_latitude("latitide", "Latitude", latitude, 8);
   WiFiManagerParameter custom_longitude("longitude", "Longitude", longitude, 8);
-  WiFiManagerParameter custom_language("language", "Language", language, 4);
+  WiFiManagerParameter custom_timezone("timezone", "Time zone", timezone, 40);
   WiFiManagerParameter custom_current_weather_server("current_weather_server", "Weather server", current_weather_server, 255);
   WiFiManagerParameter custom_current_weather_uri("current_weather_uri", "Weather URI", current_weather_uri, 255);
   WiFiManagerParameter custom_current_weather_pressure("current_weather_pressure", "Pressure key", current_weather_pressure, 40);
   WiFiManagerParameter custom_current_weather_server("current_weather_server", "Weather server", current_weather_server, 255);
   WiFiManagerParameter custom_current_weather_uri("current_weather_uri", "Weather URI", current_weather_uri, 255);
   WiFiManagerParameter custom_current_weather_pressure("current_weather_pressure", "Pressure key", current_weather_pressure, 40);
@@ -111,10 +108,9 @@ void WiFiSetup() {
   wifiManager.setSaveConfigCallback(saveConfigCallback);
 
   //add all your parameters here
   wifiManager.setSaveConfigCallback(saveConfigCallback);
 
   //add all your parameters here
-  wifiManager.addParameter(&custom_api_key);
   wifiManager.addParameter(&custom_latitude);
   wifiManager.addParameter(&custom_longitude);
   wifiManager.addParameter(&custom_latitude);
   wifiManager.addParameter(&custom_longitude);
-  wifiManager.addParameter(&custom_language);
+  wifiManager.addParameter(&custom_timezone);
   wifiManager.addParameter(&custom_current_weather_server);
   wifiManager.addParameter(&custom_current_weather_uri);
   wifiManager.addParameter(&custom_current_weather_pressure);
   wifiManager.addParameter(&custom_current_weather_server);
   wifiManager.addParameter(&custom_current_weather_uri);
   wifiManager.addParameter(&custom_current_weather_pressure);
@@ -125,6 +121,12 @@ void WiFiSetup() {
 
   wifiManager.setTimeout(300);
 
 
   wifiManager.setTimeout(300);
 
+  if (WiFi. status() != WL_CONNECTED) {
+    WiFi.disconnect();
+    WiFi.mode(WIFI_AP);
+    WiFi.begin();
+  } 
+  
   if (!wifiManager.startConfigPortal()) {
     Serial.println("failed to connect and hit timeout");
     delay(3000);
   if (!wifiManager.startConfigPortal()) {
     Serial.println("failed to connect and hit timeout");
     delay(3000);
@@ -136,10 +138,9 @@ void WiFiSetup() {
   Serial.println("connected...");
 
   //read updated parameters
   Serial.println("connected...");
 
   //read updated parameters
-  strcpy(api_key, custom_api_key.getValue());
   strcpy(latitude, custom_latitude.getValue());
   strcpy(longitude, custom_longitude.getValue());
   strcpy(latitude, custom_latitude.getValue());
   strcpy(longitude, custom_longitude.getValue());
-  strcpy(language, custom_language.getValue());
+  strcpy(timezone, custom_timezone.getValue());
   strcpy(current_weather_server, custom_current_weather_server.getValue());
   strcpy(current_weather_uri, custom_current_weather_uri.getValue());
   strcpy(current_weather_pressure, custom_current_weather_pressure.getValue());
   strcpy(current_weather_server, custom_current_weather_server.getValue());
   strcpy(current_weather_uri, custom_current_weather_uri.getValue());
   strcpy(current_weather_pressure, custom_current_weather_pressure.getValue());
@@ -152,10 +153,10 @@ void WiFiSetup() {
   if (shouldSaveConfig) {
     Serial.println("saving config");
     DynamicJsonDocument json(1024);
   if (shouldSaveConfig) {
     Serial.println("saving config");
     DynamicJsonDocument json(1024);
-    json["api_key"] = api_key;
+    // json["api_key"] = api_key;
     json["latitude"] = latitude;
     json["longitude"] = longitude;
     json["latitude"] = latitude;
     json["longitude"] = longitude;
-    json["language"] = language;
+    json["timezone"] = timezone;
     json["current_weather_server"] = current_weather_server;
     json["current_weather_uri"] = current_weather_uri;
     json["current_weather_pressure"] = current_weather_pressure;
     json["current_weather_server"] = current_weather_server;
     json["current_weather_uri"] = current_weather_uri;
     json["current_weather_pressure"] = current_weather_pressure;
@@ -205,10 +206,9 @@ void setup() {
         serializeJson(json, Serial);
         if ( ! deserializeError ) {
           Serial.println("\nparsed json");
         serializeJson(json, Serial);
         if ( ! deserializeError ) {
           Serial.println("\nparsed json");
-          if (json.containsKey("api_key")) { strcpy(api_key, json["api_key"]); }
           if (json.containsKey("latitude")) { strcpy(latitude, json["latitude"]); }
           if (json.containsKey("longitude")) { strcpy(longitude, json["longitude"]); }
           if (json.containsKey("latitude")) { strcpy(latitude, json["latitude"]); }
           if (json.containsKey("longitude")) { strcpy(longitude, json["longitude"]); }
-          if (json.containsKey("language")) { strcpy(language, json["language"]); }
+          if (json.containsKey("timezone")) { strcpy(timezone, json["timezone"]); }
           if (json.containsKey("current_weather_server")) { strcpy(current_weather_server, json["current_weather_server"]); }
           if (json.containsKey("current_weather_uri")) { strcpy(current_weather_uri, json["current_weather_uri"]); }
           if (json.containsKey("current_weather_pressure")) { strcpy(current_weather_pressure, json["current_weather_pressure"]); }
           if (json.containsKey("current_weather_server")) { strcpy(current_weather_server, json["current_weather_server"]); }
           if (json.containsKey("current_weather_uri")) { strcpy(current_weather_uri, json["current_weather_uri"]); }
           if (json.containsKey("current_weather_pressure")) { strcpy(current_weather_pressure, json["current_weather_pressure"]); }
@@ -238,6 +238,7 @@ void setup() {
     wifiManager.setTimeout(10);
     if(!wifiManager.autoConnect()) {
       Serial.println("failed to connect and hit timeout");
     wifiManager.setTimeout(10);
     if(!wifiManager.autoConnect()) {
       Serial.println("failed to connect and hit timeout");
+      WiFiSetup();
       delay(3000);
       ESP.restart();
     }  
       delay(3000);
       ESP.restart();
     }  
@@ -251,32 +252,20 @@ void setup() {
 }
 
 int TimeZoneOffset;
 }
 
 int TimeZoneOffset;
-int SunRise, SunSet;
+// int SunRise, SunSet;
 
 int HourlyDT[MaxHourlyFC];
 float HourlyTemp[MaxHourlyFC];
 float HourlyFeelsLike[MaxHourlyFC];
 float HourlyPressure[MaxHourlyFC];
 float HourlyHumidity[MaxHourlyFC];
 
 int HourlyDT[MaxHourlyFC];
 float HourlyTemp[MaxHourlyFC];
 float HourlyFeelsLike[MaxHourlyFC];
 float HourlyPressure[MaxHourlyFC];
 float HourlyHumidity[MaxHourlyFC];
-float HourlyClouds[MaxHourlyFC];
+// float HourlyClouds[MaxHourlyFC];
 float HourlyWindSpeed[MaxHourlyFC];
 float HourlyWindSpeed[MaxHourlyFC];
-float HourlyRain[MaxHourlyFC];
-float HourlySnow[MaxHourlyFC];
+// float HourlyRain[MaxHourlyFC];
+// float HourlySnow[MaxHourlyFC];
+// float HourlyShowers[MaxHourlyFC];
 float HourlyPrecip[MaxHourlyFC];
 
 float HourlyPrecip[MaxHourlyFC];
 
-int DailyDT[MaxDailyFC];
-float DailyTempMin[MaxDailyFC];
-float DailyTempMax[MaxDailyFC];
-float DailyFeelsLikeMin[MaxDailyFC];
-float DailyFeelsLikeMax[MaxDailyFC];
-float DailyPressure[MaxDailyFC];
-float DailyHumidity[MaxDailyFC];
-float DailyClouds[MaxDailyFC];
-float DailyWindSpeed[MaxDailyFC];
-float DailyRain[MaxDailyFC];
-float DailySnow[MaxDailyFC];
-float DailyPrecip[MaxDailyFC];
-
 String UnixTime(int unix_time) {
   time_t tm = unix_time;
   struct tm *now_tm = localtime(&tm);
 String UnixTime(int unix_time) {
   time_t tm = unix_time;
   struct tm *now_tm = localtime(&tm);
@@ -314,73 +303,48 @@ bool DecodeWeather(WiFiClient& json) {
   // convert it to a JsonObject
   JsonObject root = doc.as<JsonObject>();
 
   // convert it to a JsonObject
   JsonObject root = doc.as<JsonObject>();
 
-  TimeZoneOffset = root["timezone_offset"].as<int>();
+  TimeZoneOffset = root["utc_offset_seconds"].as<int>();
   
   
-  SunRise = root["current"]["sunrise"].as<int>();
-  SunSet  = root["current"]["sunset"].as<int>();
-
-  CurrentWeather.dt           = root["current"]["dt"].as<int>();
-  CurrentWeather.temp         = root["current"]["temp"].as<float>();
-  CurrentWeather.feels_like   = root["current"]["feels_like"].as<float>();
-  CurrentWeather.pressure     = 0.75 * root["current"]["pressure"].as<float>();
-  CurrentWeather.humidity     = root["current"]["humidity"].as<float>();
-  CurrentWeather.clouds       = root["current"]["clouds"].as<float>();
-  CurrentWeather.wind_speed   = root["current"]["wind_speed"].as<float>();
-  CurrentWeather.wind_deg     = root["current"]["wind_deg"].as<float>();
-  CurrentWeather.rain         = root["current"]["rain"]["1h"].as<float>();
-  CurrentWeather.snow         = root["current"]["snow"]["1h"].as<float>();
-  CurrentWeather.description  = root["current"]["weather"][0]["description"].as<char*>();
-  CurrentWeather.icon         = root["current"]["weather"][0]["icon"].as<char*>();
+
+  CurrentWeather.dt           = root["current"]["time"].as<int>();
+  CurrentWeather.temp         = root["current"]["temperature_2m"].as<float>();
+  CurrentWeather.feels_like   = root["current"]["apparent_temperature"].as<float>();
+  CurrentWeather.pressure     = 0.75 * root["current"]["surface_pressure"].as<float>();
+  CurrentWeather.humidity     = root["current"]["relative_humidity_2m"].as<float>();
+  CurrentWeather.wind_speed   = root["current"]["wind_speed_10m"].as<float>();
+  CurrentWeather.wind_deg     = root["current"]["wind_direction_10m"].as<float>();
+  CurrentWeather.precip       = root["current"]["precipitation"].as<float>();
+  CurrentWeather.wmo          = root["current"]["weather_code"].as<int>();
 
   struct timeval now = { .tv_sec =  CurrentWeather.dt };
   settimeofday(&now, NULL);
 
 
   struct timeval now = { .tv_sec =  CurrentWeather.dt };
   settimeofday(&now, NULL);
 
-  JsonArray hourly = root["hourly"];
+  int firstForecastDT = root["hourly"]["time"][0].as<int>();
+
+  int offset = (CurrentWeather.dt - firstForecastDT) / 3600;
+
   for (byte i=0; i<MaxHourlyFC; i++) {
   for (byte i=0; i<MaxHourlyFC; i++) {
-    HourlyDT[i] = HourlyForecasts[i].dt                  = hourly[i]["dt"].as<int>();
-    HourlyTemp[i] = HourlyForecasts[i].temp              = hourly[i]["temp"].as<float>();
-    HourlyFeelsLike[i] = HourlyForecasts[i].feels_like   = hourly[i]["feels_like"].as<float>();
-    HourlyPressure[i] = HourlyForecasts[i].pressure      = 0.75 * hourly[i]["pressure"].as<float>();
-    HourlyHumidity[i] = HourlyForecasts[i].humidity      = hourly[i]["humidity"].as<float>();
-    HourlyClouds[i] = HourlyForecasts[i].clouds          = hourly[i]["clouds"].as<float>();
-    HourlyWindSpeed[i] = HourlyForecasts[i].wind_speed   = hourly[i]["wind_speed"].as<float>();
-    HourlyForecasts[i].wind_deg                          = hourly[i]["wind_deg"].as<float>();
-    HourlyRain[i] = HourlyForecasts[i].rain              = hourly[i]["rain"]["1h"].as<float>();
-    HourlySnow[i] = HourlyForecasts[i].snow              = hourly[i]["snow"]["1h"].as<float>();
-    HourlyPrecip[i] = HourlyRain[i] + HourlySnow[i];
-    HourlyForecasts[i].description                       = hourly[i]["weather"][0]["description"].as<char*>();
-    HourlyForecasts[i].icon                              = hourly[i]["weather"][0]["icon"].as<char*>();
-  }
-
-  JsonArray daily = root["daily"];
-  for (byte i=0; i<MaxDailyFC; i++) {
-    DailyDT[i] = DailyForecasts[i].dt                        = daily[i]["dt"].as<int>();
-    DailyTempMin[i] = DailyForecasts[i].temp_min             = daily[i]["temp"]["min"].as<float>();
-    DailyFeelsLikeMin[i] = DailyForecasts[i].feels_like_min  = daily[i]["feels_like"]["min"].as<float>();
-    DailyTempMax[i] = DailyForecasts[i].temp_max             = daily[i]["temp"]["max"].as<float>();
-    DailyFeelsLikeMax[i] = DailyForecasts[i].feels_like_max  = daily[i]["feels_like"]["max"].as<float>();
-    DailyPressure[i] = DailyForecasts[i].pressure            = 0.75 * daily[i]["pressure"].as<float>();
-    DailyHumidity[i] = DailyForecasts[i].humidity            = daily[i]["humidity"].as<float>();
-    DailyClouds[i] = DailyForecasts[i].clouds                = daily[i]["clouds"].as<float>();
-    DailyWindSpeed[i] = DailyForecasts[i].wind_speed         = daily[i]["wind_speed"].as<float>();
-    DailyForecasts[i].wind_deg                               = daily[i]["wind_deg"].as<float>();
-    DailyRain[i] = DailyForecasts[i].rain                    = daily[i]["rain"].as<float>();
-    DailySnow[i] = DailyForecasts[i].snow                    = daily[i]["snow"].as<float>();
-    DailyPrecip[i] = DailyRain[i] + DailySnow[i];
-    DailyForecasts[i].description                            = daily[i]["weather"][0]["description"].as<char*>();
-    DailyForecasts[i].icon                                   = daily[i]["weather"][0]["icon"].as<char*>();
+    HourlyDT[i] = HourlyForecasts[i].dt                  = root["hourly"]["time"][i+offset].as<int>();
+    HourlyTemp[i] = HourlyForecasts[i].temp              = root["hourly"]["temperature_2m"][i+offset].as<float>();
+    HourlyFeelsLike[i] = HourlyForecasts[i].feels_like   = root["hourly"]["apparent_temperature"][i+offset].as<float>();
+    HourlyPressure[i] = HourlyForecasts[i].pressure      = 0.75 * root["hourly"]["surface_pressure"][i+offset].as<float>();
+    HourlyHumidity[i] = HourlyForecasts[i].humidity      = root["hourly"]["relative_humidity_2m"][i+offset].as<float>();
+    HourlyWindSpeed[i] = HourlyForecasts[i].wind_speed   = root["hourly"]["wind_speed_10m"][i+offset].as<float>();
+    HourlyForecasts[i].wind_deg                          = root["hourly"]["wind_direction_10m"][i+offset].as<float>();
+    HourlyPrecip[i] = HourlyForecasts[i].precip          = root["hourly"]["precipitation"][i+offset].as<float>();
+    HourlyForecasts[i].wmo                               = root["hourly"]["weather_code"][i+offset].as<int>();
   }
   }
-  
+
   return true;
 }
 
 bool GetWeather(WiFiClient& client) {
   client.stop(); // close connection before sending a new request
   HTTPClient http;
   return true;
 }
 
 bool GetWeather(WiFiClient& client) {
   client.stop(); // close connection before sending a new request
   HTTPClient http;
-  char uri[128];
-  sprintf(uri,"/data/2.5/onecall?lat=%s&lon=%s&appid=%s&lang=%s&units=metric",latitude,longitude,api_key,language);
+  char uri[512];
+  sprintf(uri,"/v1/forecast?latitude=%s&longitude=%s&current=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,surface_pressure,wind_speed_10m,wind_direction_10m&hourly=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,surface_pressure,wind_speed_10m,wind_direction_10m&wind_speed_unit=ms&timeformat=unixtime&forecast_days=3&timezone=%s",latitude,longitude,timezone);
   http.useHTTP10(true);
   http.useHTTP10(true);
-  Serial.println("Connecting...");
+  Serial.printf("Connecting http://%s%s ...\n", server, uri);
   http.begin(client, server, 80, uri);
   int httpCode = http.GET();
   if(httpCode == HTTP_CODE_OK) {
   http.begin(client, server, 80, uri);
   int httpCode = http.GET();
   if(httpCode == HTTP_CODE_OK) {
@@ -389,7 +353,7 @@ bool GetWeather(WiFiClient& client) {
     http.end();
     return true;
   } else {
     http.end();
     return true;
   } else {
-    Serial.printf("connection failed, error: %s\n", http.errorToString(httpCode).c_str());
+    Serial.printf("Forecast server connection failed, error: %s\n", http.errorToString(httpCode).c_str());
     client.stop();
     http.end();
     return false;
     client.stop();
     http.end();
     return false;
@@ -413,15 +377,19 @@ bool DecodeCurrentWeather(WiFiClient& json) {
 
   if (current_weather_pressure[0] && root.containsKey(current_weather_pressure)) {
     CurrentWeather.pressure     = root[current_weather_pressure].as<float>();
 
   if (current_weather_pressure[0] && root.containsKey(current_weather_pressure)) {
     CurrentWeather.pressure     = root[current_weather_pressure].as<float>();
+    Serial.printf("Current pressure: %f\n",CurrentWeather.pressure);
   }
   if (current_weather_temperature[0] && root.containsKey(current_weather_temperature)) {
     CurrentWeather.temp     = root[current_weather_temperature].as<float>();
   }
   if (current_weather_temperature[0] && root.containsKey(current_weather_temperature)) {
     CurrentWeather.temp     = root[current_weather_temperature].as<float>();
+    Serial.printf("Current temperature: %f\n",CurrentWeather.temp);
   }
   if (current_weather_humidity[0] && root.containsKey(current_weather_humidity)) {
     CurrentWeather.humidity     = root[current_weather_humidity].as<float>();
   }
   if (current_weather_humidity[0] && root.containsKey(current_weather_humidity)) {
     CurrentWeather.humidity     = root[current_weather_humidity].as<float>();
+    Serial.printf("Current humidity: %f\n",CurrentWeather.humidity);
   }
   if (current_weather_windspeed[0] && root.containsKey(current_weather_windspeed)) {
     CurrentWeather.wind_speed     = root[current_weather_windspeed].as<float>();
   }
   if (current_weather_windspeed[0] && root.containsKey(current_weather_windspeed)) {
     CurrentWeather.wind_speed     = root[current_weather_windspeed].as<float>();
+    Serial.printf("Current windspeed: %f\n",CurrentWeather.wind_speed);
   }
 
   float Ro = (CurrentWeather.humidity/100) * 6.105 * pow(2.712828, 17.27 * CurrentWeather.temp/(237.7+CurrentWeather.temp));
   }
 
   float Ro = (CurrentWeather.humidity/100) * 6.105 * pow(2.712828, 17.27 * CurrentWeather.temp/(237.7+CurrentWeather.temp));
@@ -430,8 +398,7 @@ bool DecodeCurrentWeather(WiFiClient& json) {
     float wm2 = root[current_weather_lux].as<float>()/685;
     CurrentWeather.feels_like = CurrentWeather.feels_like + 0.70*wm2/(CurrentWeather.wind_speed + 10);
   }
     float wm2 = root[current_weather_lux].as<float>()/685;
     CurrentWeather.feels_like = CurrentWeather.feels_like + 0.70*wm2/(CurrentWeather.wind_speed + 10);
   }
-  Serial.print("Calculated feels like: ");
-  Serial.println(CurrentWeather.feels_like);
+  Serial.printf("Calculated feels like: %f\n",CurrentWeather.feels_like);
   
   return true;
 }
   
   return true;
 }
@@ -442,7 +409,7 @@ bool GetCurrentWeather(WiFiClient& client) {
     client.stop(); // close connection before sending a new request
     HTTPClient http;
     http.useHTTP10(true);
     client.stop(); // close connection before sending a new request
     HTTPClient http;
     http.useHTTP10(true);
-    Serial.println("Connecting...");
+    Serial.printf("Connecting http://%s%s ...\n",current_weather_server,current_weather_uri);
     http.begin(client, current_weather_server, 80, current_weather_uri);
     int httpCode = http.GET();
     if(httpCode == HTTP_CODE_OK) {
     http.begin(client, current_weather_server, 80, current_weather_uri);
     int httpCode = http.GET();
     if(httpCode == HTTP_CODE_OK) {
@@ -451,7 +418,7 @@ bool GetCurrentWeather(WiFiClient& client) {
       http.end();
       return true;
     } else {
       http.end();
       return true;
     } else {
-      Serial.printf("connection failed, error: %s\n", http.errorToString(httpCode).c_str());
+      Serial.printf("Current weather server connection failed, error: %s\n", http.errorToString(httpCode).c_str());
       client.stop();
       http.end();
       return false;
       client.stop();
       http.end();
       return false;
@@ -774,30 +741,95 @@ void DisplayIcon(int x1, int x2, int y1, int y2, WeatherRecord weather) {
   int scale = w/14;
   int fscale = w/12;
 
   int scale = w/14;
   int fscale = w/12;
 
-  String icon = weather.icon;
-  String description = weather.description;
+  int wmo = weather.wmo;
+  String description;
 
 
-  if      (icon == "01d" || icon == "01n")  
+  if (wmo == 0) { 
     Sunny(x, y, scale);
     Sunny(x, y, scale);
-  else if (icon == "02d" || icon == "02n")  
+    description = "ясно";
+  } else if (wmo == 1) {
     MostlySunny(x, y, scale);
     MostlySunny(x, y, scale);
-  else if (icon == "03d" || icon == "03n")  
+    description = "премущественно ясно";
+  } else if (wmo == 2) {
     MostlyCloudy(x, y, scale);
     MostlyCloudy(x, y, scale);
-  else if (icon == "04d" || icon == "04n")  
+    description = "переменная облачность";
+  } else if (wmo == 3) {
     Cloudy(x, y, scale);
     Cloudy(x, y, scale);
-  else if (icon == "09d" || icon == "09n")  
+    description = "пасмурно";
+  } else if (wmo == 61) {
+    Rain(x, y, scale);
+    description = "небольшой дождь";
+  } else if (wmo == 63) {
+    Rain(x, y, scale);
+    description = "дождь";
+  } else if (wmo == 65) {
+    Rain(x, y, scale);
+    description = "сильный дождь";
+  } else if (wmo == 51) {
+    Rain(x, y, scale);
+    description = "небольшая морось";
+  } else if (wmo == 53) {
+    Rain(x, y, scale);
+    description = "морось";
+  } else if (wmo == 55) {
+    Rain(x, y, scale);
+    description = "сильная морось";
+  } else if (wmo == 66) {
+    Rain(x, y, scale);
+    description = "ледяной дождь";
+  } else if (wmo == 67) {
     Rain(x, y, scale);
     Rain(x, y, scale);
-  else if (icon == "10d" || icon == "10n")  
+    description = "сильный ледяной дождь";
+  } else if (wmo == 56) {
+    Rain(x, y, scale);
+    description = "ледяная морось";
+  } else if (wmo == 57) {
+    Rain(x, y, scale);
+    description = "сильная ледяная морось";
+  } else if (wmo == 80) {
+    ExpectRain(x, y, scale);
+    description = "возможны ливни";
+  } else if (wmo == 81) {
+    ExpectRain(x, y, scale);
+    description = "ливни";
+  } else if (wmo == 82) {
     ExpectRain(x, y, scale);
     ExpectRain(x, y, scale);
-  else if (icon == "11d" || icon == "11n")  
+    description = "сильные ливни";
+  } else if (wmo == 95) {
     Tstorms(x, y, scale);
     Tstorms(x, y, scale);
-  else if (icon == "13d" || icon == "13n")  
+    description = "гроза";
+  } else if (wmo == 96) {
+    Tstorms(x, y, scale);
+    description = "гроза с градом";
+  } else if (wmo == 97) {
+    Tstorms(x, y, scale);
+    description = "сильная гроза";
+  } else if (wmo == 71) {
+    Snow(x, y, scale);
+    description = "слабый снег";
+  } else if (wmo == 73) {
     Snow(x, y, scale);
     Snow(x, y, scale);
-  else if (icon == "50d")                   
+    description = "снег";
+  } else if (wmo == 75) {
+    Snow(x, y, scale);
+    description = "сильный снег";
+  } else if (wmo == 77) {
+    Snow(x, y, scale);
+    description = "снежная крупа";
+  } else if (wmo == 85) {
+    Snow(x, y, scale);
+    description = "возможна метель";
+  } else if (wmo == 86) {
+    Snow(x, y, scale);
+    description = "метель";
+  } else if (wmo == 48) {
     Haze(x, y, scale);
     Haze(x, y, scale);
-  else if (icon == "50n")                   
+    description = "ледяной туман";
+  } else if (wmo == 45) {
     Fog(x, y, scale);
     Fog(x, y, scale);
-
+    description = "туман";
+  }
+  
   SetCyrFont(fscale);
   drawString(x, y2-fscale*2/3, description, CENTER); 
 
   SetCyrFont(fscale);
   drawString(x, y2-fscale*2/3, description, CENTER); 
 
@@ -830,29 +862,67 @@ void DisplayForecast(int x1, int x2, int y1, int y2, WeatherRecord weather) {
   int fscale = w/6;
   if (fscale<6) fscale = 6;
 
   int fscale = w/6;
   if (fscale<6) fscale = 6;
 
-  String icon = weather.icon;
   String temperature = String(weather.temp,1);
 
   String temperature = String(weather.temp,1);
 
-  if      (icon == "01d" || icon == "01n")  
+  int wmo = weather.wmo;
+
+  if (wmo == 0) { 
     Sunny(x, y, scale);
     Sunny(x, y, scale);
-  else if (icon == "02d" || icon == "02n")  
+  } else if (wmo == 1) {
     MostlySunny(x, y, scale);
     MostlySunny(x, y, scale);
-  else if (icon == "03d" || icon == "03n")  
+  } else if (wmo == 2) {
     MostlyCloudy(x, y, scale);
     MostlyCloudy(x, y, scale);
-  else if (icon == "04d" || icon == "04n")  
+  } else if (wmo == 3) {
     Cloudy(x, y, scale);
     Cloudy(x, y, scale);
-  else if (icon == "09d" || icon == "09n")  
+  } else if (wmo == 61) {
+    Rain(x, y, scale);
+  } else if (wmo == 63) {
+    Rain(x, y, scale);
+  } else if (wmo == 65) {
+    Rain(x, y, scale);
+  } else if (wmo == 51) {
+    Rain(x, y, scale);
+  } else if (wmo == 53) {
+    Rain(x, y, scale);
+  } else if (wmo == 55) {
+    Rain(x, y, scale);
+  } else if (wmo == 66) {
+    Rain(x, y, scale);
+  } else if (wmo == 67) {
     Rain(x, y, scale);
     Rain(x, y, scale);
-  else if (icon == "10d" || icon == "10n")  
+  } else if (wmo == 56) {
+    Rain(x, y, scale);
+  } else if (wmo == 57) {
+    Rain(x, y, scale);
+  } else if (wmo == 80) {
+    ExpectRain(x, y, scale);
+  } else if (wmo == 81) {
+    ExpectRain(x, y, scale);
+  } else if (wmo == 82) {
     ExpectRain(x, y, scale);
     ExpectRain(x, y, scale);
-  else if (icon == "11d" || icon == "11n")  
+  } else if (wmo == 95) {
     Tstorms(x, y, scale);
     Tstorms(x, y, scale);
-  else if (icon == "13d" || icon == "13n")  
+  } else if (wmo == 96) {
+    Tstorms(x, y, scale);
+  } else if (wmo == 97) {
+    Tstorms(x, y, scale);
+  } else if (wmo == 71) {
+    Snow(x, y, scale);
+  } else if (wmo == 73) {
     Snow(x, y, scale);
     Snow(x, y, scale);
-  else if (icon == "50d")                   
+  } else if (wmo == 75) {
+    Snow(x, y, scale);
+  } else if (wmo == 77) {
+    Snow(x, y, scale);
+  } else if (wmo == 85) {
+    Snow(x, y, scale);
+  } else if (wmo == 86) {
+    Snow(x, y, scale);
+  } else if (wmo == 48) {
     Haze(x, y, scale);
     Haze(x, y, scale);
-  else if (icon == "50n")                   
+  } else if (wmo == 45) {
     Fog(x, y, scale);
     Fog(x, y, scale);
+  }
 
   SetCyrFont(fscale);
   drawString(x, y1+fscale*2/3, UnixTimeOnly(weather.dt+ TimeZoneOffset), CENTER); 
 
   SetCyrFont(fscale);
   drawString(x, y1+fscale*2/3, UnixTimeOnly(weather.dt+ TimeZoneOffset), CENTER); 
@@ -940,17 +1010,29 @@ void DisplayWeather() {
 void loop() {
 
   delay(2000);
 void loop() {
 
   delay(2000);
+
   WiFiManager wifiManager;
   WiFiManager wifiManager;
-  wifiManager.setTimeout(10);
-  if(!wifiManager.autoConnect()) {
+  WiFi.mode(WIFI_STA);
+  wifiManager.setConnectTimeout(10);
 
 
-    Serial.println("failed to connect and hit timeout");
+  if (WiFi.SSID().isEmpty()) {
   
   
-  } else {
+    wifiManager.setTimeout(600);
+    WiFiSetup();
+  
+  } else if (!wifiManager.autoConnect()) {
 
 
-    if (Serial.available() && Serial.read() == 'c') {
-      WiFiSetup();
-    }
+    Serial.println("failed to connect to stored SSID and hit timeout");
+    wifiManager.setTimeout(600);
+    WiFi.mode(WIFI_AP);
+    WiFiSetup();
+  
+  } else if (Serial.available() && Serial.read() == 'c') {
+      
+    wifiManager.setTimeout(600);
+    WiFiSetup();
+  
+  } else {
   
     // put your main code here, to run repeatedly:
     byte Attempts = 1;
   
     // put your main code here, to run repeatedly:
     byte Attempts = 1;