Skip to content

Instantly share code, notes, and snippets.

@Scott216
Created January 19, 2015 22:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Scott216/3cd6cc56393bccdf2981 to your computer and use it in GitHub Desktop.
Save Scott216/3cd6cc56393bccdf2981 to your computer and use it in GitHub Desktop.
Testing MoteinoMega with Davis ISS Weather Station
/*
Testing MoteinoMega with Weather station and SD card
Want to see how sketch works with no ethernet code
Does it still have long delays while syncing the frequency hopping
MoteinoMega and SD Card breakout borad from ebay will work with 5v or 3.3 volts - via selector switch
Forum: http://bit.ly/14thCKB
GitHub Repo: http://github.com/LowPowerLab
*/
// #define USE_SD_CARD // comment this out if not using SD card
#include <SPI.h> // DavisRFM69.h needs this http://arduino.cc/en/Reference/SPI
#include <DavisRFM69.h> // http://github.com/dekay/DavisRFM69
#include <SD.h> // Micro SD Card. http://arduino.cc/en/Reference/SD
// Reduce number of bogus compiler warnings, see http://bit.ly/1pU6XMe
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))
const byte SS_PIN_MICROSD = 13;
#ifdef __AVR_ATmega1284P__
#define MOTEINO_LED 15 // Moteino MEGAs have LEDs on D15
const byte SS_PIN_RADIO = 4;
#else
#define MOTEINO_LED 9 // Moteinos have LEDs on D9
const byte SS_PIN_RADIO = 10;
#endif
#define ISS_UV_INDEX 0x4
#define ISS_RAIN_SECONDS 0x5
#define ISS_SOLAR_RAD 0x6
#define ISS_OUTSIDE_TEMP 0x8
#define ISS_WIND_GUST 0x9
#define ISS_HUMIDITY 0xA
#define ISS_RAIN 0xE
DavisRFM69 radio;
const byte TRANSMITTER_STATION_ID = 3; // ISS station ID to be monitored. Default station ID is normally 1
// Weather data
byte g_rainCounter = 0; // rain data sent from outside weather station. 1 = 0.01". Just counts up to 127 then rolls over to zero
byte g_windgustmph = 0; // Wind in MPH
uint16_t g_dayRain = 0; // Accumulated rain for the day in 1/100 inch
float g_rainRate = 0; // Rain rate in inches per hour
int16_t g_outsideTemperature = 0; // Outside temperature in tenths of degrees
byte g_outsideHumidity = 0; // Outside relative humidity in %.
byte g_windSpeed = 0; // Wind speed in miles per hour
float g_windDirection_Now = 0; // Instantanious wind direction, from 1 to 360 degrees (0 = no wind data)
uint16_t g_windDirection_Avg = 0; // Average wind direction, from 1 to 360 degrees (0 = no wind data)
//=============================================================================
// Setup radio
//=============================================================================
void setup()
{
Serial.begin(9600);
pinMode(MOTEINO_LED, OUTPUT);
digitalWrite(MOTEINO_LED, LOW);
#ifdef USE_SD_CARD
pinMode(SS_PIN_MICROSD, OUTPUT);
digitalWrite(SS_PIN_MICROSD, HIGH);
// Initialize SD Card
if ( SD.begin(SS_PIN_MICROSD) )
{ Serial.println(F("\ncard initialized")); }
else
{ Serial.println(F("\nCard failed, or not present")); }
#endif
// Setup Moteino radio
radio.initialize();
radio.setChannel(0); // Frequency - Channel is *not* set in the initialization. Need to do it now
delay(10000);
printRadioInfo();
printFreeRam();
Serial.println(F("MoteinoMega test for Davis ISS"));
} // end setup()
//=============================================================================
// Main loop()
//=============================================================================
void loop()
{
bool haveFreshWeatherData = getWirelessData();
#ifdef USE_SD_CARD
if ( haveFreshWeatherData )
{ logDataToSdCard( g_windDirection_Now ); }
#endif
// Heartbeat LED
static uint32_t heartBeatLedTimer = millis();
if ( (long)(millis() - heartBeatLedTimer) > 200 )
{
digitalWrite(MOTEINO_LED, !digitalRead(MOTEINO_LED));
heartBeatLedTimer = millis();
}
} // end loop()
//=============================================================================
// Read wireless data coming from Davis ISS weather station
//=============================================================================
bool getWirelessData()
{
static uint32_t lastRxTime = 0; // timestamp of last received data. Doesn't have to be good data
static byte hopCount = 0;
bool gotGoodData = false;
// Process ISS packet
if ( radio.receiveDone() )
{
packetStats.packetsReceived++;
// check CRC
unsigned int crc = radio.crc16_ccitt(radio.DATA, 6);
if ((crc == (word(radio.DATA[6], radio.DATA[7]))) && (crc != 0))
{
processPacket();
packetStats.receivedStreak++;
hopCount = 1;
gotGoodData = true;
}
else
{
packetStats.crcErrors++;
packetStats.receivedStreak = 0;
Serial.print("CRC errors ");
Serial.println(packetStats.crcErrors);
}
// Whether CRC is right or not, we count that as reception and hop
lastRxTime = millis();
radio.hop();
} // end if(radio.receiveDone())
// If a packet was not received at the expected time, hop the radio anyway
// in an attempt to keep up. Give up after 25 failed attempts. Keep track
// of packet stats as we go. I consider a consecutive string of missed
// packets to be a single resync. Thx to Kobuki for this algorithm.
const uint16_t PACKET_INTERVAL = 2555;
if ( (hopCount > 0) && ((millis() - lastRxTime) > (hopCount * PACKET_INTERVAL + 200)) )
{
packetStats.packetsMissed++;
if (hopCount == 1)
{ packetStats.numResyncs++; }
if (++hopCount > 25)
{ hopCount = 0; }
radio.hop();
}
return gotGoodData;
} // end getWirelessData()
//=========================================================================================================
// Log data to SD Card
//=========================================================================================================
bool logDataToSdCard(float testData)
{
#ifdef USE_SD_CARD
// Build log file name: YYYYMMDD.log
char logfile[13];
sprintf(logfile, "%02d%02d%02d.log", 2015, 1, 11);
// Check to see if the file exists:
if (!SD.exists(logfile))
{
// log file doesn't exist, create it
File newFile = SD.open(logfile, FILE_WRITE);
// Create header row
newFile.print(F("Timestamp\tRx delta sec\tWind Dir")); // time stamp in minutes since reboot, Rx delta sec is seconds between date received
newFile.println();
newFile.close();
}
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open(logfile, FILE_WRITE);
// if the file is available, write to it:
static uint32_t lastRxTime = millis();
if (dataFile)
{
dataFile.print(millis() / 60000L ); // minutes since startup
dataFile.print(F("\t"));
dataFile.print((millis() - lastRxTime)/1000L); // seconds from last time data was receied
dataFile.print(F("\t"));
dataFile.print(testData);
dataFile.println();
dataFile.close();
lastRxTime = millis(); // timestamp for when data was received
return true;
}
// if the file isn't open, pop up an error:
else
{
Serial.print(F("error opening "));
Serial.println(logfile);
return false;
}
#endif
} // logDataToSdCard()
//=============================================================================
// Read the data from the ISS
//=============================================================================
void processPacket()
{
// Flags are set true as each variable comes in for the first time
static bool gotTempData = false;
static bool gotHumidityData = false;
static bool gotRainData = false;
uint16_t rainSeconds = 0; // seconds between rain bucket tips
byte byte4MSN = 0; // Holds MSB of byte 4 - used for seconds between bucket tips
// station ID - the low order three bits are the station ID. Station ID 1 is 0 in this data
byte stationId = (radio.DATA[0] & 0x07) + 1;
if ( stationId != TRANSMITTER_STATION_ID )
{ return; } // exit function if this isn't the station ID program is monitoring
// Every packet has wind speed, wind direction and battery status in it
g_windSpeed = radio.DATA[1];
// There is a dead zone on the wind vane. No values are reported between 8
// and 352 degrees inclusive. These values correspond to received byte
// values of 1 and 255 respectively
// See http://www.wxforum.net/index.php?topic=21967.50
// float windDir = 9 + radio.DATA[2] * 342.0f / 255.0f; - formula has dead zone from 352 to 10 degrees
if ( radio.DATA[2] == 0 )
{ g_windDirection_Now = 0; }
else
{ g_windDirection_Now = ((float)radio.DATA[2] * 1.40625) + 0.3; } // This formula doesn't have dead zone, see: http://bit.ly/1uxc9sf
// 0 = battery ok, 1 = battery low. Not used by anything in program
byte transmitterBatteryStatus = (radio.DATA[0] & 0x8) >> 3;
// Look at MSB in firt byte to get data type
switch (radio.DATA[0] >> 4)
{
case ISS_OUTSIDE_TEMP:
g_outsideTemperature = (int16_t)(word(radio.DATA[3], radio.DATA[4])) >> 4;
gotTempData = true; // one-time flag when data first arrives. Used to track when all the data has arrived and can be sent to PWS
break;
case ISS_HUMIDITY:
// Round humidity to nearest integer
g_outsideHumidity = (byte) ( (float)( word((radio.DATA[4] >> 4), radio.DATA[3]) ) / 10.0 + 0.5 );
gotHumidityData = true; // one-time flag when data first arrives
break;
case ISS_WIND_GUST:
g_windgustmph = radio.DATA[3];
break;
case ISS_RAIN:
g_rainCounter = radio.DATA[3];
gotRainData = true; // one-time flag when data first arrives
break;
case ISS_RAIN_SECONDS: // Seconds between bucket tips, used to calculate rain rate. See: http://www.wxforum.net/index.php?topic=10739.msg190549#msg190549
byte4MSN = radio.DATA[4] >> 4;
if ( byte4MSN < 4 )
{ rainSeconds = (radio.DATA[3] >> 4) + radio.DATA[4] - 1; }
else
{ rainSeconds = radio.DATA[3] + (byte4MSN - 4) * 256; }
break;
default:
break;
}
printData(rainSeconds); // Print data, useful for debuggging
} // end processPacket()
//=============================================================================
// Prints radio channel and RSSI
//=============================================================================
void printRadioInfo()
{
Serial.print(F("ISS ID "));
Serial.print((radio.DATA[0] & 0x07) + 1);
Serial.print(F("\tch: "));
Serial.print(radio.CHANNEL);
Serial.print(F("\tRSSI: "));
Serial.println(radio.RSSI);
} // end printRadioInfo()
//=============================================================================
// print ISS data packet in Hex
//=============================================================================
void printPacket()
{
for (byte i = 0; i < DAVIS_PACKET_LEN; i++)
{
if( radio.DATA[i] < 16 )
{ Serial.print(F("0"));} // leading zero
Serial.print(radio.DATA[i], HEX);
Serial.print(F(" "));
}
} // end printPacket()
//=============================================================================
// Prints KSS data - used for debugging
//=============================================================================
void printData(uint16_t rainSeconds)
{
static uint32_t timeElapsed = millis(); // time elapsed since last tiem printData() was called. Pretty much the same as time between data packets received
static byte headerCounter = 0;
// Header
if (headerCounter == 0)
{ Serial.println("RxTime\tR-Cnt\tdaily\tr_secs\tr-rate\tmillis_sec\tspeed\tgusts\tAvgDir\tNowDir\ttemp\thumid\t\tpacket"); }
if( headerCounter++ > 20)
{ headerCounter = 0; }
Serial.print(millis() - timeElapsed);
Serial.print("\t");
Serial.print(g_rainCounter);
Serial.print("\t");
Serial.print(g_dayRain);
Serial.print("\t");
Serial.print(rainSeconds);
Serial.print("\t");
Serial.print(g_rainRate);
Serial.print("\t");
Serial.print(millis()/1000);
Serial.print("\t");
Serial.print(g_windSpeed);
Serial.print("\t");
Serial.print(g_windgustmph);
Serial.print("\t");
Serial.print(g_windDirection_Now);
Serial.print("\t");
Serial.print(g_windDirection_Avg);
Serial.print("\t");
Serial.print(g_outsideTemperature);
Serial.print("\t");
Serial.print(g_outsideHumidity);
Serial.print("\t");
printPacket();
Serial.println();
timeElapsed = millis(); // save new timestamp
} // end printData()
//=============================================================================
// Prints free RAM
//=============================================================================
void printFreeRam()
{
extern int __heap_start, *__brkval;
int v;
Serial.print(F("Free mem: "));
Serial.println((int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval));
} // end printFreeRam()
@dmolner
Copy link

dmolner commented Feb 22, 2015

Hello,
I have a problem.
When compile I have this message:

MoteinoMega_Davis_ISS_Test.ino:314: undefined reference to `DavisRFM69::DATA'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment