DRWI Digi LTE Sites

This example uses the sensors and equipment common to older stations (2016-2020) deployed by groups participating in the DRWI Citizen Science project with the Stroud Water Research Center. It includes a Meter Hydros21 CTD (formerly know as a Decagon), a Campbell OBS3+ (Turbidity), and a Digi XBee3 LTE-M cellular board for communication. The Digi LTE module also required the use of a EnviroDIY LTEbee Adapter board (discontinued in 2021). The Digi LTE modules are no longer recommended for use and have been replace by the EnviroDIY LTEbee in all DRWI-SWRC-managed stations.

The exact hardware configuration used in this example:

  • Mayfly v0.5b board
  • Digi XBee LTE module (with Hologram SIM card and EnviroDIY bee adapter)
  • Hydros21 CTD sensor
  • Campbell OBS3+ turbidity sensor


Unique Features of the DRWI Digi LTE Example

  • Specifically for sites within the Delaware River Watershed Initiative.
  • Uses a Digi XBee3 LTE-M for live data.

To Use this Example

Prepare and set up PlatformIO

  • Register a site and sensors at the Monitor My Watershed/EnviroDIY data portal (http://monitormywatershed.org/)
  • Create a new PlatformIO project
  • Replace the contents of the platformio.ini for your new project with the platformio.ini file in the examples/DRWI_DigiLTE folder on GitHub.
    • It is important that your PlatformIO configuration has the lib_ldf_mode and build flags set as they are in the example.
    • Without this, the program won't compile.
  • Open DRWI_DigiLTE.ino and save it to your computer.
    • After opening the link, you should be able to right click anywhere on the page and select "Save Page As".
    • Move it into the src directory of your project.
    • Delete main.cpp in that folder.

Set the logger ID

  • Change the "XXXX" in this section of code to the loggerID assigned by Stroud:
1// Logger ID, also becomes the prefix for the name of the data file on SD card
2const char *LoggerID = "XXXX";

Set the calibration coefficients for the Campbell OBS3+

  • The OBS3+ ships with a calibration certificate; you need this sheet!
  • Change all of the the 0.000E+00 and 1.000E+00 values in this section of code to the values on that calibration sheet. Use numbers from the side of the calibration sheet that shows the calibration in volts.
    • The sketch will not compile if these values are not entered properly.
    • Do not change any values except those that are 0.000E+00 and 1.000E+00!
1// ==========================================================================
2// Campbell OBS 3 / OBS 3+ Analog Turbidity Sensor
3// ==========================================================================
4#include <sensors/CampbellOBS3.h>
5const int8_t OBS3Power = sensorPowerPin; // Power pin (-1 if unconnected)
6const uint8_t OBS3numberReadings = 10;
7const uint8_t ADSi2c_addr = 0x48; // The I2C address of the ADS1115 ADC
8// Campbell OBS 3+ *Low* Range Calibration in Volts
9const int8_t OBSLowADSChannel = 0; // ADS channel for *low* range output
10const float OBSLow_A = 0.000E+00; // "A" value (X^2) [*low* range]
11const float OBSLow_B = 1.000E+00; // "B" value (X) [*low* range]
12const float OBSLow_C = 0.000E+00; // "C" value [*low* range]
13CampbellOBS3 osb3low(OBS3Power, OBSLowADSChannel, OBSLow_A, OBSLow_B, OBSLow_C, ADSi2c_addr, OBS3numberReadings);
14// Campbell OBS 3+ *High* Range Calibration in Volts
15const int8_t OBSHighADSChannel = 1; // ADS channel for *high* range output
16const float OBSHigh_A = 0.000E+00; // "A" value (X^2) [*high* range]
17const float OBSHigh_B = 1.000E+00; // "B" value (X) [*high* range]
18const float OBSHigh_C = 0.000E+00; // "C" value [*high* range]
19CampbellOBS3 osb3high(OBS3Power, OBSHighADSChannel, OBSHigh_A, OBSHigh_B, OBSHigh_C, ADSi2c_addr, OBS3numberReadings);

Set the universally universal identifiers (UUID) for each variable

  • Go back to the web page for your site at the Monitor My Watershed/EnviroDIY data portal (http://monitormywatershed.org/)
  • Find and click the white "View Token UUID List" button above the small map on your site page
  • VERY CAREFULLY check that the variables are in exactly the same order as in the variable array:
1Variable* variableList[] = {
2 ...
3}
  • If any of the variables are in a different order on the web page than in your code reorder the variables in your code to match the website.
  • After you are completely certain that you have the order right in the variable section of your code use the teal "Copy" button on the website to copy the section of code containing all of the UUID's.
  • Paste the code from the website into your program in this section below the variable array
1// *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
2// Check the order of your variables in the variable list!!!
3// Be VERY certain that they match the order of your UUID's!
4// Rearrange the variables in the variable list if necessary to match!
5// *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
6/* clang-format off */
7const char* UUIDs[] = {
8 "12345678-abcd-1234-ef00-1234567890ab", // Electrical conductivity (Decagon_CTD-10_Cond)
9 "12345678-abcd-1234-ef00-1234567890ab", // Temperature (Decagon_CTD-10_Temp)
10 "12345678-abcd-1234-ef00-1234567890ab", // Water depth (Decagon_CTD-10_Depth)
11 "12345678-abcd-1234-ef00-1234567890ab", // Turbidity (Campbell_OBS3_Turb)
12 "12345678-abcd-1234-ef00-1234567890ab", // Turbidity (Campbell_OBS3_Turb)
13 "12345678-abcd-1234-ef00-1234567890ab", // Battery voltage (EnviroDIY_Mayfly_Batt)
14 "12345678-abcd-1234-ef00-1234567890ab", // Temperature (EnviroDIY_Mayfly_Temp)
15 "12345678-abcd-1234-ef00-1234567890ab", // Received signal strength indication (Digi_Cellular_RSSI)
16 "12345678-abcd-1234-ef00-1234567890ab" // Percent full scale (Digi_Cellular_SignalPercent)
17};
18const char* registrationToken = "12345678-abcd-1234-ef00-1234567890ab"; // Device registration token
19const char* samplingFeature = "12345678-abcd-1234-ef00-1234567890ab"; // Sampling feature UUID
20/* clang-format on */

Upload!

  • Test everything at home before deploying out in the wild!

PlatformIO Configuration

1; PlatformIO Project Configuration File
2;
3; Build options: build flags, source filter
4; Upload options: custom upload port, speed and extra flags
5; Library options: dependencies, extra library storages
6; Advanced options: extra scripting
7;
8; Please visit documentation for the other options and examples
9; http://docs.platformio.org/page/projectconf.html
10
11[platformio]
12description = ModularSensors example intended for DRWI users with CTD, turbidity, and a Digi brand LTE modem
13
14[env:mayfly]
15monitor_speed = 57600
16board = mayfly
17platform = atmelavr
18framework = arduino
19lib_ldf_mode = deep+
20lib_ignore =
21 RTCZero
22 Adafruit NeoPixel
23 Adafruit GFX Library
24 Adafruit SSD1306
25 Adafruit ADXL343
26 Adafruit STMPE610
27 Adafruit TouchScreen
28 Adafruit ILI9341
29build_flags =
30 -DSDI12_EXTERNAL_PCINT
31lib_deps =
32 envirodiy/EnviroDIY_ModularSensors
33; ^^ Use this when working from an official release of the library
34; https://github.com/EnviroDIY/ModularSensors.git#develop
35; ^^ Use this when if you want to pull from the develop branch

The Complete Code

1/** =========================================================================
2 * @example{lineno} DRWI_DigiLTE.ino
3 * @copyright Stroud Water Research Center
4 * @license This example is published under the BSD-3 license.
5 * @author Sara Geleskie Damiano <sdamiano@stroudcenter.org>
6 *
7 * @brief Example for DRWI CitSci LTE sites.
8 *
9 * See [the walkthrough page](@ref example_drwi_digilte) for detailed
10 * instructions.
11 *
12 * @m_examplenavigation{example_drwi_digilte,}
13 * ======================================================================= */
14
15// ==========================================================================
16// Defines for TinyGSM
17// ==========================================================================
18/** Start [defines] */
19#ifndef TINY_GSM_RX_BUFFER
20#define TINY_GSM_RX_BUFFER 64
21#endif
22#ifndef TINY_GSM_YIELD_MS
23#define TINY_GSM_YIELD_MS 2
24#endif
25/** End [defines] */
26
27// ==========================================================================
28// Include the libraries required for any data logger
29// ==========================================================================
30/** Start [includes] */
31// The Arduino library is needed for every Arduino program.
32#include <Arduino.h>
33
34// Include the main header for ModularSensors
35#include <ModularSensors.h>
36/** End [includes] */
37
38
39// ==========================================================================
40// Data Logging Options
41// ==========================================================================
42/** Start [logging_options] */
43// The name of this program file
44const char* sketchName = "DRWI_DigiLTE.ino";
45// Logger ID, also becomes the prefix for the name of the data file on SD card
46const char* LoggerID = "XXXXX";
47// How frequently (in minutes) to log data
48const uint8_t loggingInterval = 15;
49// Your logger's timezone.
50const int8_t timeZone = -5; // Eastern Standard Time
51// NOTE: Daylight savings time will not be applied! Please use standard time!
52
53// Set the input and output pins for the logger
54// NOTE: Use -1 for pins that do not apply
55const int32_t serialBaud = 57600; // Baud rate for debugging
56const int8_t greenLED = 8; // Pin for the green LED
57const int8_t redLED = 9; // Pin for the red LED
58const int8_t buttonPin = 21; // Pin for debugging mode (ie, button pin)
59const int8_t wakePin = 31; // MCU interrupt/alarm pin to wake from sleep
60// Mayfly 0.x D31 = A7
61// Set the wake pin to -1 if you do not want the main processor to sleep.
62// In a SAMD system where you are using the built-in rtc, set wakePin to 1
63const int8_t sdCardPwrPin = -1; // MCU SD card power pin
64const int8_t sdCardSSPin = 12; // SD card chip select/slave select pin
65const int8_t sensorPowerPin = 22; // MCU pin controlling main sensor power
66/** End [logging_options] */
67
68
69// ==========================================================================
70// Wifi/Cellular Modem Options
71// ==========================================================================
72/** Start [digi_xbee_cellular_transparent] */
73// For any Digi Cellular XBee's
74// NOTE: The u-blox based Digi XBee's (3G global and LTE-M global)
75// are more stable used in bypass mode (below)
76// The Telit based Digi XBees (LTE Cat1) can only use this mode.
77#include <modems/DigiXBeeCellularTransparent.h>
78
79// Create a reference to the serial port for the modem
80HardwareSerial& modemSerial = Serial1; // Use hardware serial if possible
81const int32_t modemBaud = 9600; // All XBee's use 9600 by default
82
83// Modem Pins - Describe the physical pin connection of your modem to your board
84// NOTE: Use -1 for pins that do not apply
85const int8_t modemVccPin = -2; // MCU pin controlling modem power
86const int8_t modemStatusPin = 19; // MCU pin used to read modem status
87const bool useCTSforStatus = false; // Flag to use the modem CTS pin for status
88const int8_t modemResetPin = 20; // MCU pin connected to modem reset pin
89const int8_t modemSleepRqPin = 23; // MCU pin for modem sleep/wake request
90const int8_t modemLEDPin = redLED; // MCU pin connected an LED to show modem
91 // status (-1 if unconnected)
92
93// Network connection information
94const char* apn = "hologram"; // The APN for the gprs connection
95
96DigiXBeeCellularTransparent modemXBCT(&modemSerial, modemVccPin, modemStatusPin,
97 useCTSforStatus, modemResetPin,
98 modemSleepRqPin, apn);
99// Create an extra reference to the modem by a generic name
100DigiXBeeCellularTransparent modem = modemXBCT;
101/** End [digi_xbee_cellular_transparent] */
102
103
104// ==========================================================================
105// Using the Processor as a Sensor
106// ==========================================================================
107/** Start [processor_sensor] */
108#include <sensors/ProcessorStats.h>
109
110// Create the main processor chip "sensor" - for general metadata
111const char* mcuBoardVersion = "v0.5b";
112ProcessorStats mcuBoard(mcuBoardVersion);
113/** End [processor_sensor] */
114
115
116// ==========================================================================
117// Maxim DS3231 RTC (Real Time Clock)
118// ==========================================================================
119/** Start [ds3231] */
120#include <sensors/MaximDS3231.h>
121
122// Create a DS3231 sensor object
123MaximDS3231 ds3231(1);
124/** End [ds3231] */
125
126
127// ==========================================================================
128// Campbell OBS 3 / OBS 3+ Analog Turbidity Sensor
129// ==========================================================================
130/** Start [obs3] */
131#include <sensors/CampbellOBS3.h>
132
133const int8_t OBS3Power = sensorPowerPin; // Power pin (-1 if unconnected)
134const uint8_t OBS3NumberReadings = 10;
135const uint8_t ADSi2c_addr = 0x48; // The I2C address of the ADS1115 ADC
136// Campbell OBS 3+ *Low* Range Calibration in Volts
137const int8_t OBSLowADSChannel = 0; // ADS channel for *low* range output
138const float OBSLow_A = 0.000E+00; // "A" value (X^2) [*low* range]
139const float OBSLow_B = 1.000E+00; // "B" value (X) [*low* range]
140const float OBSLow_C = 0.000E+00; // "C" value [*low* range]
141
142// Create a Campbell OBS3+ *low* range sensor object
143CampbellOBS3 osb3low(OBS3Power, OBSLowADSChannel, OBSLow_A, OBSLow_B, OBSLow_C,
144 ADSi2c_addr, OBS3NumberReadings);
145
146
147// Campbell OBS 3+ *High* Range Calibration in Volts
148const int8_t OBSHighADSChannel = 1; // ADS channel for *high* range output
149const float OBSHigh_A = 0.000E+00; // "A" value (X^2) [*high* range]
150const float OBSHigh_B = 1.000E+00; // "B" value (X) [*high* range]
151const float OBSHigh_C = 0.000E+00; // "C" value [*high* range]
152
153// Create a Campbell OBS3+ *high* range sensor object
154CampbellOBS3 osb3high(OBS3Power, OBSHighADSChannel, OBSHigh_A, OBSHigh_B,
155 OBSHigh_C, ADSi2c_addr, OBS3NumberReadings);
156/** End [obs3] */
157
158
159// ==========================================================================
160// Meter Hydros 21 Conductivity, Temperature, and Depth Sensor
161// ==========================================================================
162/** Start [hydros21] */
163#include <sensors/MeterHydros21.h>
164
165const char* hydrosSDI12address = "1"; // The SDI-12 Address of the Hydros 21
166const uint8_t hydrosNumberReadings = 6; // The number of readings to average
167const int8_t SDI12Power = sensorPowerPin; // Power pin (-1 if unconnected)
168const int8_t SDI12Data = 7; // The SDI12 data pin
169
170// Create a Meter Hydros 21 sensor object
171MeterHydros21 hydros(*hydrosSDI12address, SDI12Power, SDI12Data,
172 hydrosNumberReadings);
173/** End [hydros21] */
174
175
176// ==========================================================================
177// Creating the Variable Array[s] and Filling with Variable Objects
178// ==========================================================================
179/** Start [variable_arrays] */
180Variable* variableList[] = {
181 new MeterHydros21_Cond(&hydros),
182 new MeterHydros21_Depth(&hydros),
183 new MeterHydros21_Temp(&hydros),
184 new CampbellOBS3_Turbidity(&osb3low, "", "TurbLow"),
185 new CampbellOBS3_Turbidity(&osb3high, "", "TurbHigh"),
186 new ProcessorStats_Battery(&mcuBoard),
187 new MaximDS3231_Temp(&ds3231),
188 new Modem_SignalPercent(&modem),
189};
190
191// All UUID's, device registration, and sampling feature information can be
192// pasted directly from Monitor My Watershed.
193// To get the list, click the "View token UUID list" button on the upper right
194// of the site page.
195
196// *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
197// Check the order of your variables in the variable list!!!
198// Be VERY certain that they match the order of your UUID's!
199// Rearrange the variables in the variable list ABOVE if necessary to match!
200// Do not change the order of the variables in the section below.
201// *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
202
203// Replace all of the text in the following section with the UUID array from
204// MonitorMyWatershed
205
206/* clang-format off */
207// --------------------- Beginning of Token UUID List ---------------------
208
209
210const char* UUIDs[] = // UUID array for device sensors
211 {
212 "12345678-abcd-1234-ef00-1234567890ab", // Specific conductance (Meter_Hydros21_Cond)
213 "12345678-abcd-1234-ef00-1234567890ab", // Water depth (Meter_Hydros21_Depth)
214 "12345678-abcd-1234-ef00-1234567890ab", // Temperature (Meter_Hydros21_Temp)
215 "12345678-abcd-1234-ef00-1234567890ab", // Turbidity (Campbell_OBS3_Turb) (Low)
216 "12345678-abcd-1234-ef00-1234567890ab", // Turbidity (Campbell_OBS3_Turb) (High)
217 "12345678-abcd-1234-ef00-1234567890ab", // Battery voltage (EnviroDIY_Mayfly_Batt)
218 "12345678-abcd-1234-ef00-1234567890ab", // Battery voltage (EnviroDIY_Mayfly_Batt)
219 "12345678-abcd-1234-ef00-1234567890ab", // Percent full scale (Digi_Cellular_SignalPercent)
220};
221const char* registrationToken = "12345678-abcd-1234-ef00-1234567890ab"; // Device registration token
222const char* samplingFeature = "12345678-abcd-1234-ef00-1234567890ab"; // Sampling feature UUID
223
224
225// ----------------------- End of Token UUID List -----------------------
226/* clang-format on */
227
228// Count up the number of pointers in the array
229int variableCount = sizeof(variableList) / sizeof(variableList[0]);
230
231// Create the VariableArray object
232VariableArray varArray(variableCount, variableList, UUIDs);
233/** End [variable_arrays] */
234
235
236// ==========================================================================
237// The Logger Object[s]
238// ==========================================================================
239/** Start [loggers] */
240// Create a new logger instance
241Logger dataLogger(LoggerID, loggingInterval, &varArray);
242/** End [loggers] */
243
244
245// ==========================================================================
246// Creating Data Publisher[s]
247// ==========================================================================
248/** Start [publishers] */
249// Create a data publisher for the Monitor My Watershed/EnviroDIY POST endpoint
250#include <publishers/EnviroDIYPublisher.h>
251EnviroDIYPublisher EnviroDIYPOST(dataLogger, &modem.gsmClient,
252 registrationToken, samplingFeature);
253/** End [publishers] */
254
255
256// ==========================================================================
257// Working Functions
258// ==========================================================================
259/** Start [working_functions] */
260// Flashes the LED's on the primary board
261void greenredflash(uint8_t numFlash = 4, uint8_t rate = 75) {
262 for (uint8_t i = 0; i < numFlash; i++) {
263 digitalWrite(greenLED, HIGH);
264 digitalWrite(redLED, LOW);
265 delay(rate);
266 digitalWrite(greenLED, LOW);
267 digitalWrite(redLED, HIGH);
268 delay(rate);
269 }
270 digitalWrite(redLED, LOW);
271}
272
273// Reads the battery voltage
274// NOTE: This will actually return the battery level from the previous update!
275float getBatteryVoltage() {
276 if (mcuBoard.sensorValues[0] == -9999) mcuBoard.update();
277 return mcuBoard.sensorValues[0];
278}
279
280
281// ==========================================================================
282// Arduino Setup Function
283// ==========================================================================
284/** Start [setup] */
285void setup() {
286 // Start the primary serial connection
287 Serial.begin(serialBaud);
288
289 // Print a start-up note to the first serial port
290 Serial.print(F("Now running "));
291 Serial.print(sketchName);
292 Serial.print(F(" on Logger "));
293 Serial.println(LoggerID);
294 Serial.println();
295
296 Serial.print(F("Using ModularSensors Library version "));
297 Serial.println(MODULAR_SENSORS_VERSION);
298 Serial.print(F("TinyGSM Library version "));
299 Serial.println(TINYGSM_VERSION);
300 Serial.println();
301
302 // Start the serial connection with the modem
303 modemSerial.begin(modemBaud);
304
305 // Set up pins for the LED's
306 pinMode(greenLED, OUTPUT);
307 digitalWrite(greenLED, LOW);
308 pinMode(redLED, OUTPUT);
309 digitalWrite(redLED, LOW);
310 // Blink the LEDs to show the board is on and starting up
311 greenredflash();
312
313 pinMode(20, OUTPUT); // for proper operation of the onboard flash memory
314 // chip's ChipSelect (Mayfly v1.0 and later)
315
316 // Set the timezones for the logger/data and the RTC
317 // Logging in the given time zone
318 Logger::setLoggerTimeZone(timeZone);
319 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
320 Logger::setRTCTimeZone(0);
321
322 // Attach the modem and information pins to the logger
323 dataLogger.attachModem(modem);
324 modem.setModemLED(modemLEDPin);
325 dataLogger.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin,
326 greenLED);
327
328 // Begin the logger
329 dataLogger.begin();
330
331 // Note: Please change these battery voltages to match your battery
332 // Set up the sensors, except at lowest battery level
333 if (getBatteryVoltage() > 3.4) {
334 Serial.println(F("Setting up sensors..."));
335 varArray.setupSensors();
336 }
337
338 // Extra modem set-up - selecting AT&T as the carrier and LTE-M only
339 // NOTE: The code for this could be shortened using the "commandMode" and
340 // other XBee specific commands in TinyGSM. I've written it this way in
341 // this example to show how the settings could be changed in either bypass
342 // OR transparent mode.
343 Serial.println(F("Waking modem and setting Cellular Carrier Options..."));
344 modem.modemWake(); // NOTE: This will also set up the modem
345 // Go back to command mode to set carrier options
346 for (uint8_t i = 0; i < 5; i++) {
347 // Wait the required guard time before entering command mode
348 delay(1010);
349 modem.gsmModem.streamWrite(GF("+++")); // enter command mode
350 if (modem.gsmModem.waitResponse(2000, GF("OK\r")) == 1) break;
351 }
352 // Carrier Profile - 0 = Automatic selection
353 // - 1 = No profile/SIM ICCID selected
354 // - 2 = AT&T
355 // - 3 = Verizon
356 // NOTE: To select T-Mobile, you must enter bypass mode!
357 modem.gsmModem.sendAT(GF("CP"), 2);
358 modem.gsmModem.waitResponse(GF("OK\r"));
359 // Cellular network technology - 0 = LTE-M with NB-IoT fallback
360 // - 1 = NB-IoT with LTE-M fallback
361 // - 2 = LTE-M only
362 // - 3 = NB-IoT only
363 modem.gsmModem.sendAT(GF("N#"), 2);
364 modem.gsmModem.waitResponse();
365 // Write changes to flash and apply them
366 Serial.println(F("Wait while applying changes..."));
367 // Write changes to flash
368 modem.gsmModem.sendAT(GF("WR"));
369 modem.gsmModem.waitResponse(GF("OK\r"));
370 // Apply changes
371 modem.gsmModem.sendAT(GF("AC"));
372 modem.gsmModem.waitResponse(GF("OK\r"));
373 // Reset the cellular component to ensure network settings are changed
374 modem.gsmModem.sendAT(GF("!R"));
375 modem.gsmModem.waitResponse(30000L, GF("OK\r"));
376 // Force reset of the Digi component as well
377 // This effectively exits command mode
378 modem.gsmModem.sendAT(GF("FR"));
379 modem.gsmModem.waitResponse(5000L, GF("OK\r"));
380
381 // Sync the clock if it isn't valid or we have battery to spare
382 if (getBatteryVoltage() > 3.55 || !dataLogger.isRTCSane()) {
383 // Synchronize the RTC with NIST
384 // This will also set up the modem
385 dataLogger.syncRTC();
386 }
387
388 // Create the log file, adding the default header to it
389 // Do this last so we have the best chance of getting the time correct and
390 // all sensor names correct
391 // Writing to the SD card can be power intensive, so if we're skipping
392 // the sensor setup we'll skip this too.
393 if (getBatteryVoltage() > 3.4) {
394 Serial.println(F("Setting up file on SD card"));
395 dataLogger.turnOnSDcard(
396 true); // true = wait for card to settle after power up
397 dataLogger.createLogFile(true); // true = write a new header
398 dataLogger.turnOffSDcard(
399 true); // true = wait for internal housekeeping after write
400 }
401
402 // Call the processor sleep
403 Serial.println(F("Putting processor to sleep\n"));
404 dataLogger.systemSleep();
405}
406/** End [setup] */
407
408
409// ==========================================================================
410// Arduino Loop Function
411// ==========================================================================
412/** Start [loop] */
413// Use this short loop for simple data logging and sending
414void loop() {
415 // Note: Please change these battery voltages to match your battery
416 // At very low battery, just go back to sleep
417 if (getBatteryVoltage() < 3.4) {
418 dataLogger.systemSleep();
419 }
420 // At moderate voltage, log data but don't send it over the modem
421 else if (getBatteryVoltage() < 3.55) {
422 dataLogger.logData();
423 }
424 // If the battery is good, send the data to the world
425 else {
426 dataLogger.logDataAndPublish();
427 }
428}
429/** End [loop] */