@@ -5,74 +5,110 @@ bool otaInitialDrawDone = false;
5
5
uint8_t otaState = 0 ;
6
6
uint8_t otaProgress = 0 ;
7
7
8
- float insideTemp = 0 ;
9
8
uint32_t currTempRotateTime = 0 ;
10
9
10
+ // Set initially to false to wait for WiFi before attempting update
11
+ // These are handled outside Homie loop to ensure it still functions
12
+ // even without an MQTT connection
11
13
bool initialUpdate = false ;
12
- bool currentUpdate = false ;
13
- bool forecastUpdate = false ;
14
- bool astronomyUpdate = false ;
14
+ bool doCurrentUpdate = false ;
15
+ bool doForecastUpdate = false ;
16
+ bool doAstronomyUpdate = false ;
17
+ // Set to True inititally since sending is handled inside Homie loop
18
+ // and an MQTT connection is guarenteed
19
+ bool doTemperatureSend = true ;
15
20
16
- time_t dstOffset = 0 ;
17
21
uint8_t moonAge = 0 ;
18
22
String moonAgeImage = " " ;
19
23
uint32_t lastTemperatureSent = 0 ;
20
24
21
25
HomieNode temperatureNode (" temperature" , " temperature" );
22
26
HomieSetting<const char *> owApiKey (" ow_api_key" , " Open Weather API Key" );
27
+ HomieSetting<const char *> tzUtcOffset (" tz_utc_offset" , " Standard time UTC offset. See https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html" );
28
+ HomieSetting<const char *> tzDST (" tz_dst" , " Timezone abbrev when in Daylight Saving Time." );
29
+ HomieSetting<const char *> tzST (" tz_st" , " Timezone abbrev when in Standard Time." );
30
+ HomieSetting<const char *> dstStart (" dst_start" , " When DST starts in TZ format" );
31
+ HomieSetting<const char *> dstEnd (" dst_end" , " When DST ends in TZ format" );
32
+
23
33
24
34
void initialize () {
25
- currentUpdate = true ;
26
- forecastUpdate = true ;
27
- astronomyUpdate = true ;
28
- sensors.begin ();
35
+ // Setup timezone configurations
36
+ // https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
37
+ String tzInfo;
38
+ tzInfo.concat (tzST.get ());
39
+ tzInfo.concat (tzUtcOffset.get ());
40
+ tzInfo.concat (tzDST.get ());
41
+ tzInfo.concat (" ,M3.2.0/2,M11.1.0/2" );
42
+ Homie.getLogger () << F (" Setting TZ info '" ) << tzInfo << F (" '" ) << endl;
43
+ setenv (" TZ" , tzInfo.c_str (), 1 );
44
+ tzset (); // save the TZ variable
45
+ configTime (0 , 0 , NTP_SERVERS);
46
+
47
+ doCurrentUpdate = true ;
48
+ doForecastUpdate = true ;
49
+ doAstronomyUpdate = true ;
29
50
temperatureNode.setProperty (" unit" ).send (" c" );
30
51
}
31
52
32
53
void temperatureLoop () {
33
- if (millis () - lastTemperatureSent >= TEMPERATURE_UPDATE * 1000 ||
34
- lastTemperatureSent == 0 ) {
54
+ if (doTemperatureSend) {
35
55
sensors.requestTemperatures ();
36
- insideTemp = sensors.getTempCByIndex (0 );
56
+ float insideTemp = sensors.getTempCByIndex (0 );
37
57
Homie.getLogger () << F (" Temperature: " ) << insideTemp << endl;
38
58
temperatureNode.setProperty (" degrees" ).send (String (insideTemp));
39
- lastTemperatureSent = millis () ;
59
+ doTemperatureSend = false ;
40
60
}
41
61
}
42
62
43
63
void setup () {
44
64
Serial.begin (115200 );
45
65
66
+ time_t rtc_time_t = 1543819410 ; // fake RTC time for now
67
+ timezone tz_ = { 0 , 0 };
68
+ timeval tv_ = { rtc_time_t , 0 };
69
+ settimeofday (&tv_, &tz_);
70
+
71
+ // Setup pins
46
72
pinMode (TFT_LED, OUTPUT);
47
73
digitalWrite (TFT_LED, HIGH);
48
74
pinMode (TEMP_PIN, INPUT);
75
+ sensors.begin ();
49
76
50
- gfx.init ();
51
- gfx.fillBuffer (MINI_BLACK);
52
- gfx.commit ();
53
-
77
+ // Setup tickers
54
78
updateCurrentTicker.attach (5 * 60 * 1000 , []() {
55
- if (WiFi.status () == WL_CONNECTED) currentUpdate = true ;
79
+ if (WiFi.status () == WL_CONNECTED) doCurrentUpdate = true ;
56
80
});
57
81
updateForecastTicker.attach (20 * 60 * 1000 , []() {
58
- if (WiFi.status () == WL_CONNECTED) forecastUpdate = true ;
82
+ if (WiFi.status () == WL_CONNECTED) doForecastUpdate = true ;
59
83
});
60
84
updateAstronomyTicker.attach (60 * 60 * 1000 , []() {
61
- if (WiFi.status () == WL_CONNECTED) astronomyUpdate = true ;
85
+ if (WiFi.status () == WL_CONNECTED) doAstronomyUpdate = true ;
62
86
});
87
+ sendTemperatureTicker.attach (60 * 1000 , []() { doTemperatureSend = true ; });
63
88
89
+ // setup graphics driver
90
+ gfx.init ();
91
+ gfx.fillBuffer (MINI_BLACK);
92
+ gfx.commit ();
64
93
carousel.setFrames (frames, frameCount);
65
94
carousel.disableAllIndicators ();
66
95
carousel.setTargetFPS (3 );
67
96
97
+ // Setup HTTP clients
68
98
currentWeatherClient.setMetric (IS_METRIC);
69
99
currentWeatherClient.setLanguage (OPEN_WEATHER_LANGUAGE);
70
100
forecastClient.setMetric (IS_METRIC);
71
101
forecastClient.setLanguage (OPEN_WEATHER_LANGUAGE);
72
102
forecastClient.setAllowedHours (allowedHours, sizeof (allowedHours));
73
103
104
+ // Setup Homie
74
105
Homie_setFirmware (" weather-station" , " 0.0.1" );
75
106
Homie_setBrand (" IoT" );
107
+ tzUtcOffset.setDefaultValue (TZ_UTC_OFFSET);
108
+ tzST.setDefaultValue (TZ_ST);
109
+ tzDST.setDefaultValue (TZ_DST);
110
+ dstStart.setDefaultValue (DST_START);
111
+ dstEnd.setDefaultValue (DST_END);
76
112
Homie.onEvent (onHomieEvent);
77
113
Homie.setSetupFunction (initialize);
78
114
Homie.setLoopFunction (temperatureLoop);
@@ -131,7 +167,7 @@ void loop() {
131
167
switch (bootMode) {
132
168
case HomieBootMode::NORMAL:
133
169
// Only update data if WiFi connected and interval passed
134
- if (currentUpdate || forecastUpdate || astronomyUpdate ) {
170
+ if (doCurrentUpdate || doForecastUpdate || doAstronomyUpdate ) {
135
171
updateData ();
136
172
return ;
137
173
}
@@ -172,9 +208,9 @@ void drawWifiQuality() {
172
208
173
209
void drawTime () {
174
210
char time_str[11 ];
175
- char *dstAbbrev;
176
- time_t now = dstAdjusted. time (&dstAbbrev );
177
- struct tm *timeinfo = localtime (&now );
211
+
212
+ time_t tnow = time (nullptr );
213
+ struct tm *timeinfo = localtime (&tnow );
178
214
179
215
gfx.setTextAlignment (TEXT_ALIGN_CENTER);
180
216
gfx.setFont (ArialRoundedMTBold_14);
@@ -202,11 +238,11 @@ void drawTime() {
202
238
gfx.setFont (ArialMT_Plain_10);
203
239
gfx.setColor (MINI_BLUE);
204
240
if (IS_12H) {
205
- sprintf (time_str, " %s\n %s" , dstAbbrev ,
241
+ sprintf (time_str, " %s\n %s" , getTimezone (timeinfo) ,
206
242
timeinfo->tm_hour >= 12 ? " PM" : " AM" );
207
243
gfx.drawString (195 , 27 , time_str);
208
244
} else {
209
- sprintf (time_str, " %s" , dstAbbrev );
245
+ sprintf (time_str, " %s" , getTimezone (timeinfo) );
210
246
gfx.drawString (195 , 27 , time_str); // Known bug: Cuts off 4th character of
211
247
// timezone abbreviation
212
248
}
@@ -247,9 +283,14 @@ void drawCurrentWeather() {
247
283
gfx.setColor (MINI_WHITE);
248
284
gfx.setTextAlignment (TEXT_ALIGN_RIGHT);
249
285
250
- gfx.drawString (220 , 78 ,
251
- String (displayCurrent ? currentWeather.temp : insideTemp, 1 ) +
252
- (IS_METRIC ? " °C" : " °F" ));
286
+ if (!displayCurrent) {
287
+ sensors.requestTemperatures ();
288
+ float insideTemp = sensors.getTempCByIndex (0 );
289
+ gfx.drawString (220 , 78 , String (insideTemp, 1 ) + (IS_METRIC ? " °C" : " °F" ));
290
+ } else {
291
+ gfx.drawString (220 , 78 ,
292
+ String (currentWeather.temp , 1 ) + (IS_METRIC ? " °C" : " °F" ));
293
+ }
253
294
254
295
if (displayCurrent) {
255
296
gfx.setFont (ArialRoundedMTBold_14);
@@ -284,7 +325,7 @@ void drawForecastDetail(uint16_t x, uint16_t y, uint8_t dayIndex) {
284
325
gfx.setColor (MINI_YELLOW);
285
326
gfx.setFont (ArialRoundedMTBold_14);
286
327
gfx.setTextAlignment (TEXT_ALIGN_CENTER);
287
- time_t time = forecasts[dayIndex].observationTime + dstOffset ;
328
+ time_t time = forecasts[dayIndex].observationTime ;
288
329
struct tm *timeinfo = localtime (&time );
289
330
gfx.drawString (
290
331
x + 25 , y - 15 ,
@@ -319,10 +360,10 @@ void drawAstronomy() {
319
360
gfx.setColor (MINI_YELLOW);
320
361
gfx.drawString (5 , 250 , SUN_MOON_TEXT[0 ]);
321
362
gfx.setColor (MINI_WHITE);
322
- time_t time = currentWeather.sunrise + dstOffset ;
363
+ time_t time = currentWeather.sunrise ;
323
364
gfx.drawString (5 , 276 , SUN_MOON_TEXT[1 ] + " :" );
324
365
gfx.drawString (45 , 276 , getTime (&time ));
325
- time = currentWeather.sunset + dstOffset ;
366
+ time = currentWeather.sunset ;
326
367
gfx.drawString (5 , 291 , SUN_MOON_TEXT[2 ] + " :" );
327
368
gfx.drawString (45 , 291 , getTime (&time ));
328
369
@@ -351,43 +392,43 @@ void updateData() {
351
392
gfx.fillBuffer (MINI_BLACK);
352
393
gfx.setFont (ArialRoundedMTBold_14);
353
394
354
- configTime (UTC_OFFSET * 3600 , 0 , NTP_SERVERS);
355
- while (!time (nullptr )) {
356
- Serial.print (" #" );
357
- delay (10 );
358
- }
359
- // calculate for time calculation how much the dst class adds.
360
- dstOffset = UTC_OFFSET * 3600 + dstAdjusted.time (nullptr ) - time (nullptr );
361
-
362
- if (currentUpdate) {
395
+ if (doCurrentUpdate) {
363
396
drawProgress (50 , F (" Updating conditions..." ));
364
- currentUpdate = !currentWeatherClient.updateCurrentById (
397
+ doCurrentUpdate = !currentWeatherClient.updateCurrentById (
365
398
¤tWeather, owApiKey.get (), OPEN_WEATHER_MAP_LOCATION_ID);
366
399
Homie.getLogger () << F (" Current Forecast Successful? " )
367
- << (currentUpdate ? F (" False" ) : F (" True" )) << endl;
400
+ << (doCurrentUpdate ? F (" False" ) : F (" True" )) << endl;
368
401
}
369
402
370
- if (forecastUpdate ) {
403
+ if (doForecastUpdate ) {
371
404
drawProgress (70 , F (" Updating forecasts..." ));
372
- forecastUpdate = !forecastClient.updateForecastsById (
405
+ doForecastUpdate = !forecastClient.updateForecastsById (
373
406
forecasts, owApiKey.get (), OPEN_WEATHER_MAP_LOCATION_ID, MAX_FORECASTS);
374
407
Homie.getLogger () << F (" Forcast Update Successful? " )
375
- << (forecastUpdate ? F (" False" ) : F (" True" )) << endl;
408
+ << (doForecastUpdate ? F (" False" ) : F (" True" )) << endl;
376
409
}
377
410
378
- if (astronomyUpdate ) {
411
+ if (doAstronomyUpdate ) {
379
412
drawProgress (80 , F (" Updating astronomy..." ));
380
413
moonData = astronomy.calculateMoonData (time (nullptr ));
381
414
float lunarMonth = 29.53 ;
382
415
moonAge = moonData.phase <= 4
383
416
? lunarMonth * moonData.illumination / 2
384
417
: lunarMonth - moonData.illumination * lunarMonth / 2 ;
385
418
moonAgeImage = String ((char )(65 + ((uint8_t )((26 * moonAge / 30 ) % 26 ))));
386
- astronomyUpdate = false ;
419
+ doAstronomyUpdate = false ;
387
420
}
388
421
initialUpdate = true ;
389
422
}
390
423
424
+ const char * getTimezone (tm *timeInfo) {
425
+ if (timeInfo->tm_isdst ) {
426
+ return tzDST.get ();
427
+ } else {
428
+ return tzST.get ();
429
+ }
430
+ }
431
+
391
432
String getTime (time_t *timestamp) {
392
433
struct tm *timeInfo = gmtime (timestamp);
393
434
0 commit comments