· 4 years ago · Apr 23, 2021, 04:14 PM
1//======================================================================================//
2// //
3// Solar WiFi Weather Station V3.0 Firmware //
4// //
5// Developed by Debasish Dutta, Last Update: 30.03.2021 //
6// //
7//======================================================================================//
8
9 #include <BME280I2C.h>
10 #include "Adafruit_SI1145.h"
11 #include <BH1750.h>
12 #include <DallasTemperature.h>
13 #include <OneWire.h>
14 #include "Wire.h"
15 #include <WiFi.h>
16 #include <BlynkSimpleEsp32.h>
17 #include "esp_deep_sleep.h" //Library needed for ESP32 Sleep Functions
18
19 //=================== Pin assignment definitions ==========================================
20
21 #define WIND_SPD_PIN 14
22 #define RAIN_PIN 25
23 #define WIND_DIR_PIN 35
24 #define VOLT_PIN 33
25 #define TEMP_PIN 4 // DS18B20 hooked up to GPIO pin 4
26
27 //=======================================================================================
28
29 WiFiClient client;
30 BME280I2C bme;
31 Adafruit_SI1145 uv = Adafruit_SI1145();
32 BH1750 lightMeter(0x23);
33 OneWire oneWire(TEMP_PIN);
34 DallasTemperature sensors(&oneWire);
35
36 //=========================Declaring Variables and Constants ==================================
37
38
39 // Variables used in reading temp,pressure and humidity (BME280)
40 float temperature, humidity, pressure;
41
42 // Variables used in reading UV Index (Si1145)
43 float UVindex;
44
45 // Variables used in reading Lux Level( BH1750 )
46 float lux;
47
48 // Variables used in calculating the windspeed
49 volatile unsigned long timeSinceLastTick = 0;
50 volatile unsigned long lastTick = 0;
51 float windSpeed;
52
53 // Variables used in calculating the wind direction
54 int vin;
55 String windDir = "";
56
57 // Variables and constants used in tracking rainfall
58 #define S_IN_DAY 86400
59 #define S_IN_HR 3600
60 #define NO_RAIN_SAMPLES 2000
61 volatile long rainTickList[NO_RAIN_SAMPLES];
62 volatile int rainTickIndex = 0;
63 volatile int rainTicks = 0;
64 int rainLastDay = 0;
65 int rainLastHour = 0;
66 int rainLastHourStart = 0;
67 int rainLastDayStart = 0;
68 long secsClock = 0;
69
70 // Variables used in calculating the battery voltage
71 float batteryVolt;
72 float Vout = 0.00;
73 float Vin = 0.00;
74 float R1 = 27000.00; // resistance of R1 (27K) // You can also use 33K
75 float R2 = 100000.00; // resistance of R2 (100K)
76 int val = 0;
77
78//=========================Deep Sleep Time ================================================
79
80 //const int UpdateInterval = 1 * 60 * 1000000; // e.g. 0.33 * 60 * 1000000; // Sleep time
81 //const int UpdateInterval = 15 * 60 * 1000000; // e.g. 15 * 60 * 1000000; // // Example for a 15-Min update interval 15-mins x 60-secs * 10000
82
83 //========================= Enable Blynk or Thingspeak ===================================
84
85 // configuration control constant for use of either Blynk or Thingspeak
86 //const String App = "BLYNK"; // alternative is line below
87 const String App = "Thingspeak"; // alternative is line above
88
89 //========================= Variables for wifi server setup =============================
90
91 // Your WiFi credentials.
92 // Set password to "" for open networks.
93 char ssid[] = "XXXX"; // WiFi Router ssid
94 char pass[] = "XXXX"; // WiFi Router password
95
96 // copy it from the mail received from Blynk
97 char auth[] = "XXXX";
98
99 // Thingspeak Write API
100 const char* server = "api.thingspeak.com";
101 const char* api_key = "XXXX"; // API write key
102
103//========================= Setup Function ================================================
104
105 void setup()
106 {
107 Serial.begin(115200);
108 delay(25);
109 Serial.println("\nWeather station powered on.\n");
110 Wire.begin();
111 sensors.begin();
112 // Wire.begin(22, 21); // for BH1750
113 bme.begin(); // 0x76 is the address of the BME280 module
114 uv.begin(0x60); // 0x60 is the address of the GY1145 module
115 wifi_connect();
116
117 // Wind speed sensor setup. The windspeed is calculated according to the number
118 // of ticks per second. Timestamps are captured in the interrupt, and then converted
119 // into mph.
120 pinMode(WIND_SPD_PIN, INPUT); // Wind speed sensor
121 attachInterrupt(digitalPinToInterrupt(WIND_SPD_PIN), windTick, FALLING);
122
123 // Rain sesnor setup. Rainfall is tracked by ticks per second, and timestamps of
124 // ticks are tracked so rainfall can be "aged" (i.e., rain per hour, per day, etc)
125 pinMode(RAIN_PIN, INPUT); // Rain sensor
126 attachInterrupt(digitalPinToInterrupt(RAIN_PIN), rainTick, FALLING);
127 // Zero out the timestamp array.
128 for (int i = 0; i < NO_RAIN_SAMPLES; i++) rainTickList[i] = 0;
129
130 // ESP32 Deep SLeep Mode
131 // esp_deep_sleep_enable_timer_wakeup(UpdateInterval);
132 // Serial.println("Going to sleep now...");
133 // esp_deep_sleep_start();
134 }
135//================================ Loop Function ==============================================
136
137 void loop()
138 {
139
140 Read_Sensors_Data(); // Read all the Sensors
141 // printdata(); // Print all the sensors data on the serial monitor
142 Send_Data(); // Upload all the sensors data on the Internet ( Blynk App or Thingspeak )
143
144 }
145
146//============================ Connect to WiFi Network =========================================
147
148void wifi_connect()
149{
150 if (App == "BLYNK") // for posting datas to Blynk App
151 {
152 Blynk.begin(auth, ssid, pass);
153 }
154 else if (App == "Thingspeak") // for posting datas to Thingspeak website
155 {
156 WiFi.begin(ssid, pass);
157
158 while (WiFi.status() != WL_CONNECTED)
159 {
160 delay(500);
161 // Serial.print(".");
162 }
163 Serial.println("");
164 Serial.println("WiFi connected");
165 }
166 else
167 {
168 WiFi.begin(ssid, pass);
169 Serial.print(App);
170 Serial.println(" is not a valid application");
171 }
172
173}
174
175//===================================================================================================
176
177// Read Sensors Data ( BME280, Si1145,BH1750, Bat. Voltage, Wind Sensors, Rain Gauge )
178
179//==================================================================================================
180
181
182 void Read_Sensors_Data()
183{
184 // Reading BME280 sensor
185 bme.read(pressure, temperature, humidity, BME280::TempUnit_Celsius, BME280::PresUnit_Pa);
186
187
188 //***************************************************************************
189
190 // Reading DS18B20 sensor
191 sensors.requestTemperatures();
192
193
194 //***************************************************************************
195 // Reading GY1145 UV sensor
196
197 UVindex = uv.readUV();
198 // the index is multiplied by 100 so to get the
199 // integer index, divide by 100!
200 UVindex /= 100.0;
201 //**********************************************************************************
202 /*// Reading BH1750 sensor
203 lux = lightMeter.readLightLevel();
204
205 */
206//**********************************************************************************
207// Reading Battery Level in %
208 val = analogRead(VOLT_PIN);//reads the analog input
209 Vout = (val * 3.3 ) / 4095.0; // formula for calculating voltage out
210 batteryVolt = Vout * ( R2+R1) / R2 ; // formula for calculating voltage in
211
212
213//**********************************************************************************
214// Read Weather Meters Datas ( Wind Speed, Rain Fall and Wind Direction )
215
216 static unsigned long outLoopTimer = 0;
217 static unsigned long wundergroundUpdateTimer = 0;
218 static unsigned long clockTimer = 0;
219 static unsigned long tempMSClock = 0;
220
221 // Create a seconds clock based on the millis() count. We use this
222 // to track rainfall by the second. We've done this because the millis()
223 // count overflows eventually, in a way that makes tracking time stamps
224 // very difficult.
225 tempMSClock += millis() - clockTimer;
226 clockTimer = millis();
227 while (tempMSClock >= 1000)
228 {
229 secsClock++;
230 tempMSClock -= 1000;
231 }
232
233 // This is a once-per-second timer that calculates and prints off various
234 // values from the sensors attached to the system.
235 if (millis() - outLoopTimer >= 2000)
236 {
237 outLoopTimer = millis();
238 // Windspeed calculation, in mph. timeSinceLastTick gets updated by an
239 // interrupt when ticks come in from the wind speed sensor.
240 if (timeSinceLastTick != 0) windSpeed = 1000.0/timeSinceLastTick;
241
242 // Calculate the wind direction and display it as a string.
243 windDirCalc();
244
245 rainLastHour = 0;
246 rainLastDay = 0;
247 // If there are any captured rain sensor ticks...
248 if (rainTicks > 0)
249 {
250 // Start at the end of the list. rainTickIndex will always be one greater
251 // than the number of captured samples.
252 int i = rainTickIndex-1;
253
254 // Iterate over the list and count up the number of samples that have been
255 // captured with time stamps in the last hour.
256 while ((rainTickList[i] >= secsClock - S_IN_HR) && rainTickList[i] != 0)
257 {
258 i--;
259 if (i < 0) i = NO_RAIN_SAMPLES-1;
260 rainLastHour++;
261 }
262
263 // Repeat the process, this time over days.
264 i = rainTickIndex-1;
265 while ((rainTickList[i] >= secsClock - S_IN_DAY) && rainTickList[i] != 0)
266 {
267 i--;
268 if (i < 0) i = NO_RAIN_SAMPLES-1;
269 rainLastDay++;
270 }
271 rainLastDayStart = i;
272 }
273 }
274 }
275
276
277
278 // Keep track of when the last tick came in on the wind sensor.
279 void windTick(void)
280 {
281 timeSinceLastTick = millis() - lastTick;
282 lastTick = millis();
283 }
284
285 // Capture timestamp of when the rain sensor got tripped.
286 void rainTick(void)
287 {
288 rainTickList[rainTickIndex++] = secsClock;
289 if (rainTickIndex == NO_RAIN_SAMPLES) rainTickIndex = 0;
290 rainTicks++;
291 }
292
293// reading wind direction
294 void windDirCalc()
295 {
296
297 vin = analogRead(WIND_DIR_PIN);
298
299 if (vin < 150) windDir="202.5";
300 else if (vin < 300) windDir = "180";
301 else if (vin < 400) windDir = "247.5";
302 else if (vin < 600) windDir = "225";
303 else if (vin < 900) windDir = "292.5";
304 else if (vin < 1100) windDir = "270";
305 else if (vin < 1500) windDir = "112.5";
306 else if (vin < 1700) windDir = "135";
307 else if (vin < 2250) windDir = "337.5";
308 else if (vin < 2350) windDir = "315";
309 else if (vin < 2700) windDir = "67.5";
310 else if (vin < 3000) windDir = "90";
311 else if (vin < 3200) windDir = "22.5";
312 else if (vin < 3400) windDir = "45";
313 else if (vin < 4000) windDir = "0";
314 else windDir = "0";
315 }
316
317 //====================== Print Data on Serial Monitor ===============================================
318
319 void printdata(){
320 Serial.print("Air temperature [°C]: "); Serial.println(temperature);
321 Serial.print("Humidity [%]: "); Serial.println(int(humidity));
322 Serial.print("Barometric pressure [hPa]: "); Serial.println(pressure / 100);
323 Serial.print("UV: "); Serial.println(UVindex);
324 // Serial.print("Light: "); Serial.print(lux); Serial.println(" lx");
325 Serial.print("Windspeed: "); Serial.print(windSpeed*2.4); Serial.println(" mph");
326 Serial.print("Wind dir: "); Serial.print(" "); Serial.println(windDir);
327 Serial.print("Rainfall last hour: "); Serial.println(float(rainLastHour)*0.011, 3);
328 // Serial.print("Rainfall last day: "); Serial.println(float(rainLastDay)*0.011, 3);
329 // Serial.print("Rainfall to date: "); Serial.println(float(rainTicks)*0.011, 3);
330 Serial.print("Battery Level: "); Serial.println(batteryVolt);
331 Serial.print("Temperature in C: "); Serial.println(sensors.getTempCByIndex(0)); //print the temperature in Celsius
332 Serial.print("Temperature in F: "); Serial.println((sensors.getTempCByIndex(0) * 9.0) / 5.0 + 32.0); //print the temperature in Fahrenheit
333
334 }
335
336//======================Upload Sensors data to Blynk App or Thingspeak =================================
337
338void Send_Data()
339{
340// code block for uploading data to BLYNK App
341
342 if (App == "BLYNK") { // choose application
343 Blynk.virtualWrite(0,temperature ); // virtual pin 0
344 Blynk.virtualWrite(1, humidity ); // virtual pin 1
345 Blynk.virtualWrite(2, pressure/100 ); // virtual pin 2
346 Blynk.virtualWrite(3, UVindex); // virtual pin 3
347 // Blynk.virtualWrite(4, windSpeed*1.492 ); // virtual pin 4
348 Blynk.virtualWrite(4, windSpeed*2.4*4.5 ); // virtual pin 4
349 Blynk.virtualWrite(5, windDir); // virtual pin 5
350 Blynk.virtualWrite(6, rainLastHour); // virtual pin 6
351 Blynk.virtualWrite(7, batteryVolt); // virtual pin 7
352 Blynk.virtualWrite(8, sensors.getTempCByIndex(0)); // virtual pin 8
353 delay(12*5000);
354 }
355
356 // code block for uploading data to Thingspeak website
357
358 else if (App == "Thingspeak") {
359 // Send data to ThingSpeak
360 WiFiClient client;
361 if (client.connect(server,80)) {
362 Serial.println("Connect to ThingSpeak - OK");
363 Serial.println("");
364 Serial.println("********************************************");
365 String postStr = "";
366 postStr+="GET /update?api_key=";
367 postStr+=api_key;
368 postStr+="&field1=";
369 postStr+=String(temperature);
370 postStr+="&field2=";
371 postStr+=String(humidity);
372 postStr+="&field3=";
373 postStr+=String(pressure/100);
374 postStr+="&field4=";
375 postStr+=String(UVindex);
376 postStr+="&field5=";
377 //postStr+=String(windSpeed*1.492); //speed in mph
378 postStr+=String(windSpeed*2.4*4.5); //speed in Km/h
379 postStr+="&field6=";
380 postStr+=String(windDir);
381 postStr+="&field7=";
382 postStr+=String(float(rainTicks)*0.011, 3);
383 postStr+="&field8=";
384 postStr+=String(batteryVolt);
385 postStr+="&field9=";
386 postStr+=String(sensors.getTempCByIndex(0));
387 postStr+=" HTTP/1.1\r\nHost: a.c.d\r\nConnection: close\r\n\r\n";
388 postStr+="";
389 client.print(postStr);
390 delay(5000);
391 //*******************************************************************************
392
393}
394 while(client.available()){
395 String line = client.readStringUntil('\r');
396 // Serial.print(line);
397 }
398 }
399}
400//=============================End of the Program =================================
401
402
403
404