Created
September 3, 2014 21:19
-
-
Save azdle/dc984bf811b8e429ea42 to your computer and use it in GitHub Desktop.
Exosite Powered Sparkfun Arduino Weather Station
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
** Exosite Modifcations By Patrick Barrett <[email protected]> | |
** Modified 03-09-2014 | |
** | |
** Note: This runs on the Arduino Yun, but requires modifications to the libraries, | |
** provided by Sparkfun, to use software I2C (https://github.com/greiman/DigitalIO) | |
*/ | |
/* | |
Based on the work by | |
Weather Shield Example | |
By: Nathan Seidle | |
SparkFun Electronics | |
Date: November 16th, 2013 | |
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). | |
Much of this is based on Mike Grusin's USB Weather Board code: https://www.sparkfun.com/products/10586 | |
This example code assumes the GPS module is not used. | |
*/ | |
////////////////////////////////////////////////////// | |
#include <DigitalIO.h> | |
#include "MPL3115A2Soft.h" | |
#include "HTU21DSoft.h" | |
#include <EEPROM.h> | |
#include <SPI.h> | |
#include <Bridge.h> | |
#include <YunClient.h> | |
#include <Process.h> | |
#include <Exosite.h> | |
/*============================================================================== | |
* Configuration Variables | |
* | |
* Change these variables to your own settings. | |
*=============================================================================*/ | |
// Use these variables to customize what datasources are read and written to. | |
String returnString; | |
// Number of Errors before we try a reprovision. | |
const unsigned char reprovisionAfter = 3; | |
/*============================================================================== | |
* End of Configuration Variables | |
*=============================================================================*/ | |
class YunClient client; | |
Exosite exosite(&client); | |
unsigned char errorCount = reprovisionAfter; // Force Provision On First Loop | |
char macString[18]; // Used to store a formatted version of the MAC Address | |
#define YUN 1 | |
//Create an instance of the object | |
MPL3115A2Soft myPressure; | |
HTU21DSoft myHum; | |
//Hardware pin definitions | |
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |
// digital I/O pins | |
const byte WSPEED = 3; | |
const byte RAIN = 2; | |
const byte STAT1 = 7; | |
const byte STAT2 = 8; | |
// analog I/O pins | |
const byte REFERENCE_3V3 = A3; | |
const byte LIGHT = A1; | |
const byte BATT = A2; | |
const byte WDIR = A0; | |
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |
//Global Variables | |
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |
long lastSecond; //The millis counter to see when a second rolls by | |
byte seconds; //When it hits 60, increase the current minute | |
byte seconds_2m; //Keeps track of the "wind speed/dir avg" over last 2 minutes array of data | |
byte minutes; //Keeps track of where we are in various arrays of data | |
byte minutes_10m; //Keeps track of where we are in wind gust/dir over last 10 minutes array of data | |
long lastWindCheck = 0; | |
volatile long lastWindIRQ = 0; | |
volatile byte windClicks = 0; | |
long lastWeatherCheck = 0; | |
//These are all the weather values that wunderground expects: | |
int winddir = 0; // [0-360 instantaneous wind direction] | |
float windspeedkph = 0; // [mph instantaneous wind speed] | |
float humidity = 0; // [%] | |
float tempc = 0; // [temperature F] | |
volatile float dailyrainmm = 0; // [rain inches so far today in local time] | |
//float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent | |
float pressure = 0; | |
//float dewptf; // [dewpoint F] - It's hard to calculate dewpoint locally, do this in the agent | |
float batt_lvl = 11.8; //[analog value from 0 to 1023] | |
float light_lvl = 455; //[analog value from 0 to 1023] | |
// volatiles are subject to modification by IRQs | |
volatile unsigned long raintime, rainlast, raininterval, rain; | |
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |
//Interrupt routines (these are called by the hardware interrupts, not by the main code) | |
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |
void rainIRQ() | |
// Count rain gauge bucket tips as they occur | |
// Activated by the magnet and reed switch in the rain gauge, attached to input D2 | |
{ | |
raintime = millis(); // grab current time | |
raininterval = raintime - rainlast; // calculate interval between this and last event | |
if (raininterval > 10) // ignore switch-bounce glitches less than 10mS after initial edge | |
{ | |
dailyrainmm += 0.2794; //Each dump is 0.2794mm of water | |
rainlast = raintime; // set up for next event | |
Serial.print("It's Raining"); | |
} | |
} | |
void wspeedIRQ() | |
// Activated by the magnet in the anemometer (2 ticks per rotation), attached to input D3 | |
{ | |
static int wndcnt = 0; | |
if (millis() - lastWindIRQ > 10) // Ignore switch-bounce glitches less than 10ms (142MPH max reading) after the reed switch closes | |
{ | |
lastWindIRQ = millis(); //Grab the current time | |
windClicks++; //There is 2.4kph for each click per second. | |
} | |
} | |
void setup() | |
{ | |
Serial.begin(9600); | |
Serial.println("Weather Shield Example"); | |
pinMode(STAT1, OUTPUT); //Status LED Blue | |
pinMode(STAT2, OUTPUT); //Status LED Green | |
pinMode(WSPEED, INPUT_PULLUP); // input from wind meters windspeed sensor | |
pinMode(RAIN, INPUT_PULLUP); // input from wind meters rain gauge sensor | |
pinMode(REFERENCE_3V3, INPUT); | |
pinMode(LIGHT, INPUT); | |
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 | |
seconds = 0; | |
lastSecond = millis(); | |
lastWeatherCheck = millis(); | |
// attach external interrupt pins to IRQ functions | |
attachInterrupt(1, rainIRQ, FALLING); | |
attachInterrupt(0, wspeedIRQ, FALLING);//May Need to swap IRQ for uno | |
// turn on interrupts | |
interrupts(); | |
Bridge.begin(); | |
getYunMAC(macString, 18); | |
// Print Some Useful Info | |
Serial.print(F("MAC Address: ")); | |
Serial.println(macString); | |
} | |
void loop() | |
{ | |
// Update Global Variables | |
calcWeather(); | |
// Check if we should reprovision. | |
if(errorCount >= reprovisionAfter){ | |
if(exosite.provision("exosite", "ard-generic", macString)){ | |
errorCount = 0; | |
} | |
} | |
//Write to "uptime" and read from "uptime" and "command" datasources. | |
if ( exosite.writeRead(buildWriteString(), "", returnString)){ | |
Serial.println("OK"); | |
errorCount = 0; | |
}else{ | |
Serial.println("Error"); | |
errorCount++; | |
} | |
delay(1000); | |
} | |
//Calculates each of the variables that wunderground is expecting | |
int calcWeather() | |
{ | |
//Calc humidity | |
humidity = myHum.readHumidity(); | |
//Calc tempf from pressure sensor | |
tempc = myPressure.readTemp(); | |
//Calc pressure | |
pressure = myPressure.readPressure(); | |
//Calc light level | |
light_lvl = get_light_level(); | |
//Calc battery level | |
batt_lvl = get_battery_level(); | |
//Calc winddir | |
winddir = get_wind_direction(); | |
//Calc windspeed | |
windspeedkph = get_wind_speed(); | |
return 0; | |
} | |
//Returns the voltage of the light sensor based on the 3.3V rail | |
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) | |
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); | |
} | |
//Returns the voltage of the raw pin based on the 3.3V rail | |
//This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) | |
//Battery level is connected to the RAW pin on Arduino and is fed through two 5% resistors: | |
//3.9K on the high side (R1), and 1K on the low side (R2) | |
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); | |
} | |
//Returns the instataneous wind speed | |
float get_wind_speed() | |
{ | |
float deltaTime = millis() - lastWindCheck; //750ms | |
deltaTime /= 1000.0; //Covert to seconds | |
float windSpeed = (float)windClicks / deltaTime; //3 / 0.750s = 4 | |
windClicks = 0; //Reset and start watching for new wind | |
lastWindCheck = millis(); | |
windSpeed *= 2.4; //4 * 1.492 = 5.968MPH | |
return(windSpeed); | |
} | |
//Read the wind direction sensor, return heading in degrees | |
int get_wind_direction() | |
{ | |
unsigned int adc; | |
adc = analogRead(WDIR); // get the current reading from the sensor | |
// The following table is ADC readings for the wind direction sensor output, sorted from low to high. | |
// Each threshold is the midpoint between adjacent headings. The output is degrees for that ADC reading. | |
// Note that these are not in compass degree order! See Weather Meters datasheet for more information. | |
if (adc < 380) return (113); | |
if (adc < 393) return (68); | |
if (adc < 414) return (90); | |
if (adc < 456) return (158); | |
if (adc < 508) return (135); | |
if (adc < 551) return (203); | |
if (adc < 615) return (180); | |
if (adc < 680) return (23); | |
if (adc < 746) return (45); | |
if (adc < 801) return (248); | |
if (adc < 833) return (225); | |
if (adc < 878) return (338); | |
if (adc < 913) return (0); | |
if (adc < 940) return (293); | |
if (adc < 967) return (315); | |
if (adc < 990) return (270); | |
return (-1); // error, disconnected? | |
} | |
void getYunMAC(char* MACptr, byte bufSize) { | |
Process p; // Create a process and call it "p" | |
p.runShellCommand("/sbin/ifconfig -a | /bin/grep HWaddr |/bin/grep wlan0 | /usr/bin/awk '{print $5}'"); | |
for(int i = 0; i < (bufSize-1) && p.available() > 0; i++) { | |
MACptr[i] = p.read(); | |
MACptr[i+1] = 0; | |
} | |
} | |
String buildWriteString() | |
{ | |
return "wd=" + String(winddir) + | |
"&ws=" + String(windspeedkph) + | |
"&h=" + String(humidity) + | |
"&t=" + String(tempc) + | |
"&r=" + String(dailyrainmm) + | |
"&p=" + String(pressure) + | |
"&b=" + String(batt_lvl) + | |
"&l=" + String(light_lvl) + | |
"&u=" + String(millis()); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment