Close Menu
  • Articles
    • Learn Electronics
    • Product Review
    • Tech Articles
  • Electronics Circuits
    • 555 Timer Projects
    • Op-Amp Circuits
    • Power Electronics
  • Microcontrollers
    • Arduino Projects
    • STM32 Projects
    • AMB82-Mini IoT AI Camera
    • BLE Projects
  • IoT Projects
    • ESP8266 Projects
    • ESP32 Projects
    • ESP32 MicroPython
    • ESP32-CAM Projects
    • LoRa/LoRaWAN Projects
  • Raspberry Pi
    • Raspberry Pi Projects
    • Raspberry Pi Pico Projects
    • Raspberry Pi Pico W Projects
  • Electronics Calculator
Facebook X (Twitter) Instagram
  • About Us
  • Disclaimer
  • Privacy Policy
  • Contact Us
  • Advertise With Us
Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
How To Electronics
  • Articles
    • Learn Electronics
    • Product Review
    • Tech Articles
  • Electronics Circuits
    • 555 Timer Projects
    • Op-Amp Circuits
    • Power Electronics
  • Microcontrollers
    • Arduino Projects
    • STM32 Projects
    • AMB82-Mini IoT AI Camera
    • BLE Projects
  • IoT Projects
    • ESP8266 Projects
    • ESP32 Projects
    • ESP32 MicroPython
    • ESP32-CAM Projects
    • LoRa/LoRaWAN Projects
  • Raspberry Pi
    • Raspberry Pi Projects
    • Raspberry Pi Pico Projects
    • Raspberry Pi Pico W Projects
  • Electronics Calculator
How To Electronics
Home » MQTT Based Wind Weather Station using GSM & Arduino
Arduino Projects IoT Projects

MQTT Based Wind Weather Station using GSM & Arduino

Mamtaz AlamBy Mamtaz AlamUpdated:July 20, 20232 Comments7 Mins Read
Share Facebook Twitter LinkedIn Telegram Reddit WhatsApp
GSM Arduino Weather Station
Share
Facebook Twitter LinkedIn Pinterest Email Reddit Telegram WhatsApp

Overview

In this project, we will build an MQTT Based Wind Weather Station using GSM & Arduino. The wind weather station is a device mainly used to measure the wind speed in wild. Outdoor activities like Surfing, paragliding, kites, hot air balloons, and other activities have attracted more and more attention. Those activities are more or less affected by wind speed. This is why it is necessary to make a Wind Weather Station. The Weather Station not only measures the Wind Speed but also measures the surrounding temperature, humidity, atmospheric pressure, UV Ray Index, PM2.5 values, etc. The wind weather station can be placed in the wild to measure wind speed.

Wind Weather Station

So, in this project, we will see the functionalities of the GSM Wind Weather Station box and check its components. We will upload the basic code to read the weather station data on OLED Display. We will also make an MQTT Based Wind Weather Station and monitor the data on MQTT Dashboard. Mosquitto is a free open source MQTT broker which can be used for this application.

Before moving ahead, you can go through some previous Weather Station projects:
1. IoT Live Weather Station
2. BME280 Arduino Weather Station
3. BME280 ESP32 Mini Weather Station
4. BME280 ESP8266 Mini Weather Station
5. LoRa Based Wireless Weather Station
6. BME680 MQTT Weather Station




Wind Weather Station Hardware

To purchase this Weather Station Kit, you can check Makerfabs Link. The combined board will cost you around 45.80 dollars. In case you need an additional PM2.5 Sensor, the price will be 50.70 dollars.

The Wind Weather Station measures the outdoor humidity, temperature, atmospheric pressure, wind speed and transmits the results remotely to the server for real-time checking. These are the external Ports for connecting Anemometer and PM2.5 Sensor. You can connect the solar panel for charging the Lithium-Ion Battery.

On the other side, there are pins for connecting I2C or analog sensors. There is a slide switch to turn ON/OFF the device. The outer pin mapping details can be checked below.

1. Interface of Anemometer

2. Interface of PM2.5 Sensor

3. Other GPIOs Interfaces


Anemometer

The box also includes a Cup-Type Anemometer sensor basically with NPN output. This detects even a slight moment of air and measures the wind velocity. This Anemometer is an imporatant part of GSM Based Wind Weather Station.

Anemometer

Unlike the Analog Output Anemometer, this anemometer output pulse reflects the wind speed more accurately. Besides, this anemometer is totally Waterproof, with a stable installation design, suitable for outdoor applications. It also has a 4 pin military-type probe that connects with a connector or expansion cable. On the next end of the cable, there is a 3 pin connector that fits perfectly on the weather station box.


You can place the box along with the Anemometer at the top of the house or outdoor where you want to measure the weather parameters.


Internal Circuit & PCB

GSM Weather Station PCB

