Example for DRWI CitSci without cellular service.
Example for DRWI CitSci without cellular service.=========================================================================
See the walkthrough page for detailed instructions.
1/** =========================================================================
2 * @example{lineno} DRWI_NoCellular.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>
7 * @brief Example for DRWI CitSci without cellular service.
9 * See [the walkthrough page](@ref example_drwi_no_cell) for detailed
12 * @m_examplenavigation{example_drwi_no_cell,}
13 * ======================================================================= */
15// ==========================================================================
16// Include the libraries required for any data logger
17// ==========================================================================
18/** Start [includes] */
19// The Arduino library is needed for every Arduino program.
22// Include the main header for ModularSensors
23#include <ModularSensors.h>
27// ==========================================================================
28// Data Logging Options
29// ==========================================================================
30/** Start [logging_options] */
31// The name of this program file
32const char* sketchName = "DRWI_NoCellular.ino";
33// Logger ID, also becomes the prefix for the name of the data file on SD card
34const char* LoggerID = "XXXXX";
35// How frequently (in minutes) to log data
36const uint8_t loggingInterval = 15;
37// Your logger's timezone.
38const int8_t timeZone = -5; // Eastern Standard Time
39// NOTE: Daylight savings time will not be applied! Please use standard time!
41// Set the input and output pins for the logger
42// NOTE: Use -1 for pins that do not apply
43const int32_t serialBaud = 115200; // Baud rate for debugging
44const int8_t greenLED = 8; // Pin for the green LED
45const int8_t redLED = 9; // Pin for the red LED
46const int8_t buttonPin = 21; // Pin for debugging mode (ie, button pin)
47const int8_t wakePin = 31; // MCU interrupt/alarm pin to wake from sleep
49const int8_t sdCardPwrPin = -1; // MCU SD card power pin
50const int8_t sdCardSSPin = 12; // SD card chip select/slave select pin
51const int8_t sensorPowerPin = 22; // MCU pin controlling main sensor power
52/** End [logging_options] */
55// ==========================================================================
56// Using the Processor as a Sensor
57// ==========================================================================
58/** Start [processor_sensor] */
59#include <sensors/ProcessorStats.h>
61// Create the main processor chip "sensor" - for general metadata
62const char* mcuBoardVersion = "v1.1";
63ProcessorStats mcuBoard(mcuBoardVersion);
64/** End [processor_sensor] */
67// ==========================================================================
68// Maxim DS3231 RTC (Real Time Clock)
69// ==========================================================================
71#include <sensors/MaximDS3231.h>
73// Create a DS3231 sensor object
78// ==========================================================================
79// Campbell OBS 3 / OBS 3+ Analog Turbidity Sensor
80// ==========================================================================
82#include <sensors/CampbellOBS3.h>
84const int8_t OBS3Power = sensorPowerPin; // Power pin (-1 if unconnected)
85const uint8_t OBS3NumberReadings = 10;
86const uint8_t ADSi2c_addr = 0x48; // The I2C address of the ADS1115 ADC
87// Campbell OBS 3+ *Low* Range Calibration in Volts
88const int8_t OBSLowADSChannel = 0; // ADS channel for *low* range output
89const float OBSLow_A = 0.000E+00; // "A" value (X^2) [*low* range]
90const float OBSLow_B = 1.000E+00; // "B" value (X) [*low* range]
91const float OBSLow_C = 0.000E+00; // "C" value [*low* range]
93// Create a Campbell OBS3+ *low* range sensor object
94CampbellOBS3 osb3low(OBS3Power, OBSLowADSChannel, OBSLow_A, OBSLow_B, OBSLow_C,
95 ADSi2c_addr, OBS3NumberReadings);
98// Campbell OBS 3+ *High* Range Calibration in Volts
99const int8_t OBSHighADSChannel = 1; // ADS channel for *high* range output
100const float OBSHigh_A = 0.000E+00; // "A" value (X^2) [*high* range]
101const float OBSHigh_B = 1.000E+00; // "B" value (X) [*high* range]
102const float OBSHigh_C = 0.000E+00; // "C" value [*high* range]
104// Create a Campbell OBS3+ *high* range sensor object
105CampbellOBS3 osb3high(OBS3Power, OBSHighADSChannel, OBSHigh_A, OBSHigh_B,
106 OBSHigh_C, ADSi2c_addr, OBS3NumberReadings);
110// ==========================================================================
111// Meter Hydros 21 Conductivity, Temperature, and Depth Sensor
112// ==========================================================================
113/** Start [hydros21] */
114#include <sensors/MeterHydros21.h>
116const char* hydrosSDI12address = "1"; // The SDI-12 Address of the Hydros 21
117const uint8_t hydrosNumberReadings = 6; // The number of readings to average
118const int8_t SDI12Power = sensorPowerPin; // Power pin (-1 if unconnected)
119const int8_t SDI12Data = 7; // The SDI12 data pin
121// Create a Meter Hydros 21 sensor object
122MeterHydros21 hydros(*hydrosSDI12address, SDI12Power, SDI12Data,
123 hydrosNumberReadings);
127// ==========================================================================
128// Creating the Variable Array[s] and Filling with Variable Objects
129// ==========================================================================
130/** Start [variable_arrays] */
131Variable* variableList[] = {
132 new MeterHydros21_Cond(&hydros),
133 new MeterHydros21_Temp(&hydros),
134 new MeterHydros21_Depth(&hydros),
135 new CampbellOBS3_Turbidity(&osb3low, "", "TurbLow"),
136 new CampbellOBS3_Turbidity(&osb3high, "", "TurbHigh"),
137 new ProcessorStats_Battery(&mcuBoard),
138 new MaximDS3231_Temp(&ds3231),
141// All UUID's, device registration, and sampling feature information can be
142// pasted directly from Monitor My Watershed. To get the list, click the "View
143// token UUID list" button on the upper right of the site page.
144// Even if not publishing live data, this is needed so the logger file will be
145// "drag-and-drop" ready for manual upload to the portal.
147// *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
148// Check the order of your variables in the variable list!!!
149// Be VERY certain that they match the order of your UUID's!
150// Rearrange the variables in the variable list if necessary to match!
151// *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
152/* clang-format off */
153const char* UUIDs[] = {
154 "12345678-abcd-1234-ef00-1234567890ab", // Electrical conductivity (Decagon_CTD-10_Cond)
155 "12345678-abcd-1234-ef00-1234567890ab", // Temperature (Decagon_CTD-10_Temp)
156 "12345678-abcd-1234-ef00-1234567890ab", // Water depth (Decagon_CTD-10_Depth)
157 "12345678-abcd-1234-ef00-1234567890ab", // Turbidity (Campbell_OBS3_Turb)
158 "12345678-abcd-1234-ef00-1234567890ab", // Turbidity (Campbell_OBS3_Turb)
159 "12345678-abcd-1234-ef00-1234567890ab", // Battery voltage (EnviroDIY_Mayfly_Batt)
160 "12345678-abcd-1234-ef00-1234567890ab" // Temperature (EnviroDIY_Mayfly_Temp)
162const char* registrationToken = "12345678-abcd-1234-ef00-1234567890ab"; // Device registration token
163const char* samplingFeature = "12345678-abcd-1234-ef00-1234567890ab"; // Sampling feature UUID
166// Count up the number of pointers in the array
167int variableCount = sizeof(variableList) / sizeof(variableList[0]);
169// Create the VariableArray object
170VariableArray varArray(variableCount, variableList, UUIDs);
171/** End [variable_arrays] */
174// ==========================================================================
175// The Logger Object[s]
176// ==========================================================================
177/** Start [loggers] */
178// Create a new logger instance
179Logger dataLogger(LoggerID, loggingInterval, &varArray);
183// ==========================================================================
185// ==========================================================================
186/** Start [working_functions] */
187// Flashes the LED's on the primary board
188void greenredflash(uint8_t numFlash = 4, uint8_t rate = 75) {
189 for (uint8_t i = 0; i < numFlash; i++) {
190 digitalWrite(greenLED, HIGH);
191 digitalWrite(redLED, LOW);
193 digitalWrite(greenLED, LOW);
194 digitalWrite(redLED, HIGH);
197 digitalWrite(redLED, LOW);
200// Reads the battery voltage
201// NOTE: This will actually return the battery level from the previous update!
202float getBatteryVoltage() {
203 if (mcuBoard.sensorValues[0] == -9999) mcuBoard.update();
204 return mcuBoard.sensorValues[0];
206/** End [working_functions] */
209// ==========================================================================
210// Arduino Setup Function
211// ==========================================================================
214 // Start the primary serial connection
215 Serial.begin(serialBaud);
217 // Print a start-up note to the first serial port
218 Serial.print(F("Now running "));
219 Serial.print(sketchName);
220 Serial.print(F(" on Logger "));
221 Serial.println(LoggerID);
224 Serial.print(F("Using ModularSensors Library version "));
225 Serial.println(MODULAR_SENSORS_VERSION);
227 // Set up pins for the LED's
228 pinMode(greenLED, OUTPUT);
229 digitalWrite(greenLED, LOW);
230 pinMode(redLED, OUTPUT);
231 digitalWrite(redLED, LOW);
232 // Blink the LEDs to show the board is on and starting up
235 // Set the timezones for the logger/data and the RTC
236 // Logging in the given time zone
237 Logger::setLoggerTimeZone(timeZone);
238 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
239 Logger::setRTCTimeZone(0);
241 // Attach information pins to the logger
242 dataLogger.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin,
244 dataLogger.setSamplingFeatureUUID(samplingFeature);
249 // Note: Please change these battery voltages to match your battery
250 // Set up the sensors, except at lowest battery level
251 if (getBatteryVoltage() > 3.4) {
252 Serial.println(F("Setting up sensors..."));
253 varArray.setupSensors();
256 // Create the log file, adding the default header to it
257 // Do this last so we have the best chance of getting the time correct and
258 // all sensor names correct
259 // Writing to the SD card can be power intensive, so if we're skipping
260 // the sensor setup we'll skip this too.
261 if (getBatteryVoltage() > 3.4) {
262 Serial.println(F("Setting up file on SD card"));
263 dataLogger.turnOnSDcard(
264 true); // true = wait for card to settle after power up
265 dataLogger.createLogFile(true); // true = write a new header
266 dataLogger.turnOffSDcard(
267 true); // true = wait for internal housekeeping after write
270 // Call the processor sleep
271 Serial.println(F("Putting processor to sleep\n"));
272 dataLogger.systemSleep();
277// ==========================================================================
278// Arduino Loop Function
279// ==========================================================================
281// Use this short loop for simple data logging and sending
283 // Note: Please change these battery voltages to match your battery
284 // At very low battery, just go back to sleep
285 if (getBatteryVoltage() < 3.4) {
286 dataLogger.systemSleep();
288 // If the battery is OK, log data
290 dataLogger.logData();