This sketch reduces menu_a_la_carte.ino to provide an example of how to log to https:/ / monitormywatershed.org/ from two sensors, the BME280 and DS18. To complete the set up for logging to the web portal, the UUIDs for the site and each variable would need to be added to the sketch.
The settings for other data portals were removed from the example.
The modem settings were left unchanged because the sketch will test successfully without modem connection (wait patiently, it takes a few minutes).
This is the example you should use to deploy a logger with a modem to stream live data to the Monitor My Watershed data portal.
Unique Features of the Monitor My Watershed Example A single logger publishes data to the Monitor My Watershed data portal. Uses a cellular Digi XBee or XBee3 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/logging_to_MMW 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 logging_ to_ MMW.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
2 const char * LoggerID = "XXXX" ;
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/ ) For each variable, find the dummy UUID ("12345678-abcd-1234-ef00-1234567890ab"
) and replace it with the real UUID for the variable. Upload! Test everything at home before deploying out in the wild! PlatformIO Configuration 1 ; PlatformIO Project Configuration File
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
8 ; Please visit documentation for the other options and examples
9 ; http://docs.platformio.org/page/projectconf.html
12 description = ModularSensors example menu_a_la_carte with two external sensors logging to Monitor My Watershed
30 -DSDI12_EXTERNAL_PCINT
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} logging_to_MMW.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 data and publishing to Monitor My Watershed.
9 * See [the walkthrough page](@ref example_mmw) for detailed instructions.
11 * @m_examplenavigation{example_mmw,}
12 * ======================================================================= */
14 // ==========================================================================
16 // ==========================================================================
18 #ifndef TINY_GSM_RX_BUFFER
19 #define TINY_GSM_RX_BUFFER 64
21 #ifndef TINY_GSM_YIELD_MS
22 #define TINY_GSM_YIELD_MS 2
26 // ==========================================================================
27 // Include the libraries required for any data logger
28 // ==========================================================================
29 /** Start [includes] */
30 // The Arduino library is needed for every Arduino program.
33 // Include the main header for ModularSensors
34 #include <ModularSensors.h>
38 // ==========================================================================
39 // Data Logging Options
40 // ==========================================================================
41 /** Start [logging_options] */
42 // The name of this program file
43 const char * sketchName = "logging_to MMW.ino" ;
44 // Logger ID, also becomes the prefix for the name of the data file on SD card
45 const char * LoggerID = "XXXXX" ;
46 // How frequently (in minutes) to log data
47 const uint8_t loggingInterval = 15 ;
48 // Your logger's timezone.
49 const int8_t timeZone = -5 ; // Eastern Standard Time
50 // NOTE: Daylight savings time will not be applied! Please use standard time!
52 // Set the input and output pins for the logger
53 // NOTE: Use -1 for pins that do not apply
54 const int32_t serialBaud = 115200 ; // Baud rate for debugging
55 const int8_t greenLED = 8 ; // Pin for the green LED
56 const int8_t redLED = 9 ; // Pin for the red LED
57 const int8_t buttonPin = 21 ; // Pin for debugging mode (ie, button pin)
58 const int8_t wakePin = 31 ; // MCU interrupt/alarm pin to wake from sleep
60 // Set the wake pin to -1 if you do not want the main processor to sleep.
61 // In a SAMD system where you are using the built-in rtc, set wakePin to 1
62 const int8_t sdCardPwrPin = -1 ; // MCU SD card power pin
63 const int8_t sdCardSSPin = 12 ; // SD card chip select/slave select pin
64 const int8_t sensorPowerPin = 22 ; // MCU pin controlling main sensor power
65 /** End [logging_options] */
68 // ==========================================================================
69 // Wifi/Cellular Modem Options
70 // ==========================================================================
71 /** Start [digi_xbee_cellular_transparent] */
72 // For any Digi Cellular XBee's
73 // NOTE: The u-blox based Digi XBee's (3G global and LTE-M global) can be used
74 // in either bypass or transparent mode, each with pros and cons
75 // The Telit based Digi XBees (LTE Cat1) can only use this mode.
76 #include <modems/DigiXBeeCellularTransparent.h>
78 // Create a reference to the serial port for the modem
79 HardwareSerial & modemSerial = Serial1 ; // Use hardware serial if possible
80 const int32_t modemBaud = 9600 ; // All XBee's use 9600 by default
82 // Modem Pins - Describe the physical pin connection of your modem to your board
83 // NOTE: Use -1 for pins that do not apply
84 const int8_t modemVccPin = -2 ; // MCU pin controlling modem power
85 const int8_t modemStatusPin = 19 ; // MCU pin used to read modem status
86 const bool useCTSforStatus = false ; // Flag to use the XBee CTS pin for status
87 const int8_t modemResetPin = 20 ; // MCU pin connected to modem reset pin
88 const int8_t modemSleepRqPin = 23 ; // MCU pin for modem sleep/wake request
89 const int8_t modemLEDPin = redLED ; // MCU pin connected an LED to show modem
90 // status (-1 if unconnected)
92 // Network connection information
93 const char * apn = "xxxxx" ; // The APN for the gprs connection
95 // NOTE: If possible, use the `STATUS/SLEEP_not` (XBee pin 13) for status, but
96 // the `CTS` pin can also be used if necessary
97 DigiXBeeCellularTransparent modemXBCT ( & modemSerial , modemVccPin , modemStatusPin ,
98 useCTSforStatus , modemResetPin ,
99 modemSleepRqPin , apn );
100 // Create an extra reference to the modem by a generic name
101 DigiXBeeCellularTransparent modem = modemXBCT ;
102 /** End [digi_xbee_cellular_transparent] */
105 // ==========================================================================
106 // Using the Processor as a Sensor
107 // ==========================================================================
108 /** Start [processor_sensor] */
109 #include <sensors/ProcessorStats.h>
111 // Create the main processor chip "sensor" - for general metadata
112 const char * mcuBoardVersion = "v1.1" ;
113 ProcessorStats mcuBoard ( mcuBoardVersion );
114 /** End [processor_sensor] */
117 // ==========================================================================
118 // Maxim DS3231 RTC (Real Time Clock)
119 // ==========================================================================
121 #include <sensors/MaximDS3231.h>
123 // Create a DS3231 sensor object
124 MaximDS3231 ds3231 ( 1 );
128 // ==========================================================================
129 // Bosch BME280 Environmental Sensor
130 // ==========================================================================
132 #include <sensors/BoschBME280.h>
134 const int8_t I2CPower = sensorPowerPin ; // Power pin (-1 if unconnected)
135 uint8_t BMEi2c_addr = 0x76 ;
136 // The BME280 can be addressed either as 0x77 (Adafruit default) or 0x76 (Grove
137 // default) Either can be physically mofidied for the other address
139 // Create a Bosch BME280 sensor object
140 BoschBME280 bme280 ( I2CPower , BMEi2c_addr );
144 // ==========================================================================
145 // Maxim DS18 One Wire Temperature Sensor
146 // ==========================================================================
148 #include <sensors/MaximDS18.h>
150 // OneWire Address [array of 8 hex characters]
151 // If only using a single sensor on the OneWire bus, you may omit the address
152 // DeviceAddress OneWireAddress1 = {0x28, 0xFF, 0xBD, 0xBA, 0x81, 0x16, 0x03,
154 const int8_t OneWirePower = sensorPowerPin ; // Power pin (-1 if unconnected)
155 const int8_t OneWireBus = 6 ; // OneWire Bus Pin (-1 if unconnected)
157 // Create a Maxim DS18 sensor objects (use this form for a known address)
158 // MaximDS18 ds18(OneWireAddress1, OneWirePower, OneWireBus);
160 // Create a Maxim DS18 sensor object (use this form for a single sensor on bus
161 // with an unknown address)
162 MaximDS18 ds18 ( OneWirePower , OneWireBus );
166 // ==========================================================================
167 // Creating the Variable Array[s] and Filling with Variable Objects
168 // ==========================================================================
169 /** Start [variable_arrays] */
170 Variable * variableList [] = {
171 new ProcessorStats_SampleNumber ( & mcuBoard ,
172 "12345678-abcd-1234-ef00-1234567890ab" ),
173 new BoschBME280_Temp ( & bme280 , "12345678-abcd-1234-ef00-1234567890ab" ),
174 new BoschBME280_Humidity ( & bme280 , "12345678-abcd-1234-ef00-1234567890ab" ),
175 new BoschBME280_Pressure ( & bme280 , "12345678-abcd-1234-ef00-1234567890ab" ),
176 new BoschBME280_Altitude ( & bme280 , "12345678-abcd-1234-ef00-1234567890ab" ),
177 new MaximDS18_Temp ( & ds18 , "12345678-abcd-1234-ef00-1234567890ab" ),
178 new ProcessorStats_Battery ( & mcuBoard ,
179 "12345678-abcd-1234-ef00-1234567890ab" ),
180 new MaximDS3231_Temp ( & ds3231 , "12345678-abcd-1234-ef00-1234567890ab" ),
181 new Modem_RSSI ( & modem , "12345678-abcd-1234-ef00-1234567890ab" ),
182 new Modem_SignalPercent ( & modem , "12345678-abcd-1234-ef00-1234567890ab" ),
186 // Count up the number of pointers in the array
187 int variableCount = sizeof ( variableList ) / sizeof ( variableList [ 0 ]);
189 // Create the VariableArray object
190 VariableArray varArray ( variableCount , variableList );
191 /** End [variable_arrays] */
194 // ==========================================================================
195 // The Logger Object[s]
196 // ==========================================================================
197 /** Start [loggers] */
198 // Create a new logger instance
199 Logger dataLogger ( LoggerID , loggingInterval , & varArray );
203 // ==========================================================================
204 // Creating Data Publisher[s]
205 // ==========================================================================
206 /** Start [publishers] */
207 // A Publisher to Monitor My Watershed / EnviroDIY Data Sharing Portal
208 // Device registration and sampling feature information can be obtained after
209 // registration at https://monitormywatershed.org or https://data.envirodiy.org
210 const char * registrationToken =
211 "12345678-abcd-1234-ef00-1234567890ab" ; // Device registration token
212 const char * samplingFeature =
213 "12345678-abcd-1234-ef00-1234567890ab" ; // Sampling feature UUID
215 // Create a data publisher for the Monitor My Watershed/EnviroDIY POST endpoint
216 #include <publishers/EnviroDIYPublisher.h>
217 EnviroDIYPublisher EnviroDIYPOST ( dataLogger , & modem . gsmClient ,
218 registrationToken , samplingFeature );
219 /** End [publishers] */
222 // ==========================================================================
224 // ==========================================================================
225 /** Start [working_functions] */
226 // Flashes the LED's on the primary board
227 void greenredflash ( uint8_t numFlash = 4 , uint8_t rate = 75 ) {
228 for ( uint8_t i = 0 ; i < numFlash ; i ++ ) {
229 digitalWrite ( greenLED , HIGH );
230 digitalWrite ( redLED , LOW );
232 digitalWrite ( greenLED , LOW );
233 digitalWrite ( redLED , HIGH );
236 digitalWrite ( redLED , LOW );
239 // Reads the battery voltage
240 // NOTE: This will actually return the battery level from the previous update!
241 float getBatteryVoltage () {
242 if ( mcuBoard . sensorValues [ 0 ] == -9999 ) mcuBoard . update ();
243 return mcuBoard . sensorValues [ 0 ];
245 /** End [working_functions] */
248 // ==========================================================================
249 // Arduino Setup Function
250 // ==========================================================================
253 // Wait for USB connection to be established by PC
254 // NOTE: Only use this when debugging - if not connected to a PC, this
255 // could prevent the script from starting
256 #if defined(SERIAL_PORT_USBVIRTUAL)
257 while ( ! SERIAL_PORT_USBVIRTUAL && ( millis () < 10000 )) {
262 // Start the primary serial connection
263 Serial . begin ( serialBaud );
265 // Print a start-up note to the first serial port
266 Serial . print ( F ( "Now running " ));
267 Serial . print ( sketchName );
268 Serial . print ( F ( " on Logger " ));
269 Serial . println ( LoggerID );
272 Serial . print ( F ( "Using ModularSensors Library version " ));
273 Serial . println ( MODULAR_SENSORS_VERSION );
274 Serial . print ( F ( "TinyGSM Library version " ));
275 Serial . println ( TINYGSM_VERSION );
278 // Allow interrupts for software serial
279 #if defined(SoftwareSerial_ExtInts_h)
280 enableInterrupt ( softSerialRx , SoftwareSerial_ExtInts :: handle_interrupt ,
283 #if defined(NeoSWSerial_h)
284 enableInterrupt ( neoSSerial1Rx , neoSSerial1ISR , CHANGE );
287 // Start the serial connection with the modem
288 modemSerial . begin ( modemBaud );
290 // Set up pins for the LED's
291 pinMode ( greenLED , OUTPUT );
292 digitalWrite ( greenLED , LOW );
293 pinMode ( redLED , OUTPUT );
294 digitalWrite ( redLED , LOW );
295 // Blink the LEDs to show the board is on and starting up
298 // Set the timezones for the logger/data and the RTC
299 // Logging in the given time zone
300 Logger :: setLoggerTimeZone ( timeZone );
301 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
302 Logger :: setRTCTimeZone ( 0 );
304 // Attach the modem and information pins to the logger
305 dataLogger . attachModem ( modem );
306 modem . setModemLED ( modemLEDPin );
307 dataLogger . setLoggerPins ( wakePin , sdCardSSPin , sdCardPwrPin , buttonPin ,
313 // Note: Please change these battery voltages to match your battery
314 // Set up the sensors, except at lowest battery level
315 if ( getBatteryVoltage () > 3.4 ) {
316 Serial . println ( F ( "Setting up sensors..." ));
317 varArray . setupSensors ();
320 // Sync the clock if it isn't valid or we have battery to spare
321 if ( getBatteryVoltage () > 3.55 || ! dataLogger . isRTCSane ()) {
322 // Synchronize the RTC with NIST
323 // This will also set up the modem
324 dataLogger . syncRTC ();
327 // Create the log file, adding the default header to it
328 // Do this last so we have the best chance of getting the time correct and
329 // all sensor names correct
330 // Writing to the SD card can be power intensive, so if we're skipping
331 // the sensor setup we'll skip this too.
332 if ( getBatteryVoltage () > 3.4 ) {
333 Serial . println ( F ( "Setting up file on SD card" ));
334 dataLogger . turnOnSDcard (
335 true ); // true = wait for card to settle after power up
336 dataLogger . createLogFile ( true ); // true = write a new header
337 dataLogger . turnOffSDcard (
338 true ); // true = wait for internal housekeeping after write
341 // Call the processor sleep
342 Serial . println ( F ( "Putting processor to sleep \n " ));
343 dataLogger . systemSleep ();
348 // ==========================================================================
349 // Arduino Loop Function
350 // ==========================================================================
352 // Use this short loop for simple data logging and sending
354 // Note: Please change these battery voltages to match your battery
355 // At very low battery, just go back to sleep
356 if ( getBatteryVoltage () < 3.4 ) {
357 dataLogger . systemSleep ();
359 // At moderate voltage, log data but don't send it over the modem
360 else if ( getBatteryVoltage () < 3.55 ) {
361 dataLogger . logData ();
363 // If the battery is good, send the data to the world
365 dataLogger . logDataAndPublish ();