Example logging at two different timing intervals.
Example logging at two different timing intervals=========================================================================
See the walkthrough page for detailed instructions.
1/** =========================================================================
2 * @example{lineno} double_logger.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 logging at two different timing intervals
9 * See [the walkthrough page](@ref example_double_log) for detailed
12 * @m_examplenavigation{example_double_log,}
13 * ======================================================================= */
15// ==========================================================================
17// ==========================================================================
19#ifndef TINY_GSM_RX_BUFFER
20#define TINY_GSM_RX_BUFFER 64
22#ifndef TINY_GSM_YIELD_MS
23#define TINY_GSM_YIELD_MS 2
27// ==========================================================================
28// Include the libraries required for any data logger
29// ==========================================================================
30/** Start [includes] */
31// The Arduino library is needed for every Arduino program.
34// Include the main header for ModularSensors
35#include <ModularSensors.h>
39// ==========================================================================
40// Data Logging Options
41// ==========================================================================
42/** Start [logging_options] */
43// The name of this program file
44const char* sketchName = "double_logger.ino";
45// Logger ID - we're only using one logger ID for both "loggers"
46const char* LoggerID = "XXXXX";
47// The TWO filenames for the different logging intervals
48const char* FileName5min = "Logger_5MinuteInterval.csv";
49const char* FileName1min = "Logger_1MinuteInterval.csv";
50// Your logger's timezone.
51const int8_t timeZone = -5; // Eastern Standard Time
52// NOTE: Daylight savings time will not be applied! Please use standard time!
54// Set the input and output pins for the logger
55// NOTE: Use -1 for pins that do not apply
56const int32_t serialBaud = 115200; // Baud rate for debugging
57const int8_t greenLED = 8; // Pin for the green LED
58const int8_t redLED = 9; // Pin for the red LED
59const int8_t buttonPin = 21; // Pin for debugging mode (ie, button pin)
60const int8_t wakePin = 31; // MCU interrupt/alarm pin to wake from sleep
62// Set the wake pin to -1 if you do not want the main processor to sleep.
63// In a SAMD system where you are using the built-in rtc, set wakePin to 1
64const int8_t sdCardPwrPin = -1; // MCU SD card power pin
65const int8_t sdCardSSPin = 12; // SD card chip select/slave select pin
66const int8_t sensorPowerPin = 22; // MCU pin controlling main sensor power
67/** End [logging_options] */
70// ==========================================================================
71// Wifi/Cellular Modem Options
72// ==========================================================================
73/** Start [xbee_wifi] */
74// For the Digi Wifi XBee (S6B)
75#include <modems/DigiXBeeWifi.h>
76// Create a reference to the serial port for the modem
78HardwareSerial& modemSerial = Serial1; // Use hardware serial if possible
79const int32_t modemBaud = 9600; // All XBee's use 9600 by default
81// Modem Pins - Describe the physical pin connection of your modem to your board
82// NOTE: Use -1 for pins that do not apply
83const int8_t modemVccPin = -2; // MCU pin controlling modem power
84const int8_t modemStatusPin = 19; // MCU pin used to read modem status
85const bool useCTSforStatus = true; // Flag to use the modem CTS pin for status
86const int8_t modemResetPin = 20; // MCU pin connected to modem reset pin
87const int8_t modemSleepRqPin = 23; // MCU pin for modem sleep/wake request
88const int8_t modemLEDPin = redLED; // MCU pin connected an LED to show modem
89 // status (-1 if unconnected)
91// Network connection information
92const char* wifiId = "xxxxx"; // WiFi access point, unnecessary for GPRS
93const char* wifiPwd = "xxxxx"; // WiFi password, unnecessary for GPRS
95DigiXBeeWifi modemXBWF(&modemSerial, modemVccPin, modemStatusPin,
96 useCTSforStatus, modemResetPin, modemSleepRqPin, wifiId,
98// Create an extra reference to the modem by a generic name
99DigiXBeeWifi modem = modemXBWF;
100/** End [xbee_wifi] */
103// ==========================================================================
104// Using the Processor as a Sensor
105// ==========================================================================
106/** Start [processor_sensor] */
107#include <sensors/ProcessorStats.h>
109// Create the main processor chip "sensor" - for general metadata
110const char* mcuBoardVersion = "v1.1";
111ProcessorStats mcuBoard(mcuBoardVersion);
112/** End [processor_sensor] */
115// ==========================================================================
116// Maxim DS3231 RTC (Real Time Clock)
117// ==========================================================================
119#include <sensors/MaximDS3231.h>
121// Create a DS3231 sensor object
122MaximDS3231 ds3231(1);
126// ==========================================================================
127// AOSong AM2315 Digital Humidity and Temperature Sensor
128// ==========================================================================
129/** Start [ao_song_am2315] */
130#include <sensors/AOSongAM2315.h>
132const int8_t I2CPower = sensorPowerPin; // Power pin (-1 if unconnected)
134// Create and return the AOSong AM2315 sensor object
135AOSongAM2315 am2315(I2CPower);
136/** End [ao_song_am2315] */
139// ==========================================================================
140// Creating the Variable Array[s] and Filling with Variable Objects
141// ==========================================================================
142/** Start [variable_arrays] */
143// The variables to record at 1 minute intervals
144Variable* variableList_at1min[] = {new AOSongAM2315_Humidity(&am2315),
145 new AOSongAM2315_Temp(&am2315)};
146// Count up the number of pointers in the 1-minute array
147int variableCount1min = sizeof(variableList_at1min) /
148 sizeof(variableList_at1min[0]);
149// Create the 1-minute VariableArray object
150VariableArray array1min;
152// The variables to record at 5 minute intervals
153Variable* variableList_at5min[] = {new MaximDS3231_Temp(&ds3231),
154 new ProcessorStats_Battery(&mcuBoard),
155 new ProcessorStats_FreeRam(&mcuBoard)};
156// Count up the number of pointers in the 5-minute array
157int variableCount5min = sizeof(variableList_at5min) /
158 sizeof(variableList_at5min[0]);
159// Create the 5-minute VariableArray object
160VariableArray array5min;
161/** End [variable_arrays] */
164// ==========================================================================
165// The Logger Object[s]
166// ==========================================================================
167/** Start [loggers] */
168// Create the 1-minute logger instance
171// Create the 5-minute logger instance
176// ==========================================================================
178// ==========================================================================
179/** Start [working_functions] */
180// Flashes the LED's on the primary board
181void greenredflash(uint8_t numFlash = 4, uint8_t rate = 75) {
182 for (uint8_t i = 0; i < numFlash; i++) {
183 digitalWrite(greenLED, HIGH);
184 digitalWrite(redLED, LOW);
186 digitalWrite(greenLED, LOW);
187 digitalWrite(redLED, HIGH);
190 digitalWrite(redLED, LOW);
192/** End [working_functions] */
195// ==========================================================================
196// Arduino Setup Function
197// ==========================================================================
200 // Start the primary serial connection
201 Serial.begin(serialBaud);
203 // Print a start-up note to the first serial port
204 Serial.print(F("Now running "));
205 Serial.print(sketchName);
206 Serial.print(F(" on Logger "));
207 Serial.println(LoggerID);
210 Serial.print(F("Using ModularSensors Library version "));
211 Serial.println(MODULAR_SENSORS_VERSION);
212 Serial.print(F("TinyGSM Library version "));
213 Serial.println(TINYGSM_VERSION);
216 // Start the serial connection with the modem
217 modemSerial.begin(modemBaud);
219 // Set up pins for the LED's
220 pinMode(greenLED, OUTPUT);
221 digitalWrite(greenLED, LOW);
222 pinMode(redLED, OUTPUT);
223 digitalWrite(redLED, LOW);
224 // Blink the LEDs to show the board is on and starting up
227 // Set the timezones for the logger/data and the RTC
228 // Logging in the given time zone
229 Logger::setLoggerTimeZone(timeZone);
230 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
231 Logger::setRTCTimeZone(0);
233 // Begin the variable array[s], logger[s], and publisher[s]
234 array1min.begin(variableCount1min, variableList_at1min);
235 array5min.begin(variableCount5min, variableList_at5min);
236 logger1min.begin(LoggerID, 1, &array1min);
237 logger5min.begin(LoggerID, 5, &array5min);
238 logger1min.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin,
240 logger5min.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin,
244 modem.setModemLED(modemLEDPin);
246 // Set up the sensors (do this directly on the VariableArray)
247 array1min.setupSensors();
248 array5min.setupSensors();
250 // Print out the current time
251 Serial.print(F("Current RTC time is: "));
252 Serial.println(Logger::formatDateTime_ISO8601(Logger::getNowUTCEpoch()));
253 Serial.print(F("Current localized logger time is: "));
254 Serial.println(Logger::formatDateTime_ISO8601(Logger::getNowLocalEpoch()));
255 // Connect to the network
256 if (modem.connectInternet()) {
257 // Synchronize the RTC
258 logger1min.setRTClock(modem.getNISTTime());
259 modem.updateModemMetadata();
260 // Disconnect from the network
261 modem.disconnectInternet();
263 // Turn off the modem
264 modem.modemSleepPowerDown();
266 // Give the loggers different file names
267 // If we wanted to auto-generate the file name, that could also be done by
268 // not calling this function, but in that case if both "loggers" have the
269 // same logger id, they will end up with the same filename
270 logger1min.setFileName(FileName1min);
271 logger5min.setFileName(FileName5min);
273 // Setup the logger files. Specifying true will put a default header at
274 // on to the file when it's created.
275 // Because we've already called setFileName, we do not need to specify the
276 // file name for this function.
277 logger1min.turnOnSDcard(
278 true); // true = wait for card to settle after power up
279 logger1min.createLogFile(true); // true = write a new header
280 logger5min.createLogFile(true); // true = write a new header
281 logger1min.turnOffSDcard(
282 true); // true = wait for internal housekeeping after write
284 Serial.println(F("Logger setup finished!\n"));
285 Serial.println(F("------------------------------------------"));
288 // Call the processor sleep
289 // Only need to do this for one of the loggers
290 logger1min.systemSleep();
295// ==========================================================================
296// Arduino Loop Function
297// ==========================================================================
299// Because of the way alarms work on the RTC, it will wake the processor and
300// start the loop every minute exactly on the minute.
301// The processor may also be woken up by another interrupt or level change on a
302// pin - from a button or some other input.
303// The "if" statements in the loop determine what will happen - whether the
304// sensors update, testing mode starts, or it goes back to sleep.
306 // Check if the current time is an even interval of the logging interval
307 // For whichever logger we call first, use the checkInterval() function.
308 if (logger1min.checkInterval()) {
309 // Print a line to show new reading
310 Serial.println(F("--------------------->111<---------------------"));
311 // Turn on the LED to show we're taking a reading
312 digitalWrite(greenLED, HIGH);
314 // Send power to all of the sensors (do this directly on the
316 Serial.print(F("Powering sensors...\n"));
317 array1min.sensorsPowerUp();
318 logger1min.watchDogTimer.resetWatchDog();
319 // Wake up all of the sensors (do this directly on the VariableArray)
320 Serial.print(F("Waking sensors...\n"));
321 array1min.sensorsWake();
322 logger1min.watchDogTimer.resetWatchDog();
323 // Update the values from all attached sensors (do this directly on the
325 Serial.print(F("Updating sensor values...\n"));
326 array1min.updateAllSensors();
327 logger1min.watchDogTimer.resetWatchDog();
328 // Put sensors to sleep (do this directly on the VariableArray)
329 Serial.print(F("Putting sensors back to sleep...\n"));
330 array1min.sensorsSleep();
331 logger1min.watchDogTimer.resetWatchDog();
332 // Cut sensor power (do this directly on the VariableArray)
333 Serial.print(F("Cutting sensor power...\n"));
334 array1min.sensorsPowerDown();
335 logger1min.watchDogTimer.resetWatchDog();
337 // Stream the csv data to the SD card
338 logger1min.turnOnSDcard(true);
339 logger1min.logToSD();
340 logger1min.turnOffSDcard(true);
341 logger1min.watchDogTimer.resetWatchDog();
344 digitalWrite(greenLED, LOW);
345 // Print a line to show reading ended
346 Serial.println(F("---------------------<111>---------------------\n"));
348 // Check if the already marked time is an even interval of the logging
349 // interval For logger[s] other than the first one, use the
350 // checkMarkedInterval() function.
351 if (logger5min.checkMarkedInterval()) {
352 // Print a line to show new reading
353 Serial.println(F("--------------------->555<---------------------"));
354 // Turn on the LED to show we're taking a reading
355 digitalWrite(redLED, HIGH);
357 // Send power to all of the sensors (do this directly on the
359 Serial.print(F("Powering sensors...\n"));
360 array5min.sensorsPowerUp();
361 logger1min.watchDogTimer.resetWatchDog();
362 // Wake up all of the sensors (do this directly on the VariableArray)
363 Serial.print(F("Waking sensors...\n"));
364 array5min.sensorsWake();
365 logger1min.watchDogTimer.resetWatchDog();
366 // Update the values from all attached sensors (do this directly on the
368 Serial.print(F("Updating sensor values...\n"));
369 array5min.updateAllSensors();
370 logger1min.watchDogTimer.resetWatchDog();
371 // Put sensors to sleep (do this directly on the VariableArray)
372 Serial.print(F("Putting sensors back to sleep...\n"));
373 array5min.sensorsSleep();
374 logger1min.watchDogTimer.resetWatchDog();
375 // Cut sensor power (do this directly on the VariableArray)
376 Serial.print(F("Cutting sensor power...\n"));
377 array5min.sensorsPowerDown();
378 logger1min.watchDogTimer.resetWatchDog();
380 // Stream the csv data to the SD card
381 logger5min.turnOnSDcard(true);
382 logger5min.logToSD();
383 logger5min.turnOffSDcard(true);
384 logger1min.watchDogTimer.resetWatchDog();
387 digitalWrite(redLED, LOW);
388 // Print a line to show reading ended
389 Serial.println(F("--------------------<555>---------------------\n"));
391 // Once a day, at noon, sync the clock
392 if (Logger::markedLocalEpochTime % 86400 == 43200) {
395 // Connect to the network
396 if (modem.connectInternet()) {
397 // Synchronize the RTC
398 logger1min.setRTClock(modem.getNISTTime());
399 // Disconnect from the network
400 modem.disconnectInternet();
402 // Turn off the modem
403 modem.modemSleepPowerDown();
406 // Call the processor sleep
407 // Only need to do this for one of the loggers
408 logger1min.systemSleep();