To check the PCB Board and construction of this system, you need to open the box. After removing the screw you can open the 3D Casing. The inside has a PCB Board, few Antennas, and a Battery. The battery is a Lithium-Ion Battery of 3.7V and 1800 mAh capacity. The GPS and GSM antennas are connected to the board with UFL Connector. There is a 2pin removable battery connector as well.

The PCB has an A9G GSM+GPRS+GPS Module. The A9G GPS Tracker is an IoT (Internet of things) Solution-based product that integrates a micro Controller ATSAMD21G18, GRRS/GSM+GPS module A9G with the best power management and storage. The board is low-powered and manufactured by AI-Thinker.

The PCB has a Microcontroller called ATSAMD21G18 which is a 32-Bit ARM Cortex M0+ microcontroller from Microchip. There is a Micro-USB Port for programming and Serial Application. The board integrates DHT11 Humidity and Temperature Sensor, BMP280 Barometric Pressure Sensor, and some ports for connecting external sensors like PM2.5 & Anemometer. The LED & Buzzer is for indication. You can disable them for lower power consumption. A reset button can be used for debugging and testing. You can connect a 6V Solar panel to charge the Lithium-Ion Battery. Hence this is a Solar powered Wind Weather Station using GSM & Arduino.

The backside of the PCB has a 0.91″ OLED Display. It also has an SD Card Slot so that you can insert the SD Card and use it as a data logger. The long reset button on the board is used for enabling or disabling the OLED Display. There is a SIM Card Tray which only supports 2G SIM for GPRS Applications. You can insert a Mini-SIM inside the SIM Tray. Be careful while inserting the SIM and check the direction of the SIM.




Setting Up Arduino IDE for Programming

The ATSAMD21G18 doesn’t have pre-installed Board in the Arduino IDE. So, we need to install “Arduino Zero Board” from the Board Manager.

Open the Boards Manager From the top Arduino IDE menu, select Tools-> Board-> Boards Manager… to open the Boards Manager dialog box. Then install Arduino SAMD Boards(32-bits ARM Cortex-M0+).

Once, installation is completed, you can now select the Arduino Zero board as shown in the image below. To program this Board you need to connect MicroUSB Data Cable.


Basic Code for Reading Wind Weather Station Data

Let us move to the Test Code or the default example code first. Open your Arduino IDE and paste the following code. This is a test code to check whether the device works or not.

This code requires some of the libraries like BMP280 Library, Adafruit SSD1306, Adafruit GFX, and also the DHT11 Library. First, download the following libraries and add them to the Library Folder.

1. BMP280 Library: https://github.com/adafruit/Adafruit_BMP280_Library
2. SSD1306 Library: https://github.com/adafruit/Adafruit_SSD1306
3. GFX Library: https://github.com/adafruit/Adafruit-GFX-Library
4. DHT11 Library: https://github.com/adafruit/DHT-sensor-library


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
#include <Wire.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <SD.h>
 
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
bool tag = 0;
bool ledStateTag = 0;
 
#define DHTPIN 13 // the number of the DHT11 pin
//#define DHTPIN A0
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
 
#define VCC_PIN 2 //3.3V
#define VDD_PIN 7 //5V
#define BUZZER_PIN 12
#define SD_CS 4
#define pinInterrupt A0 // the number of the Wind Speed sensor pin
#define PM_READ_PIN A1
#define PM_LED_PIN 10
#define ledPin 11   // the number of the LED pin
#define buttonPin 3 // the number of the pushbutton pin
#define UV_PIN A4
 
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
 
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
#define BMP280_I2C_ADDRESS 0x76
#define BMP280_DEVICE_ID 0x58
Adafruit_BMP280 bmp; // I2C
 
int humidity_value = 0;
int temperature_value = 0;
int speed_value = 0;
int pressure_value = 0;
int show_index = 0;
 
int Count = 0;
int runtime = 0;
int sensortime = 0;
int dhttime = 0;
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 1000; // the debounce time; increase if the output flickers
 
void setup()
{
  SerialUSB.begin(115200);
  SerialUSB.println("---------------Start----------------------");
 
  pin_init();
  SerialUSB.println("Pin init over");
 
  //sd_test();
 
  //i2c_scan();
  i2c_dev_init();
  logo_show();
 
  dht.begin();
}
 
