556 lines
29 KiB
C++
556 lines
29 KiB
C++
#include "Meteo.h"
|
|
#include "Ecran.h"
|
|
#include "common.h"
|
|
#include "common_functions.h"
|
|
#include "Ctrl.h"
|
|
|
|
|
|
Meteo::Meteo(Ecran * _ecran, Connect * _connect, Timer * _timer, String _apikey, String _server, String _City, String _Country)
|
|
{
|
|
ecran = _ecran;
|
|
connect = _connect;
|
|
timer = _timer;
|
|
apikey = _apikey;
|
|
server = _server;
|
|
City = _City;
|
|
Country = _Country;
|
|
}
|
|
|
|
bool Meteo::loadData()
|
|
{
|
|
byte Attempts = 1;
|
|
bool RxWeather = false, RxForecast = false;
|
|
while ((RxWeather == false || RxForecast == false) && Attempts <= 2) { // Try up-to 2 time for Weather and Forecast data
|
|
if (RxWeather == false) RxWeather = getWeather(connect->client, "weather");
|
|
if (RxForecast == false) RxForecast = getWeather(connect->client, "forecast");
|
|
Attempts++;
|
|
}
|
|
return RxWeather && RxForecast;
|
|
}
|
|
|
|
//#########################################################################################
|
|
// Symbols are drawn on a relative 10x10grid and 1 scale unit = 1 drawing unit
|
|
void Meteo::addcloud(int x, int y, int scale, int linesize) {
|
|
//Draw cloud outer
|
|
ecran->_display->fillCircle(x - scale * 3, y, scale, GxEPD_BLACK); // Left most circle
|
|
ecran->_display->fillCircle(x + scale * 3, y, scale, GxEPD_BLACK); // Right most circle
|
|
ecran->_display->fillCircle(x - scale, y - scale, scale * 1.4, GxEPD_BLACK); // left middle upper circle
|
|
ecran->_display->fillCircle(x + scale * 1.5, y - scale * 1.3, scale * 1.75, GxEPD_BLACK); // Right middle upper circle
|
|
ecran->_display->fillRect(x - scale * 3 - 1, y - scale, scale * 6, scale * 2 + 1, GxEPD_BLACK); // Upper and lower lines
|
|
//Clear cloud inner
|
|
ecran->_display->fillCircle(x - scale * 3, y, scale - linesize, GxEPD_WHITE); // Clear left most circle
|
|
ecran->_display->fillCircle(x + scale * 3, y, scale - linesize, GxEPD_WHITE); // Clear right most circle
|
|
ecran->_display->fillCircle(x - scale, y - scale, scale * 1.4 - linesize, GxEPD_WHITE); // left middle upper circle
|
|
ecran->_display->fillCircle(x + scale * 1.5, y - scale * 1.3, scale * 1.75 - linesize, GxEPD_WHITE); // Right middle upper circle
|
|
ecran->_display->fillRect(x - scale * 3 + 2, y - scale + linesize - 1, scale * 5.9, scale * 2 - linesize * 2 + 2, GxEPD_WHITE); // Upper and lower lines
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::addraindrop(int x, int y, int scale) {
|
|
ecran->_display->fillCircle(x, y, scale / 2, GxEPD_BLACK);
|
|
ecran->_display->fillTriangle(x - scale / 2, y, x, y - scale * 1.2, x + scale / 2, y , GxEPD_BLACK);
|
|
x = x + scale * 1.6; y = y + scale / 3;
|
|
ecran->_display->fillCircle(x, y, scale / 2, GxEPD_BLACK);
|
|
ecran->_display->fillTriangle(x - scale / 2, y, x, y - scale * 1.2, x + scale / 2, y , GxEPD_BLACK);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::addrain(int x, int y, int scale, bool IconSize) {
|
|
if (IconSize == SmallIcon) scale *= 1.34;
|
|
for (int d = 0; d < 4; d++) {
|
|
addraindrop(
|
|
x + scale * (7.8 - d * 1.95) - scale * 5.2,
|
|
y + scale * 2.1 - scale / 6,
|
|
scale / 1.6);
|
|
}
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::addsnow(int x, int y, int scale, bool IconSize) {
|
|
int dxo, dyo, dxi, dyi;
|
|
for (int flakes = 0; flakes < 5; flakes++) {
|
|
for (int i = 0; i < 360; i = i + 45) {
|
|
dxo = 0.5 * scale * cos((i - 90) * 3.14 / 180); dxi = dxo * 0.1;
|
|
dyo = 0.5 * scale * sin((i - 90) * 3.14 / 180); dyi = dyo * 0.1;
|
|
ecran->_display->drawLine(dxo + x + flakes * 1.5 * scale - scale * 3, dyo + y + scale * 2, dxi + x + 0 + flakes * 1.5 * scale - scale * 3, dyi + y + scale * 2, GxEPD_BLACK);
|
|
}
|
|
}
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::addtstorm(int x, int y, int scale) {
|
|
y = y + scale / 2;
|
|
for (int i = 0; i < 5; i++) {
|
|
ecran->_display->drawLine(x - scale * 4 + scale * i * 1.5 + 0, y + scale * 1.5, x - scale * 3.5 + scale * i * 1.5 + 0, y + scale, GxEPD_BLACK);
|
|
if (scale != Small) {
|
|
ecran->_display->drawLine(x - scale * 4 + scale * i * 1.5 + 1, y + scale * 1.5, x - scale * 3.5 + scale * i * 1.5 + 1, y + scale, GxEPD_BLACK);
|
|
ecran->_display->drawLine(x - scale * 4 + scale * i * 1.5 + 2, y + scale * 1.5, x - scale * 3.5 + scale * i * 1.5 + 2, y + scale, GxEPD_BLACK);
|
|
}
|
|
ecran->_display->drawLine(x - scale * 4 + scale * i * 1.5, y + scale * 1.5 + 0, x - scale * 3 + scale * i * 1.5 + 0, y + scale * 1.5 + 0, GxEPD_BLACK);
|
|
if (scale != Small) {
|
|
ecran->_display->drawLine(x - scale * 4 + scale * i * 1.5, y + scale * 1.5 + 1, x - scale * 3 + scale * i * 1.5 + 0, y + scale * 1.5 + 1, GxEPD_BLACK);
|
|
ecran->_display->drawLine(x - scale * 4 + scale * i * 1.5, y + scale * 1.5 + 2, x - scale * 3 + scale * i * 1.5 + 0, y + scale * 1.5 + 2, GxEPD_BLACK);
|
|
}
|
|
ecran->_display->drawLine(x - scale * 3.5 + scale * i * 1.4 + 0, y + scale * 2.5, x - scale * 3 + scale * i * 1.5 + 0, y + scale * 1.5, GxEPD_BLACK);
|
|
if (scale != Small) {
|
|
ecran->_display->drawLine(x - scale * 3.5 + scale * i * 1.4 + 1, y + scale * 2.5, x - scale * 3 + scale * i * 1.5 + 1, y + scale * 1.5, GxEPD_BLACK);
|
|
ecran->_display->drawLine(x - scale * 3.5 + scale * i * 1.4 + 2, y + scale * 2.5, x - scale * 3 + scale * i * 1.5 + 2, y + scale * 1.5, GxEPD_BLACK);
|
|
}
|
|
}
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::addsun(int x, int y, int scale, bool IconSize) {
|
|
int linesize = 3;
|
|
if (IconSize == SmallIcon) linesize = 1;
|
|
ecran->_display->fillRect(x - scale * 2, y, scale * 4, linesize, GxEPD_BLACK);
|
|
ecran->_display->fillRect(x, y - scale * 2, linesize, scale * 4, GxEPD_BLACK);
|
|
ecran->_display->drawLine(x - scale * 1.3, y - scale * 1.3, x + scale * 1.3, y + scale * 1.3, GxEPD_BLACK);
|
|
ecran->_display->drawLine(x - scale * 1.3, y + scale * 1.3, x + scale * 1.3, y - scale * 1.3, GxEPD_BLACK);
|
|
if (IconSize == LargeIcon) {
|
|
ecran->_display->drawLine(1 + x - scale * 1.3, y - scale * 1.3, 1 + x + scale * 1.3, y + scale * 1.3, GxEPD_BLACK);
|
|
ecran->_display->drawLine(2 + x - scale * 1.3, y - scale * 1.3, 2 + x + scale * 1.3, y + scale * 1.3, GxEPD_BLACK);
|
|
ecran->_display->drawLine(3 + x - scale * 1.3, y - scale * 1.3, 3 + x + scale * 1.3, y + scale * 1.3, GxEPD_BLACK);
|
|
ecran->_display->drawLine(1 + x - scale * 1.3, y + scale * 1.3, 1 + x + scale * 1.3, y - scale * 1.3, GxEPD_BLACK);
|
|
ecran->_display->drawLine(2 + x - scale * 1.3, y + scale * 1.3, 2 + x + scale * 1.3, y - scale * 1.3, GxEPD_BLACK);
|
|
ecran->_display->drawLine(3 + x - scale * 1.3, y + scale * 1.3, 3 + x + scale * 1.3, y - scale * 1.3, GxEPD_BLACK);
|
|
}
|
|
ecran->_display->fillCircle(x, y, scale * 1.3, GxEPD_WHITE);
|
|
ecran->_display->fillCircle(x, y, scale, GxEPD_BLACK);
|
|
ecran->_display->fillCircle(x, y, scale - linesize, GxEPD_WHITE);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::addfog(int x, int y, int scale, int linesize, bool IconSize) {
|
|
if (IconSize == SmallIcon) {
|
|
y -= 10;
|
|
linesize = 1;
|
|
}
|
|
for (int i = 0; i < 6; i++) {
|
|
ecran->_display->fillRect(x - scale * 3, y + scale * 1.5, scale * 6, linesize, GxEPD_BLACK);
|
|
ecran->_display->fillRect(x - scale * 3, y + scale * 2.0, scale * 6, linesize, GxEPD_BLACK);
|
|
ecran->_display->fillRect(x - scale * 3, y + scale * 2.5, scale * 6, linesize, GxEPD_BLACK);
|
|
}
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Sunny(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Small;
|
|
if (IconSize == LargeIcon) scale = Large;
|
|
else y = y - 3; // Shift up small sun icon
|
|
if (IconName.endsWith("n")) addMoon(x, y + 3, scale, IconSize);
|
|
scale = scale * 1.6;
|
|
addsun(x, y, scale, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::MostlySunny(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Small, linesize = 3, offset = 5;
|
|
if (IconSize == LargeIcon) {
|
|
scale = Large;
|
|
offset = 10;
|
|
}
|
|
if (scale == Small) linesize = 1;
|
|
if (IconName.endsWith("n")) addMoon(x, y + offset, scale, IconSize);
|
|
addcloud(x, y + offset, scale, linesize);
|
|
addsun(x - scale * 1.8, y - scale * 1.8 + offset, scale, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::MostlyCloudy(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Small, linesize = 3;
|
|
if (IconSize == LargeIcon) {
|
|
scale = Large;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
addsun(x - scale * 1.8, y - scale * 1.8, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Cloudy(int x, int y, bool IconSize, String IconName) {
|
|
|
|
int scale = Large, linesize = 3;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
linesize = 1;
|
|
addcloud(x, y, scale, linesize);
|
|
}
|
|
else {
|
|
y += 10;
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addcloud(x + 30, y - 45, 5, linesize); // Cloud top right
|
|
addcloud(x - 20, y - 30, 7, linesize); // Cloud top left
|
|
addcloud(x, y, scale, linesize); // Main cloud
|
|
}
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Rain(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Large, linesize = 3;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
addrain(x, y, scale, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::ExpectRain(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Large, linesize = 3;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addsun(x - scale * 1.8, y - scale * 1.8, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
addrain(x, y, scale, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::ChanceRain(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Large, linesize = 3;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addsun(x - scale * 1.8, y - scale * 1.8, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
addrain(x, y, scale, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Tstorms(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Large, linesize = 3;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
addtstorm(x, y, scale);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Snow(int x, int y, bool IconSize, String IconName) {
|
|
int scale = Large, linesize = 3;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addcloud(x, y, scale, linesize);
|
|
addsnow(x, y, scale, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Fog(int x, int y, bool IconSize, String IconName) {
|
|
int linesize = 3, scale = Large;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addcloud(x, y - 5, scale, linesize);
|
|
addfog(x, y - 5, scale, linesize, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Haze(int x, int y, bool IconSize, String IconName) {
|
|
int linesize = 3, scale = Large;
|
|
if (IconSize == SmallIcon) {
|
|
scale = Small;
|
|
linesize = 1;
|
|
}
|
|
if (IconName.endsWith("n")) addMoon(x, y, scale, IconSize);
|
|
addsun(x, y - 5, scale * 1.4, IconSize);
|
|
addfog(x, y - 5, scale * 1.4, linesize, IconSize);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::CloudCover(int x, int y, int CCover) {
|
|
// addcloud(x - 9, y - 3, Small * 0.5, 2); // Cloud top left
|
|
// addcloud(x + 3, y - 3, Small * 0.5, 2); // Cloud top right
|
|
// addcloud(x, y, Small * 0.5, 2); // Main cloud
|
|
ecran->fonts.setFont(u8g2_font_helvB12_tf);
|
|
ecran->drawString(x, y, String(CCover) + "%", LEFT);
|
|
}
|
|
//#########################################################################################
|
|
void Meteo::Visibility(int x, int y, String Visi) {
|
|
y = y - 3; //
|
|
float start_angle = 0.52, end_angle = 2.61;
|
|
int r = 10;
|
|
for (float i = start_angle; i < end_angle; i = i + 0.05) {
|
|
ecran->_display->drawPixel(x + r * cos(i), y - r / 2 + r * sin(i), GxEPD_BLACK);
|
|
ecran->_display->drawPixel(x + r * cos(i), 1 + y - r / 2 + r * sin(i), GxEPD_BLACK);
|
|
}
|
|
start_angle = 3.61; end_angle = 5.78;
|
|
for (float i = start_angle; i < end_angle; i = i + 0.05) {
|
|
ecran->_display->drawPixel(x + r * cos(i), y + r / 2 + r * sin(i), GxEPD_BLACK);
|
|
ecran->_display->drawPixel(x + r * cos(i), 1 + y + r / 2 + r * sin(i), GxEPD_BLACK);
|
|
}
|
|
ecran->_display->fillCircle(x, y, r / 4, GxEPD_BLACK);
|
|
ecran->fonts.setFont(FONT_08);
|
|
ecran->drawString(x + 12, y - 3, Visi, LEFT);
|
|
}
|
|
|
|
//#########################################################################################
|
|
void Meteo::Convert_Readings_to_Imperial() {
|
|
conditions[0].Pressure = hPa_to_inHg(conditions[0].Pressure);
|
|
previsions[1].Rainfall = mm_to_inches(previsions[1].Rainfall);
|
|
previsions[1].Snowfall = mm_to_inches(previsions[1].Snowfall);
|
|
}
|
|
|
|
//#########################################################################################
|
|
// Problems with stucturing JSON decodes, see here: https://arduinojson.org/assistant/
|
|
bool Meteo::DecodeWeather(WiFiClient& json, String Type) {
|
|
if (debug) Serial.print(F("\nCreating object...and "));
|
|
// allocate the JsonDocument
|
|
DynamicJsonDocument doc(35 * 1024);
|
|
// Deserialize the JSON document
|
|
DeserializationError error = deserializeJson(doc, json);
|
|
// Test if parsing succeeds.
|
|
if (error) {
|
|
if (debug) Serial.print(F("deserializeJson() failed: "));
|
|
if (debug) Serial.println(error.c_str());
|
|
return false;
|
|
}
|
|
// convert it to a JsonObject
|
|
JsonObject root = doc.as<JsonObject>();
|
|
if (debug) Serial.println(" Decoding " + Type + " data");
|
|
if (Type == "weather") {
|
|
// All if (debug) Serial.println statements are for diagnostic purposes and not required, remove if not needed
|
|
conditions[0].lon = root["coord"]["lon"].as<float>(); if (debug) Serial.println(" Lon: "+String(conditions[0].lon));
|
|
conditions[0].lat = root["coord"]["lat"].as<float>(); if (debug) Serial.println(" Lat: "+String(conditions[0].lat));
|
|
conditions[0].Main0 = root["weather"][0]["main"].as<const char*>(); if (debug) Serial.println("Main: "+String(conditions[0].Main0));
|
|
conditions[0].Forecast0 = root["weather"][0]["description"].as<const char*>(); if (debug) Serial.println("For0: "+String(conditions[0].Forecast0));
|
|
conditions[0].Forecast1 = root["weather"][1]["description"].as<const char*>(); if (debug) Serial.println("For1: "+String(conditions[0].Forecast1));
|
|
conditions[0].Forecast2 = root["weather"][2]["description"].as<const char*>(); if (debug) Serial.println("For2: "+String(conditions[0].Forecast2));
|
|
conditions[0].Icon = root["weather"][0]["icon"].as<const char*>(); if (debug) Serial.println("Icon: "+String(conditions[0].Icon));
|
|
conditions[0].Temperature = root["main"]["temp"].as<float>(); if (debug) Serial.println("Temp: "+String(conditions[0].Temperature));
|
|
conditions[0].Pressure = root["main"]["pressure"].as<float>(); if (debug) Serial.println("Pres: "+String(conditions[0].Pressure));
|
|
conditions[0].Humidity = root["main"]["humidity"].as<float>(); if (debug) Serial.println("Humi: "+String(conditions[0].Humidity));
|
|
conditions[0].Low = root["main"]["temp_min"].as<float>(); if (debug) Serial.println("TLow: "+String(conditions[0].Low));
|
|
conditions[0].High = root["main"]["temp_max"].as<float>(); if (debug) Serial.println("THig: "+String(conditions[0].High));
|
|
conditions[0].Windspeed = root["wind"]["speed"].as<float>(); if (debug) Serial.println("WSpd: "+String(conditions[0].Windspeed));
|
|
conditions[0].Winddir = root["wind"]["deg"].as<float>(); if (debug) Serial.println("WDir: "+String(conditions[0].Winddir));
|
|
conditions[0].Cloudcover = root["clouds"]["all"].as<int>(); if (debug) Serial.println("CCov: "+String(conditions[0].Cloudcover)); // in % of cloud cover
|
|
conditions[0].Visibility = root["visibility"].as<int>(); if (debug) Serial.println("Visi: "+String(conditions[0].Visibility)); // in metres
|
|
conditions[0].Rainfall = root["rain"]["1h"].as<float>(); if (debug) Serial.println("Rain: "+String(conditions[0].Rainfall));
|
|
conditions[0].Snowfall = root["snow"]["1h"].as<float>(); if (debug) Serial.println("Snow: "+String(conditions[0].Snowfall));
|
|
conditions[0].Country = root["sys"]["country"].as<const char*>(); if (debug) Serial.println("Ctry: "+String(conditions[0].Country));
|
|
conditions[0].Sunrise = root["sys"]["sunrise"].as<int>(); if (debug) Serial.println("SRis: "+String(conditions[0].Sunrise));
|
|
conditions[0].Sunset = root["sys"]["sunset"].as<int>(); if (debug) Serial.println("SSet: "+String(conditions[0].Sunset));
|
|
conditions[0].Timezone = root["timezone"].as<int>(); if (debug) Serial.println("TZon: "+String(conditions[0].Timezone));
|
|
}
|
|
if (Type == "forecast") {
|
|
//if (debug) Serial.println(json);
|
|
if (debug) Serial.print(F("\nReceiving Forecast period - ")); //------------------------------------------------
|
|
JsonArray list = root["list"];
|
|
for (byte r = 0; r < max_readings; r++) {
|
|
// if (debug) Serial.println("\nPeriod-" + String(r) + "--------------");
|
|
previsions[r].Dt = list[r]["dt"].as<int>(); if (debug) Serial.println("DTim: "+String(previsions[r].Dt));
|
|
previsions[r].Temperature = list[r]["main"]["temp"].as<float>(); if (debug) Serial.println("Temp: "+String(previsions[r].Temperature));
|
|
previsions[r].Low = list[r]["main"]["temp_min"].as<float>(); if (debug) Serial.println("TLow: "+String(previsions[r].Low));
|
|
previsions[r].High = list[r]["main"]["temp_max"].as<float>(); if (debug) Serial.println("THig: "+String(previsions[r].High));
|
|
previsions[r].Pressure = list[r]["main"]["pressure"].as<float>(); if (debug) Serial.println("Pres: "+String(previsions[r].Pressure));
|
|
previsions[r].Humidity = list[r]["main"]["humidity"].as<float>(); if (debug) Serial.println("Humi: "+String(previsions[r].Humidity));
|
|
previsions[r].Forecast0 = list[r]["weather"][0]["main"].as<const char*>(); if (debug) Serial.println("For0: "+String(previsions[r].Forecast0));
|
|
previsions[r].Forecast1 = list[r]["weather"][1]["main"].as<const char*>(); if (debug) Serial.println("For1: "+String(previsions[r].Forecast1));
|
|
previsions[r].Forecast2 = list[r]["weather"][2]["main"].as<const char*>(); if (debug) Serial.println("For2: "+String(previsions[r].Forecast2));
|
|
previsions[r].Icon = list[r]["weather"][0]["icon"].as<const char*>(); if (debug) Serial.println("Icon: "+String(previsions[r].Icon));
|
|
previsions[r].Description = list[r]["weather"][0]["description"].as<const char*>(); if (debug) Serial.println("Desc: "+String(previsions[r].Description));
|
|
previsions[r].Cloudcover = list[r]["clouds"]["all"].as<int>(); if (debug) Serial.println("CCov: "+String(previsions[r].Cloudcover)); // in % of cloud cover
|
|
previsions[r].Windspeed = list[r]["wind"]["speed"].as<float>(); if (debug) Serial.println("WSpd: "+String(previsions[r].Windspeed));
|
|
previsions[r].Winddir = list[r]["wind"]["deg"].as<float>(); if (debug) Serial.println("WDir: "+String(previsions[r].Winddir));
|
|
previsions[r].Rainfall = list[r]["rain"]["3h"].as<float>(); if (debug) Serial.println("Rain: "+String(previsions[r].Rainfall));
|
|
previsions[r].Snowfall = list[r]["snow"]["3h"].as<float>(); if (debug) Serial.println("Snow: "+String(previsions[r].Snowfall));
|
|
previsions[r].Pop = list[r]["pop"].as<float>(); if (debug) Serial.println("Pop: "+String(previsions[r].Pop));
|
|
previsions[r].Period = list[r]["dt_txt"].as<const char*>(); if (debug) Serial.println("Peri: "+String(previsions[r].Period));
|
|
}
|
|
//------------------------------------------
|
|
float pressure_trend = previsions[2].Pressure - previsions[0].Pressure; // Measure pressure slope between ~now and later
|
|
pressure_trend = ((int)(pressure_trend * 10)) / 10.0; // Remove any small variations less than 0.1
|
|
conditions[0].Trend = "0";
|
|
if (pressure_trend > 0) conditions[0].Trend = "+";
|
|
if (pressure_trend < 0) conditions[0].Trend = "-";
|
|
if (pressure_trend == 0) conditions[0].Trend = "0";
|
|
|
|
if (Units == "I") Convert_Readings_to_Imperial();
|
|
}
|
|
return true;
|
|
}
|
|
//#########################################################################################
|
|
String Meteo::ConvertUnixTime(int unix_time) {
|
|
// Returns either '21:12 ' or ' 09:12pm' depending on Units mode
|
|
time_t tm = unix_time;
|
|
struct tm *now_tm = gmtime(&tm);
|
|
char output[40];
|
|
if (Units == "M") {
|
|
strftime(output, sizeof(output), "%H:%M %d/%m/%y", now_tm);
|
|
}
|
|
else {
|
|
strftime(output, sizeof(output), "%I:%M%P %m/%d/%y", now_tm);
|
|
}
|
|
return output;
|
|
}
|
|
//#########################################################################################
|
|
//WiFiClient client; // wifi client object
|
|
|
|
bool Meteo::getWeather(WiFiClient& client, const String& RequestType) {
|
|
if (debug) Serial.println("B - getWeather");
|
|
const String units = (Units == "M" ? "metric" : "imperial");
|
|
client.stop(); // close connection before sending a new request
|
|
HTTPClient http;
|
|
|
|
String uri = "/data/2.5/" + RequestType + "?q=" + City + "," + Country + "&APPID=" + apikey + "&mode=json&units=" + units + "&lang=" + Language;
|
|
if(RequestType != "weather")
|
|
{
|
|
uri += "&cnt=" + String(max_readings);
|
|
}
|
|
//http.begin(uri,test_root_ca); //HTTPS example connection
|
|
http.begin(client, server.c_str(), 80, uri);
|
|
int httpCode = http.GET();
|
|
if(httpCode == HTTP_CODE_OK) {
|
|
if (!DecodeWeather(http.getStream(), RequestType)) return false;
|
|
client.stop();
|
|
http.end();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (debug) Serial.printf("connection failed, error: %s", http.errorToString(httpCode).c_str());
|
|
client.stop();
|
|
http.end();
|
|
return false;
|
|
}
|
|
http.end();
|
|
if (debug) Serial.println("E - getWeather");
|
|
return true;
|
|
}
|
|
|
|
//#########################################################################################
|
|
void Meteo::drawMoon(int x, int y) {
|
|
if (debug) Serial.println("B - draw moon");
|
|
|
|
double Phase = normalizedTodayPhase();
|
|
if (debug) Serial.print(" ");
|
|
if (debug) Serial.println(hemisphere);
|
|
if (hemisphere == "south") Phase = 1 - Phase;
|
|
// Draw dark part of moon
|
|
ecran->_display->fillCircle(x + MOON_DIAMETER - 1, y + MOON_DIAMETER, MOON_DIAMETER / 2 + 1, GxEPD_BLACK);
|
|
if (debug) Serial.println("circle done");
|
|
|
|
const int number_of_lines = 90;
|
|
for (double Ypos = 0; Ypos <= number_of_lines / 2; Ypos++) {
|
|
double Xpos = sqrt(number_of_lines / 2 * number_of_lines / 2 - Ypos * Ypos);
|
|
// Determine the edges of the lighted part of the moon
|
|
double Rpos = 2 * Xpos;
|
|
double Xpos1, Xpos2;
|
|
if (Phase < 0.5) {
|
|
Xpos1 = -Xpos;
|
|
Xpos2 = Rpos - 2 * Phase * Rpos - Xpos;
|
|
}
|
|
else {
|
|
Xpos1 = Xpos;
|
|
Xpos2 = Xpos - 2 * Phase * Rpos + Rpos;
|
|
}
|
|
// Draw light part of moon
|
|
double pW1x = (Xpos1 + number_of_lines) / number_of_lines * MOON_DIAMETER + x;
|
|
double pW1y = (number_of_lines - Ypos) / number_of_lines * MOON_DIAMETER + y;
|
|
double pW2x = (Xpos2 + number_of_lines) / number_of_lines * MOON_DIAMETER + x;
|
|
double pW2y = (number_of_lines - Ypos) / number_of_lines * MOON_DIAMETER + y;
|
|
double pW3x = (Xpos1 + number_of_lines) / number_of_lines * MOON_DIAMETER + x;
|
|
double pW3y = (Ypos + number_of_lines) / number_of_lines * MOON_DIAMETER + y;
|
|
double pW4x = (Xpos2 + number_of_lines) / number_of_lines * MOON_DIAMETER + x;
|
|
double pW4y = (Ypos + number_of_lines) / number_of_lines * MOON_DIAMETER + y;
|
|
ecran->_display->drawLine(pW1x, pW1y, pW2x, pW2y, GxEPD_WHITE);
|
|
ecran->_display->drawLine(pW3x, pW3y, pW4x, pW4y, GxEPD_WHITE);
|
|
}
|
|
ecran->_display->drawCircle(x + MOON_DIAMETER - 1, y + MOON_DIAMETER, MOON_DIAMETER / 2, GxEPD_BLACK);
|
|
if (debug) Serial.println("E - draw moon");
|
|
|
|
}
|
|
//#########################################################################################
|
|
String Meteo::calculateTodayPhase() {
|
|
if (debug) Serial.println("B - moon phase");
|
|
|
|
time_t now = time(NULL);
|
|
struct tm * now_utc = gmtime(&now);
|
|
// Panel * panel = Panel::getSingletonInstance();
|
|
|
|
int d = timer->day; //now_utc->tm_mday;
|
|
int m = timer->month; // now_utc->tm_mon + 1;
|
|
int y = timer->year; // now_utc->tm_year + 1900;
|
|
|
|
int c, e;
|
|
double jd;
|
|
int b;
|
|
if (m < 3) {
|
|
y--;
|
|
m += 12;
|
|
}
|
|
++m;
|
|
c = 365.25 * y;
|
|
e = 30.6 * m;
|
|
jd = c + e + d - 694039.09; /* jd is total days elapsed */
|
|
jd /= 29.53059; /* divide by the moon cycle (29.53 days) */
|
|
b = jd; /* int(jd) -> b, take integer part of jd */
|
|
jd -= b; /* subtract integer part to leave fractional part of original jd */
|
|
b = jd * 8 + 0.5; /* scale fraction from 0-8 and round by adding 0.5 */
|
|
b = b & 7; /* 0 and 8 are the same phase so modulo 8 for 0 */
|
|
if (hemisphere == "south") b = 7 - b;
|
|
if (debug) Serial.print("hemisphere=");
|
|
if (debug) Serial.println(b);
|
|
phase = b;
|
|
if (debug) Serial.println("E - moon phase");
|
|
|
|
if (b == 0) return TXT_MOON_NEW; // New; 0% illuminated
|
|
if (b == 1) return TXT_MOON_WAXING_CRESCENT; // Waxing crescent; 25% illuminated
|
|
if (b == 2) return TXT_MOON_FIRST_QUARTER; // First quarter; 50% illuminated
|
|
if (b == 3) return TXT_MOON_WAXING_GIBBOUS; // Waxing gibbous; 75% illuminated
|
|
if (b == 4) return TXT_MOON_FULL; // Full; 100% illuminated
|
|
if (b == 5) return TXT_MOON_WANING_GIBBOUS; // Waning gibbous; 75% illuminated
|
|
if (b == 6) return TXT_MOON_THIRD_QUARTER; // Third quarter; 50% illuminated
|
|
if (b == 7) return TXT_MOON_WANING_CRESCENT; // Waning crescent; 25% illuminated
|
|
|
|
return "";
|
|
}
|
|
|
|
double Meteo::normalizedTodayPhase() {
|
|
if (debug) Serial.println("B - normalizedTodayPhase");
|
|
|
|
time_t now = time(NULL);
|
|
struct tm * now_utc = gmtime(&now);
|
|
|
|
int d = timer->day; //now_utc->tm_mday;
|
|
int m = timer->month; // now_utc->tm_mon + 1;
|
|
int y = timer->year; // now_utc->tm_year + 1900;
|
|
if (debug) Serial.print(d);
|
|
if (debug) Serial.print(" ");
|
|
if (debug) Serial.print(m);
|
|
if (debug) Serial.print(" ");
|
|
if (debug) Serial.println(y);
|
|
|
|
//Panel * panel = Panel::getSingletonInstance();
|
|
|
|
int j = JulianDate(d, m, y);
|
|
//Calculate the approximate phase of the moon
|
|
double Phase = (j + 4.867) / 29.53059;
|
|
|
|
if (debug) Serial.print("E - normalizedTodayPhase ");
|
|
return (Phase - (int) Phase);
|
|
}
|
|
|
|
//#########################################################################################
|
|
void Meteo::addMoon(int x, int y, int scale, bool largeIcon) {
|
|
if (largeIcon) {
|
|
if (!DRAW_MOON_IN_CONDITION) {
|
|
ecran->_display->fillCircle(x - 62, y - 68, scale, GxEPD_BLACK);
|
|
ecran->_display->fillCircle(x - 43, y - 68, scale * 1.6, GxEPD_WHITE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ecran->_display->fillCircle(x - 25, y - 15, scale, GxEPD_BLACK);
|
|
ecran->_display->fillCircle(x - 18, y - 15, scale * 1.6, GxEPD_WHITE);
|
|
}
|
|
}
|
|
|
|
void Meteo::drawTodayMoon(int x, int y)
|
|
{
|
|
String phase_txt = calculateTodayPhase();
|
|
drawMoon(x, y);
|
|
|
|
// ecran->drawString(x + 4, y + 64, phase_txt, LEFT);
|
|
|
|
} |