Parts list
| Part | Qty | Approx. | Buy |
|---|---|---|---|
| Arduino Uno R3 (CH340 clone) | 1 | ₹450 | Buy Arduino Uno R3 (CH340 clone) |
| BMP180 pressure sensor module (GY-68, with regulator) | 1 | ₹90 | Buy BMP180 pressure sensor module (GY-68, with regulator) |
| 16×2 LCD with I2C backpack (0x27) | 1 | ₹220 | Buy 16×2 LCD with I2C backpack (0x27) |
| Active buzzer module (high-level trigger) | 1 | ₹25 | Buy Active buzzer module (high-level trigger) |
| Jumper wires | 12 | ₹36 | Buy Jumper wires |
| 9 V 1 A adapter (or USB + a power bank for power cuts) | 1 | ₹150 | Buy 9 V 1 A adapter (or USB + a power bank for power cuts) |
| Total | ₹971 |
Affiliate disclosure: “Buy” links may earn FlashReady a small commission at no extra cost to you. Prices are indicative.
Wiring
| Arduino Uno R3 | Part · pin | Wire | Notes |
|---|---|---|---|
| A5 | BMP180 pressure and temperature sensor (GY-68) · SCL | yellow | |
| A4 | BMP180 pressure and temperature sensor (GY-68) · SDA | blue | |
| 5V | BMP180 pressure and temperature sensor (GY-68) · VIN | red | The GY-68 has its own 3.3 V regulator and 3.3 V pull-ups |
| GND | BMP180 pressure and temperature sensor (GY-68) · GND | black | |
| SCL | 16×2 LCD + I2C backpack · SCL | yellow | The SCL header pin is the same signal as A5 |
| SDA | 16×2 LCD + I2C backpack · SDA | blue | The SDA header pin is the same signal as A4 |
| 5V | 16×2 LCD + I2C backpack · VCC | red | |
| GND | 16×2 LCD + I2C backpack · GND | black | |
| D8 | Active buzzer module (high-level trigger) · I/O | orange | |
| 5V | Active buzzer module (high-level trigger) · VCC | red | |
| GND | Active buzzer module (high-level trigger) · GND | black |
Board quirks: In the tropics the air pressure rises and falls by 1–1.5 hPa twice every day by itself (the “pressure tide”, highs near 10 am and 10 pm). That’s why the strong warning compares with the same time yesterday — the tide cancels out. The thresholds (3 hPa in 3 h to watch, 5 hPa in 24 h to warn) are rules of thumb from marine weather practice, not an official IMD criterion. Always follow IMD’s cyclone bulletins and local evacuation orders. Set <code>ALTITUDE_M</code> to your height above sea level so the display matches the sea-level pressure in weather reports. The trend works without it. The history is kept in RAM, so it needs 24 hours of running after a reset before the 24-hour comparison works. Run it from a power bank or UPS in cyclone season.
Code
// Storm pressure alert — Arduino Uno + BMP180 (GY-68) + 16x2 I2C LCD + active buzzer module
// BMP180 and LCD share I2C (SDA A4, SCL A5), both at 5V (the GY-68 has its own 3.3 V regulator).
// Buzzer module I/O → D8. Logs the air pressure every hour and warns when it is falling fast —
// a cyclone or a strong pre-monsoon storm (kalbaisakhi / norwester) shows up as a pressure drop
// hours before the wind. Comparing with 24 hours ago cancels the twice-daily tropical pressure tide.
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <LiquidCrystal_I2C.h>
constexpr uint8_t BUZZER_PIN = 8;
constexpr float ALTITUDE_M = 10; // your height above sea level, for the sea-level figure
constexpr float WATCH_3H_HPA = 3.0; // fall in 3 hours that deserves a look
constexpr float WARN_24H_HPA = 5.0; // fall in 24 hours that means a real system is coming
constexpr unsigned long HOUR_MS = 3600000UL;
Adafruit_BMP085 bmp;
LiquidCrystal_I2C lcd(0x27, 16, 2);
float hourly[25]; // [0] = now-ish, [k] = k hours ago (sea-level hPa); 0 = no reading yet
unsigned long lastHour = 0, lastBeep = 0;
bool sensorOk = false;
float seaLevel(float pa) { // barometric formula, as used for weather reports
return pa / 100.0 / pow(1.0 - ALTITUDE_M / 44330.0, 5.255);
}
void beep(uint8_t times) {
for (uint8_t i = 0; i < times; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(150);
digitalWrite(BUZZER_PIN, LOW);
delay(150);
}
}
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
lcd.init();
lcd.backlight();
lcd.print(F("Storm alert"));
sensorOk = bmp.begin();
if (!sensorOk) {
Serial.println(F("BMP180 not found — check SDA A4, SCL A5 and 5V"));
lcd.setCursor(0, 1);
lcd.print(F("BMP180 missing!"));
}
Serial.println(F("hours,hpa_sea,change_3h,change_24h,status"));
}
void loop() {
if (!sensorOk) {
delay(1000);
return;
}
float now = seaLevel(bmp.readPressure());
float t = bmp.readTemperature();
// Shift the hourly log once an hour (and fill it on the very first reading).
if (hourly[0] == 0 || millis() - lastHour >= HOUR_MS) {
lastHour = millis();
if (hourly[0] != 0) memmove(hourly + 1, hourly, sizeof(float) * 24);
hourly[0] = now;
}
float d3 = hourly[3] ? now - hourly[3] : 0;
float d24 = hourly[24] ? now - hourly[24] : 0;
const char* status = "Steady";
uint8_t level = 0;
if (d24 <= -WARN_24H_HPA) status = "STORM WARNING", level = 2;
else if (d3 <= -WATCH_3H_HPA) status = "Falling fast", level = 1;
else if (d3 >= WATCH_3H_HPA) status = "Rising fast";
lcd.setCursor(0, 0);
lcd.print(now, 1);
lcd.print(F("hPa "));
lcd.print(t, 0);
lcd.print(F("C "));
lcd.setCursor(0, 1);
lcd.print(status);
lcd.print(F(" "));
static unsigned long lastLog = 0;
if (lastLog == 0 || millis() - lastLog >= 600000UL) { // a CSV line every 10 minutes
lastLog = millis();
Serial.print(millis() / HOUR_MS);
Serial.print(',');
Serial.print(now, 1);
Serial.print(',');
Serial.print(d3, 1);
Serial.print(',');
Serial.print(d24, 1);
Serial.print(',');
Serial.println(status);
}
// Warning: 3 beeps every 10 minutes; watch: 1 beep every hour.
unsigned long gap = level == 2 ? 600000UL : HOUR_MS;
if (level && (lastBeep == 0 || millis() - lastBeep >= gap)) {
lastBeep = millis();
beep(level == 2 ? 3 : 1);
}
delay(5000);
}// Storm pressure alert — Arduino Uno + BMP180 (GY-68) + 16x2 I2C LCD + active buzzer module
// BMP180 and LCD share I2C (SDA A4, SCL A5), both at 5V (the GY-68 has its own 3.3 V regulator).
// Buzzer module I/O → D8. Logs the air pressure every hour and warns when it is falling fast —
// a cyclone or a strong pre-monsoon storm (kalbaisakhi / norwester) shows up as a pressure drop
// hours before the wind. Comparing with 24 hours ago cancels the twice-daily tropical pressure tide.
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <LiquidCrystal_I2C.h>
constexpr uint8_t BUZZER_PIN = 8;
constexpr float ALTITUDE_M = 10; // your height above sea level, for the sea-level figure
constexpr float WATCH_3H_HPA = 3.0; // fall in 3 hours that deserves a look
constexpr float WARN_24H_HPA = 5.0; // fall in 24 hours that means a real system is coming
constexpr unsigned long HOUR_MS = 3600000UL;
Adafruit_BMP085 bmp;
LiquidCrystal_I2C lcd(0x27, 16, 2);
float hourly[25]; // [0] = now-ish, [k] = k hours ago (sea-level hPa); 0 = no reading yet
unsigned long lastHour = 0, lastBeep = 0;
bool sensorOk = false;
float seaLevel(float pa) { // barometric formula, as used for weather reports
return pa / 100.0 / pow(1.0 - ALTITUDE_M / 44330.0, 5.255);
}
void beep(uint8_t times) {
for (uint8_t i = 0; i < times; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(150);
digitalWrite(BUZZER_PIN, LOW);
delay(150);
}
}
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
lcd.init();
lcd.backlight();
lcd.print(F("Storm alert"));
sensorOk = bmp.begin();
if (!sensorOk) {
Serial.println(F("BMP180 not found — check SDA A4, SCL A5 and 5V"));
lcd.setCursor(0, 1);
lcd.print(F("BMP180 missing!"));
}
Serial.println(F("hours,hpa_sea,change_3h,change_24h,status"));
}
void loop() {
if (!sensorOk) {
delay(1000);
return;
}
float now = seaLevel(bmp.readPressure());
float t = bmp.readTemperature();
// Shift the hourly log once an hour (and fill it on the very first reading).
if (hourly[0] == 0 || millis() - lastHour >= HOUR_MS) {
lastHour = millis();
if (hourly[0] != 0) memmove(hourly + 1, hourly, sizeof(float) * 24);
hourly[0] = now;
}
float d3 = hourly[3] ? now - hourly[3] : 0;
float d24 = hourly[24] ? now - hourly[24] : 0;
const char* status = "Steady";
uint8_t level = 0;
if (d24 <= -WARN_24H_HPA) status = "STORM WARNING", level = 2;
else if (d3 <= -WATCH_3H_HPA) status = "Falling fast", level = 1;
else if (d3 >= WATCH_3H_HPA) status = "Rising fast";
lcd.setCursor(0, 0);
lcd.print(now, 1);
lcd.print(F("hPa "));
lcd.print(t, 0);
lcd.print(F("C "));
lcd.setCursor(0, 1);
lcd.print(status);
lcd.print(F(" "));
static unsigned long lastLog = 0;
if (lastLog == 0 || millis() - lastLog >= 600000UL) { // a CSV line every 10 minutes
lastLog = millis();
Serial.print(millis() / HOUR_MS);
Serial.print(',');
Serial.print(now, 1);
Serial.print(',');
Serial.print(d3, 1);
Serial.print(',');
Serial.print(d24, 1);
Serial.print(',');
Serial.println(status);
}
// Warning: 3 beeps every 10 minutes; watch: 1 beep every hour.
unsigned long gap = level == 2 ? 600000UL : HOUR_MS;
if (level && (lastBeep == 0 || millis() - lastBeep >= gap)) {
lastBeep = millis();
beep(level == 2 ? 3 : 1);
}
delay(5000);
}Compiled for uno on avr 1.8.8 with Adafruit BMP085 Library 1.2.4 · 3 Nov 2026
How it works
Before a cyclone or a strong storm reaches the coast, the air pressure falls — often steadily for a day, then quickly in the last hours. Fishermen and sailors have watched barometers for exactly this for two centuries. Along India’s coasts (Odisha, Andhra Pradesh, Tamil Nadu and West Bengal in the Bay of Bengal season; Gujarat and Maharashtra on the Arabian Sea) and under the pre-monsoon kalbaisakhi (norwester) storms of eastern India, a barometer that watches the trend is a useful second opinion next to the radio.
How it works
The BMP180 measures absolute air pressure to about ±1 hPa, and its readings are very repeatable, which is what a trend needs. Every 5 seconds the Uno reads it and converts to sea-level pressure with the standard barometric formula and your altitude. Once an hour it stores the value in a 25-slot log — now, 1 hour ago … 24 hours ago.
From that log it works out two changes:
- 3-hour change — a fall of 3 hPa or more shows “Falling fast” and beeps once an hour.
- 24-hour change — a fall of 5 hPa or more compared with the same hour yesterday shows STORM WARNING and beeps three times every 10 minutes.
A rise of 3 hPa in 3 hours (“Rising fast”) usually means the storm has passed, or a cold, gusty outflow from a thunderstorm.
The LCD’s first line shows the pressure and temperature; the second the status. Every 10 minutes a CSV line goes to Serial: hours since start, hPa, 3 h change, 24 h change, status.
Why these parts
The GY-68 BMP180 board has its own 3.3 V regulator and pull-ups to 3.3 V, so it connects straight to the 5 V Uno — unlike the bare purple BMP280 boards, which need 3.3 V and level shifting. The Adafruit BMP085 library reads it (the BMP180 is register-compatible with the older BMP085). The 16×2 LCD shares the I2C bus, and the active buzzer module needs one pin.
Placement
Indoors is fine — pressure is the same inside and out — but keep it out of direct sun and away from the AC’s airflow, which changes the temperature reading. Don’t put it in a sealed box.
Troubleshooting
The LCD shows “BMP180 missing!”
Check SDA (A4) and SCL (A5) and 5 V on the GY-68’s VIN. Run the I2C scanner: the BMP180 answers at 0x77, the LCD at 0x27 or 0x3F.
The LCD is lit but blank
Turn the blue contrast pot on the backpack. If your backpack is at 0x3F, change 0x27 in the sketch.
The pressure differs from the weather app
Apps show sea-level pressure. Set ALTITUDE_M correctly; a remaining offset of 1–2 hPa is within the BMP180’s accuracy and doesn’t affect the trend.
Upgrades
- Swap to an ESP32 and push the warning to your phone.
- Log the 24-hour curve to an SD card and compare it with IMD’s station data afterwards.
- Add a wind speed sensor: falling pressure plus rising wind is the strongest sign.



