Introduction: BLEWeather: a Portable Bluetooth Weather Station

Imagine having the ability to collect information about your surroundings from the comfort of your own house! In the age of the internet, this may not seem quite so impressive, but trust me when I say it's awesome.

This instructable will outline the process of creating a portable Arduino-powered bluetooth weather station and a native android application to receive data.

What you will need:

Arduino Mega 2560 ($46)

Sparkfun Weathershield ($40)

nRF8001 Bluetooth Chip ($20)

Voltaic Solar Kit ($90)

1x USB Type B

17x Male-to-Male Wires

Github Sources:

Step 1: Wiring the Arduino

Wiring the Arduino components may appear difficult, however once you understand the connections it's relatively simple.

First, connect the breadboard +5V and GND connections to Arduino's. You can then place the nRF8001 pins in the breadboard.

Next, follow these connection instructions to wire up the nRF8001:

nRF8001 => Arduino

  • SCK => DIG-52
  • MISO => DIG-50
  • MOSI => DIG-51
  • REQ => DIG-10
  • RDY => DIG-2
  • RST => DIG-9
  • GND => GND
  • VIN => VINNow we will wire the Weather Shield:

WeatherShield => Arduino

  • WS-7 => DIG-7
  • WS-8 => DIG-8
  • WS-SDA => SDA
  • WS-SCL => SCL
  • WS-+5V => +3.3V
  • WS-VIN => VIN
  • WS-GND => GND
  • WS-A1 => A1
  • WS-A2 => A2
  • WS-A3 => A3

Step 2: The Arduino Code

// Enable lightweight


// Libraries
#include //Serial Peripheral Interface #include "Adafruit_BLE_UART.h" //nRF8001 bluetooth chip #include //BLE communication #include //I2C needed for sensors #include "SparkFunMPL3115A2.h" //Pressure sensor #include "SparkFunHTU21D.h" //Humidity sensor #include "LowPower.h" //Low power for arduino

//Hardware pin definitions
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // digital I/O pins int reset = 3; #define ADAFRUITBLE_REQ 10 #define ADAFRUITBLE_RDY 2 #define ADAFRUITBLE_RST 9 // analog I/O pins const byte REFERENCE_3V3 = A3; const byte LIGHT = A1; const byte BATT = A2; //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// Instances
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= MPL3115A2 myPressure; //Create an instance of the pressure sensor HTU21D myHumidity; //Create an instance of the humidity sensor aREST rest = aREST(); Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST); //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//Global Variables
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= float humidity; float tempf; float pressure; float batt_lvl; //[analog value from 0 to 1023] float light_lvl; //[analog value from 0 to 1023] //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void(* resetFunc) (void) = 0;
void setup(void) { // Start Serial Serial.begin(9600); // Start BLE BTLEserial.begin();

// Expose variables to API rest.variable("humidity",&humidity); rest.variable("temperature",&tempf); rest.variable("pressure",&pressure); rest.variable("battery",&batt_lvl); rest.variable("light",&light_lvl);

pinMode(REFERENCE_3V3, INPUT); pinMode(LIGHT, INPUT); pinMode(reset, OUTPUT); digitalWrite(reset, LOW);

//Configure the pressure sensor myPressure.begin(); // Get sensor online myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa myPressure.setOversampleRate(7); // Set Oversample to the recommended 128 myPressure.enableEventFlags(); // Enable all three pressure and temp event flags

//Configure the humidity sensor myHumidity.begin();

// Welcome message Serial.println("Weather station started"); }

aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED; // If it exits loop, display disconnect message

void loop() {

LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

// Read and store sensor values humidity = myHumidity.readHumidity() + 200; tempf = myPressure.readTempF() + 100; pressure = myPressure.readPressure()/1000 + 250; light_lvl = get_light_level() + 400; batt_lvl = get_battery_level() + 500; // Ask what is our current status aci_evt_opcode_t status = BTLEserial.getState();

// Status updates if (status != laststatus) { if (status == ACI_EVT_DEVICE_STARTED) { Serial.println(F("* Advertising started")); } if (status == ACI_EVT_CONNECTED) { Serial.println(F("* Connected!")); } if (status == ACI_EVT_DISCONNECTED) { Serial.println(F("* Disconnected or advertising timed out")); } laststatus = status; } // Tell the nRF8001 to do whatever it should be working on. BTLEserial.pollACI(); // Handle REST calls if (status == ACI_EVT_CONNECTED) { rest.handle(BTLEserial); }

// Reset call if (digitalRead(reset) == HIGH){ digitalWrite(reset, LOW); resetFunc(); } }

float get_light_level(){ float operatingVoltage = analogRead(REFERENCE_3V3); float lightSensor = analogRead(LIGHT); operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V lightSensor = operatingVoltage * lightSensor; return(lightSensor); }

float get_battery_level(){ float operatingVoltage = analogRead(REFERENCE_3V3); float rawVoltage = analogRead(BATT); operatingVoltage = 3.30 / operatingVoltage; //The reference voltage is 3.3V rawVoltage = operatingVoltage * rawVoltage; //Convert the 0 to 1023 int to actual voltage on BATT pin rawVoltage *= 4.90; //(3.9k+1k)/1k - multiple BATT voltage by the voltage divider to get actual system voltage return(rawVoltage); }

Step 3: Writing the App

This step is a little more challenging. Attached will be the github link to the source code, however there are some factors to be taken into account:

  • The app is for android only
  • You need android studio to compile the source
  • The layout was designed for a 5 inch screen and may appear different on different dimension screens.

With that said, visit the github link and download the included APK file. If you would like to compile the source yourself, you need android studio. Just load the files into your projects directory.

Step 4: Putting It All Together

With the Arduino, bluetooth chip and weather shield all wired together and the BLEWeather application installed on your bluetooth capable device, you're ready to finalize the device.

For the container, you're going to want something that's approximately 6x12 inches and at least 2.5 inches tall. This is so the solar panel fits nicely on the cover and absorbs light, obviously charging the battery but also preventing the internal temperature from increasing too much. The height of 2.5 inches is to give enough room for the weather shield to be propped up against the side of the container so it can accurately read light levels, as seen in the photos above.

Step 5: Solar Powered

To connect the solar panel to the Arduino, you need a solar kit similar to the one linked in the introduction. The battery will fit nicely inside the container, and a small cutout will allow the connection to the solar panel to be weather tight. The solar panel will rest on the lid because this provides the most efficient charging, and it is rain resistant after all.

Step 6: Adding Longevity

While there are already methods implemented to reduce power consumption, the nRF8001 has built-in methods of low power consumption. If you live somewhere that isn't often sunny, this may be something to look into.

If you feel more inclined to tinker with the Arduino code, what I found works best is to reduce the time spent broadcasting. This is the main power consumption.

Step 7: The Results

Because the weather shield is housed inside of a plastic container, I anticipated a difference between readings from the contained device and the exposed device.

To test these differences, I ran two 30 minute tests on the same day at the same location: one with the sensors exposed and one with them contained. Graphed above are the results for temperature, pressure and humidity.

As you can see, there wasn't much difference. The contained readings seemed to steady increase in temperature, which makes sense because the container essentially acts as a greenhouse. It would be an oven if the solar panel wasn't protecting the top.

The pressure readings were a little funky, as were the humidity readings. This is most likely due to the sensors not being as accurate, or at least they have a lot of variability. Nonetheless, there didn't appear to be much of a difference.