void loop()
{
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
 
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonState == HIGH)
  {
  }
  else
  {
    delay(50);
    if (digitalRead(buttonPin) == 0)
    {
      tag = !tag;
      if (tag)
      {
        Wire.endTransmission();     //
        digitalWrite(ledPin, HIGH); // turn LED off:
        delay(100);
        digitalWrite(VCC_PIN, LOW);
        delay(100);
        digitalWrite(VDD_PIN, LOW);
        delay(100);
        SerialUSB.println("Power 3V3 off");
      }
      else
      {
        // turn LED on:
        digitalWrite(ledPin, LOW);
        delay(100);
        digitalWrite(VCC_PIN, HIGH);
        delay(100);
        digitalWrite(VDD_PIN, HIGH);
        delay(100);
        SerialUSB.println("Power 3V3 on");
 
        i2c_dev_init(); //re-init
 
        dht.begin();
      }
    }
  }
  if (!tag)
  {
 
    wind_speed();
 
    if ((millis() - sensortime) > 1000)
    {
      SerialUSB.println("Read bmp");
      bmp_read();
      //i2c_scan();
      sensortime = millis();
    }
 
    //DHT is slow
    if ((millis() - dhttime) > 4000)
    {
      SerialUSB.println("Read dht");
      dht_read();
      dhttime = millis();
    }
 
    if ((millis() - runtime) > 2000)
    {
      sensor_show();
      runtime = millis();
    }
  }
 
  //ledStateTag=!ledStateTag;
}
 
void pin_init()
{
  pinMode(VDD_PIN, OUTPUT);
  pinMode(VCC_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(PM_LED_PIN, OUTPUT);
 
  pinMode(pinInterrupt, INPUT_PULLUP); //set as input pin
  attachInterrupt(digitalPinToInterrupt(pinInterrupt), onChange, FALLING);
 
  digitalWrite(VDD_PIN, LOW);
  delay(500);
  digitalWrite(VDD_PIN, HIGH);
 
  digitalWrite(VCC_PIN, LOW);
  delay(500);
  digitalWrite(VCC_PIN, HIGH);
 
  digitalWrite(BUZZER_PIN, HIGH);
  delay(500);
  digitalWrite(BUZZER_PIN, LOW);
 
  delay(1000);
}
 
void i2c_scan()
{
  Wire.begin();
  byte error, address;
  int nDevices;
 
  static int s = 0;
  SerialUSB.print(s++);
  SerialUSB.println(". Scanning...");
 
  nDevices = 0;
  for (address = 1; address < 127; address++)
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      SerialUSB.print("I2C device found at address 0x");
      if (address < 16)
        SerialUSB.print("0");
      SerialUSB.print(address, HEX);
      SerialUSB.println("  !");
 
      nDevices++;
    }
    else if (error == 4)
    {
      SerialUSB.print("Unknown error at address 0x");
      if (address < 16)
        SerialUSB.print("0");
      SerialUSB.println(address, HEX);
    }
  }
  if (nDevices == 0)
    SerialUSB.println("No I2C devices found\n");
  else
  {
    SerialUSB.print(">>>> Found total ");
    ;
    SerialUSB.print(nDevices);
    SerialUSB.println(" devices\n");
  }
}
 
void dht_read()
{
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);
 
  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f))
  {
    SerialUSB.println(F("Failed to read from DHT sensor!"));
    return;
  }
 
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
 
  SerialUSB.print(F("Humidity: "));
  SerialUSB.print(h);
  SerialUSB.print(F("%  Temperature: "));
  SerialUSB.print(t);
  SerialUSB.print(F("°C "));
  SerialUSB.print(f);
  SerialUSB.print(F("°F  Heat index: "));
  SerialUSB.print(hic);
  SerialUSB.print(F("°C "));
  SerialUSB.print(hif);
  SerialUSB.println(F("°F"));
 
  humidity_value = (int)h;
  temperature_value = (int)t;
}
 
void bmp_read()
{
  SerialUSB.print(F("Temperature = "));
  SerialUSB.print(bmp.readTemperature());
  SerialUSB.println(" *C");
 
  SerialUSB.print(F("Pressure = "));
  SerialUSB.print(pressure_value = bmp.readPressure());
  SerialUSB.println(" Pa");
 
  SerialUSB.print(F("Approx altitude = "));
  SerialUSB.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */
  SerialUSB.println(" m");
 
  SerialUSB.println();
}
 
void i2c_dev_init()
{
 
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
  { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }
  SerialUSB.println("SSD1306 found");
 
  if (!bmp.begin(BMP280_I2C_ADDRESS, BMP280_DEVICE_ID))
  {
    SerialUSB.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1)
      ;
  }
  SerialUSB.println("BMP280 found");
 
  /* Default settings from datasheet. */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
 
  SerialUSB.println("BMP280 init over");
  //i2c_scan();
}
 
void logo_show()
{
  display.clearDisplay();
 
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2); // Draw 2X-scale text
  display.setCursor(10, 0);
  display.println(F("Makerfabs"));
  display.setTextSize(1);
  display.setCursor(10, 16);
  display.println(F("Weather Station"));
  display.display(); // Show initial text
  delay(100);
 
  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x01);
  delay(4000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
}
 
