#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 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_windspeed[40] = "";
char current_weather_lux[40] = "LUX";
-const char server[] = "api.openweathermap.org";
+const char server[] = "api.open-meteo.com";
int SleepDuration = 10;
// 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_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);
wifiManager.setSaveConfigCallback(saveConfigCallback);
//add all your parameters here
- wifiManager.addParameter(&custom_api_key);
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.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);
Serial.println("connected...");
//read updated parameters
- strcpy(api_key, custom_api_key.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());
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["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;
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("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"]); }
wifiManager.setTimeout(10);
if(!wifiManager.autoConnect()) {
Serial.println("failed to connect and hit timeout");
+ WiFiSetup();
delay(3000);
ESP.restart();
}
}
int TimeZoneOffset;
-int SunRise, SunSet;
+// int SunRise, SunSet;
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 HourlyRain[MaxHourlyFC];
-float HourlySnow[MaxHourlyFC];
+// float HourlyRain[MaxHourlyFC];
+// float HourlySnow[MaxHourlyFC];
+// float HourlyShowers[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);
// 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);
- 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++) {
- 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;
- 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¤t=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);
- 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.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;
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>();
+ 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>();
+ 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>();
+ 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 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;
}
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.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;
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);
- else if (icon == "02d" || icon == "02n")
+ description = "ясно";
+ } else if (wmo == 1) {
MostlySunny(x, y, scale);
- else if (icon == "03d" || icon == "03n")
+ description = "премущественно ясно";
+ } else if (wmo == 2) {
MostlyCloudy(x, y, scale);
- else if (icon == "04d" || icon == "04n")
+ description = "переменная облачность";
+ } else if (wmo == 3) {
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);
- 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);
- else if (icon == "11d" || icon == "11n")
+ description = "сильные ливни";
+ } else if (wmo == 95) {
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);
- 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);
- else if (icon == "50n")
+ description = "ледяной туман";
+ } else if (wmo == 45) {
Fog(x, y, scale);
-
+ description = "туман";
+ }
+
SetCyrFont(fscale);
drawString(x, y2-fscale*2/3, description, CENTER);
int fscale = w/6;
if (fscale<6) fscale = 6;
- String icon = weather.icon;
String temperature = String(weather.temp,1);
- if (icon == "01d" || icon == "01n")
+ int wmo = weather.wmo;
+
+ if (wmo == 0) {
Sunny(x, y, scale);
- else if (icon == "02d" || icon == "02n")
+ } else if (wmo == 1) {
MostlySunny(x, y, scale);
- else if (icon == "03d" || icon == "03n")
+ } else if (wmo == 2) {
MostlyCloudy(x, y, scale);
- else if (icon == "04d" || icon == "04n")
+ } else if (wmo == 3) {
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);
- 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);
- else if (icon == "11d" || icon == "11n")
+ } else if (wmo == 95) {
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);
- 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);
- else if (icon == "50n")
+ } else if (wmo == 45) {
Fog(x, y, scale);
+ }
SetCyrFont(fscale);
drawString(x, y1+fscale*2/3, UnixTimeOnly(weather.dt+ TimeZoneOffset), CENTER);
void loop() {
delay(2000);
+
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;