Skip to content

Commit 82c7f67

Browse files
committed
Update OWMclient: place all weather report content in (private) struct; update comments; cleanup.
1 parent d661670 commit 82c7f67

File tree

2 files changed

+134
-195
lines changed

2 files changed

+134
-195
lines changed

marquee/OpenWeatherMapClient.cpp

Lines changed: 82 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,30 @@
77
* Change History:
88
* 20250628 rob040 Completely changed this OWM client API and OWM access API to use the Free Service
99
* 20250712 rob040 Revised data invalidation and data get retry count until data invalid error. New API dataGetRetryCount(), removed API getCached().
10-
* 20250714 rob040 add more options for geo location; it is no longer centered around CityID
10+
* 20250714 rob040 add more options for geo location; it is no longer centered around CityID, Class Ctor does not need CityID, new method setGeoLocation()
1111
*
1212
*/
1313

1414
#include "OpenWeatherMapClient.h"
1515
#include "timeStr.h"
1616

17-
//OpenWeatherMapClient::OpenWeatherMapClient(const String &ApiKey, int CityID, boolean isMetric) {
18-
// myGeoLocation_CityID = CityID;
19-
// myGeoLocation = "";
20-
// myGeoLocationType = LOC_CITYID;
21-
// myApiKey = ApiKey;
22-
// this->isMetric = isMetric;
23-
// isValid = false;
24-
//}
25-
OpenWeatherMapClient::OpenWeatherMapClient(const String &ApiKey, boolean isMetric) {
17+
OpenWeatherMapClient::OpenWeatherMapClient(const String &ApiKey, bool isMetric) {
2618
myGeoLocation = "";
2719
myGeoLocation_CityID = 0;
2820
myGeoLocationType = LOC_UNSET;
2921
myApiKey = ApiKey;
3022
this->isMetric = isMetric;
31-
isValid = false;
23+
weather.isValid = false;
3224
}
3325

3426
// setGeoLocation
3527
// args String location
3628
// return int 0 on success, 1 on failure such as invalid location; no check with weather server has been performed.
3729
//
38-
// location string can be: A) CityID number (old backwards compatibility), B) Longitude,lattitude,
39-
// C) Cityname[,state],Countrycode
30+
// location string can be:
31+
// A) CityID number (old backwards compatibility),
32+
// B) Longitude,lattitude,
33+
// C) Cityname[[,state],Countrycode]
4034
// The location name must be spelled with ASCII-64, no special chars are allowed. This is
4135
// because the HTML page text encoding is in UTF-8 and internally we use only ASCII with
4236
// LED matrix font using ANSI CP437 extended ASCII, however there is no conversion from
@@ -63,6 +57,7 @@ int OpenWeatherMapClient::setGeoLocation(const String &location) {
6357
}
6458
}
6559