void sensor_show()
{
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
 
  switch (show_index)
  {
  case 0:
 
    display.setCursor(0, 0);
    display.print("Temp:");
    display.print(temperature_value);
    display.println(" C");
 
    display.setCursor(0, 16);
    display.print("Humi:");
    display.print(humidity_value);
    display.println(" %");
    break;
 
  case 1:
    display.setCursor(0, 0);
    display.print("Humi:");
    display.print(humidity_value);
    display.println(" %");
 
    display.setCursor(0, 16);
    display.print("Wind:");
    display.print(speed_value);
    display.println(" m/s");
    break;
 
  case 2:
    display.setCursor(0, 0);
    display.print("PM2.5:");
 
    display.setCursor(0, 16);
    display.print(pm25());
    display.println(" mg/m3");
    break;
 
  case 3:
    display.setCursor(0, 0);
    display.println("Pressure:");
 
    display.setCursor(0, 16);
    display.print(pressure_value);
    display.println(" Pa");
    break;
 
  case 4:
    display.setCursor(0, 0);
    display.print("UV:");
    display.println(UV());
 
    display.setCursor(0, 16);
    display.println("mW/m^2");
    break;
  }
 
  display.display(); // Show initial text
  show_index++;
  show_index %= 5;
}
 
void sd_test()
{
  File myFile;
  //SD(SPI)
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
 
  if (!SD.begin(SD_CS))
  {
    SerialUSB.println("Card Mount Failed");
    while (1)
      ;
  }
  else
  {
    SerialUSB.println("SD OK");
  }
 
  if (SD.exists("example.txt"))
  {
    SerialUSB.println("example.txt exists.");
  }
  else
  {
    SerialUSB.println("example.txt doesn't exist.");
  }
 
  // open a new file and immediately close it:
  SerialUSB.println("Creating example.txt...");
  myFile = SD.open("example.txt", FILE_WRITE);
  myFile.close();
 
  // Check to see if the file exists:
  if (SD.exists("example.txt"))
  {
    SerialUSB.println("example.txt exists.");
  }
  else
  {
    SerialUSB.println("example.txt doesn't exist.");
  }
 
  // delete the file:
  SerialUSB.println("Removing example.txt...");
  SD.remove("example.txt");
 
  if (SD.exists("example.txt"))
  {
    SerialUSB.println("example.txt exists.");
  }
  else
  {
    SerialUSB.println("example.txt doesn't exist.");
  }
}
 
void onChange()
{
  if (digitalRead(pinInterrupt) == LOW)
    Count++;
  //      Serial.println("Key Down");
  //   else
  //      Serial.println("Key UP");
}
 
void wind_speed()
{
  if ((millis() - lastDebounceTime) > debounceDelay)
  {
    lastDebounceTime = millis();
    speed_value = Count * 8.75 * 0.01;
    SerialUSB.print(speed_value);
    Count = 0;
    SerialUSB.println("m/s");
  }
}
 
int pm25()
{
  int samplingTime = 280;
  int deltaTime = 40;
  int sleepTime = 9680;
 
  float voMeasured = 0;
  float calcVoltage = 0;
  float dustDensity = 0;
  digitalWrite(PM_LED_PIN, HIGH); // power on the LED
  delayMicroseconds(samplingTime);
 
  voMeasured = analogRead(PM_READ_PIN); // read the dust value
  voMeasured = voMeasured * 2.0 / 3.0;  //5V to 3.3V
  delayMicroseconds(deltaTime);
  digitalWrite(PM_LED_PIN, LOW); // turn the LED off
  delayMicroseconds(sleepTime);
 
  // 0 - 5V mapped to 0 - 1023 integer values
  // recover voltage
  calcVoltage = voMeasured * (5.0 / 1024.0);
 
  // linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/
  // Chris Nafis (c) 2012
  dustDensity = 170 * calcVoltage - 0.1;
 
  SerialUSB.println("PM2.5:");
  SerialUSB.println(dustDensity); // unit: ug/m3
  return (int)dustDensity;
}
 
double UV()
{
  int sensorValue;
  long sum = 0;
  for (int i = 0; i < 256; i++) // accumulate readings for 1024 times
  {
    sensorValue = analogRead(UV_PIN);
    sum = sensorValue + sum;
    delay(2);
  }
  long meanVal = sum / 256; // get mean value
  double UV_value = (meanVal * 1000 / 4.3 - 83) / 21;
 
  SerialUSB.print("The A4 is:");
  SerialUSB.println(meanVal); // get a detailed calculating expression for UV index in schematic files.
  SerialUSB.print("The current UV index is:");
  SerialUSB.print(UV_value); // get a detailed calculating expression for UV index in schematic files.
  SerialUSB.print(" mW/m^2\n");
 
  return UV_value;
}


Testing Wind Weather Station

GSM Arduino MQTT Wind Weather Station

Connect the Micro-USB cable to the USB Port of the PCB. And on the other end connect the cable to the computer. Now click on the upload button and the code will be uploaded within few seconds.



Once uploading is done, open the Serial Monitor. You can see the wind speed value along with the Temperature, Pressure, altitude value from BMP280 Sensor. From the DHT11 Sensor, you will see the value for Humidity, Temperature and Heat Index Value. So this means the sensors are working pretty well.

The OLED Display will also display the weather parameter like temperature, humidity, pressure, wind speed, UV Index.

GSM Arduino Weather Station


MQTT Based Wind Weather Station using GSM & Arduino

Let’s convert this product into IoT Based product using the GSM GPRS Applications. We will use the MQTT Connection to transmit Weather Station Data using GSM & Arduino. It has a little difficulty if you don’t have any knowledge about MQTT.

Here is a complete code for the MQTT weather Station. You can copy the code and upload it to the Arduino Zero board.

1
sendData("AT+CGDCONT=1,\"IP\",\"ntnet\"", 1000, DEBUG);

From the above line, you need to change the SIM APN. I am staying in Nepal and using Nepal Telecom SIM, so my APN is ntnet. You can check your APN from the service provider.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
#include <stdio.h>
#include <string.h>
 
#include <Wire.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <SD.h>
 
 
 
#define DEBUG true
#define PWR_KEY 9
#define RST_KEY 6
#define LOW_PWR_KEY 5
 
#define VCC_PIN 2
#define VDD_PIN 7
#define BUZZER_PIN 12
#define SD_CS 4
#define pinInterrupt A0
#define PM_READ_PIN A1
#define PM_LED_PIN 10
#define DHTPIN 13
 
 
//#define DHTPIN A0
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
 
bool ModuleState = false;
 
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
 
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
#define BMP280_I2C_ADDRESS  0x76
#define BMP280_DEVICE_ID    0x58
Adafruit_BMP280 bmp; // I2C
 
int humidity_value = 0;
int temperature_value = 0;
int speed_value = 0;
int pressure_value = 0;
int show_index = 0;
 
int Count = 0;
int runtime = 0;
int sensortime = 0;
int dhttime = 0;
int Mqtttime = 0;
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 1000; // the debounce time; increase if the output flickers
 
 
 
void setup()
{
    SerialUSB.begin(115200);
    Serial1.begin(115200);
 
    pinMode(VDD_PIN, OUTPUT);
    pinMode(VCC_PIN, OUTPUT);
    pinMode(BUZZER_PIN, OUTPUT);
    pinMode(PM_LED_PIN, OUTPUT);
    pinMode(pinInterrupt, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(pinInterrupt), onChange, FALLING);
 
    pinMode(PWR_KEY, OUTPUT);
    pinMode(RST_KEY, OUTPUT);
    pinMode(LOW_PWR_KEY, OUTPUT);
 
    digitalWrite(VDD_PIN, LOW);
    delay(500);
    digitalWrite(VDD_PIN, HIGH);
 
    digitalWrite(VCC_PIN, LOW);
    delay(500);
    digitalWrite(VCC_PIN, HIGH);
 
    digitalWrite(BUZZER_PIN, HIGH);
    delay(500);
    digitalWrite(BUZZER_PIN, LOW);
 
    digitalWrite(RST_KEY, LOW);
    digitalWrite(LOW_PWR_KEY, HIGH);
    digitalWrite(PWR_KEY, HIGH);
    
    digitalWrite(PWR_KEY, LOW);
    delay(3000);
    digitalWrite(PWR_KEY, HIGH);
    delay(10000);
 
    ModuleState = moduleStateCheck();
    if (ModuleState == false) //if it's off, turn on it.
    {
        digitalWrite(PWR_KEY, LOW);
        delay(3000);
        digitalWrite(PWR_KEY, HIGH);
        delay(10000);
        SerialUSB.println("Now turnning the A9/A9G on.");
    }
 
    sendData("AT+CCID", 3000, DEBUG);
    sendData("AT+CREG?", 3000, DEBUG);
    sendData("AT+CGATT=1", 1000, DEBUG);
    
    sendData("AT+CGDCONT=1,\"IP\",\"ntnet\"", 1000, DEBUG);
    sendData("AT+CGACT=1,1", 1000, DEBUG);
    sendData("AT+MQTTCONN=\"test.mosquitto.org\",1883,\"mqttx_0931852d35\",120,0", 1000, DEBUG);
    String topic_W = "AT+MQTTPUB=\"/public/TEST/makerfabs-W\",\""+(String)30+"\",0,0,0";
    String topic_T = "AT+MQTTPUB=\"/public/TEST/makerfabs-T\",\""+(String)73.5+"\",0,0,0";
    String topic_H = "AT+MQTTPUB=\"/public/TEST/makerfabs-H\",\""+(String)46.8+"\",0,0,0";
    String topic_P = "AT+MQTTPUB=\"/public/TEST/makerfabs-P\",\""+(String)pressure_value+"\",0,0,0";
    //String topic_H = "AT+MQTTPUB=\"/public/TEST/makerfabs-H\",\""+(String)h+"\",0,0,0";
 
    SerialUSB.println(topic_T);
    //sendData(topic_T, 1000, DEBUG);
    SerialUSB.println(topic_H);
 
    i2c_dev_init();
  logo_show();
 
  dht.begin();
 
}
 
