use live weather data #16

pull/1/head
Thomas Ballmann 4 years ago
parent 191338aa3a
commit 1cfba3c284

@ -1 +1 @@
{"coord":{"lon":13.04,"lat":47.8},"weather":[{"id":803,"main":"Clouds","description":"Überwiegend bewölkt","icon":"04d"}],"base":"stations","main":{"temp":282.55,"feels_like":276.58,"temp_min":279.26,"temp_max":285.15,"pressure":1000,"humidity":61},"visibility":10000,"wind":{"speed":6.2,"deg":140,"gust":11.8},"clouds":{"all":75},"dt":1582986835,"sys":{"type":1,"id":6877,"country":"AT","sunrise":1582955413,"sunset":1582995046},"timezone":3600,"id":2766824,"name":"Salzburg","cod":200}
{"coord":{"lon":13.04,"lat":47.8},"weather":[{"id":520,"main":"Rain","description":"Leichter Regenschauer","icon":"09d"}],"base":"stations","main":{"temp":3.72,"feels_like":-0.89,"temp_min":2.22,"temp_max":5.56,"pressure":1019,"humidity":86},"visibility":10000,"wind":{"speed":4.1,"deg":290},"clouds":{"all":75},"dt":1583595650,"sys":{"type":1,"id":6877,"country":"AT","sunrise":1583559395,"sunset":1583600476},"timezone":3600,"id":2766824,"name":"Salzburg","cod":200}

@ -1 +1 @@
{"cod":"200","message":0,"cnt":3,"list":[{"dt":1582988400,"main":{"temp":281.77,"feels_like":277.27,"temp_min":281.77,"temp_max":282.14,"pressure":1004,"sea_level":1004,"grnd_level":944,"humidity":61,"temp_kf":-0.37},"weather":[{"id":804,"main":"Clouds","description":"Bedeckt","icon":"04d"}],"clouds":{"all":100},"wind":{"speed":3.93,"deg":154},"sys":{"pod":"d"},"dt_txt":"2020-02-29 15:00:00"},{"dt":1582999200,"main":{"temp":277.8,"feels_like":274.11,"temp_min":277.8,"temp_max":278.08,"pressure":1005,"sea_level":1005,"grnd_level":946,"humidity":80,"temp_kf":-0.28},"weather":[{"id":804,"main":"Clouds","description":"Bedeckt","icon":"04n"}],"clouds":{"all":100},"wind":{"speed":2.77,"deg":164},"sys":{"pod":"n"},"dt_txt":"2020-02-29 18:00:00"},{"dt":1583010000,"main":{"temp":275.73,"feels_like":271.41,"temp_min":275.73,"temp_max":275.91,"pressure":1006,"sea_level":1006,"grnd_level":946,"humidity":66,"temp_kf":-0.18},"weather":[{"id":804,"main":"Clouds","description":"Bedeckt","icon":"04n"}],"clouds":{"all":100},"wind":{"speed":2.74,"deg":174},"sys":{"pod":"n"},"dt_txt":"2020-02-29 21:00:00"}],"city":{"id":2766824,"name":"Salzburg","coord":{"lat":47.7994,"lon":13.044},"country":"AT","timezone":3600,"sunrise":1582955412,"sunset":1582995045}}
{"city":{"id":2766824,"name":"Salzburg","coord":{"lon":13.044,"lat":47.7994},"country":"AT","population":0,"timezone":3600},"cod":"200","message":0.0756077,"cnt":3,"list":[{"dt":1583578800,"sunrise":1583559394,"sunset":1583600475,"temp":{"day":276.7,"min":273.5,"max":276.7,"night":273.5,"eve":274.74,"morn":276.7},"feels_like":{"day":271.93,"night":269.99,"eve":271.06,"morn":271.93},"pressure":1018,"humidity":75,"weather":[{"id":600,"main":"Snow","description":"Mäßiger Schnee","icon":"13d"}],"speed":3.89,"deg":274,"clouds":100,"rain":2.38,"snow":0.31},{"dt":1583665200,"sunrise":1583645675,"sunset":1583686964,"temp":{"day":281.7,"min":272.09,"max":281.7,"night":275.81,"eve":276.57,"morn":272.09},"feels_like":{"day":279.03,"night":272.32,"eve":273.21,"morn":268.74},"pressure":1021,"humidity":53,"weather":[{"id":801,"main":"Clouds","description":"Ein paar Wolken","icon":"02d"}],"speed":0.88,"deg":259,"clouds":24},{"dt":1583751600,"sunrise":1583731955,"sunset":1583773453,"temp":{"day":276.82,"min":274.09,"max":277.7,"night":274.09,"eve":276.3,"morn":275.27},"feels_like":{"day":272.12,"night":270.38,"eve":272.51,"morn":272.04},"pressure":1016,"humidity":97,"weather":[{"id":501,"main":"Rain","description":"Mäßiger Regen","icon":"10d"}],"speed":4.63,"deg":250,"clouds":100,"rain":5.57}]}

