diff --git a/.github/workflows/BuildLibrary.yml b/.github/workflows/BuildLibrary.yml index 3f362de..2b1f9ae 100644 --- a/.github/workflows/BuildLibrary.yml +++ b/.github/workflows/BuildLibrary.yml @@ -19,7 +19,7 @@ jobs: # Space separated list without double quotes around the list. # If you need a library with a space in its name, like Adafruit NeoPixel or Adafruit INA219, you must use double quotes # around the name and have at least 2 entries, where the first must be without double quotes! You may use Servo as dummy entry. - REQUIRED_LIBRARIES: TheThingsNetwork "SparkFun MPL3115A2 Altitude and Pressure Sensor Breakout" "SparkFun HTU21D Humidity and Temperature Sensor Breakout" ArduinoJson + REQUIRED_LIBRARIES: ArduinoJson "Beelan LoRaWAN" "SparkFun MPL3115A2 Altitude and Pressure Sensor Breakout" "SparkFun HTU21D Humidity and Temperature Sensor Breakout" strategy: matrix: @@ -39,6 +39,7 @@ jobs: - arduino:samd:nano_33_iot - arduino:mbed:nano33ble - esp8266:esp8266:huzzah:eesz=4M3M,xtal=80 + - esp32:esp32:featheresp32:FlashFreq=80 - STM32:stm32:GenF1:pnum=BLUEPILL_F103C8 # Specify parameters for each board. @@ -57,6 +58,10 @@ jobs: - arduino-boards-fqbn: esp8266:esp8266:huzzah:eesz=4M3M,xtal=80 platform-url: https://arduino.esp8266.com/stable/package_esp8266com_index.json + - arduino-boards-fqbn: esp32:esp32:featheresp32:FlashFreq=80 + platform-url: https://dl.espressif.com/dl/package_esp32_index.json + examples-exclude: Basic_LoRaWAN_Beelan + - arduino-boards-fqbn: STM32:stm32:GenF1:pnum=BLUEPILL_F103C8 platform-url: https://github.com/stm32duino/BoardManagerFiles/raw/dev/STM32/package_stm_index.json @@ -76,4 +81,4 @@ jobs: arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} platform-url: ${{ matrix.platform-url }} libraries: ${{ env.REQUIRED_LIBRARIES }} - examples-exclude: DetectingReaders \ No newline at end of file + examples-exclude: ${{ matrix.examples-exclude }} \ No newline at end of file diff --git a/README.md b/README.md index 3a4b80a..c8c376e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![LibraryBuild](https://github.com/ElectronicCats/CayenneLPP/workflows/LibraryBuild/badge.svg?branch=master) + # CayenneLPP This is an Arduino Library for Arduino Compatible with Cayenne Low Power Payload with Extended Data Types. diff --git a/examples/Basic_LoRaWAN_Beelan/Basic_LoRaWAN_Beelan.ino b/examples/Basic_LoRaWAN_Beelan/Basic_LoRaWAN_Beelan.ino new file mode 100644 index 0000000..dd4cfd7 --- /dev/null +++ b/examples/Basic_LoRaWAN_Beelan/Basic_LoRaWAN_Beelan.ino @@ -0,0 +1,83 @@ +/** + * Example of ABP device + * Authors: + * Ivan Moreno + * Eduardo Contreras + * June 2019 + * + * This code is beerware; if you see me (or any other collaborator + * member) at the local, and you've found our code helpful, + * please buy us a round! + * Distributed as-is; no warranty is given. + */ +#include + +//ABP Credentials +const char *devAddr = "00000000"; +const char *nwkSKey = "00000000000000000000000000000000"; +const char *appSKey = "00000000000000000000000000000000"; + +const unsigned long interval = 10000; // 10 s interval to send message +unsigned long previousMillis = 0; // will store last time message sent +unsigned int counter = 0; // message counter + +char myStr[50]; +char outStr[255]; +byte recvStatus = 0; + +const sRFM_pins RFM_pins = { + .CS = 20, + .RST = 9, + .DIO0 = 0, + .DIO1 = 1, + .DIO2 = 2, + .DIO5 = 15, +}; + +void setup() { + // Setup loraid access + Serial.begin(115200); + delay(2000); + if(!lora.init()){ + Serial.println("RFM95 not detected"); + delay(5000); + return; + } + + // Set LoRaWAN Class change CLASS_A or CLASS_C + lora.setDeviceClass(CLASS_A); + + // Set Data Rate + lora.setDataRate(SF8BW125); + + // set channel to random + lora.setChannel(MULTI); + + // Put ABP Key and DevAddress here + lora.setNwkSKey(nwkSKey); + lora.setAppSKey(appSKey); + lora.setDevAddr(devAddr); +} + +void loop() { + // Check interval overflow + if(millis() - previousMillis > interval) { + previousMillis = millis(); + + sprintf(myStr, "Counter-%d", counter); + + Serial.print("Sending: "); + Serial.println(myStr); + + lora.sendUplink(myStr, strlen(myStr), 0); + counter++; + } + + recvStatus = lora.readData(outStr); + if(recvStatus) { + Serial.println(outStr); + } + + // Check Lora RX + lora.update(); +} \ No newline at end of file diff --git a/examples/Basic_library_TTN/Basic_library_TTN.ino b/examples/Basic_library_TTN/Basic_library_TTN.ino deleted file mode 100644 index b242f3c..0000000 --- a/examples/Basic_library_TTN/Basic_library_TTN.ino +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -// Set your AppEUI and AppKey -const char *appEui = "0000000000000000"; -const char *appKey = "00000000000000000000000000000000"; - -#define loraSerial Serial1 -#define debugSerial Serial - -// Replace REPLACE_ME with TTN_FP_EU868 or TTN_FP_US915 -#define freqPlan TTN_FP_US915 - -TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); -CayenneLPP lpp(51); - -void setup() -{ - loraSerial.begin(57600); - debugSerial.begin(9600); - - // Wait a maximum of 10s for Serial Monitor - while (!debugSerial && millis() < 10000) - ; - - debugSerial.println("-- STATUS"); - ttn.showStatus(); - - debugSerial.println("-- JOIN"); - ttn.join(appEui, appKey); -} - -void loop() -{ - debugSerial.println("-- LOOP"); - - lpp.reset(); - lpp.addTemperature(1, 22.5); - lpp.addBarometricPressure(2, 1073.21); - lpp.addGPS(3, 52.37365, 4.88650, 2); - - // Send it off - ttn.sendBytes(lpp.getBuffer(), lpp.getSize()); - - delay(10000); -} diff --git a/examples/WeatherStation_LMIC/WeatherStation_LMIC.ino b/examples/WeatherStation_LMIC/WeatherStation_LMIC.ino deleted file mode 100644 index d24a6e4..0000000 --- a/examples/WeatherStation_LMIC/WeatherStation_LMIC.ino +++ /dev/null @@ -1,598 +0,0 @@ -/* - LoRaWAN Weather Station Example - By: Eduardo Contreras and Andres Sabas - Electronic Cats - - By: Nathan Seidle - SparkFun Electronics - Date: Jun 27, 2017 - 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 is a more advanced example of how to utilize every aspect of the weather shield. See the basic - example if you're just getting started. - - 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. - Hardware: - - Shield Weather Station SparkFun - - Shield LoRa ElectronicCats - - Arduino MEGA - */ - -#include //I2C needed for sensors -#include "SparkFunMPL3115A2.h" //Pressure sensor - Search "SparkFun MPL3115" and install from Library Manager -#include "SparkFunHTU21D.h" //Humidity sensor - Search "SparkFun HTU21D" and install from Library Manager -#include -#include -#include -#include - -CayenneLPP lpp(51); - -MPL3115A2 myPressure; //Create an instance of the pressure sensor -HTU21D myHumidity; //Create an instance of the humidity sensor - -//Hardware pin definitions -//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -// digital I/O pins -const byte WSPEED = 18; -const byte RAIN = 19; -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; - -//We need to keep track of the following variables: -//Wind speed/dir each update (no storage) -//Wind gust/dir over the day (no storage) -//Wind speed/dir, avg over 2 minutes (store 1 per second) -//Wind gust/dir over last 10 minutes (store 1 per minute) -//Rain over the past hour (store 1 per minute) -//Total rain over date (store one per day) - -byte windspdavg[120]; //120 bytes to keep track of 2 minute average - -#define WIND_DIR_AVG_SIZE 120 -int winddiravg[WIND_DIR_AVG_SIZE]; //120 ints to keep track of 2 minute average -float windgust_10m[10]; //10 floats to keep track of 10 minute max -int windgustdirection_10m[10]; //10 ints to keep track of 10 minute max -volatile float rainHour[60]; //60 floating numbers to keep track of 60 minutes of rain - -//These are all the weather values that wunderground expects: -int winddir = 0; // [0-360 instantaneous wind direction] -float windspeedmph = 0; // [mph instantaneous wind speed] -float windgustmph = 0; // [mph current wind gust, using software specific time period] -int windgustdir = 0; // [0-360 using software specific time period] -float windspdmph_avg2m = 0; // [mph 2 minute average wind speed mph] -int winddir_avg2m = 0; // [0-360 2 minute average wind direction] -float windgustmph_10m = 0; // [mph past 10 minutes wind gust mph ] -int windgustdir_10m = 0; // [0-360 past 10 minutes wind gust direction] -float humidity = 0; // [%] -float tempf = 0; // [temperature F] -float rainin = 0; // [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min -volatile float dailyrainin = 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] - -// This EUI must be in little-endian format, so least-significant-byte -// first. When copying an EUI from ttnctl output, this means to reverse -// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, -// 0x70. -static const u1_t PROGMEM APPEUI[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; -void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);} - -// This should also be in little endian format, see above. -static const u1_t PROGMEM DEVEUI[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; -void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} - -// This key should be in big endian format (or, since it is not really a -// number but a block of memory, endianness does not really apply). In -// practice, a key taken from ttnctl can be copied as-is. -// The key shown here is the semtech default key. -static const u1_t PROGMEM APPKEY[16] = {0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x14,0x82}; -void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} - -static osjob_t sendjob; - -// Schedule TX every this many seconds (might become longer due to duty -// cycle limitations). -const unsigned TX_INTERVAL = 10; - -// Pin mapping -const lmic_pinmap lmic_pins = { - .nss = 53, - .rxtx = LMIC_UNUSED_PIN, - .rst = 9, - .dio = {2, 3, 4}, //Pines empalmados -}; - -void onEvent (ev_t ev) { - Serial.print(os_getTime()); - Serial.print(": "); - switch(ev) { - case EV_SCAN_TIMEOUT: - Serial.println(F("EV_SCAN_TIMEOUT")); - break; - case EV_BEACON_FOUND: - Serial.println(F("EV_BEACON_FOUND")); - break; - case EV_BEACON_MISSED: - Serial.println(F("EV_BEACON_MISSED")); - break; - case EV_BEACON_TRACKED: - Serial.println(F("EV_BEACON_TRACKED")); - break; - case EV_JOINING: - Serial.println(F("EV_JOINING")); - break; - case EV_JOINED: - Serial.println(F("EV_JOINED")); - - // Disable link check validation (automatically enabled - // during join, but not supported by TTN at this time). - LMIC_setLinkCheckMode(0); - // turn on interrupts - interrupts(); - break; - case EV_RFU1: - Serial.println(F("EV_RFU1")); - break; - case EV_JOIN_FAILED: - Serial.println(F("EV_JOIN_FAILED")); - break; - case EV_REJOIN_FAILED: - Serial.println(F("EV_REJOIN_FAILED")); - break; - break; - case EV_TXCOMPLETE: - Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); - if (LMIC.txrxFlags & TXRX_ACK) - Serial.println(F("Received ack")); - if (LMIC.dataLen) { - Serial.println(F("Received ")); - Serial.println(LMIC.dataLen); - Serial.println(F(" bytes of payload")); - } - // Schedule next transmission - os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); - break; - case EV_LOST_TSYNC: - Serial.println(F("EV_LOST_TSYNC")); - break; - case EV_RESET: - Serial.println(F("EV_RESET")); - break; - case EV_RXCOMPLETE: - // data received in ping slot - Serial.println(F("EV_RXCOMPLETE")); - break; - case EV_LINK_DEAD: - Serial.println(F("EV_LINK_DEAD")); - break; - case EV_LINK_ALIVE: - Serial.println(F("EV_LINK_ALIVE")); - break; - default: - Serial.println(F("Unknown event")); - break; - } -} - -void do_send(osjob_t* j){ - // Check if there is not a current TX/RX job running - if (LMIC.opmode & OP_TXRXPEND) { - Serial.println(F("OP_TXRXPEND, not sending")); - } else { - // Prepare upstream data transmission at the next possible time. - printWeather(); - LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0); - Serial.println(F("Packet queued")); - - } - // Next TX is scheduled after TX_COMPLETE event. -} - -// 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.011; //Each dump is 0.011" of water - rainHour[minutes] += 0.011; //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 (142MPH max reading) after the reed switch closes - { - lastWindIRQ = millis(); //Grab the current time - windClicks++; //There is 1.492MPH for each click per second. - } -} - - -void setup() -{ - Serial.begin(115200); - - 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); - - // LMIC init - os_init(); - // Reset the MAC state. Session and pending data transfers will be discarded. - LMIC_reset(); - - //Configuration for SubBand 7 - for (int channel=0; channel<72; ++channel) { - LMIC_disableChannel(channel); - } - - LMIC_enableChannel(48); - LMIC_enableChannel(49); - LMIC_enableChannel(50); - LMIC_enableChannel(51); - LMIC_enableChannel(52); - LMIC_enableChannel(53); - LMIC_enableChannel(54); - LMIC_enableChannel(55); - LMIC_enableChannel(70); - - // TTN uses SF9 for its RX2 window. This is configured in the - // join accept message, but the LMIC library does not currently - // process this part of the join accept yet (see Arduino-LMIC issue #20). - LMIC.dn2Dr = DR_SF9; - - // Use a fixed data rate of SF9 (not sure if tx power is - // actually used). SF9 is the lowest datarate that (withing the - // TTN fair-usage-policy of 30 seconds of airtime per day) - // allows us to send at least 4 packets every hour. - LMIC_setDrTxpow(DR_SF7, 14); - - // Let LMIC compensate for +/- 1% clock error - LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); - - - //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(F("Weather Shield online!")); - - // Start job (sending automatically starts OTAA too) - do_send(&sendjob); - -} - -void loop() -{ - - //Keep track of which minute it is - if(millis() - lastSecond >= 1000) - { - digitalWrite(STAT1, HIGH); //Blink stat LED - - lastSecond += 1000; - - //Take a speed and direction reading every second for 2 minute average - if(++seconds_2m > 119) seconds_2m = 0; - - //Calc the wind speed and direction every second for 120 second to get 2 minute average - float currentSpeed = get_wind_speed(); - windspeedmph = currentSpeed; //update global variable for windspeed when using the printWeather() function - //float currentSpeed = random(5); //For testing - int currentDirection = get_wind_direction(); - windspdavg[seconds_2m] = (int)currentSpeed; - winddiravg[seconds_2m] = currentDirection; - //if(seconds_2m % 10 == 0) displayArrays(); //For testing - - //Check to see if this is a gust for the minute - if(currentSpeed > windgust_10m[minutes_10m]) - { - windgust_10m[minutes_10m] = currentSpeed; - windgustdirection_10m[minutes_10m] = currentDirection; - } - - //Check to see if this is a gust for the day - if(currentSpeed > windgustmph) - { - windgustmph = currentSpeed; - windgustdir = currentDirection; - } - - if(++seconds > 59) - { - seconds = 0; - - if(++minutes > 59) minutes = 0; - if(++minutes_10m > 9) minutes_10m = 0; - - rainHour[minutes] = 0; //Zero out this minute's rainfall amount - windgust_10m[minutes_10m] = 0; //Zero out this minute's gust - } - - //Report all readings every second - //printWeather(); - - digitalWrite(STAT1, LOW); //Turn off stat LED - } - - //delay(100); - - os_runloop_once(); -} - -//Calculates each of the variables that wunderground is expecting -void calcWeather() -{ - //Calc winddir - winddir = get_wind_direction(); - - //Calc windspeed - //windspeedmph = get_wind_speed(); //This is calculated in the main loop on line 179 - - //Calc windgustmph - //Calc windgustdir - //These are calculated in the main loop - - //Calc windspdmph_avg2m - float temp = 0; - for(int i = 0 ; i < 120 ; i++) - temp += windspdavg[i]; - temp /= 120.0; - windspdmph_avg2m = temp; - - //Calc winddir_avg2m, Wind Direction - //You can't just take the average. Google "mean of circular quantities" for more info - //We will use the Mitsuta method because it doesn't require trig functions - //And because it sounds cool. - //Based on: http://abelian.org/vlf/bearings.html - //Based on: http://stackoverflow.com/questions/1813483/averaging-angles-again - long sum = winddiravg[0]; - int D = winddiravg[0]; - for(int i = 1 ; i < WIND_DIR_AVG_SIZE ; i++) - { - int delta = winddiravg[i] - D; - - if(delta < -180) - D += delta + 360; - else if(delta > 180) - D += delta - 360; - else - D += delta; - - sum += D; - } - winddir_avg2m = sum / WIND_DIR_AVG_SIZE; - if(winddir_avg2m >= 360) winddir_avg2m -= 360; - if(winddir_avg2m < 0) winddir_avg2m += 360; - - //Calc windgustmph_10m - //Calc windgustdir_10m - //Find the largest windgust in the last 10 minutes - windgustmph_10m = 0; - windgustdir_10m = 0; - //Step through the 10 minutes - for(int i = 0; i < 10 ; i++) - { - if(windgust_10m[i] > windgustmph_10m) - { - windgustmph_10m = windgust_10m[i]; - windgustdir_10m = windgustdirection_10m[i]; - } - } - - //Calc humidity - humidity = myHumidity.readHumidity(); - //float temp_h = myHumidity.readTemperature(); - //Serial.print(" TempH:"); - //Serial.print(temp_h, 2); - - //Calc tempf from pressure sensor - tempf = myPressure.readTempF(); - //Serial.print(" TempP:"); - //Serial.print(tempf, 2); - - //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(); - - //Calc dewptf - - //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 rawVoltage = analogRead(BATT); - - rawVoltage = (5.00 * rawVoltage) / 1023.0; - - 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 *= 1.492; //4 * 1.492 = 5.968MPH - - /* Serial.println(); - Serial.print("Windspeed:"); - Serial.println(windSpeed);*/ - - 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? -} - - -//Prints the various variables directly to the port -//I don't like the way this function is written but Arduino doesn't support floats under sprintf -void printWeather() -{ - calcWeather(); //Go calc all the various sensors - lpp.reset(); - - Serial.println(); - Serial.print(F("$,winddir=")); - Serial.print(winddir); - lpp.addAnalogInput(1, winddir); - - Serial.print(F(",windspeedmph=")); - Serial.print(windspeedmph, 1); - lpp.addAnalogInput(2, windspeedmph); - - Serial.print(F(",humidity=")); - Serial.print(humidity, 1); - lpp.addRelativeHumidity(3, humidity); - - Serial.print(F(",tempf=")); - Serial.print(tempf, 1); - lpp.addTemperature(4, tempf); - - Serial.print(F(",rainin=")); - Serial.print(rainin, 2); - lpp.addAnalogInput(5, rainin); - - Serial.print(F(",dailyrainin=")); - Serial.print(dailyrainin, 2); - lpp.addAnalogInput(6, dailyrainin); - - Serial.print(F(",pressure=")); - Serial.print((pressure/100.0), 2); - lpp.addBarometricPressure(7,(pressure/100.0)); - - Serial.print(F(",batt_lvl=")); - Serial.print(batt_lvl, 2); - lpp.addAnalogInput(8, batt_lvl); - - Serial.print(F(",light_lvl=")); - Serial.println(light_lvl, 2); - lpp.addLuminosity(9,light_lvl); -}