· 6 years ago · Dec 31, 2019, 08:44 AM
1*/
2#include <ESPWiFi.h>
3#include <ESPHTTPClient.h>
4#include <JsonListener.h>
5#include <Adafruit_Sensor.h>
6#include <Adafruit_BME280.h>
7// time
8#include <time.h> // time() ctime()
9#include <sys/time.h> // struct timeval
10#include <coredecls.h> // settimeofday_cb()
11//#include "SSD1306Wire.h"
12#include "SH1106Wire.h"
13#include "OLEDDisplayUi.h"
14#include <Wire.h>
15#include "OpenWeatherMapCurrent.h"
16#include "OpenWeatherMapForecast.h"
17#include "WeatherStationFonts.h"
18#include "WeatherStationImages.h"
19
20
21// Create the Lightsensor instance
22#define BME_SCK 13
23#define BME_MISO 12
24#define BME_MOSI 11
25#define BME_CS 10
26#define SEALEVELPRESSURE_HPA (1013.25)
27Adafruit_BME280 bme; // I2C
28//DHTesp dht;
29/***************************
30 * Begin Settings
31 **************************/
32
33// WIFI
34const char* WIFI_SSID = "Levitia";
35const char* WIFI_PWD = "8167809261799352";
36
37String humi1;
38String temp1;
39#define TZ 7 // (utc+) TZ in hours
40#define DST_MN 60 // use 60mn for summer time in some countries
41
42// Setup
43const int UPDATE_INTERVAL_SECS = 10 * 60; // Update every 20 minutes
44unsigned long delayTime;
45// Display Settings
46const int I2C_DISPLAY_ADDRESS = 0x3c;
47#if defined(ESP8266)
48const int SDA_PIN = D2;
49const int SDC_PIN = D1;
50const int DH1=D5;
51#else
52const int SDA_PIN = 4; //D3;
53const int SDC_PIN = 5; //D4;
54const int DH1=14;
55#endif
56// OpenWeatherMap Settings
57// Sign up here to get an API key:
58// https://docs.thingpulse.com/how-tos/openweathermap-key/
59String OPEN_WEATHER_MAP_APP_ID = "f59dd9b53e53a99f7d1128af251a1431";
60/*
61Go to https://openweathermap.org/find?q= and search for a location. Go through the
62result set and select the entry closest to the actual location you want to display
63data for. It'll be a URL like https://openweathermap.org/city/2657896. The number
64at the end is what you assign to the constant below.
65 */
66String OPEN_WEATHER_MAP_LOCATION_ID = "2944368";
67
68// Pick a language code from this list:
69// Arabic - ar, Bulgarian - bg, Catalan - ca, Czech - cz, German - de, Greek - el,
70// English - en, Persian (Farsi) - fa, Finnish - fi, French - fr, Galician - gl,
71// Croatian - hr, Hungarian - hu, Italian - it, Japanese - ja, Korean - kr,
72// Latvian - la, Lithuanian - lt, Macedonian - mk, Dutch - nl, Polish - pl,
73// Portuguese - pt, Romanian - ro, Russian - ru, Swedish - se, Slovak - sk,
74// Slovenian - sl, Spanish - es, Turkish - tr, Ukrainian - ua, Vietnamese - vi,
75// Chinese Simplified - zh_cn, Chinese Traditional - zh_tw.
76String OPEN_WEATHER_MAP_LANGUAGE = "de";
77const uint8_t MAX_FORECASTS = 4;
78
79const boolean IS_METRIC = true;
80
81// Adjust according to your language
82const String WDAY_NAMES[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
83const String MONTH_NAMES[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
84
85/***************************
86 * End Settings
87 **************************/
88 // Initialize the oled display for address 0x3c
89 // sda-pin=14 and sdc-pin=12
90 //SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
91SH1106Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
92 OLEDDisplayUi ui( &display );
93
94OpenWeatherMapCurrentData currentWeather;
95OpenWeatherMapCurrent currentWeatherClient;
96
97OpenWeatherMapForecastData forecasts[MAX_FORECASTS];
98OpenWeatherMapForecast forecastClient;
99
100#define TZ_MN ((TZ)*60)
101#define TZ_SEC ((TZ)*3600)
102#define DST_SEC ((DST_MN)*60)
103time_t now;
104
105// flag changed in the ticker function every 10 minutes
106bool readyForWeatherUpdate = false;
107
108String lastUpdate = "--";
109
110long timeSinceLastWUpdate = 0;
111
112//declaring prototypes
113void drawProgress(OLEDDisplay *display, int percentage, String label);
114void updateData(OLEDDisplay *display);
115void drawBME(OLEDDisplay *display,OLEDDisplayUiState* state,int16_t x, int16_t y);
116void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
117void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
118void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
119void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex);
120void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
121void setReadyForWeatherUpdate();
122
123
124// Add frames
125// this array keeps function pointers to all frames
126// frames are the single views that slide from right to left
127FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast, drawBME};
128int numberOfFrames = 4;
129
130OverlayCallback overlays[] = { drawHeaderOverlay };
131int numberOfOverlays = 1;
132
133void setup() {
134 Serial.begin(115200);
135 Serial.println();
136 Serial.println(F("BME280 test"));
137 bool status;
138 status = bme.begin(0x76);
139 if (!status) {
140 Serial.println("Could not find a valid BME280 sensor, check wiring!");
141 while (1);
142 Serial.println("-- Default Test --");
143 delayTime = 1000;
144
145 Serial.println();
146 }
147 // initialize dispaly
148 display.init();
149 display.clear();
150 display.display();
151
152 //display.flipScreenVertically();
153 display.setFont(ArialMT_Plain_10);
154 display.setTextAlignment(TEXT_ALIGN_CENTER);
155 display.setContrast(255);
156 WiFi.begin(WIFI_SSID, WIFI_PWD);
157 int counter = 0;
158 while (WiFi.status() != WL_CONNECTED) {
159 delay(500);
160 Serial.print(".");
161 display.clear();
162 display.drawString(64, 10, "Connecting to WiFi");
163 display.drawXbm(40, 30, 8, 8, counter % 3 == 0 ? activeSymbole : inactiveSymbole);
164 display.drawXbm(54, 30, 8, 8, counter % 3 == 1 ? activeSymbole : inactiveSymbole);
165 display.drawXbm(68, 30, 8, 8, counter % 3 == 2 ? activeSymbole : inactiveSymbole);
166 display.display();
167
168 counter++;
169 }
170 // Get time from network time service
171 configTime(TZ_SEC, DST_SEC, "pool.ntp.org");
172
173 ui.setTargetFPS(30);
174
175 ui.setActiveSymbol(activeSymbole);
176 ui.setInactiveSymbol(inactiveSymbole);
177
178 // You can change this to
179 // TOP, LEFT, BOTTOM, RIGHT
180 ui.setIndicatorPosition(BOTTOM);
181
182 // Defines where the first frame is located in the bar.
183 ui.setIndicatorDirection(LEFT_RIGHT);
184
185 // You can change the transition that is used
186 // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
187 ui.setFrameAnimation(SLIDE_LEFT);
188
189 ui.setFrames(frames, numberOfFrames);
190
191 ui.setOverlays(overlays, numberOfOverlays);
192
193 // Inital UI takes care of initalising the display too.
194 ui.init();
195
196 Serial.println("");
197
198 updateData(&display);
199
200}
201
202void loop() {
203 if (millis() - timeSinceLastWUpdate > (1000L*UPDATE_INTERVAL_SECS)) {
204 setReadyForWeatherUpdate();
205 timeSinceLastWUpdate = millis();
206 }
207
208 if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
209 updateData(&display);
210 }
211
212 int remainingTimeBudget = ui.update();
213
214 if (remainingTimeBudget > 0) {
215 // You can do some work here
216 // Don't do stuff if you are below your
217 // time budget.
218 delay(remainingTimeBudget);
219 }
220
221}
222
223void drawProgress(OLEDDisplay *display, int percentage, String label) {
224 display->clear();
225 display->setTextAlignment(TEXT_ALIGN_CENTER);
226 display->setFont(ArialMT_Plain_10);
227 display->drawString(64, 10, label);
228 display->drawProgressBar(2, 28, 124, 10, percentage);
229 display->display();
230}
231
232void updateData(OLEDDisplay *display) {
233 drawProgress(display, 10, "Updating time...");
234 drawProgress(display, 30, "Updating weather...");
235 currentWeatherClient.setMetric(IS_METRIC);
236 currentWeatherClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
237 currentWeatherClient.updateCurrentById(¤tWeather, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID);
238 drawProgress(display, 50, "Updating forecasts...");
239 forecastClient.setMetric(IS_METRIC);
240 forecastClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
241 uint8_t allowedHours[] = {12};
242 forecastClient.setAllowedHours(allowedHours, sizeof(allowedHours));
243 forecastClient.updateForecastsById(forecasts, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID, MAX_FORECASTS);
244
245 readyForWeatherUpdate = false;
246 drawProgress(display, 100, "Done...");
247 delay(1000);
248}
249
250void drawBME(OLEDDisplay *display,OLEDDisplayUiState* state,int16_t x, int16_t y){
251
252 float temp1=bme.readTemperature();
253 float pres1=bme.readPressure()/100.0F;
254 float humi1=bme.readHumidity();
255 delay(delayTime);
256 display->setTextAlignment(TEXT_ALIGN_CENTER);
257 display->setFont(ArialMT_Plain_16);
258 String humi=(IS_METRIC ? "H:" : "H:")+String(humi1, 1)+(IS_METRIC ? "%" : "%");
259 display->drawString(64+x, y, humi);
260 display->setTextAlignment(TEXT_ALIGN_CENTER);
261 display->setFont(ArialMT_Plain_16);
262 String temp=(IS_METRIC ? " T:" : "T:")+String(temp1, 1)+(IS_METRIC ? "буC" : "буF");
263 display->drawString(64+x, 15+y, temp);
264 display->setTextAlignment(TEXT_ALIGN_CENTER);
265 display->setFont(ArialMT_Plain_16);
266 String pres=(IS_METRIC ? " P:" : "P:")+String(pres1, 1)+(IS_METRIC ? "hPa" : "hPa");
267 display->drawString(64+x, 30+y, pres);
268 }
269
270void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
271 now = time(nullptr);
272 struct tm* timeInfo;
273 timeInfo = localtime(&now);
274 char buff[16];
275
276
277 display->setTextAlignment(TEXT_ALIGN_CENTER);
278 display->setFont(ArialMT_Plain_10);
279 String date = WDAY_NAMES[timeInfo->tm_wday];
280
281 sprintf_P(buff, PSTR("%s, %02d/%02d/%04d"), WDAY_NAMES[timeInfo->tm_wday].c_str(), timeInfo->tm_mday, timeInfo->tm_mon+1, timeInfo->tm_year + 1900);
282 display->drawString(64 + x, 5 + y, String(buff));
283 display->setFont(ArialMT_Plain_24);
284
285 sprintf_P(buff, PSTR("%02d:%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
286 display->drawString(64 + x, 15 + y, String(buff));
287 display->setTextAlignment(TEXT_ALIGN_LEFT);
288}
289
290void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
291 display->setFont(ArialMT_Plain_10);
292 display->setTextAlignment(TEXT_ALIGN_CENTER);
293 display->drawString(64 + x, 38 + y, currentWeather.description);
294
295 display->setFont(ArialMT_Plain_24);
296 display->setTextAlignment(TEXT_ALIGN_LEFT);
297 String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "буC" : "буF");
298 display->drawString(60 + x, 5 + y, temp);
299
300 display->setFont(Meteocons_Plain_36);
301 display->setTextAlignment(TEXT_ALIGN_CENTER);
302 display->drawString(32 + x, 0 + y, currentWeather.iconMeteoCon);
303}
304
305
306void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
307 drawForecastDetails(display, x, y, 0);
308 drawForecastDetails(display, x + 44, y, 1);
309 drawForecastDetails(display, x + 88, y, 2);
310}
311
312void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex) {
313 time_t observationTimestamp = forecasts[dayIndex].observationTime;
314 struct tm* timeInfo;
315 timeInfo = localtime(&observationTimestamp);
316 display->setTextAlignment(TEXT_ALIGN_CENTER);
317 display->setFont(ArialMT_Plain_10);
318 display->drawString(x + 20, y, WDAY_NAMES[timeInfo->tm_wday]);
319
320 display->setFont(Meteocons_Plain_21);
321 display->drawString(x + 20, y + 12, forecasts[dayIndex].iconMeteoCon);
322 String temp = String(forecasts[dayIndex].temp, 0) + (IS_METRIC ? "буC" : "буF");
323 display->setFont(ArialMT_Plain_10);
324 display->drawString(x + 20, y + 34, temp);
325 display->setTextAlignment(TEXT_ALIGN_LEFT);
326}
327
328void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
329 now = time(nullptr);
330 struct tm* timeInfo;
331 timeInfo = localtime(&now);
332 char buff[14];
333 sprintf_P(buff, PSTR("%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min);
334
335 display->setColor(WHITE);
336 display->setFont(ArialMT_Plain_10);
337 display->setTextAlignment(TEXT_ALIGN_LEFT);
338 display->drawString(0, 54, String(buff));
339 display->setTextAlignment(TEXT_ALIGN_RIGHT);
340 String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "буC" : "буF");
341 display->drawString(128, 54, temp);
342 display->drawHorizontalLine(0, 52, 128);
343}
344
345void setReadyForWeatherUpdate() {
346 Serial.println("Setting readyForUpdate to true");
347 readyForWeatherUpdate = true;
348}