void loop()
{
    wind_speed();
      
    if ((millis() - sensortime) > 1000)
    {  
      SerialUSB.println("Read bmp");
      bmp_read();
      //i2c_scan();
      sensortime = millis();
    }
      
    //DHT is slow
    if ((millis() - dhttime) > 4000)
    {
      SerialUSB.println("Read dht");
      dht_read();
      dhttime = millis();
    }
      
    if ((millis() - runtime) > 2000)
    {
      sensor_show();
      runtime = millis();
    }  
    
    if ((millis() - Mqtttime) > 16000)
    {
      String topic_P = "AT+MQTTPUB=\"/public/TEST/makerfabs-P\",\""+(String)pressure_value+" Pa\",0,0,0";
      String topic_W = "AT+MQTTPUB=\"/public/TEST/makerfabs-W\",\""+(String)speed_value+" m/s\",0,0,0";
      String topic_T = "AT+MQTTPUB=\"/public/TEST/makerfabs-T\",\""+(String)temperature_value+" C\",0,0,0";
      String topic_H = "AT+MQTTPUB=\"/public/TEST/makerfabs-H\",\""+(String)humidity_value+" %RH\",0,0,0";
      sendData(topic_T, 1000, DEBUG);
      SerialUSB.println("send T");
      sendData(topic_H, 1000, DEBUG);
      sendData(topic_W, 1000, DEBUG);
      sendData(topic_P, 1000, DEBUG);
      Mqtttime = millis();
    }
  
}
 
 
 
 
bool moduleStateCheck()
{
    int i = 0;
    bool moduleState = false;
    for (i = 0; i < 5; i++)
    {
        String msg = String("");
        msg = sendData("AT", 1000, DEBUG);
        if (msg.indexOf("OK") >= 0)
        {
            SerialUSB.println("A9/A9G Module had turned on.");
            moduleState = true;
            return moduleState;
        }
        delay(1000);
    }
    return moduleState;
}
 
String sendData(String command, const int timeout, boolean debug)
{
    String response = "";
    Serial1.println(command);
    long int time = millis();
    while ((time + timeout) > millis())
    {
        while (Serial1.available())
        {
            char c = Serial1.read();
            response += c;
        }
    }
    if (debug)
    {
        SerialUSB.print(response);
    }
    return response;
}
 
 
void i2c_scan()
{
  Wire.begin();
  byte error, address;
  int nDevices;
 
  static int s = 0;
  SerialUSB.print(s++);
  SerialUSB.println(". Scanning...");
 
  nDevices = 0;
  for (address = 1; address < 127; address++)
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      SerialUSB.print("I2C device found at address 0x");
      if (address < 16)
        SerialUSB.print("0");
      SerialUSB.print(address, HEX);
      SerialUSB.println("  !");
 
      nDevices++;
    }
    else if (error == 4)
    {
      SerialUSB.print("Unknown error at address 0x");
      if (address < 16)
        SerialUSB.print("0");
      SerialUSB.println(address, HEX);
    }
  }
  if (nDevices == 0)
    SerialUSB.println("No I2C devices found\n");
  else
  {
    SerialUSB.print(">>>> Found total ");
    ;
    SerialUSB.print(nDevices);
    SerialUSB.println(" devices\n");
  }
}
 
void dht_read()
{
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);
 
  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f))
  {
    SerialUSB.println(F("Failed to read from DHT sensor!"));
    return;
  }
 
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
 
  SerialUSB.print(F("Humidity: "));
  SerialUSB.print(h);
  SerialUSB.print(F("%  Temperature: "));
  SerialUSB.print(t);
  SerialUSB.print(F("°C "));
  SerialUSB.print(f);
  SerialUSB.print(F("°F  Heat index: "));
  SerialUSB.print(hic);
  SerialUSB.print(F("°C "));
  SerialUSB.print(hif);
  SerialUSB.println(F("°F"));
 
  humidity_value = (int)h;
  temperature_value = (int)t;
}
 
void bmp_read()
{
  SerialUSB.print(F("Temperature = "));
  SerialUSB.print(bmp.readTemperature());
  SerialUSB.println(" *C");
 
  SerialUSB.print(F("Pressure = "));
  SerialUSB.print(pressure_value = bmp.readPressure());
  SerialUSB.println(" Pa");
 
  SerialUSB.print(F("Approx altitude = "));
  SerialUSB.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */
  SerialUSB.println(" m");
 
  SerialUSB.println();
}
 
void i2c_dev_init()
{
 
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
  { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }
  SerialUSB.println("SSD1306 found");
 
  if (!bmp.begin(BMP280_I2C_ADDRESS, BMP280_DEVICE_ID))
  {
    SerialUSB.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1)
      ;
  }
  SerialUSB.println("BMP280 found");
 
  /* Default settings from datasheet. */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
 
  SerialUSB.println("BMP280 init over");
  //i2c_scan();
}
 