60+
// Find out what kind of GeoLocation has been passed
6661
myGeoLocationType = LOC_UNKNOWN;
6762
myGeoLocation = "";
6863
myGeoLocation_CityID = 0;
@@ -81,9 +76,6 @@ int OpenWeatherMapClient::setGeoLocation(const String &location) {
8176
if ((ch_cnt_digits == 0) && (ch_cnt_letters >= len-2)) {
8277
myGeoLocationType = LOC_NAME; // city,state,countrycode OR city,countrycode OR city
8378
myGeoLocation = location;
84-
// USE http://api.openweathermap.org/geo/1.0/direct?q={city-name},{state-code},{country-code}&limit={limit}&appid={API-key}
85-
// to convert location to lat,lon
86-
// OR
8779
// USE http://api.openweathermap.org/data/2.5/weather?q={city-name}&appid={API-key}
8880
// USE http://api.openweathermap.org/data/2.5/weather?q={city-name},{country-code}&appid={API-key}
8981
// USE http://api.openweathermap.org/data/2.5/weather?q={city-name},{state-code},{country-code}&appid={API-key}
@@ -100,7 +92,7 @@ void OpenWeatherMapClient::updateWeather() {
10092
if (myApiKey == "") {
10193
errorMsg = F("Please provide an API key for weather.");
10294
Serial.println(errorMsg);
103-
isValid = false;
95+
weather.isValid = false;
10496
return;
10597
}
10698
switch (myGeoLocationType) {
@@ -109,7 +101,7 @@ void OpenWeatherMapClient::updateWeather() {
109101
case LOC_UNKNOWN:
110102
errorMsg = F("Please set location for weather.");
111103
Serial.println(errorMsg);
112-
isValid = false;
104+
weather.isValid = false;
113105
return;
114106
case LOC_CITYID:
115107
apiGetData += F("id=");
@@ -141,7 +133,7 @@ void OpenWeatherMapClient::updateWeather() {
141133
else {
142134
errorMsg = F("Connection for weather data failed");
143135
Serial.println(errorMsg);
144-
if (++dataGetRetryCount > dataGetRetryCountError) isValid = false;
136+
if (++dataGetRetryCount > dataGetRetryCountError) weather.isValid = false;
145137
return;
146138
}
147139

@@ -159,7 +151,7 @@ void OpenWeatherMapClient::updateWeather() {
159151
if ((millis()-start) >= timeout_ms) {
160152
errorMsg = F("TIMEOUT on weatherClient data receive");
161153
Serial.println(errorMsg);
162-
if (++dataGetRetryCount > dataGetRetryCountError) isValid = false;
154+
if (++dataGetRetryCount > dataGetRetryCountError) weather.isValid = false;
163155
return;
164156
}
165157
//else { //FIXME DEBUG
@@ -174,7 +166,7 @@ void OpenWeatherMapClient::updateWeather() {
174166
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
175167
errorMsg = F("Unexpected response: ") + String(status);
176168
Serial.println(errorMsg);
177-
if (++dataGetRetryCount > dataGetRetryCountError) isValid = false;
169+
if (++dataGetRetryCount > dataGetRetryCountError) weather.isValid = false;
178170
return;
179171
}
180172

@@ -183,7 +175,7 @@ void OpenWeatherMapClient::updateWeather() {
183175
if (!weatherClient.find(endOfHeaders)) {
184176
errorMsg = F("Invalid response endOfHeaders");
185177
Serial.println(errorMsg);
186-
if (++dataGetRetryCount > dataGetRetryCountError) isValid = false;
178+
if (++dataGetRetryCount > dataGetRetryCountError) weather.isValid = false;
187179
return;
188180
}
189181

@@ -193,7 +185,7 @@ void OpenWeatherMapClient::updateWeather() {
193185
if (error) {
194186
errorMsg = F("Weather Data Parsing failed!");
195187
Serial.println(errorMsg);
196-
if (++dataGetRetryCount > dataGetRetryCountError) isValid = false;
188+
if (++dataGetRetryCount > dataGetRetryCountError) weather.isValid = false;
197189
return;
198190
}
199191

@@ -204,164 +196,114 @@ void OpenWeatherMapClient::updateWeather() {
204196
Serial.println(F("Error incomplete message, size ") + String(len));
205197
errorMsg = F("Error: ") + jdoc[F("message")].as<String>();
206198
Serial.println(errorMsg);
207-
if (++dataGetRetryCount > dataGetRetryCountError) isValid = false;
199+
if (++dataGetRetryCount > dataGetRetryCountError) weather.isValid = false;
208200
return;
209201
}
210202

211203

212-
lat = jdoc["coord"]["lat"];
213-
lon = jdoc["coord"]["lon"];
214-
reportTimestamp = jdoc["dt"];
215-
city = jdoc["name"].as<String>();
216-
country = jdoc["sys"]["country"].as<String>();
217-
temperature = jdoc["main"]["temp"];
218-
humidity = jdoc["main"]["humidity"];
219-
weatherId = jdoc["weather"][0]["id"];
220-
weatherCondition = jdoc["weather"][0]["main"].as<String>();
221-
weatherDescription = jdoc["weather"][0]["description"].as<String>();
222-
icon = jdoc["weather"][0]["icon"].as<String>();
223-
pressure = jdoc["main"]["grnd_level"];
224-
if (pressure == 0) // no local ground level pressure? then get main pressure (at sea level)
225-
pressure = jdoc["main"]["pressure"];
226-
windSpeed = jdoc["wind"]["speed"];
227-
windDirection = jdoc["wind"]["deg"];
228-
cloudCoverage = jdoc["clouds"]["all"];
229-
tempHigh = jdoc["main"]["temp_max"];
230-
tempLow = jdoc["main"]["temp_min"];
231-
timeZone = jdoc["timezone"];
232-
sunRise = jdoc["sys"]["sunrise"];
233-
sunSet = jdoc["sys"]["sunset"];
234-
isValid = true;
204+
weather.lat = jdoc["coord"]["lat"];
205+
weather.lon = jdoc["coord"]["lon"];
206+
weather.reportTimestamp = jdoc["dt"];
207+
weather.city = jdoc["name"].as<String>();
208+
weather.country = jdoc["sys"]["country"].as<String>();
209+
weather.temperature = jdoc["main"]["temp"];
210+
weather.humidity = jdoc["main"]["humidity"];
211+
weather.weatherId = jdoc["weather"][0]["id"];
212+
weather.condition = jdoc["weather"][0]["main"].as<String>();
213+
weather.description = jdoc["weather"][0]["description"].as<String>();
214+
weather.icon = jdoc["weather"][0]["icon"].as<String>();
215+
weather.pressure = jdoc["main"]["grnd_level"];
216+
if (weather.pressure == 0) // no local ground level pressure? then get main pressure (at sea level)
217+
weather.pressure = jdoc["main"]["pressure"];
218+
weather.windSpeed = jdoc["wind"]["speed"];
219+
weather.windDirection = jdoc["wind"]["deg"];
220+
weather.cloudCoverage = jdoc["clouds"]["all"];
221+
weather.tempHigh = jdoc["main"]["temp_max"];
222+
weather.tempLow = jdoc["main"]["temp_min"];
223+
weather.timeZone = jdoc["timezone"];
224+
weather.sunRise = jdoc["sys"]["sunrise"];
225+
weather.sunSet = jdoc["sys"]["sunset"];
226+
weather.isValid = true;
235227

236228
if (isMetric) {
237229
// convert m/s to kmh
238-
windSpeed *= 3.6;
230+
weather.windSpeed *= 3.6;
239231
} else {
240232
// Imperial mode
241233
// windspeed is already in mph
242234
//convert millibars (hPa) to Inches mercury (inHg)
243-
pressure = (int)((float)pressure * 0.0295300586 + 0.5);
235+
weather.pressure = (int)((float)weather.pressure * 0.0295300586 + 0.5);
244236
//convert millibars (hPa) to PSI
245237
//pressure = (int)((float)pressure * 0.0145037738 + 0.5);
246238
}
247239

248240
#if 1 //DEBUG
249241
Serial.println(F("Weather data:"));
250-
//Serial.print(F("lat: ")); Serial.println(lat);
251-
//Serial.print(F("lon: ")); Serial.println(lon);
252-
Serial.print(F("reportTimestamp: ")); Serial.println(reportTimestamp);
253-
//Serial.print(F("city: ")); Serial.println(city);
254-
//Serial.print(F("country: ")); Serial.println(country);
255-
Serial.print(F("temperature: ")); Serial.println(temperature);
256-
Serial.print(F("humidity: ")); Serial.println(humidity);
257-
Serial.print(F("wind: ")); Serial.println(windSpeed);
258-
Serial.print(F("windDirection: ")); Serial.println(windDirection);
259-
//Serial.print(F("weatherId: ")); Serial.println(weatherId);
260-
Serial.print(F("weatherCondition: ")); Serial.println(weatherCondition);
261-
Serial.print(F("weatherDescription: ")); Serial.println(weatherDescription);
262-
//Serial.print(F("icon: ")); Serial.println(icon);
242+
//Serial.print(F("lat: ")); Serial.println(weather.lat);
243+
//Serial.print(F("lon: ")); Serial.println(weather.lon);
244+
//Serial.print(F("reportTimestamp: ")); Serial.println(weather.reportTimestamp);
245+
//Serial.print(F("city: ")); Serial.println(weather.city);
246+
//Serial.print(F("country: ")); Serial.println(weather.country);
247+
Serial.print(F("temperature: ")); Serial.println(weather.temperature);
248+
Serial.print(F("humidity: ")); Serial.println(weather.humidity);
249+
Serial.print(F("wind: ")); Serial.println(weather.windSpeed);
250+
Serial.print(F("windDirection: ")); Serial.println(weather.windDirection);
251+
//Serial.print(F("weatherId: ")); Serial.println(weather.weatherId);
252+
Serial.print(F("weatherCondition: ")); Serial.println(weather.condition);
253+
Serial.print(F("weatherDescription: ")); Serial.println(weather.description);
254+
//Serial.print(F("icon: ")); Serial.println(weather.icon);
263255
Serial.print(F("timezone: ")); Serial.println(getTimeZone());
264256
Serial.println();
265257
#endif
266258
}
267259

268260

269261
String OpenWeatherMapClient::getWindDirectionText() {
270-
int val = floor((windDirection / 22.5) + 0.5);
262+
int val = floor((weather.windDirection / 22.5) + 0.5);
271263
String arr[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
272264
return arr[(val % 16)];
273265
}
274266

275267

276268
String OpenWeatherMapClient::getWeekDay() {
277269
String rtnValue = "";
278-
long timestamp = reportTimestamp;
270+
long timestamp = weather.reportTimestamp;
279271
long day = 0;
280-
/*static const char* dayarr[] = {
281-
"Sunday",
282-
"Monday",
283-
"Tuesday",
284-
"Wednesday",
285-
"Thursday",
286-
"Friday",
287-
"Saturday"
288-
};*/
289272
if (timestamp != 0) {
290-
//day = (((timestamp + (3600 * (int)offset)) / 86400) + 4) % 7;
291273
// Add timezone from OWM
292-
timestamp += timeZone;
274+
timestamp += weather.timeZone;
293275
day = ((timestamp / 86400) + 4) % 7;
294276
rtnValue = getDayName(day);
295277
}
296278
return rtnValue;
297279
}
298280

299281
String OpenWeatherMapClient::getWeatherIcon() {
300-
int id = weatherId;
301-
String W = ")";
302-
switch(id)
282+
// match weather condition codes to OLED icon in the weatherstation font
283+
// see https://openweathermap.org/weather-conditions
284+
// TODO: the weatherstation fonts (Meteocons, http://oleddisplay.squix.ch/) contain far more icons than used here
285+
// TODO: There is no night/day difference made here
286+
// TODO: check if translation from weather icon code OLED icon makes more sense.
287+
static const struct { int16_t nr; char w;} lookuptable[] =
303288
{
304-
case 800: W = "B"; break;
305-
case 801: W = "Y"; break;
306-
case 802: W = "H"; break;
307-
case 803: W = "H"; break;
308-
case 804: W = "Y"; break;
309-
310-
case 200: W = "0"; break;
311-
case 201: W = "0"; break;
312-
case 202: W = "0"; break;
313-
case 210: W = "0"; break;
314-
case 211: W = "0"; break;
315-
case 212: W = "0"; break;
316-
case 221: W = "0"; break;
317-
case 230: W = "0"; break;
318-
case 231: W = "0"; break;
319-
case 232: W = "0"; break;
320-
321-
case 300: W = "R"; break;
322-
case 301: W = "R"; break;
323-
case 302: W = "R"; break;
324-
case 310: W = "R"; break;
325-
case 311: W = "R"; break;
326-
case 312: W = "R"; break;
327-
case 313: W = "R"; break;
328-
case 314: W = "R"; break;
329-
case 321: W = "R"; break;
330-
331-
case 500: W = "R"; break;
332-
case 501: W = "R"; break;
333-
case 502: W = "R"; break;
334-
case 503: W = "R"; break;
335-
case 504: W = "R"; break;
336-
case 511: W = "R"; break;
337-
case 520: W = "R"; break;
338-
case 521: W = "R"; break;
339-
case 522: W = "R"; break;
340-
case 531: W = "R"; break;
341-
342-
case 600: W = "W"; break;
343-
case 601: W = "W"; break;
344-
case 602: W = "W"; break;
345-
case 611: W = "W"; break;
346-
case 612: W = "W"; break;
347-
case 615: W = "W"; break;
348-
case 616: W = "W"; break;
349-
case 620: W = "W"; break;
350-
case 621: W = "W"; break;
351-
case 622: W = "W"; break;
352-
353-
case 701: W = "M"; break;
354-
case 711: W = "M"; break;
355-
case 721: W = "M"; break;
356-
case 731: W = "M"; break;
357-
case 741: W = "M"; break;
358-
case 751: W = "M"; break;
359-
case 761: W = "M"; break;
360-
case 762: W = "M"; break;
361-
case 771: W = "M"; break;
362-
case 781: W = "M"; break;
363-
364-
default:break;
289+
{ 800, 'B'}, { 801, 'Y'}, { 802, 'H'}, { 803, 'H'}, { 804, 'Y'},
290+
{ 200, '0'}, { 201, '0'}, { 202, '0'}, { 210, '0'}, { 211, '0'},
291+
{ 212, '0'}, { 221, '0'}, { 230, '0'}, { 231, '0'}, { 232, '0'},
292+
{ 300, 'R'}, { 301, 'R'}, { 302, 'R'}, { 310, 'R'}, { 311, 'R'},
293+
{ 312, 'R'}, { 313, 'R'}, { 314, 'R'}, { 321, 'R'},
294+
{ 500, 'R'}, { 501, 'R'}, { 502, 'R'}, { 503, 'R'}, { 504, 'R'},
295+
{ 511, 'R'}, { 520, 'R'}, { 521, 'R'}, { 522, 'R'}, { 531, 'R'},
296+
{ 600, 'W'}, { 601, 'W'}, { 602, 'W'}, { 611, 'W'}, { 612, 'W'},
297+
{ 615, 'W'}, { 616, 'W'}, { 620, 'W'}, { 621, 'W'}, { 622, 'W'},
298+
{ 701, 'M'}, { 711, 'M'}, { 721, 'M'}, { 731, 'M'}, { 741, 'M'},
299+
{ 751, 'M'}, { 761, 'M'}, { 762, 'M'}, { 771, 'M'}, { 781, 'M'},
300+
{ 0, ')'}
301+
};
302+
int id = weather.weatherId;
303+
int i;
304+
for (i=0; lookuptable[i].nr != 0; i++)
305+
{
306+
if (lookuptable[i].nr == id) break;
365307
}
366-
return W;
308+
return String(lookuptable[i].w);
367309
}

0 commit comments

Comments
 (0)