danionescu
Published © GPL3+

DIY Rain Prediction Using Arduino, Python and Keras

So the big aim here is obviously to predict the rain in the future. We'll build a system that does just that from scratch!

AdvancedFull instructions provided13,242
DIY Rain Prediction Using Arduino, Python and Keras

Things used in this project

Hardware components

Small plastic box with detachable lids (mine has screws)
×1
three AAA battery holder
×1
three AAA rechargeable batteries
×1
6V small solar panel
×1
Arduino Pro Mini 328 - 5V/16MHz
SparkFun Arduino Pro Mini 328 - 5V/16MHz
×1
1N4004 diode
×1
General Purpose Transistor NPN
General Purpose Transistor NPN
×1
a rain sensor
×1
HC-12 serial communication module
×1
HC-12 USB serial module
×1
SparkFun Atmospheric Sensor Breakout - BME280
SparkFun Atmospheric Sensor Breakout - BME280
×1
BH1750
×1
PCB, wires, solder, KF301-2P plug in screw connector, male&female pcb connectors, glue
×1
3.3V regulator
×1

Hand tools and fabrication machines

USB to serial FTDI adapter FT232RL
Drill
Soldering iron (generic)
Soldering iron (generic)
Screwdrivers

Story

Read more

Schematics

Fritzing schematic

Schematic

Weather station arduino sketch

Code

Code snippet #2

Plain text
#include "LowPower.h"<br>#include "SoftwareSerial.h"
#include "Wire.h"
#include "Adafruit_Sensor.h"
#include "Adafruit_BME280.h"
#include "BH1750.h"

SoftwareSerial serialComm(4, 5); // RX, TX
Adafruit_BME280 bme; 
BH1750 lightMeter;
const byte rainPin = A0;

byte sensorsCode = 1;
/**
 * voltage level that will pun the microcontroller in deep sleep instead of regular sleep
 */
int voltageDeepSleepThreshold = 4200; 
const byte peripherialsPowerPin = 6;
char buffer[] = {' ',' ',' ',' ',' ',' ',' '};

struct sensorData
  {
      byte humidity;    
      int temperature;
      byte rain;
      int  pressure;
      long voltage;
      int light;
  };

sensorData sensors;

void setup() 
{  
    Serial.begin(9600);
    serialComm.begin(9600);
    pinMode(peripherialsPowerPin, OUTPUT);
    digitalWrite(peripherialsPowerPin, HIGH);
    delay(500);
    if (!bme.begin()) {
        Serial.println("Could not find a valid BME280 sensor, check wiring!");
        while (1) {
           customSleep(100);
        }
    }
    Serial.println("Initialization finished succesfully");
    delay(50);
    digitalWrite(peripherialsPowerPin, HIGH);
}

void loop() 
{    
    updateSenzors();
    transmitData();    
    customSleep(75);       
}

void updateSenzors() 
{
    bme.begin();
    lightMeter.begin();
    delay(300);
    sensors.temperature = bme.readTemperature();
    sensors.pressure = bme.readPressure() / 100.0F;
    sensors.humidity = bme.readHumidity();
    sensors.light = lightMeter.readLightLevel();
    sensors.voltage = readVcc();
    sensors.rain = readRain();
}

void transmitData()
{
    emptyIncommingSerialBuffer();
    Serial.print("Temp:");Serial.println(sensors.temperature);
    Serial.print("Humid:");Serial.println(sensors.humidity);
    Serial.print("Pressure:");Serial.println(sensors.pressure);
    Serial.print("Light:");Serial.println(sensors.light);
    Serial.print("Voltage:");Serial.println(sensors.voltage);
    Serial.print("Rain:");Serial.println(sensors.rain);
    transmitSenzorData("T", sensors.temperature);
    transmitSenzorData("H", sensors.humidity);
    transmitSenzorData("PS", sensors.pressure);
    transmitSenzorData("L", sensors.light);
    transmitSenzorData("V", sensors.voltage);
    transmitSenzorData("R", sensors.rain);
}

void emptyIncommingSerialBuffer()
{
    while (serialComm.available() > 0) {
        serialComm.read();
        delay(5);
   }
}

void transmitSenzorData(String type, int value)
{
    serialComm.print(type);
    serialComm.print(sensorsCode);
    serialComm.print(":");
    serialComm.print(value);
    serialComm.print("|");
    delay(50);
}

void customSleep(long eightSecondCycles)
{
    if (sensors.voltage > voltageDeepSleepThreshold) {
        delay(eightSecondCycles * 8000);
        return;
    }
    digitalWrite(peripherialsPowerPin, LOW);
    for (int i = 0; i < eightSecondCycles; i++) {
        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);  
    }
    digitalWrite(peripherialsPowerPin, HIGH);
    delay(500);
}

byte readRain()
{
    byte level = analogRead(rainPin);

    return map(level, 0, 1023, 0, 100);  
}