void logo_show()
{
  display.clearDisplay();
 
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2); // Draw 2X-scale text
  display.setCursor(10, 0);
  display.println(F("Makerfabs"));
  display.setTextSize(1);
  display.setCursor(10, 16);
  display.println(F("Weather Station"));
  display.display(); // Show initial text
  delay(100);
 
  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x01);
  delay(4000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
}
 
void sensor_show()
{
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  switch (show_index)
  {
  case 0:
 
    display.setCursor(0, 0);
    display.print("Temp:");
    display.print(temperature_value);
    display.println(" C");
 
    display.setCursor(0, 16);
    display.print("Humi:");
    display.print(humidity_value);
    display.println(" %");
    break;
 
  case 1:
    display.setCursor(0, 0);
    display.print("Humi:");
    display.print(humidity_value);
    display.println(" %");
 
    display.setCursor(0, 16);
    display.print("Wind:");
    display.print(speed_value);
    display.println(" m/s");
    break;
 
  case 2:
    display.setCursor(0, 0);
    display.print("PM2.5:");
 
    display.setCursor(0, 16);
    display.print(pm25());
    display.println(" mg/m3");
    break;
 
  case 3:
    display.setCursor(0, 0);
    display.println("Pressure:");
 
    display.setCursor(0, 16);
    display.print(pressure_value);
    display.println(" Pa");
    break;
  }
 
  display.display(); // Show initial text
  show_index++;
  show_index %= 4;
}
 
 
void wind_speed()
{
  lastDebounceTime = millis();
  Count = 0;
  while(!((millis() - lastDebounceTime) > debounceDelay));
  if ((millis() - lastDebounceTime) > debounceDelay)
  {
    //lastDebounceTime = millis();
    speed_value = Count * 8.75 * 0.01;
    SerialUSB.print(speed_value);
    Count = 0;
    SerialUSB.println("m/s");
  }
}
 
int pm25()
{
  int samplingTime = 280;
  int deltaTime = 40;
  int sleepTime = 9680;
 
  float voMeasured = 0;
  float calcVoltage = 0;
  float dustDensity = 0;
  digitalWrite(PM_LED_PIN, HIGH); // power on the LED
  delayMicroseconds(samplingTime);
 
  voMeasured = analogRead(PM_READ_PIN); // read the dust value  
  voMeasured = voMeasured*2.0/3.0;//5V to 3.3V
  delayMicroseconds(deltaTime);
  digitalWrite(PM_LED_PIN, LOW); // turn the LED off
  delayMicroseconds(sleepTime);
 
  // 0 - 5V mapped to 0 - 1023 integer values
  // recover voltage
  calcVoltage = voMeasured * (5.0 / 1024.0);
 
  // linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/
  // Chris Nafis (c) 2012
  dustDensity = 170 * calcVoltage - 0.1;
 
  //SerialUSB.println(dustDensity); // unit: ug/m3
  if(dustDensity < 5)
      dustDensity = 0;
  return (int)dustDensity;
}
 
void onChange()
{
  if (digitalRead(pinInterrupt) == LOW)
    Count++;
  //      Serial.println("Key Down");
  //   else
  //      Serial.println("Key UP");
}



Checking the data on MQTT Dashboard

First, you have to get an MQTT broker such as the Mosquitto which is used in the demo. Second, define a client ID which is the only one. This is done in the Android App. So download the Android App from the link below.

Download: MQTT Dashboard App

Open the Android App and type the information to the MQTT client: the server URL is test.mosquitto.org, the server port is 1883, the server name is makerfabs-g.

Setting MQTT Dashbooard

Use the MQTT client and subscribe to the topics which are “/public/TEST/makerfabs-T“, “/public/TEST/makerfabs-H“, “/public/TEST/makerfabs-W“, “/public/TEST/makerfabs-P“. It will receive the temperature, humidity, pressure and wind speed.

MQTT Datas


Video Tutorial & Guide

MQTT Wind Weather Station Project using GSM & Arduino | Battery Powered with Solar Charging
Watch this video on YouTube.

This is how you can design your MQTT Based Wind Weather Station using GSM & Arduino to monitor the Wind Weather Data remotely.

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Reddit Telegram WhatsApp
Previous ArticleHome Automation with Arduino IoT Cloud using ESP32
Next Article How to interface Quectel L80 GPS Module with Arduino

Related Posts

ESP32 Fingerprint Attendance System with Live Web Dashboard

ESP32 Fingerprint Attendance System with Live Web Dashboard

Updated:June 21, 2026
IoT Based PM & Air Quality Monitoring System using ESP32

IoT Based PM & Air Quality Monitoring System using ESP32

Updated:June 14, 2026
DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

Updated:May 10, 20262K
IoT Activity Tracker with ESP32 & Accelerometer Gyroscope

