In a
previous post, I went over how the weatherstation data will be accessed--an Arduino-based webserver. However, this implementation had a major limitation: no data logging or visualization. I decided to switch to uploading the received data to
Xively, which provides the data logging and visualization.
Receiver Hardware
I added a protoshield on top of the Ethernet shield. The protoshield has the 433 MHz receiver soldered onto it.
Show Code
// Author: Zac DeMeo
// Uses VirtualWire to receive transmissions of weather data. Sends data to Xively for logging.
#include <Xively.h>
#include <HttpClient.h>
#include <VirtualWire.h>
#include <Ethernet.h>
#include <SPI.h>
#define RX_PIN 7
#define RX_RATE 500
#define DELAY 3600
#define FEEDID YOUR_FEED_ID
// Time
unsigned long mark = 0;
// Ethernet shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Arduino Ethernet shield MAC
EthernetClient xivelyEthernetClient;
// Xively channel key and IDs
const char xivelyKey[] = YOUR_XIVELY_KEY;
char tempID[] = "Temperature";
char presID[] = "Pressure";
char rhID[] = "Relative_Humidity";
char dewpointID[] = "Dewpoint";
char voltID[] = "Battery_Voltage";
char hiID[] = "Heat_Index";
// Define the strings for our datastream IDs
XivelyDatastream datastreams[] = {
XivelyDatastream(tempID, strlen(tempID), DATASTREAM_FLOAT),
XivelyDatastream(presID, strlen(presID), DATASTREAM_FLOAT),
XivelyDatastream(rhID, strlen(rhID), DATASTREAM_FLOAT),
XivelyDatastream(dewpointID, strlen(dewpointID), DATASTREAM_FLOAT),
XivelyDatastream(voltID, strlen(voltID), DATASTREAM_FLOAT),
XivelyDatastream(hiID, strlen(hiID), DATASTREAM_FLOAT)
};
// Create feed
XivelyFeed feed(FEEDID, datastreams, 6);
XivelyClient xivelyClient(xivelyEthernetClient);
// Weather data
// Index 0: Relative humidity (%)
// Index 1: Temperature (F)
// Index 2: Estimated dewpoint (F)
// Index 3: Barometric pressure (inHg)
// Index 4: Vcc on weatherstation (V)
char values[5][8];
void setup() {
vw_setup(RX_RATE);
vw_set_rx_pin(RX_PIN);
vw_rx_start();
getIPAddress();
}
void loop() {
listenForTx();
// Re-establish connection with router every hour
if (millis() - mark >= DELAY) {
getIPAddress();
mark = millis();
}
}
// Get IP address using DHCP
void getIPAddress() {
int connection;
do {
connection = Ethernet.begin(mac);
} while (connection == 0);
}
void listenForTx() {
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) {
char message[30]; // String to copy buf into
message[0] = '\0';
// Check if transmission is valid. If all sensors have returned data, message will have 4 "," characters
// If there are not 4 commas, return without parsing data and wait for next transmission
int k = 0;
for (int i = 0; i < buflen; i++) {
if (buf[i] == ',') {
k++;
}
}
if (k != 4) {
return;
}
// Read buffer into string and split at each ","
int j = 0;
for (int i = 0; i < buflen; i++) {
if (buf[i] != ',') {
int length = strlen(message);
message[length] = buf[i];
message[length + 1] = '\0';
if (i == (buflen - 1)) {
strcpy(values[j], message);
break;
}
}
else {
strcpy(values[j], message);
message[0] = '\0';
j++;
}
}
// Log data to Xively
logData();
}
}
void logData() {
float rh = atof(values[0]);
float t = atof(values[1]);
float dp = atof(values[2]);
float p = atof(values[3]);
float v = atof(values[4]);
float hi = heatIndex(t, rh);
// Add sensor values to datastream
datastreams[0].setFloat(t);
datastreams[1].setFloat(p);
datastreams[2].setFloat(rh);
datastreams[3].setFloat(dp);
datastreams[4].setFloat(v);
datastreams[5].setFloat(hi);
// Send data to Xively
int retval = xivelyClient.put(feed, xivelyKey);
// Something's wrong with our connection
// Try to establish a connection with the router
if (retval < 0) {
getIPAddress();
}
}
// Uses NOAA heat index calculation from http://www.hpc.ncep.noaa.gov/html/heatindex_equation.shtml
float heatIndex(float t, float rh) {
float hi;
// First, calculate simple index
hi = 0.5 * (t + 61.0 + ((t-68.0)*1.2) + (rh*0.094));
hi = 0.5*(hi + t);
// When the heat index is >80 F, calculate using alternative method
if (hi >= 80) {
hi = -42.379 + 2.04901523*t + 10.14333127*rh - .22475541*t*rh - .00683783*t*t - .05481717*rh*rh + .00122874*t*t*rh + .00085282*t*rh*rh - .00000199*t*t*rh*rh;
// When the relative humidity is <13% and temperature is [80,112] F
if (rh < 13.0 && t >= 80.0 && t <= 112.0) {
hi = hi - (((13-rh)/4)*sqrt((17-abs(t-95.))/17));
} else if (rh > 85.0 && t >= 80.0 && t <= 87.0) { // When the relative humidity is >85% and temperature is [80,112] F
hi = hi + (((rh-85)/10) * ((87-t)/5));
}
}
return hi;
}
Because the receiver is connected to a router, the router sometimes needs to be reset. Therefore, the script calls
getIPAddress() every hour.