long readVcc() {
    // Read 1.1V reference against AVcc
    // set the reference to Vcc and the measurement to the internal 1.1V reference
    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
    #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
      ADMUX = _BV(MUX3) | _BV(MUX2);
    #else
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #endif  
  
    delay(2); // Wait for Vref to settle
    ADCSRA |= _BV(ADSC); // Start conversion
    while (bit_is_set(ADCSRA,ADSC)); // measuring
    uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH  
    uint8_t high = ADCH; // unlocks both
    long result = (high<<8) | low;
    result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
    
    return result; // Vcc in millivolts
}

Code snippet #5

Plain text
cd weather-predict 
# create anaconda environment named "weather" with python 3.6.2
conda create --name weather python=3.6.2 

# activate environment
conda activate weather

# install all packages 
pip install -r requirements.txt 

Code snippet #6

Plain text
mongodb = {
    'host': 'localhost',
    'port': 27017
}
...

Code snippet #10

Plain text
conda activate weather

python serial_listener.py

# every 10 minutes you should see data from the weather station coming in :

[Sensor: type(temperature), value(14.3)]

[Sensor: type(pressure), value(1056.0)]

...

Code snippet #15

Plain text
{	
        "_id" : "04_27_2017_06_17",
	"humidity" : 65,
	"date" : ISODate("2017-04-27T06:17:18Z"),
	"pressure" : 1007,
	"temperature" : 9,
	"rain" : 0,
	"light" : 15
}

Code snippet #16

Plain text
client = MongoClient(host, port).weather.datapoints 

cursor = client.find(
            {'$and' : [
                {'date' : {'$gte' : start_date}},
                {'date' : {'$lte' : end_date}}
            ]}
        )
data = list(cursor)
..

Code snippet #18

Plain text
_id date  humidity  light  pressure  rain  temperature
                                                                            
04_27_2017_03_08 2017-04-27 03:08:36      67.0    0.0    1007.0   0.0         11.0
04_27_2017_03_19 2017-04-27 03:19:05      66.0    0.0    1007.0   0.0         11.0
04_27_2017_03_29 2017-04-27 03:29:34      66.0    0.0    1007.0   0.0         11.0 

Code snippet #22

Plain text
_id has_rain  humidity_10percentile  humidity_30percentile  humidity_70percentile  humidity_90percentile          ...           temperature_steady_4  temperature_steady_5  temperature_steady_6  temperature_steady_7  temperature_steady_8                                                                                                                         ...                                                                                                                       
04_27_2017_3         0                   36.0                   44.8                   61.0                   63.0          ...                            NaN                   NaN                   NaN                   NaN                   NaN
04_28_2017_0         0                   68.0                   70.0                   74.0                   75.0          ...                           14.0                   NaN                   NaN                   NaN                   NaN
04_28_2017_1         0                   40.0                   45.0                   63.2                   69.0          ...                           20.0                  14.0                   NaN                   NaN                   NaN
04_28_2017_2         0                   34.0                   35.9                   40.0                   41.0          ...                           29.0                  20.0                  14.0                   NaN                   NaN
04_28_2017_3         0                   36.1                   40.6                   52.0                   54.0          ...                           19.0                  29.0                  20.0                  14.0                   NaN
04_29_2017_0         0                   52.0                   54.0                   56.0                   58.0          ...                           26.0                  19.0                  29.0                  20.0                  14.0
04_29_2017_1         0                   39.4                   43.2                   54.6                   57.0          ...                           18.0                  26.0                  19.0                  29.0                  20.0
04_29_2017_2         1                   41.0                   42.0                   44.2                   47.0          ...                           28.0                  18.0                  26.0                  19.0                  29.0 

Code snippet #23

Plain text
from sklearn.model_selection import train_test_split 

...

main_data, test_data = train_test_split(dataframe, test_size=percent_test_data) 

...

Code snippet #25

Plain text
from sklearn.preprocessing import StandardScaler

from sklearn.externals import joblib

..

scaler = StandardScaler()

X = scaler.fit_transform(X) 

...

# of course we should be careful to save the scaled model for later reuse

joblib.dump(scaler, 'model_file_name.save') 

Code snippet #26

Plain text
from keras.models import Sequential

from keras.layers import Dense
from keras.layers import Dropout 
...
input_dimensions = X.shape[1] 
optimizer = 'rmsprop'
dropout = 0.05
model = Sequential()
inner_nodes = int(input_dimensions / 2)
model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))
model.add(Dropout(rate=dropout))
model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))
model.add(Dropout(rate=dropout))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))
model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) 

model.fit(X, y, batch_size=1, epochs=50)
...

# save the model for later use
classifier.save('file_model_name')

Github

https://github.com/claws/BH1750

Github

https://github.com/rocketscream/Low-Power

Github

https://github.com/adafruit/Adafruit_Sensor

Github

https://github.com/adafruit/Adafruit_BME280_Library

Github

https://github.com/danionescu0/home-automation

Credits

danionescu

danionescu

11 projects • 72 followers
I'm an electronics enthusiast, passionate about science, and programming.I like the challenges involved with building things from scratch.

Comments