IoT Activity Tracker with ESP32 & Accelerometer/Gyroscope

Updated:May 2, 2026

ESP32 IoT Vehicle Motion Analyzer with MPU6050 & LIS3MDL

Updated:April 27, 20261K
High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

Updated:April 27, 20262K
View 2 Comments

2 Comments

  1. Paul Onley on January 22, 2022 3:47 AM

    Didn’t read closely enough. This device only has 2G connectivity. There is no other way to get the data off the board so at least in the USA it is basicaly useless. Wifi would have been nice.

    Reply
  2. Sergey on May 11, 2023 5:19 PM

    I tried to adapt your sketch for the board on the LGTF 28P chip (Chinese clone of Arduino Nano), but when compiling, I got an error stating that we do not have enough flash memory (111% or 33186 bytes with 29696 bytes available). It turns out that a lot of program memory is occupied by the old OLED library from Adafruit. Please, try a lighter library for OLED from russian developer @Alex_Giver: https://github.com/GyverLibs/GyverOLED
    It also has lightweight libraries for other sensors, displays, keyboards, various algorithms, and more: https://github.com/GyverLibs

    Reply

CommentsCancel reply

Latest Posts
ESP32 Fingerprint Attendance System with Live Web Dashboard

ESP32 Fingerprint Attendance System with Live Web Dashboard

June 21, 2026
IoT Based PM & Air Quality Monitoring System using ESP32

IoT Based PM & Air Quality Monitoring System using ESP32

June 14, 2026
DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

May 10, 2026
IoT Activity Tracker with ESP32 & Accelerometer Gyroscope

IoT Activity Tracker with ESP32 & Accelerometer/Gyroscope

May 2, 2026
A Guide to Sourcing Obsolete ICs for Vintage Projects

Beyond AliExpress: A Guide to Sourcing Obsolete ICs for Vintage Projects

April 21, 2026

ESP32 IoT Vehicle Motion Analyzer with MPU6050 & LIS3MDL

April 27, 2026
Building a Smart Sensor Node with a BLE Microcontroller

Building a Smart Sensor Node with a BLE Microcontroller

February 26, 2026
High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

April 27, 2026
Top Posts & Pages
  • ESP32 Fingerprint Attendance System with Live Web Dashboard
    ESP32 Fingerprint Attendance System with Live Web Dashboard
  • IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
    IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
  • 12V DC to 220V AC Inverter Circuit & PCB
    12V DC to 220V AC Inverter Circuit & PCB
  • ESP32 CAN Bus Tutorial | Interfacing MCP2515 CAN Module with ESP32
    ESP32 CAN Bus Tutorial | Interfacing MCP2515 CAN Module with ESP32
  • IoT Based ECG Monitoring with AD8232 ECG Sensor & ESP32
    IoT Based ECG Monitoring with AD8232 ECG Sensor & ESP32
  • How to use Modbus RTU with ESP32 to read Sensor Data
    How to use Modbus RTU with ESP32 to read Sensor Data
  • Half Wave Rectifier Basics, Circuit, Working & Applications
    Half Wave Rectifier Basics, Circuit, Working & Applications
  • How to use INA226 DC Current Sensor with Arduino
    How to use INA226 DC Current Sensor with Arduino
Categories
  • Arduino Projects (197)
  • Articles (60)
    • Learn Electronics (19)
    • Product Review (15)
    • Tech Articles (28)
  • Electronics Circuits (46)
    • 555 Timer Projects (21)
    • Op-Amp Circuits (7)
    • Power Electronics (13)
  • IoT Projects (205)
    • ESP32 MicroPython (7)
    • ESP32 Projects (82)
    • ESP32-CAM Projects (15)
    • ESP8266 Projects (76)
    • LoRa/LoRaWAN Projects (22)
  • Microcontrollers (38)
    • AMB82-Mini IoT AI Camera (4)
    • BLE Projects (18)
    • STM32 Projects (19)
  • Raspberry Pi (93)
    • Raspberry Pi Pico Projects (57)
    • Raspberry Pi Pico W Projects (12)
    • Raspberry Pi Projects (24)
Follow Us
  • Facebook
  • Twitter
  • Pinterest
  • Instagram
  • YouTube
About Us

“‘How to Electronics’ is a vibrant community for electronics enthusiasts and professionals. We deliver latest insights in areas such as Embedded Systems, Power Electronics, AI, IoT, and Robotics. Our goal is to stimulate innovation and provide practical solutions for students, organizations, and industries. Join us to transform learning into a joyful journey of discovery and innovation.

Copyright © How To Electronics. All rights reserved.
  • About Us
  • Disclaimer
  • Privacy Policy
  • Contact Us
  • Advertise With Us

Type above and press Enter to search. Press Esc to cancel.

Ad Blocker Enabled!
Ad Blocker Enabled!
Looks like you're using an ad blocker. Please allow ads on our site. We rely on advertising to help fund our site.