Learn EnviroDIY Course

This shows the simplest use of a "logger" object. That is, creating an array of variable objects and then creating a logger object that utilizes those variables to update all of the variable results together and save the data to a SD card. The processor then goes to sleep between readings. This example calls on two of the sensors available in this library. The example may be run exactly as written.

This is the example you should use to deploy a logger somewhere where you don't want or have access to a way of streaming live data and you won't want to upload data to the Monitor My Watershed data portal.



Unique Features of the Learn EnviroDIY Example

  • Only logs data to an SD card.
  • Uses a few more sensors than the other simple logging example

To Use this Example

Prepare and set up PlatformIO

  • Create a new PlatformIO project
  • Replace the contents of the platformio.ini for your new project with the platformio.ini file in the examples/simple_logging_LearnEnviroDIY 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 simple_logging_LearnEnviroDIY.ino and save it to your computer. Put 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";

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 logging data to an SD card from external sensors
13
14[env:mayfly]
15monitor_speed = 115200
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
31 -DNEOSWSERIAL_EXTERNAL_PCINT
32 -DMQTT_MAX_PACKET_SIZE=240
33 -DTINY_GSM_RX_BUFFER=64
34 -DTINY_GSM_YIELD_MS=2
35lib_deps =
36 envirodiy/EnviroDIY_ModularSensors
37; ^^ Use this when working from an official release of the library
38; https://github.com/EnviroDIY/ModularSensors.git#develop
39; ^^ Use this when if you want to pull from the develop branch
40 https://github.com/PaulStoffregen/AltSoftSerial.git
41 https://github.com/SRGDamia1/NeoSWSerial.git
42 https://github.com/EnviroDIY/SoftwareSerial_ExternalInts.git
43; ^^ These are software serial port emulator libraries, you may not need them

The Complete Code

1/** =========================================================================
2 * @example{lineno} simple_logging_LearnEnviroDIY.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 A data logging example for the Learn EnviroDIY tutorial.
8 *
9 * See [the walkthrough page](@ref example_learn_envirodiy) for detailed
10 * instructions.
11 *
12 * @m_examplenavigation{example_learn_envirodiy,}
13 * ======================================================================= */
14
15// ==========================================================================
16// Include the libraries required for any data logger
17// ==========================================================================
18/** Start [includes] */
19// The Arduino library is needed for every Arduino program.
20#include <Arduino.h>
21
22// Include the main header for ModularSensors
23#include <ModularSensors.h>
24/** End [includes] */
25
26
27// ==========================================================================
28// Data Logging Options
29// ==========================================================================
30/** Start [logging_options] */
31// The name of this program file
32const char* sketchName = "simple_logging.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!
40
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
48// Mayfly 0.x D31 = A7
49// Set the wake pin to -1 if you do not want the main processor to sleep.
50// In a SAMD system where you are using the built-in rtc, set wakePin to 1
51const int8_t sdCardPwrPin = -1; // MCU SD card power pin
52const int8_t sdCardSSPin = 12; // SD card chip select/slave select pin
53const int8_t sensorPowerPin = 22; // MCU pin controlling main sensor power
54/** End [logging_options] */
55
56
57// ==========================================================================
58// Using the Processor as a Sensor
59// ==========================================================================
60/** Start [processor_sensor] */
61#include <sensors/ProcessorStats.h>
62
63// Create the main processor chip "sensor" - for general metadata
64const char* mcuBoardVersion = "v1.1";
65ProcessorStats mcuBoard(mcuBoardVersion);
66/** End [processor_sensor] */
67
68
69// ==========================================================================
70// Maxim DS3231 RTC (Real Time Clock)
71// ==========================================================================
72/** Start [ds3231] */
73#include <sensors/MaximDS3231.h> // Includes wrapper functions for Maxim DS3231 RTC
74
75// Create a DS3231 sensor object, using this constructor function:
76MaximDS3231 ds3231(1);
77/** End [ds3231] */
78
79
80// ==========================================================================
81// Settings for Additional Sensors
82// ==========================================================================
83// Additional sensors can setup here, similar to the RTC, but only if
84// they have been supported with ModularSensors wrapper functions. See:
85// https://github.com/EnviroDIY/ModularSensors/wiki#just-getting-started
86// Syntax for the include statement and constructor function for each sensor is
87// at
88// https://github.com/EnviroDIY/ModularSensors/wiki#these-sensors-are-currently-supported
89// or can be copied from the `menu_a_la_carte.ino` example
90
91
92// ==========================================================================
93// Bosch BME280 Environmental Sensor
94// ==========================================================================
95/** Start [bme280] */
96#include <sensors/BoschBME280.h>
97
98const int8_t I2CPower = sensorPowerPin; // Power pin (-1 if unconnected)
99uint8_t BMEi2c_addr = 0x76;
100// The BME280 can be addressed either as 0x77 (Adafruit default) or 0x76 (Grove
101// default) Either can be physically mofidied for the other address
102
103// Create a Bosch BME280 sensor object
104BoschBME280 bme280(I2CPower, BMEi2c_addr);
105/** End [bme280] */
106
107
108// ==========================================================================
109// Maxim DS18 One Wire Temperature Sensor
110// ==========================================================================
111/** Start [ds18] */
112#include <sensors/MaximDS18.h>
113
114// OneWire Address [array of 8 hex characters]
115// If only using a single sensor on the OneWire bus, you may omit the address
116// DeviceAddress OneWireAddress1 = {0x28, 0xFF, 0xBD, 0xBA, 0x81, 0x16, 0x03,
117// 0x0C};
118const int8_t OneWirePower = sensorPowerPin; // Power pin (-1 if unconnected)
119const int8_t OneWireBus = 6; // OneWire Bus Pin (-1 if unconnected)
120
121// Create a Maxim DS18 sensor objects (use this form for a known address)
122// MaximDS18 ds18(OneWireAddress1, OneWirePower, OneWireBus);
123
124// Create a Maxim DS18 sensor object (use this form for a single sensor on bus
125// with an unknown address)
126MaximDS18 ds18(OneWirePower, OneWireBus);
127/** End [ds18] */
128
129
130// ==========================================================================
131// Creating the Variable Array[s] and Filling with Variable Objects
132// ==========================================================================
133/** Start [variable_arrays] */
134Variable* variableList[] = {
135 new ProcessorStats_SampleNumber(&mcuBoard),
136 new ProcessorStats_FreeRam(&mcuBoard),
137 new ProcessorStats_Battery(&mcuBoard),
138 new MaximDS3231_Temp(&ds3231),
139 new BoschBME280_Temp(&bme280),
140 new BoschBME280_Humidity(&bme280),
141 new BoschBME280_Pressure(&bme280),
142 new BoschBME280_Altitude(&bme280),
143 new MaximDS18_Temp(&ds18)
144 // Additional sensor variables can be added here, by copying the syntax
145 // for creating the variable pointer (FORM1) from the
146 // `menu_a_la_carte.ino` example
147 // The example code snippets in the wiki are primarily FORM2.
148};
149// Count up the number of pointers in the array
150int variableCount = sizeof(variableList) / sizeof(variableList[0]);
151
152// Create the VariableArray object
153VariableArray varArray;
154/** End [variable_arrays] */
155
156
157// ==========================================================================
158// The Logger Object[s]
159// ==========================================================================
160/** Start [loggers] */
161// Create a logger instance
162Logger dataLogger;
163/** End [loggers] */
164
165
166// ==========================================================================
167// Working Functions
168// ==========================================================================
169/** Start [working_functions] */
170// Flashes the LED's on the primary board
171void greenredflash(uint8_t numFlash = 4, uint8_t rate = 75) {
172 for (uint8_t i = 0; i < numFlash; i++) {
173 digitalWrite(greenLED, HIGH);
174 digitalWrite(redLED, LOW);
175 delay(rate);
176 digitalWrite(greenLED, LOW);
177 digitalWrite(redLED, HIGH);
178 delay(rate);
179 }
180 digitalWrite(redLED, LOW);
181}
182/** End [working_functions] */
183
184
185// ==========================================================================
186// Arduino Setup Function
187// ==========================================================================
188/** Start [setup] */
189void setup() {
190 // Start the primary serial connection
191 Serial.begin(serialBaud);
192
193 // Print a start-up note to the first serial port
194 Serial.print(F("Now running "));
195 Serial.print(sketchName);
196 Serial.print(F(" on Logger "));
197 Serial.println(LoggerID);
198 Serial.println();
199
200 Serial.print(F("Using ModularSensors Library version "));
201 Serial.println(MODULAR_SENSORS_VERSION);
202
203 // Set up pins for the LED's
204 pinMode(greenLED, OUTPUT);
205 digitalWrite(greenLED, LOW);
206 pinMode(redLED, OUTPUT);
207 digitalWrite(redLED, LOW);
208 // Blink the LEDs to show the board is on and starting up
209 greenredflash();
210
211 // Set the timezones for the logger/data and the RTC
212 // Logging in the given time zone
213 Logger::setLoggerTimeZone(timeZone);
214 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
215 Logger::setRTCTimeZone(0);
216
217 // Set information pins
218 dataLogger.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin,
219 greenLED);
220
221 // Begin the variable array[s], logger[s], and publisher[s]
222 varArray.begin(variableCount, variableList);
223 dataLogger.begin(LoggerID, loggingInterval, &varArray);
224
225 // Set up the sensors
226 Serial.println(F("Setting up sensors..."));
227 varArray.setupSensors();
228
229 // Create the log file, adding the default header to it
230 // Do this last so we have the best chance of getting the time correct and
231 // all sensor names correct
232 dataLogger.createLogFile(true); // true = write a new header
233
234 // Call the processor sleep
235 dataLogger.systemSleep();
236}
237/** End [setup] */
238
239
240// ==========================================================================
241// Arduino Loop Function
242// ==========================================================================
243/** Start [loop] */
244void loop() {
245 dataLogger.logData();
246}
247/** End [loop] */