· 6 years ago · Jan 19, 2020, 03:56 PM
1#include <ESPWiFi.h>
2#include <ESPHTTPClient.h>
3#include <JsonListener.h>
4
5// time
6#include <time.h> // time() ctime()
7#include <sys/time.h> // struct timeval
8#include <coredecls.h> // settimeofday_cb()
9
10#include "SSD1306Wire.h"
11#include "OLEDDisplayUi.h"
12#include "Wire.h"
13#include "OpenWeatherMapCurrent.h"
14#include "OpenWeatherMapForecast.h"
15#include "WeatherStationFonts.h"
16#include "WeatherStationImages.h"
17#include <ESP8266WiFi.h>
18
19#include "Adafruit_BMP085.h"
20
21/***************************
22 WIFI Settings
23 **************************/
24const char* WIFI_SSID = "VirgBoris";
25const char* WIFI_PWD = "virgboris1233";
26
27/***************************
28 Begin DHT11 Settings
29 **************************/
30WiFiClient client;
31const char *host = "api.thingspeak.com"; //IP address of the thingspeak server
32const char *api_key = "L2OWRSOLGF7XI0IG"; //Your own thingspeak api_key
33const int httpPort = 80;
34#define pin 14 // ESP8266-12E D5 read emperature and Humidity data
35int temp = 0; //temperature
36int humi = 0; //humidity
37void readTemperatureHumidity();
38void uploadTemperatureHumidity();
39long readTime = 0;
40long uploadTime = 0;
41
42/***************************
43 Begin Atmosphere and Light Sensor Settings
44 **************************/
45void readLight();
46void readAtmosphere();
47Adafruit_BMP085 bmp;
48const int Light_ADDR = 0b0100011; // address:0x23
49const int Atom_ADDR = 0b1110111; // address:0x77
50int tempLight = 0;
51int tempAtom = 0;
52
53/***************************
54 Begin Settings
55 **************************/
56#define TZ 2 // (utc+) TZ in hours
57#define DST_MN 60 // use 60mn for summer time in some countries
58
59// Setup
60const int UPDATE_INTERVAL_SECS = 20 * 60; // Update every 20 minutes
61// Display Settings
62const int I2C_DISPLAY_ADDRESS = 0x3c;
63#if defined(ESP8266)
64//const int SDA_PIN = D1;
65//const int SDC_PIN = D2;
66
67const int SDA_PIN = D3;
68const int SDC_PIN = D4;
69#else
70//const int SDA_PIN = GPIO5;
71//const int SDC_PIN = GPIO4
72
73const int SDA_PIN=GPIO0;
74const int SDC_PIN=GPIO2;
75#endif
76
77
78// OpenWeatherMap Settings
79// Sign up here to get an API key:
80// https://docs.thingpulse.com/how-tos/openweathermap-key/
81const boolean IS_METRIC = true;
82// Add your own thingpulse ID
83String OPEN_WEATHER_MAP_APP_ID = "64bb9d33663467eef8833cb109bfb7d8";
84String OPEN_WEATHER_MAP_LOCATION = "Zurich,CH";
85
86// Pick a language code from this list:
87// Arabic - ar, Bulgarian - bg, Catalan - ca, Czech - cz, German - de, Greek - el,
88// English - en, Persian (Farsi) - fa, Finnish - fi, French - fr, Galician - gl,
89// Croatian - hr, Hungarian - hu, Italian - it, Japanese - ja, Korean - kr,
90// Latvian - la, Lithuanian - lt, Macedonian - mk, Dutch - nl, Polish - pl,
91// Portuguese - pt, Romanian - ro, Russian - ru, Swedish - se, Slovak - sk,
92// Slovenian - sl, Spanish - es, Turkish - tr, Ukrainian - ua, Vietnamese - vi,
93// Chinese Simplified - zh_cn, Chinese Traditional - zh_tw.
94
95String OPEN_WEATHER_MAP_LANGUAGE = "en";
96const uint8_t MAX_FORECASTS = 4;
97
98// Adjust according to your language
99const String WDAY_NAMES[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
100const String MONTH_NAMES[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
101
102/***************************
103 End Settings
104 **************************/
105// Initialize the oled display for address 0x3c
106SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
107OLEDDisplayUi ui( &display );
108
109OpenWeatherMapCurrentData currentWeather;
110OpenWeatherMapCurrent currentWeatherClient;
111
112OpenWeatherMapForecastData forecasts[MAX_FORECASTS];
113OpenWeatherMapForecast forecastClient;
114
115#define TZ_MN ((TZ)*60)
116#define TZ_SEC ((TZ)*3600)
117#define DST_SEC ((DST_MN)*60)
118time_t now;
119
120// flag changed in the ticker function every 10 minutes
121bool readyForWeatherUpdate = false;
122String lastUpdate = "--";
123long timeSinceLastWUpdate = 0;
124//declaring prototypes
125void drawProgress(OLEDDisplay *display, int percentage, String label);
126void updateData(OLEDDisplay *display);
127void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
128void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
129void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
130void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex);
131void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
132void setReadyForWeatherUpdate();
133
134
135// Add frames
136// this array keeps function pointers to all frames
137// frames are the single views that slide from right to left
138FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast };
139int numberOfFrames = 3;
140
141OverlayCallback overlays[] = { drawHeaderOverlay };
142int numberOfOverlays = 1;
143
144void setup() {
145 Serial.begin(115200);
146
147 Wire.begin(0, 2);
148
149 Wire.beginTransmission(Atom_ADDR);
150 //initialize Atmosphere sensor
151 if (!bmp.begin()) {
152 Serial.println("Could not find BMP180 or BMP085 sensor at 0x77");
153 } else {
154 Serial.println("Find BMP180 or BMP085 sensor at 0x77");
155 }
156 Wire.endTransmission();
157
158 //initialize light sensor
159 Wire.beginTransmission(Light_ADDR);
160 Wire.write(0b00000001);
161 Wire.endTransmission();
162
163 // initialize dispaly
164 display.init();
165 display.clear();
166 display.display();
167
168 //display.flipScreenVertically();
169 display.setFont(ArialMT_Plain_10);
170 display.setTextAlignment(TEXT_ALIGN_CENTER);
171 display.setContrast(255);
172
173 WiFi.begin(WIFI_SSID, WIFI_PWD);
174
175 int counter = 0;
176 while (WiFi.status() != WL_CONNECTED) {
177 delay(500);
178 Serial.print(".");
179 display.clear();
180 display.drawString(64, 10, "Connecting to WiFi");
181 display.drawXbm(46, 30, 8, 8, counter % 3 == 0 ? activeSymbole : inactiveSymbole);
182 display.drawXbm(60, 30, 8, 8, counter % 3 == 1 ? activeSymbole : inactiveSymbole);
183 display.drawXbm(74, 30, 8, 8, counter % 3 == 2 ? activeSymbole : inactiveSymbole);
184 display.display();
185
186 counter++;
187 }
188 // Get time from network time service
189 configTime(TZ_SEC, DST_SEC, "pool.ntp.org");
190 ui.setTargetFPS(30);
191 ui.setActiveSymbol(activeSymbole);
192 ui.setInactiveSymbol(inactiveSymbole);
193 // You can change this to
194 // TOP, LEFT, BOTTOM, RIGHT
195 ui.setIndicatorPosition(BOTTOM);
196 // Defines where the first frame is located in the bar.
197 ui.setIndicatorDirection(LEFT_RIGHT);
198 // You can change the transition that is used
199 // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
200 ui.setFrameAnimation(SLIDE_LEFT);
201 ui.setFrames(frames, numberOfFrames);
202 ui.setOverlays(overlays, numberOfOverlays);
203 // Inital UI takes care of initalising the display too.
204 ui.init();
205 Serial.println("");
206 updateData(&display);
207 while (!client.connect(host, httpPort)) {
208 Serial.println("Connection Failed");
209 }
210
211}
212
213void loop() {
214 //Read Temperature Humidity every 5 seconds
215 if (millis() - readTime > 5000) {
216 readTemperatureHumidity();
217 readLight();
218 readAtmosphere();
219 readTime = millis();
220 }
221 //Upload Temperature Humidity every 60 seconds
222 if (millis() - uploadTime > 60000) {
223 uploadTemperatureHumidity();
224 uploadTime = millis();
225 }
226
227 if (millis() - timeSinceLastWUpdate > (1000L * UPDATE_INTERVAL_SECS)) {
228 setReadyForWeatherUpdate();
229 timeSinceLastWUpdate = millis();
230 }
231
232 if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
233 updateData(&display);
234 }
235
236 int remainingTimeBudget = ui.update();
237
238 if (remainingTimeBudget > 0) {
239 // You can do some work here
240 // Don't do stuff if you are below your
241 // time budget.
242 delay(remainingTimeBudget);
243 }
244}
245
246void drawProgress(OLEDDisplay *display, int percentage, String label) {
247 display->clear();
248 display->setTextAlignment(TEXT_ALIGN_CENTER);
249 display->setFont(ArialMT_Plain_10);
250 display->drawString(64, 10, label);
251 display->drawProgressBar(2, 28, 124, 10, percentage);
252 display->display();
253}
254
255void updateData(OLEDDisplay *display) {
256 drawProgress(display, 10, "Updating time...");
257 drawProgress(display, 30, "Updating weather...");
258 currentWeatherClient.setMetric(IS_METRIC);
259 currentWeatherClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
260 currentWeatherClient.updateCurrent(¤tWeather, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION);
261 drawProgress(display, 50, "Updating forecasts...");
262 forecastClient.setMetric(IS_METRIC);
263 forecastClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
264 uint8_t allowedHours[] = {12};
265 forecastClient.setAllowedHours(allowedHours, sizeof(allowedHours));
266 forecastClient.updateForecasts(forecasts, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION, MAX_FORECASTS);
267 readyForWeatherUpdate = false;
268 drawProgress(display, 100, "Done...");
269 delay(1000);
270}
271
272
273
274void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
275 now = time(nullptr);
276 struct tm* timeInfo;
277 timeInfo = localtime(&now);
278 char buff[16];
279
280
281 display->setTextAlignment(TEXT_ALIGN_CENTER);
282 display->setFont(ArialMT_Plain_10);
283 String date = WDAY_NAMES[timeInfo->tm_wday];
284
285 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);
286 display->drawString(64 + x, 5 + y, String(buff));
287 display->setFont(ArialMT_Plain_24);
288
289 sprintf_P(buff, PSTR("%02d:%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
290 display->drawString(64 + x, 15 + y, String(buff));
291 display->setTextAlignment(TEXT_ALIGN_LEFT);
292}
293
294void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
295 display->setFont(ArialMT_Plain_10);
296 display->setTextAlignment(TEXT_ALIGN_CENTER);
297 display->drawString(64 + x, 38 + y, currentWeather.description);
298
299 display->setFont(ArialMT_Plain_24);
300 display->setTextAlignment(TEXT_ALIGN_LEFT);
301 String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "°C" : "°F");
302 display->drawString(60 + x, 5 + y, temp);
303
304 display->setFont(Meteocons_Plain_36);
305 display->setTextAlignment(TEXT_ALIGN_CENTER);
306 display->drawString(32 + x, 0 + y, currentWeather.iconMeteoCon);
307}
308
309
310void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
311 drawForecastDetails(display, x, y, 0);
312 drawForecastDetails(display, x + 44, y, 1);
313 drawForecastDetails(display, x + 88, y, 2);
314}
315
316void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex) {
317 time_t observationTimestamp = forecasts[dayIndex].observationTime;
318 struct tm* timeInfo;
319 timeInfo = localtime(&observationTimestamp);
320 display->setTextAlignment(TEXT_ALIGN_CENTER);
321 display->setFont(ArialMT_Plain_10);
322 display->drawString(x + 20, y, WDAY_NAMES[timeInfo->tm_wday]);
323
324 display->setFont(Meteocons_Plain_21);
325 display->drawString(x + 20, y + 12, forecasts[dayIndex].iconMeteoCon);
326 String temp = String(forecasts[dayIndex].temp, 0) + (IS_METRIC ? "°C" : "°F");
327 display->setFont(ArialMT_Plain_10);
328 display->drawString(x + 20, y + 34, temp);
329 display->setTextAlignment(TEXT_ALIGN_LEFT);
330}
331
332void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
333 now = time(nullptr);
334 struct tm* timeInfo;
335 timeInfo = localtime(&now);
336 char buff[14];
337 sprintf_P(buff, PSTR("%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min);
338
339 display->setColor(WHITE);
340 display->setFont(ArialMT_Plain_10);
341 display->setTextAlignment(TEXT_ALIGN_LEFT);
342 display->drawString(0, 54, String(buff));
343 display->setTextAlignment(TEXT_ALIGN_RIGHT);
344 String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "°C" : "°F");
345 display->drawString(128, 54, temp);
346 display->drawHorizontalLine(0, 52, 128);
347}
348
349void setReadyForWeatherUpdate() {
350 Serial.println("Setting readyForUpdate to true");
351 readyForWeatherUpdate = true;
352}
353
354
355
356//read temperature humidity data
357void readTemperatureHumidity() {
358 int j;
359 unsigned int loopCnt;
360 int chr[40] = {0};
361 unsigned long time1;
362bgn:
363 delay(2000);
364 //Set interface mode 2 to: output
365 //Output low level 20ms (>18ms)
366 //Output high level 40μs
367 pinMode(pin, OUTPUT);
368 digitalWrite(pin, LOW);
369 delay(20);
370 digitalWrite(pin, HIGH);
371 delayMicroseconds(40);
372 digitalWrite(pin, LOW);
373 //Set interface mode 2: input
374 pinMode(pin, INPUT);
375 //High level response signal
376 loopCnt = 10000;
377 while (digitalRead(pin) != HIGH) {
378 if (loopCnt-- == 0) {
379 //If don't return to high level for a long time, output a prompt and start over
380 Serial.println("HIGH");
381 goto bgn;
382 }
383 }
384 //Low level response signal
385 loopCnt = 30000;
386 while (digitalRead(pin) != LOW) {
387 if (loopCnt-- == 0) {
388 //If don't return low for a long time, output a prompt and start over
389 Serial.println("LOW");
390 goto bgn;
391 }
392 }
393 //Start reading the value of bit1-40
394 for (int i = 0; i < 40; i++) {
395 while (digitalRead(pin) == LOW) {}
396 //When the high level occurs, write down the time "time"
397 time1 = micros();
398 while (digitalRead(pin) == HIGH) {}
399 //When there is a low level, write down the time and subtract the time just saved
400 //If the value obtained is greater than 50μs, it is ‘1’, otherwise it is ‘0’
401 //And save it in an array
402 if (micros() - time1 > 50) {
403 chr[i] = 1;
404 } else {
405 chr[i] = 0;
406 }
407 }
408
409 //Humidity, 8-bit bit, converted to a value
410 humi = chr[0] * 128 + chr[1] * 64 + chr[2] * 32 + chr[3] * 16 + chr[4] * 8 + chr[5] * 4 + chr[6] * 2 + chr[7];
411 //Temperature, 8-bit bit, converted to a value
412 temp = chr[16] * 128 + chr[17] * 64 + chr[18] * 32 + chr[19] * 16 + chr[20] * 8 + chr[21] * 4 + chr[22] * 2 + chr[23];
413
414 Serial.print("temp:");
415 Serial.print(temp);
416 Serial.print(" humi:");
417 Serial.println(humi);
418
419}
420
421void readLight() {
422 // reset
423 Wire.beginTransmission(Light_ADDR);
424 Wire.write(0b00000111);
425 Wire.endTransmission();
426
427 Wire.beginTransmission(Light_ADDR);
428 Wire.write(0b00100000);
429 Wire.endTransmission();
430 // typical read delay 120ms
431 delay(120);
432 Wire.requestFrom(Light_ADDR, 2); // 2byte every time
433 for (tempLight = 0; Wire.available() >= 1; ) {
434 char c = Wire.read();
435 tempLight = (tempLight << 8) + (c & 0xFF);
436 }
437 tempLight = tempLight / 1.2;
438 Serial.print("light: ");
439 Serial.println(tempLight);
440}
441
442
443void readAtmosphere() {
444 tempAtom = bmp.readPressure();
445 Serial.print("Pressure = ");
446 Serial.print(tempAtom);
447 Serial.println(" Pascal");
448}
449
450//upload temperature humidity data to thinkspak.com
451void uploadTemperatureHumidity() {
452 if (!client.connect(host, httpPort)) {
453 Serial.println("connection failed");
454 return;
455 }
456 // Three values(field1 field2 field3 field4) have been set in thingspeak.com
457 client.print(String("GET ") + "/update?api_key=" + api_key + "&field1=" + temp + "&field2=" + humi + "&field3=" + tempLight + "&field4=" + tempAtom + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
458 while (client.available()) {
459 String line = client.readStringUntil('\r');
460 Serial.print(line);
461 }
462}