@ -1,26 +1,41 @@
#ifndef FACE_WEATHER_H
#define FACE_WEATHER_H
// TODO
struct faceWeatherData
{
//char hostname[64];
//int port;
// global
char location[20];
// current condition
char current_icon[4];
char current_description[20];
int current_temp;
int current_min;
int current_max;
char location[20];
// forecast +1 (tomorrow)
char forecast_1_icon[4];
int forecast_1_min;
int forecast_1_max;
// current
int current_temp;
int today_min;
int today_max;
// forecast +2
char forecast_2_icon[4];
int forecast_2_min;
int forecast_2_max;
// forecast +3
char forecast_3_icon[4];
int forecast_3_min;
int forecast_3_max;
// forecast
// forecast +4
char forecast_4_icon[4];
int forecast_4_min;
int forecast_4_max;
};
void setupFaceWeather();
void loopFaceWeather();
bool updateWeatherData();
#endif

@ -16,11 +16,11 @@ faceWeatherData weatherData;
void render_current();
void render_forecast();
bool downloadWeatherData();
void readWeatherData();
bool readWeatherData();
void setupFaceWeather()
{
readWeatherData();
}
void loopFaceWeather()
@ -40,38 +40,39 @@ void loopFaceWeather()
void render_current()
{
// name
display.setFont(&FreeSansBold18pt7b);
display.setTextSize(1);
display.setCursor(20, 220);
display.println(weatherData.location);
// temperature
display.setFont(&FreeSansBold24pt7b);
display.setTextSize(2);
display.setCursor(50, 120);
display.println("");
display.println(weatherData.current_temp);
// icon
const uint *icon = getIconById("02n", 192); // 192
const unsigned char *icon = getIconById(weatherData.current_icon, 256);
if (icon)
{
//display.drawInvertedBitmap(224, 30, myIcon, 192, 192, GxEPD_WHITE);
display.drawBitmap(224, 30, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE);
display.drawInvertedBitmap(192, 0, icon, 256, 256, GxEPD_WHITE);
}
// text
display.setTextSize(1);
display.setCursor(400, 300);
//display.println("Ein paar Wolken");
// 250 height
// high
display.setTextSize(1);
display.setCursor(500, 30);
display.println("");
display.setCursor(500, 100);
display.println(weatherData.current_max);
// low
display.setCursor(500, 60);
display.println("-3°");
display.setCursor(500, 180);
display.println(weatherData.current_min);
}
void render_forecast()
{
const uint *icon;
const unsigned char *icon;
// line forecast
display.drawRect(0, 250, 640, 2, GxEPD_WHITE);
@ -90,12 +91,12 @@ void render_forecast()
uint16_t tempRangeY = 260 + 64 + 40;
// day +1
icon = getIconById("03d", 64);
icon = getIconById(weatherData.forecast_1_icon, 64);
if (icon)
{
display.drawBitmap(0 + 48, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE);
display.drawInvertedBitmap(0 + 48, 260, icon, 64, 64, GxEPD_WHITE);
sprintf(label, "%2d ... %2d", -3, 11);
sprintf(label, "%2d ... %2d", weatherData.forecast_1_min, weatherData.forecast_1_max);
display.getTextBounds(label, 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((160 - tbw) / 2) - tbx;
display.setCursor(x, tempRangeY);
@ -103,12 +104,12 @@ void render_forecast()
}
// day +2
icon = getIconById("09d", 64);
icon = getIconById(weatherData.forecast_2_icon, 64);
if (icon)
{
display.drawBitmap(160 + 48, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE);
display.drawInvertedBitmap(160 + 48, 260, icon, 64, 64, GxEPD_WHITE);
sprintf(label, "%2d ... %2d", 0, 7);
sprintf(label, "%2d ... %2d", weatherData.forecast_2_min, weatherData.forecast_2_max);
display.getTextBounds(label, 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((160 - tbw) / 2) - tbx;
display.setCursor(160 + x, tempRangeY);
@ -116,12 +117,12 @@ void render_forecast()
}
// day +3
icon = getIconById("13d", 64);
icon = getIconById(weatherData.forecast_3_icon, 64);
if (icon)
{
display.drawBitmap(320 + 48, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE);
display.drawInvertedBitmap(320 + 48, 260, icon, 64, 64, GxEPD_WHITE);
sprintf(label, "%2d ... %2d", 1, 21);
sprintf(label, "%2d ... %2d", weatherData.forecast_3_min, weatherData.forecast_3_max);
display.getTextBounds(label, 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((160 - tbw) / 2) - tbx;
display.setCursor(320 + x, tempRangeY);
@ -129,12 +130,12 @@ void render_forecast()
}
// day +4
icon = getIconById("13d", 64);
icon = getIconById(weatherData.forecast_4_icon, 64);
if (icon)
{
display.drawBitmap(480 + 48, 260, (uint8_t *)icon + 4, icon[0], icon[1], GxEPD_WHITE);
display.drawInvertedBitmap(480 + 48, 260, icon, 64, 64, GxEPD_WHITE);
sprintf(label, "%2d ... %2d", 19, 35);
sprintf(label, "%2d ... %2d", weatherData.forecast_4_min, weatherData.forecast_4_max);
display.getTextBounds(label, 0, 0, &tbx, &tby, &tbw, &tbh);
x = ((160 - tbw) / 2) - tbx;
display.setCursor(480 + x, tempRangeY);
@ -162,10 +163,11 @@ bool downloadWeatherData()
}
// https://openweathermap.org/forecast5
url = "http://api.openweathermap.org/data/2.5/forecast?";
// http://api.openweathermap.org/data/2.5/forecast/daily?id=2766824&APPID=883b3c87223430d6f3a399645f8ba12b&lang=de&cnt=3
url = "http://api.openweathermap.org/data/2.5/forecast/daily?";
url += "APPID=883b3c87223430d6f3a399645f8ba12b"; // api key
url += "&id=2766824"; // location
url += "&lang=de&cnt=3&units=metric"; // settings
url += "&lang=de&cnt=4&units=metric"; // settings
if (!downloadFile(url, faceWeatherForecast))
{
return false;
@ -174,41 +176,106 @@ bool downloadWeatherData()
return true;
}
void readWeatherData()
/**
* download and update weather data
*/
bool updateWeatherData()
{
if (downloadWeatherData())
{
readWeatherData();
return true;
}
return false;
}
/**
* read weather data from json file
*/
bool readWeatherData()
{
Serial.println(" readWeatherData");
File file;
DeserializationError error;
// current weather
file = SPIFFS.open(faceWeatherCurrent);
if (!file)
{
Serial.print("Failed to open file: ");
Serial.println(faceWeatherCurrent);
return false;
}
StaticJsonDocument<976> docCurrent; // Use arduinojson.org/v6/assistant to compute the capacity.
error = deserializeJson(docCurrent, file);
file.close();
if (error)
{
Serial.println(F("Failed to read file, using default configuration"));
Serial.print("Failed to read file: ");
Serial.println(faceWeatherCurrent);
Serial.println(error.c_str());
return false;
}
// TODO Copy values from the JsonDocument to the Config
weatherData.current_temp = 12;
//serializeJsonPretty(docCurrent, Serial);
//Serial.println(docCurrent["weather"][0]["icon"].as<char *>());
//Serial.println(docCurrent["weather"][0]["main"].as<char *>());
//Serial.println(docCurrent["sys"]["country"].as<char *>());
//Serial.println(docCurrent["main"]["temp"].as<int>());
/*
config.port = doc["port"] | 2731;
strlcpy(config.hostname, // <- destination
doc["hostname"] | "example.com", // <- source
sizeof(config.hostname)); // <- destination's capacity
*/
file.close();
// copy required values
strlcpy(weatherData.location, docCurrent["name"] | "?", sizeof(weatherData.location));
weatherData.current_temp = round(docCurrent["main"]["temp"].as<int>());
weatherData.current_min = floor(docCurrent["main"]["temp_min"].as<int>());
weatherData.current_max = ceil(docCurrent["main"]["temp_max"].as<int>());
strlcpy(weatherData.current_icon, docCurrent["weather"][0]["icon"] | "50n", sizeof(weatherData.current_icon));
// forecast
file = SPIFFS.open(faceWeatherForecast);
StaticJsonDocument<2180> docForecast; // Use arduinojson.org/v6/assistant to compute the capacity.
if (!file)
{
Serial.print("Failed to open file: ");
Serial.println(faceWeatherForecast);
return false;
}
StaticJsonDocument<3000> docForecast; // Use arduinojson.org/v6/assistant to compute the capacity.
error = deserializeJson(docForecast, file);
file.close();
if (error)
{
Serial.println(F("Failed to read file, using default configuration"));
Serial.print("Failed to read file: ");
Serial.println(faceWeatherForecast);
Serial.println(error.c_str());
return false;
}
// TODO get values
// copy required values
weatherData.forecast_1_min = round(docForecast["list"][0]["temp"]["min"].as<int>());
weatherData.forecast_1_max = round(docForecast["list"][0]["temp"]["max"].as<int>());
strlcpy(weatherData.forecast_1_icon, docForecast["list"][0]["weather"][0]["icon"] | "50n", sizeof(weatherData.forecast_1_icon));
file.close();
weatherData.forecast_2_min = round(docForecast["list"][1]["temp"]["min"].as<int>());
weatherData.forecast_2_max = round(docForecast["list"][1]["temp"]["max"].as<int>());
strlcpy(weatherData.forecast_2_icon, docForecast["list"][1]["weather"][0]["icon"] | "50n", sizeof(weatherData.forecast_2_icon));
weatherData.forecast_3_min = round(docForecast["list"][2]["temp"]["min"].as<int>());
weatherData.forecast_3_max = round(docForecast["list"][2]["temp"]["max"].as<int>());
strlcpy(weatherData.forecast_3_icon, docForecast["list"][2]["weather"][0]["icon"] | "50n", sizeof(weatherData.forecast_3_icon));
weatherData.forecast_4_min = round(docForecast["list"][3]["temp"]["min"].as<int>());
weatherData.forecast_4_max = round(docForecast["list"][3]["temp"]["max"].as<int>());
strlcpy(weatherData.forecast_4_icon, docForecast["list"][3]["weather"][0]["icon"] | "50n", sizeof(weatherData.forecast_4_icon));
return true;
}
Loading…
Cancel
Save