Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
weather.cpp
Go to the documentation of this file.
1#include <WiFiClientSecure.h>
2#include <HTTPClient.h>
3
4#include "weather.h"
5#include "weather_parser.h"
6
8static String owm_url = "https://api.openweathermap.org/data/2.5/forecast?q={0},{1}&appid={2}&mode=json&cnt=1";
9
10// Valid till 07 Jul 2023
11static const char *cert = "-----BEGIN CERTIFICATE-----\n" \
12 "MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\n" \
13 "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" \
14 "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" \
15 "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\n" \
16 "MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\n" \
17 "BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n" \
18 "aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\n" \
19 "dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" \
20 "AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n" \
21 "3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\n" \
22 "tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\n" \
23 "Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\n" \
24 "VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n" \
25 "79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\n" \
26 "c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\n" \
27 "Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\n" \
28 "c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\n" \
29 "UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\n" \
30 "Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n" \
31 "BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\n" \
32 "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\n" \
33 "Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\n" \
34 "VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\n" \
35 "ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n" \
36 "8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\n" \
37 "iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\n" \
38 "Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\n" \
39 "XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\n" \
40 "qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\n" \
41 "VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\n" \
42 "L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\n" \
43 "jjxDah2nGN59PRbxYvnKkKj9\n" \
44 "-----END CERTIFICATE-----\n";
45
46int8_t PaperdinkUIWeatherClass::fetch_data(const char *city, const char *country, const char *owm_api_id, const char *units)
47{
48 int httpCode, ret = 0;
49
50 WiFiClientSecure *client = new WiFiClientSecure;
51 client->setCACert(cert);
52
53 snprintf(Paperdink_Weather.city, 10, "%s", city);
54 snprintf(Paperdink_Weather.country, 10, "%s", country);
55
56 owm_url.replace("{0}", city);
57 owm_url.replace("{1}", country);
58 owm_url.replace("{2}", owm_api_id);
59
60 if (units[0] == 'M')
61 owm_url += "&units=metric";
62 else
63 owm_url += "&units=imperial";
64
65 DEBUG.printf("OWM URL: %s\r\n", owm_url.c_str());
66
67 {
68 HTTPClient https;
69 https.begin(*client, owm_url.c_str());
70 https.addHeader("Content-Type", "application/json", 0, 0);
71
72 httpCode = https.GET();
73
74 if (httpCode == HTTP_CODE_OK) { // Check for the return code
75 // Parser updates weather_string directly
76 DEBUG.printf("[HTTP] GET SUCCESS\r\n");
77 DynamicJsonDocument json(35 * 1024);
78
79 // Deserialize the JSON document
80 // ReadLoggingStream can be used to debug the stream
81 //ReadLoggingStream loggingStream(https.getStream(), Serial);
82 //DeserializationError error = deserializeJson(json, loggingStream);
83 DeserializationError error = deserializeJson(json, https.getStream());
84 // Test if parsing succeeds.
85 if (error) {
86 Serial.print(F("deserializeJson() failed: "));
87 Serial.println(error.c_str());
88 ret = -1;
89 } else {
90 // convert it to a JsonObject
91 JsonObject root = json.as<JsonObject>();
92
93 snprintf(Paperdink_Weather.weather_string, 10, "%s", root["list"][0]["weather"][0]["main"].as<const char *>());
94 Paperdink_Weather.day_max_temp = root["list"][0]["main"]["temp_max"].as<float>();
95 Paperdink_Weather.day_min_temp = root["list"][0]["main"]["temp_min"].as<float>();
96 Paperdink_Weather.rain = root["list"][0]["rain"]["1h"].as<float>();
97 Paperdink_Weather.snow = root["list"][0]["snow"]["1h"].as<float>();
98 if (Paperdink_Weather.rain == 0)
99 Paperdink_Weather.rain = root["list"][0]["rain"]["3h"].as<float>();
100 if (Paperdink_Weather.snow == 0)
101 Paperdink_Weather.snow = root["list"][0]["snow"]["3h"].as<float>();
102 }
103
104 //ArudinoStreamParser parser;
105 //parser.setListener(&weather_listener);
106 //https.writeToStream(&parser);
107 } else {
108 DEBUG.printf("[HTTP] Failed, error: %s\r\n", https.errorToString(httpCode).c_str());
109 ret = -1;
110 }
111
112 https.end();
113 }
114
115 DEBUG.printf("[HTTP] COMPLETED \r\n");
116
117 delete client;
118 return ret;
119}
120
121void PaperdinkUIWeatherClass::display_weather_text_center(GxEPD2_GFX& display, uint16_t x, uint16_t y, uint16_t w)
122{
123 int16_t xt, yt;
124 uint16_t wt, ht;
125
126 display.setFont(font);
127 display.setTextColor(primary_color);
128 display.getTextBounds(Paperdink_Weather.weather_string, 0, 0, &xt, &yt, &wt, &ht);
129 display.setCursor(x + ((w - wt) / 2), y + ht);
130 display.print(weather_string);
131}
132
134{
135 int16_t xt, yt;
136 uint16_t wt, ht, prev_width = x, prev_height = y;
137
138 display.setFont(font);
139 display.setTextColor(primary_color);
140
141 // Show min and max temperature
142 display.drawBitmap(prev_width, prev_height, thermometer_sml, thermometer_sml_width, thermometer_sml_height, primary_color);
143 prev_width += thermometer_sml_width;
144
145 display.getTextBounds("77", 0, 0, &xt, &yt, &wt, &ht);
146 display.setCursor(prev_width + 10, prev_height + ht + 2);
147 display.printf("%d / %d", (int16_t)Paperdink_Weather.day_max_temp, (int16_t)Paperdink_Weather.day_min_temp);
148 prev_height += thermometer_sml_height;
149
150 prev_width = x; // Reset width for next line
151
152 // TODO: OWM API provides rain/snow in mm only. Convert to in
153 // Show rain
154 display.drawBitmap(prev_width, prev_height + 10, umbrella_sml, umbrella_sml_width, umbrella_sml_height, primary_color);
155 prev_width += umbrella_sml_width;
156
157 display.setCursor(prev_width + 10, prev_height + 10 + ht + 2);
158 display.printf("%.2f mm", Paperdink_Weather.rain);
159 prev_height += umbrella_sml_height + 10;
160
161 prev_width = x; // Reset width for next line
162
163 // Show snow
164 display.drawBitmap(prev_width, prev_height + 10, snowflake_sml, snowflake_sml_width, snowflake_sml_height, primary_color);
165 prev_width += snowflake_sml_width;
166
167 display.setCursor(prev_width + 10, prev_height + 10 + ht + 2);
168 display.printf("%.2f mm", Paperdink_Weather.snow);
169}
170
171void PaperdinkUIWeatherClass::display_weather_style2_center(GxEPD2_GFX& display, uint16_t x, uint16_t y, uint16_t w)
172{
173 const uint8_t *bitmap;
174
175 if (!strcmp(weather_string, "Drizzle")) {
176 bitmap = drizzle_xlrg;
177 } else if (!strcmp(Paperdink_Weather.weather_string, "Thunderstorm") || !strcmp(Paperdink_Weather.weather_string, "Lightning")) {
178 bitmap = lightning_xlrg;
179 } else if (!strcmp(Paperdink_Weather.weather_string, "Rain")) {
180 bitmap = rain_xlrg;
181 } else if (!strcmp(Paperdink_Weather.weather_string, "Snow")) {
182 bitmap = snow_xlrg;
183 } else if (!strcmp(Paperdink_Weather.weather_string, "Clear")) {
184 bitmap = sun_xlrg;
185 } else if (!strcmp(Paperdink_Weather.weather_string, "Clouds")) {
186 bitmap = cloud_xlrg;
187 } else {
188 bitmap = alert_xlrg;
189 DEBUG.printf("Invalid weather: %s\r\n", Paperdink_Weather.weather_string);
190 }
191
192 display.drawBitmap(x + (w - alert_xlrg_width) / 2, y, bitmap, alert_xlrg_width, alert_xlrg_height, primary_color);
193}
194
#define alert_xlrg_height
Definition alert_xlrg.h:2
#define alert_xlrg_width
Definition alert_xlrg.h:1
const unsigned char alert_xlrg[288]
Definition alert_xlrg.h:4
const GFXfont * font
Definition ui_base.h:9
int8_t fetch_data(const char *city, const char *country, const char *owm_api_id, const char *units="M")
Definition weather.cpp:46
void display_weather_style1(GxEPD2_GFX &display, uint16_t x, uint16_t y)
Definition weather.cpp:133
void display_weather_text_center(GxEPD2_GFX &display, uint16_t x, uint16_t y, uint16_t w)
Definition weather.cpp:121
char weather_string[10]
Definition weather.h:13
void display_weather_style2_center(GxEPD2_GFX &display, uint16_t x, uint16_t y, uint16_t w)
Definition weather.cpp:171
const unsigned char cloud_xlrg[288]
Definition cloud_xlrg.h:4
const unsigned char drizzle_xlrg[288]
Definition drizzle_xlrg.h:4
const unsigned char lightning_xlrg[288]
const unsigned char rain_xlrg[288]
Definition rain_xlrg.h:4
const unsigned char snow_xlrg[288]
Definition snow_xlrg.h:4
const unsigned char snowflake_sml[72]
#define snowflake_sml_height
#define snowflake_sml_width
const unsigned char sun_xlrg[288]
Definition sun_xlrg.h:4
#define thermometer_sml_height
const unsigned char thermometer_sml[72]
#define thermometer_sml_width
#define umbrella_sml_width
Definition umbrella_sml.h:1
#define umbrella_sml_height
Definition umbrella_sml.h:2
const unsigned char umbrella_sml[72]
Definition umbrella_sml.h:4
WeatherJsonListener weather_listener
Definition weather.cpp:7
PaperdinkUIWeatherClass Paperdink_Weather
Definition weather.cpp:195
PaperdinkUIWeatherClass Paperdink_Weather
Definition weather.cpp:195
#define DEBUG
Definition weather.h:6