Example logging data and publishing to AWS IoT Core.
Example logging data and publishing to AWS IoT Core.
Before using this example, you MUST obtain the certificates from AWS IoT and upload them to your modem. This library does NOT support SSL connections natively - it offload the SSL connection process onto the modem. This means that the modem must be able to handle the SSL connection and must have the certificates loaded onto it. Make sure you know the certificate file name as you loaded it onto the module. For supported modems, you can use the AWS_IoT_SetCertificates program in the extras folder to load your certificates. Once you have confirmed your certificates are loaded and working, there is no reason to rerun that program unless you have a new modem, reset your modem, or your certificates change. Most modules store the certificates in flash, which has a limited number of read/write cycles. To avoid wearing out the flash unnecessarily, you should only run load/write the certificates when necessarily, instead of every time you re-start your board.
See the walkthrough page for detailed instructions.
1/** =========================================================================
2 * @example{lineno} AWS_IoT_Core.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 AWS IoT Core.
9 * Before using this example, you **MUST** obtain the certificates from AWS IoT
10 * and upload them to your modem. This library does NOT support SSL connections
11 * natively - it offload the SSL connection process onto the modem. This means
12 * that the modem must be able to handle the SSL connection and must have the
13 * certificates loaded onto it. Make sure you know the certificate file name as
14 * you loaded it onto the module. For supported modems, you can use the
15 * AWS_IoT_SetCertificates program in the extras folder to load your
16 * certificates. Once you have confirmed your certificates are loaded and
17 * working, there is no reason to rerun that program unless you have a new
18 * modem, reset your modem, or your certificates change. Most modules store the
19 * certificates in flash, which has a limited number of read/write cycles. To
20 * avoid wearing out the flash unnecessarily, you should only run load/write the
21 * certificates when necessarily, instead of every time you re-start your board.
23 * See [the walkthrough page](@ref example_aws_iot_core) for detailed
26 * @m_examplenavigation{example_aws_iot_core,}
27 * ======================================================================= */
29// ==========================================================================
31// ==========================================================================
33#ifndef TINY_GSM_RX_BUFFER
34#define TINY_GSM_RX_BUFFER 64
36#ifndef TINY_GSM_YIELD_MS
37#define TINY_GSM_YIELD_MS 2
39#ifndef MQTT_MAX_PACKET_SIZE
40#define MQTT_MAX_PACKET_SIZE 1024
44// ==========================================================================
45// Include the libraries required for any data logger
46// ==========================================================================
47/** Start [includes] */
48// The Arduino library is needed for every Arduino program.
51// Include the main header for ModularSensors
52#include <ModularSensors.h>
56// ==========================================================================
57// Data Logging Options
58// ==========================================================================
59/** Start [logging_options] */
60static const char AWS_IOT_ENDPOINT[] TINY_GSM_PROGMEM =
61 "YOUR_ENDPOINT-ats.iot.YOUR_REGION.amazonaws.com";
62#define THING_NAME "YOUR_THING_NAME"
63// The name of this program file - this is used only for console printouts at
65const char* sketchName = "AWS_IoT_Core.ino";
66// Logger ID, also becomes the prefix for the name of the data file on SD card
67// NOTE: Your LoggerID will be used as your Thing Name, primary topic, and
68// client name when connecting to AWS IoT Core. _**Make sure it is unique!**_
69const char* LoggerID = THING_NAME;
70// Sampling feature UUID
71// This is used as the sub-topic for AWS IOT Core
72const char* samplingFeature = "YOUR_SAMPLING_FEATURE_ID";
73// How frequently (in minutes) to log data
74const int8_t loggingInterval = 5;
75// Your logger's timezone.
76const int8_t timeZone = -5; // Eastern Standard Time
77// NOTE: Daylight savings time will not be applied! Please use standard time!
79// Set the input and output pins for the logger
80// NOTE: Use -1 for pins that do not apply
81const int32_t serialBaud = 115200; // Baud rate for debugging
82const int8_t greenLED = 8; // Pin for the green LED
83const int8_t redLED = 9; // Pin for the red LED
84const int8_t buttonPin = 21; // Pin for debugging mode (ie, button pin)
85const int8_t wakePin = 31; // MCU interrupt/alarm pin to wake from sleep
87// Set the wake pin to -1 if you do not want the main processor to sleep.
88// In a SAMD system where you are using the built-in rtc, set wakePin to 1
89const int8_t sdCardPwrPin = -1; // MCU SD card power pin
90const int8_t sdCardSSPin = 12; // SD card chip select/slave select pin
91const int8_t sensorPowerPin = 22; // MCU pin controlling main sensor power
92/** End [logging_options] */
95// ==========================================================================
96// Wifi/Cellular Modem Options
97// ==========================================================================
98/** Start [espressif_esp32] */
99// For almost anything based on the Espressif ESP32 using the AT command
101#include <modems/EspressifESP32.h>
102// Create a reference to the serial port for the modem
103HardwareSerial& modemSerial = Serial1; // Use hardware serial if possible
104const int32_t modemBaud = 115200; // Communication speed of the modem
105// NOTE: This baud rate too fast for an 8MHz board, like the Mayfly! The
106// module should be programmed to a slower baud rate or set to auto-baud using
107// the AT+UART_CUR or AT+UART_DEF command.
109// Modem Pins - Describe the physical pin connection of your modem to your board
110// NOTE: Use -1 for pins that do not apply
111const int8_t modemVccPin = -2; // MCU pin controlling modem power
112const int8_t modemResetPin = 20; // MCU pin connected to modem reset pin
113const int8_t modemLEDPin =
114 redLED; // MCU pin connected an LED to show modem status
116// Network connection information
117const char* wifiId = "xxxxx"; // The WiFi access point
118const char* wifiPwd = "xxxxx"; // The password for connecting to WiFi
120// Create the loggerModem object
121EspressifESP32 modemESP(&modemSerial, modemVccPin, modemResetPin, wifiId,
123// Create an extra reference to the modem by a generic name
124EspressifESP32 modem = modemESP;
125/** End [espressif_esp32] */
127/** Start [modem_variables] */
128// Create RSSI and signal strength variable pointers for the modem
129/** End [modem_variables] */
132// ==========================================================================
133// Using the Processor as a Sensor
134// ==========================================================================
135/** Start [processor_stats] */
136#include <sensors/ProcessorStats.h>
138// Create the main processor chip "sensor" - for general metadata
139#if defined(ENVIRODIY_STONEFLY_M4)
140const char* mcuBoardVersion = "v0.1";
141#elif defined(ARDUINO_AVR_ENVIRODIY_MAYFLY)
142const char* mcuBoardVersion = "v1.1";
144const char* mcuBoardVersion = "unknown";
146ProcessorStats mcuBoard(mcuBoardVersion, 5);
147/** End [processor_stats] */
150// ==========================================================================
151// Everlight ALS-PT19 Ambient Light Sensor
152// ==========================================================================
153/** Start [everlight_alspt19] */
154#include <sensors/EverlightALSPT19.h>
156// NOTE: Use -1 for any pins that don't apply or aren't being used.
157const int8_t alsPower = sensorPowerPin; // Power pin
158#if defined(ENVIRODIY_STONEFLY_M4)
159const int8_t alsData = A8; // The ALS PT-19 data pin
161const int8_t alsData = A4; // The ALS PT-19 data pin
163const int8_t alsSupply = 3.3; // The ALS PT-19 supply power voltage
164const int8_t alsResistance = 10; // The ALS PT-19 loading resistance (in kΩ)
165const uint8_t alsNumberReadings = 10;
167// Create a Everlight ALS-PT19 sensor object
168EverlightALSPT19 alsPt19(alsPower, alsData, alsSupply, alsResistance,
170/** End [everlight_alspt19] */
172// ==========================================================================
173// Sensirion SHT4X Digital Humidity and Temperature Sensor
174// ==========================================================================
175/** Start [sensirion_sht4x] */
176#include <sensors/SensirionSHT4x.h>
178// NOTE: Use -1 for any pins that don't apply or aren't being used.
179const int8_t SHT4xPower = sensorPowerPin; // Power pin
180const bool SHT4xUseHeater = true;
182// Create an Sensirion SHT4X sensor object
183SensirionSHT4x sht4x(SHT4xPower, SHT4xUseHeater);
184/** End [sensirion_sht4x] */
187// ==========================================================================
188// Creating the Variable Array[s] and Filling with Variable Objects
189// ==========================================================================
190/** Start [variable_arrays] */
191Variable* variableList[] = {
192 new SensirionSHT4x_Humidity(&sht4x, "12345678-abcd-1234-ef00-1234567890ab"),
193 new SensirionSHT4x_Temp(&sht4x, "12345678-abcd-1234-ef00-1234567890ab"),
194 new EverlightALSPT19_Voltage(&alsPt19,
195 "12345678-abcd-1234-ef00-1234567890ab"),
196 new EverlightALSPT19_Current(&alsPt19,
197 "12345678-abcd-1234-ef00-1234567890ab"),
198 new EverlightALSPT19_Illuminance(&alsPt19,
199 "12345678-abcd-1234-ef00-1234567890ab"),
201 new Modem_RSSI(&modem, "12345678-abcd-1234-ef00-1234567890ab", "RSSI"),
202 new Modem_SignalPercent(&modem, "12345678-abcd-1234-ef00-1234567890ab",
204#if defined(TINY_GSM_MODEM_HAS_BATTERY)
205 new Modem_BatteryState(&modem, "12345678-abcd-1234-ef00-1234567890ab",
207 new Modem_BatteryPercent(&modem, "12345678-abcd-1234-ef00-1234567890ab",
209 new Modem_BatteryVoltage(&modem, "12345678-abcd-1234-ef00-1234567890ab",
212#if defined(TINY_GSM_MODEM_HAS_TEMPERATURE)
214 new Modem_Temp(&modem, "12345678-abcd-1234-ef00-1234567890ab", "modemTemp"),
216 new ProcessorStats_Battery(&mcuBoard,
217 "12345678-abcd-1234-ef00-1234567890ab"),
218 new ProcessorStats_FreeRam(&mcuBoard,
219 "12345678-abcd-1234-ef00-1234567890ab"),
220 new ProcessorStats_SampleNumber(&mcuBoard,
221 "12345678-abcd-1234-ef00-1234567890ab"),
222 new ProcessorStats_ResetCode(&mcuBoard,
223 "12345678-abcd-1234-ef00-1234567890ab"),
225// Count up the number of pointers in the array
226int variableCount = sizeof(variableList) / sizeof(variableList[0]);
228// Create the VariableArray object
229VariableArray varArray;
230/** End [variable_arrays] */
233// ==========================================================================
234// The Logger Object[s]
235// ==========================================================================
236/** Start [loggers] */
237// Create a logger instance
242// ==========================================================================
243// AWS IoT Core MQTT Publisher
244// ==========================================================================
245/** Start [aws_io_t_publisher] */
246// The endpoint for your AWS IoT instance
247const char* awsIoTEndpoint = AWS_IOT_ENDPOINT;
248// The name of your certificate authority certificate file
249const char* caCertName = "AmazonRootCA1.pem";
250// The name of your client certificate file
251const char* clientCertName = THING_NAME "-certificate.pem.crt";
252// The name of your client private key file
253const char* clientKeyName = THING_NAME "-private-key.pem.key";
255// Create a data publisher for AWS IoT Core
256#include <publishers/AWS_IoT_Publisher.h>
257AWS_IoT_Publisher awsIoTPub(dataLogger, awsIoTEndpoint, caCertName,
258 clientCertName, clientKeyName, samplingFeature);
259/** End [aws_io_t_publisher] */
262// ==========================================================================
264// ==========================================================================
265/** Start [working_functions] */
266// Flashes the LED's on the primary board
267void greenRedFlash(uint8_t numFlash = 4, uint8_t rate = 75) {
268 for (uint8_t i = 0; i < numFlash; i++) {
269 digitalWrite(greenLED, HIGH);
270 digitalWrite(redLED, LOW);
272 digitalWrite(greenLED, LOW);
273 digitalWrite(redLED, HIGH);
276 digitalWrite(redLED, LOW);
279// Reads the battery voltage
280// NOTE: This will actually return the battery level from the previous update!
281float getBatteryVoltage() {
282 if (mcuBoard.sensorValues[0] == -9999) mcuBoard.update();
283 return mcuBoard.sensorValues[0];
285/** End [working_functions] */
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 // Set the timezones for the logger/data and the RTC
321 // Logging in the given time zone
322 Logger::setLoggerTimeZone(timeZone);
323 // It is STRONGLY RECOMMENDED that you set the RTC to be in UTC (UTC+0)
324 loggerClock::setRTCOffset(0);
326 // Attach the modem and information pins to the logger
327 dataLogger.attachModem(modem);
328 modem.setModemLED(modemLEDPin);
329 dataLogger.setLoggerPins(wakePin, sdCardSSPin, sdCardPwrPin, buttonPin,
332 // Begin the variable array[s], logger[s], and publisher[s]
333 varArray.begin(variableCount, variableList);
334 dataLogger.begin(LoggerID, loggingInterval, &varArray);
336 // Note: Please change these battery voltages to match your battery
337 // Set up the sensors, except at lowest battery level
338 if (getBatteryVoltage() > 3.4) {
339 Serial.println(F("Setting up sensors..."));
340 varArray.setupSensors();
343 // Sync the clock if it isn't valid or we have battery to spare
344 if (getBatteryVoltage() > 3.55 || !loggerClock::isRTCSane()) {
345 // Synchronize the RTC with NIST
346 // This will also set up the modem
347 dataLogger.syncRTC();
350 // Create the log file, adding the default header to it
351 // Do this last so we have the best chance of getting the time correct and
352 // all sensor names correct
353 // Writing to the SD card can be power intensive, so if we're skipping
354 // the sensor setup we'll skip this too.
355 if (getBatteryVoltage() > 3.4) {
356 Serial.println(F("Setting up file on SD card"));
357 dataLogger.turnOnSDcard(
358 true); // true = wait for card to settle after power up
359 dataLogger.createLogFile(true); // true = write a new header
360 dataLogger.turnOffSDcard(
361 true); // true = wait for internal housekeeping after write
364 // Call the processor sleep
365 Serial.println(F("Putting processor to sleep"));
366 dataLogger.systemSleep();
371// ==========================================================================
372// Arduino Loop Function
373// ==========================================================================
375// Use this short loop for simple data logging and sending
377 // Note: Please change these battery voltages to match your battery
378 // At very low battery, just go back to sleep
379 if (getBatteryVoltage() < 3.4) {
380 dataLogger.systemSleep();
382 // At moderate voltage, log data but don't send it over the modem
383 else if (getBatteryVoltage() < 3.55) {
384 dataLogger.logData();
386 // If the battery is good, send the data to the world
388 dataLogger.logDataAndPublish();
393// cSpell:ignore modemBatterymV