// The Arduino library is needed for every Arduino program. #include // EnableInterrupt is used by ModularSensors for external and pin change // interrupts and must be explicitly included in the main program. #include // To get all of the base classes for ModularSensors, include LoggerBase. // NOTE: Individual sensor definitions must be included separately. #include /** End [includes] */ // ========================================================================== // Data Logging Options // ========================================================================== /** Start [logging_options] */ // The name of this program file const char* sketchName = "ECU_Xbee_mDot_LoRa"; // Logger ID, also becomes the prefix for the name of the data file on SD card const char* LoggerID = "2021-001"; // How frequently (in minutes) to log data const uint8_t loggingInterval = 5; // Your logger's timezone. const int8_t timeZone = -5; // Eastern Standard Time // NOTE: Daylight savings time will not be applied! Please use standard time! // Set the input and output pins for the logger // NOTE: Use -1 for pins that do not apply const int32_t serialBaud = 115200; // Baud rate for debugging const int8_t greenLED = 8; // Pin for the green LED const int8_t redLED = 9; // Pin for the red LED const int8_t buttonPin = 21; // Pin for debugging mode (ie, button pin) const int8_t wakePin = A7; // MCU interrupt/alarm pin to wake from sleep // Set the wake pin to -1 if you do not want the main processor to sleep. // In a SAMD system where you are using the built-in rtc, set wakePin to 1 const int8_t sdCardPwrPin = -1; // MCU SD card power pin const int8_t sdCardSSPin = 12; // SD card chip select/slave select pin const int8_t sensorPowerPin = 22; // MCU pin controlling main sensor power /** End [logging_options] */ // Create a reference to the serial port for the modem HardwareSerial& modemSerial = Serial1; // Use hardware serial if possible const int32_t modemBaud = 9600; // All XBee's use 9600 by default // Modem Pins - Describe the physical pin connection of your modem to your board // NOTE: Use -1 for pins that do not apply const int8_t modemVccPin = -2; // MCU pin controlling modem power const int8_t modemStatusPin = 19; // MCU pin used to read modem status const bool useCTSforStatus = false; // Flag to use the modem CTS pin for status const int8_t modemResetPin = 20; // MCU pin connected to modem reset pin const int8_t modemLEDPin = redLED; // MCU pin connected an LED to show modem // status (-1 if unconnected) const int mDotResetPin = A0; // Important: Ensure Arduino A0 is connected to mDot pin 5 const int8_t XBEE_SleepPin = 23; // Set the sleep pin for the Xbee. // ========================================================================== // Using the Processor as a Sensor // ========================================================================== /** Start [processor_sensor] */ #include // Create the main processor chip "sensor" - for general metadata const char* mcuBoardVersion = "v0.5b"; ProcessorStats mcuBoard(mcuBoardVersion); /** End [processor_sensor] */ // ========================================================================== // Maxim DS3231 RTC (Real Time Clock) // ========================================================================== /** Start [ds3231] */ #include // Create a DS3231 sensor object MaximDS3231 ds3231(1); /** End [ds3231] */ // ========================================================================== // Campbell OBS 3 / OBS 3+ Analog Turbidity Sensor // ========================================================================== /** Start [obs3] */ #include const int8_t OBS3Power = sensorPowerPin; // Power pin (-1 if unconnected) const uint8_t OBS3NumberReadings = 10; const uint8_t ADSi2c_addr = 0x48; // The I2C address of the ADS1115 ADC // Campbell OBS 3+ *Low* Range Calibration in Volts const int8_t OBSLowADSChannel = 0; // ADS channel for *low* range output const float OBSLow_A = 0.000E+00; // "A" value (X^2) [*low* range] const float OBSLow_B = 1.000E+00; // "B" value (X) [*low* range] const float OBSLow_C = 0.000E+00; // "C" value [*low* range] // Create a Campbell OBS3+ *low* range sensor object CampbellOBS3 osb3low(OBS3Power, OBSLowADSChannel, OBSLow_A, OBSLow_B, OBSLow_C, ADSi2c_addr, OBS3NumberReadings); // Campbell OBS 3+ *High* Range Calibration in Volts const int8_t OBSHighADSChannel = 1; // ADS channel for *high* range output const float OBSHigh_A = 0.000E+00; // "A" value (X^2) [*high* range] const float OBSHigh_B = 1.000E+00; // "B" value (X) [*high* range] const float OBSHigh_C = 0.000E+00; // "C" value [*high* range] // Create a Campbell OBS3+ *high* range sensor object CampbellOBS3 osb3high(OBS3Power, OBSHighADSChannel, OBSHigh_A, OBSHigh_B, OBSHigh_C, ADSi2c_addr, OBS3NumberReadings); /** End [obs3] */ // ========================================================================== // Meter Hydros 21 Conductivity, Temperature, and Depth Sensor // ========================================================================== /** Start [decagon_ctd] */ #include const char* CTDSDI12address = "1"; // The SDI-12 Address of the CTD const uint8_t CTDNumberReadings = 6; // The number of readings to average const int8_t SDI12Power = sensorPowerPin; // Power pin (-1 if unconnected) const int8_t SDI12Data = 7; // The SDI12 data pin // Create a Decagon CTD sensor object DecagonCTD ctd(*CTDSDI12address, SDI12Power, SDI12Data, CTDNumberReadings); /** End [decagon_ctd] */ // ========================================================================== // Creating the Variable Array[s] and Filling with Variable Objects // ========================================================================== /** Start [variable_arrays] */ Variable* variableList[] = { new DecagonCTD_Cond(&ctd), new DecagonCTD_Temp(&ctd), new DecagonCTD_Depth(&ctd), new CampbellOBS3_Turbidity(&osb3low, "", "TurbLow"), new CampbellOBS3_Turbidity(&osb3high, "", "TurbHigh"), new ProcessorStats_Battery(&mcuBoard), new MaximDS3231_Temp(&ds3231), }; // Count up the number of pointers in the array int variableCount = sizeof(variableList) / sizeof(variableList[0]); // Create the VariableArray object VariableArray varArray(variableCount, variableList); /** End [variable_arrays] */ // ========================================================================== // Creating The Things Network Objects // ========================================================================== // Set your AppEUI and AppKey const char *appEui = "70B3D57ED0037B14"; const char *appKey = "FFD7F99EE14E074CCBEDC5C0A09B1E29"; // ========================================================================== // The Logger Object[s] // ========================================================================== /** Start [loggers] */ // Create a new logger instance Logger dataLogger(LoggerID, loggingInterval, &varArray); /** End [loggers] */ // ========================================================================== // Working Functions // ========================================================================== /** Start [working_functions] */ // Flashes the LED's on the primary board void greenredflash(uint8_t numFlash = 4, uint8_t rate = 75) { for (uint8_t i = 0; i < numFlash; i++) { digitalWrite(greenLED, HIGH); digitalWrite(redLED, LOW); delay(rate); digitalWrite(greenLED, LOW); digitalWrite(redLED, HIGH); delay(rate); } digitalWrite(redLED, LOW); } // Reads the battery voltage // NOTE: This will actually return the battery level from the previous update! float getBatteryVoltage() { if (mcuBoard.sensorValues[0] == -9999) mcuBoard.update(); return mcuBoard.sensorValues[0]; } /** End [working_functions] */ // ========================================================================== // Arduino Setup Function // ========================================================================== /** Start [setup] */ void setup() { // Start the primary serial connection Serial.begin(serialBaud); Serial1.begin(modemBaud); pinMode(greenLED, OUTPUT); //Green LED pinMode(redLED, OUTPUT); //Red LED digitalWrite(greenLED, HIGH); //turn on the Green LED and leave it on digitalWrite(redLED, LOW); //turn off the Red LED, we'll use it later to indicate Xbee wake // Print a start-up note to the first serial port Serial.print(F("Now running ")); Serial.print(sketchName); Serial.print(F(" on Logger ")); Serial.println(LoggerID); Serial.println(); Serial.print(F("Using ModularSensors Library version ")); Serial.println(MODULAR_SENSORS_VERSION); // Set the timezones for the logger/data and the RTC // Logging in the given time zone Logger::setLoggerTimeZone(timeZone); // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0) Logger::setRTCTimeZone(0); // Attach information pins to the logger dataLogger.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin, greenLED); // dataLogger.setSamplingFeatureUUID(samplingFeature); // Begin the logger dataLogger.begin(); // Note: Please change these battery voltages to match your battery // Set up the sensors, except at lowest battery level if (getBatteryVoltage() > 3.4) { Serial.println(F("Setting up sensors...")); varArray.setupSensors(); } // Create the log file, adding the default header to it // Do this last so we have the best chance of getting the time correct and // all sensor names correct // Writing to the SD card can be power intensive, so if we're skipping // the sensor setup we'll skip this too. if (getBatteryVoltage() > 3.4) { Serial.println(F("Setting up file on SD card")); dataLogger.turnOnSDcard( true); // true = wait for card to settle after power up dataLogger.createLogFile(true); // true = write a new header dataLogger.turnOffSDcard( true); // true = wait for internal housekeeping after write } // Call the processor sleep Serial.println(F("Putting processor to sleep\n")); dataLogger.systemSleep(); } /** End [setup] */ void sleepXbee(){ Serial.println("Putting the Xbee to sleep"); delay(100); pinMode(XBEE_SleepPin, INPUT_PULLUP); // Set the "wake-up pin" to output digitalWrite(XBEE_SleepPin,HIGH); //put the Xbee to sleep digitalWrite(redLED, LOW); //turn off the RED LED when the Xbee is asleep } void wakeXbee() { Serial.println("Waking up the Xbee"); delay(100); pinMode(XBEE_SleepPin, OUTPUT); // Set the "wake-up pin" to output digitalWrite(XBEE_SleepPin,LOW); // wake-up XBee digitalWrite(redLED, HIGH); // turn on the RED LED when the Xbee is awake } // ========================================================================== // Arduino Loop Function // ========================================================================== /** Start [loop] */ // Use this short loop for simple data logging and sending void loop() { // Note: Please change these battery voltages to match your battery // At very low battery, just go back to sleep if (getBatteryVoltage() < 3.4) { dataLogger.systemSleep(); Serial.println(F("The battery is too low for operation.")); } // If the battery is OK, log data else { dataLogger.logData(); } String response; wakeXbee(); delay(3000); //give the Xbee a few seconds to wake up and be seen by the network // Send test message to The Things network // Register with The Things network //Serial.println("Check current settings"); //Serial.println("AT&V"); //Serial1.println("AT&V"); // Read the response and print to the serial monitor //response = Serial1.readStringUntil('\n'); //Serial.println("Response: " + response); // Set the LoRa sub-band to the US version 915 Serial.println("Flushing the Serial port"); Serial1.flush(); delay(500); Serial.println("Check what band the module is set for."); Serial.println("Sending command: AT+FREQ"); //Serial1.println("AT+IPR=9600"); //Serial1.println("AT&W"); //Serial1.println("ATZ"); // Read the response and print to the serial monitor // Clear out the serial1 getBuffer delay(500); Serial1.print("AT+FREQ"); response = Serial1.readStringUntil('\n'); delay(5000); Serial.println("Response: " + response); Serial1.flush(); // Set the LoRa sub-band to the US version 915 //Serial.println("Setting the frequency to 915MHz (US BAND)"); //Serial.println("AT+FSB=0"); //Serial1.println("AT+FSB=0"); // Read the response and print to the serial monitor //response = Serial1.readString(); //Serial.println("Response: " + response); // Send the AppEUI //Serial.println("Sending the AppEUI to the network."); //Serial.println("AT+NI=0,70B3D57ED0037B14"); //Serial1.println("AT+NI=0,70B3D57ED0037B14"); // Read the response and print to the serial monitor //response = Serial1.readString(); //Serial.println("Response: " + response); // Send the AppKey //Serial.println("Sending the AppKey to the network."); //Serial.println("AT+NK=0,FFD7F99EE14E074CCBEDC5C0A09B1E29"); //Serial1.println("AT+NK=0,FFD7F99EE14E074CCBEDC5C0A09B1E29"); // Read the response and print to the serial monitor //response = Serial1.readString(); //Serial.println("Response: " + response); // Set the device to OTA join mode //Serial.println("Setting the device to use OTA join mode"); //Serial1.println("AT+NJM=1"); // Read the response and print to the serial monitor //response = Serial1.readString(); //Serial.println("Response: " + response); // Set the device to OTA join mode //Serial.println("Join the nework"); //Serial1.println("AT+JOIN"); // Read the response and print to the serial monitor //response = Serial1.readString(); //Serial.println("Response: " + response); // Send a test message //Serial.println("Sending a test message."); //Serial.println("AT+SEND=THIS IS A TEST"); //Serial1.println("AT+SEND=THIS IS A TEST"); // Read the response and print to the serial monitor //response = Serial1.readString(); //Serial.println("Response: " + response); delay(3000); //give the Xbee a few seconds before putting it back to sleep sleepXbee(); } /** End [loop] */