Last active
August 29, 2015 14:05
-
-
Save tuxite/b1ee48a7c7935c0f8e4c to your computer and use it in GitHub Desktop.
Arduino sketch for Sparfun Weather Shield, sending weather data through UDP broascast Json
This file contains 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
/* | |
Weather Shield using Ethernet | |
by Matthieu Morin | |
created on 2014-08-10 | |
Licence: GPL V3 | |
Based on: | |
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 code reads all the various sensors (wind speed, direction, rain gauge, humidty, pressure, light, batt_lvl) | |
and reports it over the serial comm port. This can be easily routed to an datalogger (such as OpenLog) or | |
a wireless transmitter (such as Electric Imp). | |
Measurements are reported once a second but windspeed and rain gauge are tied to interrupts that are | |
calcualted at each report. | |
This example code assumes the GPS module is not used. | |
*/ | |
#include <Wire.h> //I2C needed for sensors | |
#include "MPL3115A2.h" //Pressure sensor | |
#include "HTU21D.h" //Humidity sensor | |
#include <SPI.h> | |
#include <Ethernet.h> | |
// [CONFIG] Sensor instances --------------------------------------------------- | |
MPL3115A2 myPressure; | |
HTU21D myHumidity; | |
// ----------------------------------------------------------------------------- | |
// [CONFIG] 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; | |
// ----------------------------------------------------------------------------- | |
// [CONFIG] Ethernet ----------------------------------------------------------- | |
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x21, 0xD9 }; // MAC Address of the Ethernet Shield | |
int port = 8000; // Port of the remote server | |
// Instances of the Ethernet library | |
EthernetClient client; | |
char server[] = "iridium"; | |
// ----------------------------------------------------------------------------- | |
//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 minutes; //Keeps track of where we are in various arrays of data | |
long lastWindCheck = 0; | |
volatile long lastWindIRQ = 0; | |
volatile byte windClicks = 0; | |
volatile float rainHour[60]; //60 floating numbers to keep track of 60 minutes of rain | |
int winddir = 0; // [0-360 instantaneous wind direction] | |
float windspeedkmh = 0; // [kmh instantaneous wind speed] | |
float humidity = 0; // [%] | |
float tempc = 0; // [temperature C] | |
float rainin = 0; // [rain mm over the past hour)] -- the accumulated rainfall in the past 60 min | |
volatile float dailyrainin = 0; // [rain mm so far today in local time] | |
float pressure = 0; | |
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 | |
{ | |
dailyrainin += 0.2794; // Each dump is 0.2794mm of water | |
rainHour[minutes] += 0.2794; //Increase this minute's amount of rain | |
rainlast = raintime; // set up for next event | |
} | |
} | |
void wspeedIRQ() | |
// Activated by the magnet in the anemometer (2 ticks per rotation), attached to input D3 | |
{ | |
if (millis() - lastWindIRQ > 10) // Ignore switch-bounce glitches less than 10ms (240kmh max reading) after the reed switch closes | |
{ | |
lastWindIRQ = millis(); //Grab the current time | |
windClicks++; //There is 2.4km/h for each click per second. | |
} | |
} | |
// Setup ----------------------------------------------------------------------- | |
void setup() | |
{ | |
// Open serial communications and wait for port to open: | |
Serial.begin(9600); | |
Serial.println("DSM Weather Station Prototype"); | |
// Start the Ethernet connection using DHCP: | |
if (Ethernet.begin(mac) == 0) { | |
Serial.println("Failed to configure Ethernet using DHCP"); | |
} | |
// print your local IP address: | |
Serial.print("My IP address: "); | |
for (byte thisByte = 0; thisByte < 4; thisByte++) { | |
// print the value of each byte of the IP address: | |
Serial.print(Ethernet.localIP()[thisByte], DEC); | |
Serial.print('.'); | |
} | |
Serial.println(); | |
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); | |
//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(); | |
seconds = 0; | |
lastSecond = millis(); | |
// attach external interrupt pins to IRQ functions | |
attachInterrupt(0, rainIRQ, FALLING); | |
attachInterrupt(1, wspeedIRQ, FALLING); | |
// turn on interrupts | |
interrupts(); | |
Serial.println("Weather Shield online!"); | |
} | |
void loop() | |
{ | |
//-------------------------------------------------------------------------- | |
// Start of the Weather sensors Loop | |
//-------------------------------------------------------------------------- | |
// Keep track of which minute it is | |
if(millis() - lastSecond >= 1000){ | |
digitalWrite(STAT2, HIGH); //Blink stat LED | |
lastSecond += 1000; | |
// Calc the wind speed and direction every second for 120 second to get 2 minute average | |
float currentSpeed = get_wind_speed(); | |
windspeedkmh = currentSpeed; | |
int currentDirection = get_wind_direction(); | |
if(++seconds > 59) | |
{ | |
seconds = 0; | |
if(++minutes > 59) minutes = 0; | |
rainHour[minutes] = 0; // Zero out this minute's rainfall amount | |
} | |
calcWeather(); | |
// Read the server response if any for debugging purpose | |
if (client.available()) { | |
char c; | |
while (c != 0x0A){ // Read only the first line of the server response. | |
c = client.read(); | |
Serial.print(c); | |
} | |
client.flush(); // Flush the client response for next iteration of the loop. | |
} | |
// Connect to the server | |
connection(); | |
// Send the data then close the connection if connected. | |
if (client.connected()){ | |
printWeather(); | |
client.stop(); | |
} | |
digitalWrite(STAT2, LOW); //Turn off stat LED | |
} | |
delay(100); | |
} | |
//Calculates each of the variables that wunderground is expecting | |
void calcWeather() | |
{ | |
//Calc winddir | |
winddir = get_wind_direction(); | |
//Calc humidity | |
humidity = myHumidity.readHumidity(); | |
//Calc tempc from pressure sensor | |
tempc = myPressure.readTemp(); | |
//Total rainfall for the day is calculated within the interrupt | |
//Calculate amount of rainfall for the last 60 minutes | |
rainin = 0; | |
for(int i = 0 ; i < 60 ; i++) | |
rainin += rainHour[i]; | |
//Calc pressure | |
pressure = myPressure.readPressure()/100.0; | |
//Calc light level | |
light_lvl = get_light_level(); | |
//Calc battery level | |
batt_lvl = get_battery_level(); | |
} | |
//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 instantaneous wind speed, in km/h | |
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 * 2.4 = 9.6kmh | |
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? | |
} | |
// Adds all data to a Json object (will be printed in UDP). | |
void printWeather() | |
{ | |
String request = "GET /feed?platform=arduino"; | |
char buf[6]; // To store the value of floats during conversion to String. | |
// We print only instant value, the computation will be done server side. | |
request += urlAdd("wind_speed"); | |
dtostrf(windspeedkmh, 4, 2, buf); | |
request += buf; | |
request += urlAdd("wind_dir"); | |
request += winddir; | |
request += urlAdd("humidity"); | |
dtostrf(humidity, 4, 2, buf); | |
request += buf; | |
request += urlAdd("temperature"); | |
dtostrf(tempc, 4, 2, buf); | |
request += buf; | |
request += urlAdd("pressure"); | |
dtostrf(pressure, 4, 2, buf); | |
request += buf; | |
// The rain is computed for one hour | |
request += urlAdd("rain"); | |
dtostrf(rainin, 4, 2, buf); | |
request += buf; | |
request += urlAdd("battery_level"); | |
dtostrf(batt_lvl, 4, 2, buf); | |
request += buf; | |
request += urlAdd("light_level"); | |
dtostrf(light_lvl, 4, 2, buf); | |
request += buf; | |
request += " HTTP/1.1\nHost: "; | |
request += server; | |
client.println(request); | |
} | |
String urlAdd(const char* name){ | |
String url = "&"; | |
url += name; | |
url += "="; | |
return url; | |
} | |
void connection(){ | |
if (client.connect(server, port)) { | |
Serial.print("Connected to "); | |
Serial.println(server); | |
} | |
else { | |
// If you didn't get a connection to the server: | |
Serial.println("Connection failed"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment