The DRWI EnviroDIY LTEbee 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 Hydros 21 (CTD), a Campbell OBS3+, (Turbidity) and a SIM7080G-based EnviroDIY LTEbee for communication.
The exact hardware configuration used in this example:
Mayfly v1.x board EnviroDIY SIM7080 LTE module (with Hologram SIM card) Hydros21 CTD sensor Campbell Scientific OBS3+ Turbidity sensor An EnviroDIY LTE SIM7080 module can be used with the older Mayfly v0.5b boards if you change line 101 (for modemVccPin) from 18 to -1. This is because the Mayfly v1.0 board has a separate 3.3v regulator to power the Bee socket and is controlled by turning pin 18 on or off. Mayfly v0.5b has the Bee socket constantly powered, therefore using "-1" is the proper setting for that line of code.
The EnviroDIY LTE SIM7080 module includes 2 antennas in the package. The small thin one is the cellular antenna, and should be connected to the socket labeled "CELL". The thicker block is the GPS antenna, and should be connected to the "GPS" socket, but only if you intend to use the GPS functionality of the module. ModularSensors does not currently suport GPS functionality, but other libraries such as TinyGPS can work with the SIM7080 module.
The included cell antenna works best in high-signal-strength areas. For most remote areas and logger deployments, we suggest a larger LTE antenna, like the W3907B0100 from PulseLarsen (Digikey 1837-1003-ND or Mouser 673-W3907B0100)
Unique Features of the DRWI EnviroDIY LTE Example Specifically for sites within the Delaware River Watershed Initiative. Uses a EnviroDIY LTE Bee based on the SIMCom SIM7080G 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 intended for DRWI users with CTD, turbidity, and a EnviroDIY SIM7080G LTE modem
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} DRWI_SIM7080LTE.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 LTE sites.
9 * This example shows proper settings for the following configuration:
12 * EnviroDIY SIM7080 LTE module (with Hologram SIM card)
14 * Campbell Scientific OBS3+ Turbidity sensor
16 * See [the walkthrough page](@ref example_drwi_ediylte) for detailed
19 * @m_examplenavigation{example_drwi_ediylte,}
20 * ======================================================================= */
22 // ==========================================================================
24 // ==========================================================================
26 #ifndef TINY_GSM_RX_BUFFER
27 #define TINY_GSM_RX_BUFFER 64
29 #ifndef TINY_GSM_YIELD_MS
30 #define TINY_GSM_YIELD_MS 2
34 // ==========================================================================
35 // Include the libraries required for any data logger
36 // ==========================================================================
37 /** Start [includes] */
38 // The Arduino library is needed for every Arduino program.
41 // Include the main header for ModularSensors
42 #include <ModularSensors.h>
46 // ==========================================================================
47 // Data Logging Options
48 // ==========================================================================
49 /** Start [logging_options] */
50 // The name of this program file
51 const char * sketchName = "DRWI_SIM7080LTE.ino" ;
52 // Logger ID, also becomes the prefix for the name of the data file on SD card
53 const char * LoggerID = "XXXXX" ;
54 // How frequently (in minutes) to log data
55 const uint8_t loggingInterval = 15 ;
56 // Your logger's timezone.
57 const int8_t timeZone = -5 ; // Eastern Standard Time
58 // NOTE: Daylight savings time will not be applied! Please use standard time!
60 // Set the input and output pins for the logger
61 // NOTE: Use -1 for pins that do not apply
62 const int32_t serialBaud = 57600 ; // Baud rate for debugging
63 const int8_t greenLED = 8 ; // Pin for the green LED
64 const int8_t redLED = 9 ; // Pin for the red LED
65 const int8_t buttonPin = 21 ; // Pin for debugging mode (ie, button pin)
66 const int8_t wakePin = 31 ; // MCU interrupt/alarm pin to wake from sleep
68 const int8_t sdCardPwrPin = -1 ; // MCU SD card power pin
69 const int8_t sdCardSSPin = 12 ; // SD card chip select/slave select pin
70 const int8_t sensorPowerPin = 22 ; // MCU pin controlling main sensor power
71 /** End [logging_options] */
74 // ==========================================================================
75 // Wifi/Cellular Modem Options
76 // ==========================================================================
77 /** Start [sim_com_sim7080] */
78 // For almost anything based on the SIMCom SIM7080G
79 #include <modems/SIMComSIM7080.h>
81 // Create a reference to the serial port for the modem
82 HardwareSerial & modemSerial = Serial1 ; // Use hardware serial if possible
83 const int32_t modemBaud = 9600 ; // SIM7080 does auto-bauding by default, but
84 // for simplicity we set to 9600
86 // Modem Pins - Describe the physical pin connection of your modem to your board
87 // NOTE: Use -1 for pins that do not apply
89 const int8_t modemVccPin = 18 ;
90 // MCU pin controlling modem power --- Pin 18 is the power enable pin for the
91 // bee socket on Mayfly v1.0, use -1 if using Mayfly 0.5b or if the bee socket
92 // is constantly powered (ie you changed SJ18 on Mayfly 1.x to 3.3v)
93 const int8_t modemStatusPin = 19 ; // MCU pin used to read modem status
94 const int8_t modemSleepRqPin = 23 ; // MCU pin for modem sleep/wake request
95 const int8_t modemLEDPin = redLED ; // MCU pin connected an LED to show modem
98 // Network connection information
100 "hologram" ; // APN connection name, typically Hologram unless you have a
101 // different provider's SIM card. Change as needed
103 // Create the modem object
104 SIMComSIM7080 modem7080 ( & modemSerial , modemVccPin , modemStatusPin ,
105 modemSleepRqPin , apn );
106 // Create an extra reference to the modem by a generic name
107 SIMComSIM7080 modem = modem7080 ;
108 /** End [sim_com_sim7080] */
111 // ==========================================================================
112 // Using the Processor as a Sensor
113 // ==========================================================================
114 /** Start [processor_sensor] */
115 #include <sensors/ProcessorStats.h>
117 // Create the main processor chip "sensor" - for general metadata
118 const char * mcuBoardVersion = "v1.1" ;
119 ProcessorStats mcuBoard ( mcuBoardVersion );
120 /** End [processor_sensor] */
123 // ==========================================================================
124 // Maxim DS3231 RTC (Real Time Clock)
125 // ==========================================================================
127 #include <sensors/MaximDS3231.h>
129 // Create a DS3231 sensor object
130 MaximDS3231 ds3231 ( 1 );
134 // ==========================================================================
135 // Meter Hydros 21 Conductivity, Temperature, and Depth Sensor
136 // ==========================================================================
137 /** Start [hydros21] */
138 #include <sensors/MeterHydros21.h>
140 const char * hydrosSDI12address = "1" ; // The SDI-12 Address of the Hydros 21
141 const uint8_t hydrosNumberReadings = 6 ; // The number of readings to average
142 const int8_t SDI12Power = sensorPowerPin ; // Power pin (-1 if unconnected)
143 const int8_t SDI12Data = 7 ; // The SDI12 data pin
145 // Create a Meter Hydros 21 sensor object
146 MeterHydros21 hydros ( * hydrosSDI12address , SDI12Power , SDI12Data ,
147 hydrosNumberReadings );
151 // ==========================================================================
152 // Campbell OBS 3 / OBS 3+ Analog Turbidity Sensor
153 // ==========================================================================
155 #include <sensors/CampbellOBS3.h>
157 const int8_t OBS3Power = sensorPowerPin ; // Power pin (-1 if unconnected)
158 const uint8_t OBS3NumberReadings = 10 ;
159 const uint8_t ADSi2c_addr = 0x48 ; // The I2C address of the ADS1115 ADC
160 // Campbell OBS 3+ *Low* Range Calibration in Volts
161 const int8_t OBSLowADSChannel = 0 ; // ADS channel for *low* range output
162 const float OBSLow_A = 0.000E+00 ; // "A" value (X^2) [*low* range]
163 const float OBSLow_B = 1.000E+00 ; // "B" value (X) [*low* range]
164 const float OBSLow_C = 0.000E+00 ; // "C" value [*low* range]
166 // Create a Campbell OBS3+ *low* range sensor object
167 CampbellOBS3 osb3low ( OBS3Power , OBSLowADSChannel , OBSLow_A , OBSLow_B , OBSLow_C ,
168 ADSi2c_addr , OBS3NumberReadings );
171 // Campbell OBS 3+ *High* Range Calibration in Volts
172 const int8_t OBSHighADSChannel = 1 ; // ADS channel for *high* range output
173 const float OBSHigh_A = 0.000E+00 ; // "A" value (X^2) [*high* range]
174 const float OBSHigh_B = 1.000E+00 ; // "B" value (X) [*high* range]
175 const float OBSHigh_C = 0.000E+00 ; // "C" value [*high* range]
177 // Create a Campbell OBS3+ *high* range sensor object
178 CampbellOBS3 osb3high ( OBS3Power , OBSHighADSChannel , OBSHigh_A , OBSHigh_B ,
179 OBSHigh_C , ADSi2c_addr , OBS3NumberReadings );
183 // ==========================================================================
184 // Creating the Variable Array[s] and Filling with Variable Objects
185 // ==========================================================================
186 /** Start [variable_arrays] */
187 Variable * variableList [] = {
188 new MeterHydros21_Cond ( & hydros ),
189 new MeterHydros21_Depth ( & hydros ),
190 new MeterHydros21_Temp ( & hydros ),
191 new CampbellOBS3_Turbidity ( & osb3low , "" , "TurbLow" ),
192 new CampbellOBS3_Turbidity ( & osb3high , "" , "TurbHigh" ),
193 new ProcessorStats_Battery ( & mcuBoard ),
194 new MaximDS3231_Temp ( & ds3231 ),
195 new Modem_SignalPercent ( & modem ),
198 // All UUID's, device registration, and sampling feature information can be
199 // pasted directly from Monitor My Watershed.
200 // To get the list, click the "View token UUID list" button on the upper right
203 // *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
204 // Check the order of your variables in the variable list!!!
205 // Be VERY certain that they match the order of your UUID's!
206 // Rearrange the variables in the variable list ABOVE if necessary to match!
207 // Do not change the order of the variables in the section below.
208 // *** CAUTION --- CAUTION --- CAUTION --- CAUTION --- CAUTION ***
210 // Replace all of the text in the following section with the UUID array from
213 /* clang-format off */
214 // --------------------- Beginning of Token UUID List ---------------------
217 const char * UUIDs [] = // UUID array for device sensors
219 "12345678-abcd-1234-ef00-1234567890ab" , // Specific conductance (Meter_Hydros21_Cond)
220 "12345678-abcd-1234-ef00-1234567890ab" , // Water depth (Meter_Hydros21_Depth)
221 "12345678-abcd-1234-ef00-1234567890ab" , // Temperature (Meter_Hydros21_Temp)
222 "12345678-abcd-1234-ef00-1234567890ab" , // Turbidity (Campbell_OBS3_Turb) (Low)
223 "12345678-abcd-1234-ef00-1234567890ab" , // Turbidity (Campbell_OBS3_Turb) (High)
224 "12345678-abcd-1234-ef00-1234567890ab" , // Battery voltage (EnviroDIY_Mayfly_Batt)
225 "12345678-abcd-1234-ef00-1234567890ab" , // Battery voltage (EnviroDIY_Mayfly_Batt)
226 "12345678-abcd-1234-ef00-1234567890ab" , // Percent full scale (EnviroDIY_LTEB_SignalPercent)
228 const char * registrationToken = "12345678-abcd-1234-ef00-1234567890ab" ; // Device registration token
229 const char * samplingFeature = "12345678-abcd-1234-ef00-1234567890ab" ; // Sampling feature UUID
232 // ----------------------- End of Token UUID List -----------------------
235 // Count up the number of pointers in the array
236 int variableCount = sizeof ( variableList ) / sizeof ( variableList [ 0 ]);
238 // Create the VariableArray object
239 VariableArray varArray ( variableCount , variableList , UUIDs );
240 /** End [variable_arrays] */
243 // ==========================================================================
244 // The Logger Object[s]
245 // ==========================================================================
246 /** Start [loggers] */
247 // Create a new logger instance
248 Logger dataLogger ( LoggerID , loggingInterval , & varArray );
252 // ==========================================================================
253 // Creating Data Publisher[s]
254 // ==========================================================================
255 /** Start [publishers] */
256 // Create a data publisher for the Monitor My Watershed/EnviroDIY POST endpoint
257 #include <publishers/EnviroDIYPublisher.h>
258 EnviroDIYPublisher EnviroDIYPOST ( dataLogger , & modem . gsmClient ,
259 registrationToken , samplingFeature );
260 /** End [publishers] */
263 // ==========================================================================
265 // ==========================================================================
266 /** Start [working_functions] */
267 // Flashes the LED's on the primary board
268 void greenredflash ( uint8_t numFlash = 4 , uint8_t rate = 75 ) {
269 for ( uint8_t i = 0 ; i < numFlash ; i ++ ) {
270 digitalWrite ( greenLED , HIGH );
271 digitalWrite ( redLED , LOW );
273 digitalWrite ( greenLED , LOW );
274 digitalWrite ( redLED , HIGH );
277 digitalWrite ( redLED , LOW );
280 // Reads the battery voltage
281 // NOTE: This will actually return the battery level from the previous update!
282 float getBatteryVoltage () {
283 if ( mcuBoard . sensorValues [ 0 ] == -9999 ) mcuBoard . update ();
284 return mcuBoard . sensorValues [ 0 ];
288 // ==========================================================================
289 // Arduino Setup Function
290 // ==========================================================================
293 // Start the primary serial connection
294 Serial . begin ( serialBaud );
296 // Print a start-up note to the first serial port
297 Serial . print ( F ( "Now running " ));
298 Serial . print ( sketchName );
299 Serial . print ( F ( " on Logger " ));
300 Serial . println ( LoggerID );
303 Serial . print ( F ( "Using ModularSensors Library version " ));
304 Serial . println ( MODULAR_SENSORS_VERSION );
305 Serial . print ( F ( "TinyGSM Library version " ));
306 Serial . println ( TINYGSM_VERSION );
309 // Start the serial connection with the modem
310 modemSerial . begin ( modemBaud );
312 // Set up pins for the LED's
313 pinMode ( greenLED , OUTPUT );
314 digitalWrite ( greenLED , LOW );
315 pinMode ( redLED , OUTPUT );
316 digitalWrite ( redLED , LOW );
317 // Blink the LEDs to show the board is on and starting up
320 pinMode ( 20 , OUTPUT ); // for proper operation of the onboard flash memory
321 // chip's ChipSelect (Mayfly v1.0 and later)
323 // Set the timezones for the logger/data and the RTC
324 // Logging in the given time zone
325 Logger :: setLoggerTimeZone ( timeZone );
326 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
327 Logger :: setRTCTimeZone ( 0 );
329 // Attach the modem and information pins to the logger
330 dataLogger . attachModem ( modem );
331 modem . setModemLED ( modemLEDPin );
332 dataLogger . setLoggerPins ( wakePin , sdCardSSPin , sdCardPwrPin , buttonPin ,
338 // Note: Please change these battery voltages to match your battery
339 // Set up the sensors, except at lowest battery level
340 if ( getBatteryVoltage () > 3.4 ) {
341 Serial . println ( F ( "Setting up sensors..." ));
342 varArray . setupSensors ();
345 /** Start [setup_sim7080] */
346 modem . setModemWakeLevel ( HIGH ); // ModuleFun Bee inverts the signal
347 modem . setModemResetLevel ( HIGH ); // ModuleFun Bee inverts the signal
348 Serial . println ( F ( "Waking modem and setting Cellular Carrier Options..." ));
349 modem . modemWake (); // NOTE: This will also set up the modem
350 modem . gsmModem . setBaud ( modemBaud ); // Make sure we're *NOT* auto-bauding!
351 modem . gsmModem . setNetworkMode ( 38 ); // set to LTE only
355 // 51 GSM and LTE only
356 modem . gsmModem . setPreferredMode ( 1 ); // set to CAT-M
359 // 3 CAT-M and NB-IoT
360 /** End [setup_sim7080] */
363 // Sync the clock if it isn't valid or we have battery to spare
364 if ( getBatteryVoltage () > 3.55 || ! dataLogger . isRTCSane ()) {
365 // Synchronize the RTC with NIST
366 // This will also set up the modem
367 dataLogger . syncRTC ();
370 // Create the log file, adding the default header to it
371 // Do this last so we have the best chance of getting the time correct and
372 // all sensor names correct
373 // Writing to the SD card can be power intensive, so if we're skipping
374 // the sensor setup we'll skip this too.
375 if ( getBatteryVoltage () > 3.4 ) {
376 Serial . println ( F ( "Setting up file on SD card" ));
377 dataLogger . turnOnSDcard (
378 true ); // true = wait for card to settle after power up
379 dataLogger . createLogFile ( true ); // true = write a new header
380 dataLogger . turnOffSDcard (
381 true ); // true = wait for internal housekeeping after write
384 // Call the processor sleep
385 Serial . println ( F ( "Putting processor to sleep \n " ));
386 dataLogger . systemSleep ();
391 // ==========================================================================
392 // Arduino Loop Function
393 // ==========================================================================
395 // Use this short loop for simple data logging and sending
397 // Note: Please change these battery voltages to match your battery
398 // At very low battery, just go back to sleep
399 if ( getBatteryVoltage () < 3.4 ) {
400 dataLogger . systemSleep ();
402 // At moderate voltage, log data but don't send it over the modem
403 else if ( getBatteryVoltage () < 3.55 ) {
404 dataLogger . logData ();
406 // If the battery is good, send the data to the world
408 dataLogger . logDataAndPublish ();