diff --git a/examples/SARA-R5_Example17_ThingSpeak_MQTT/SARA-R5_Example17_ThingSpeak_MQTT.ino b/examples/SARA-R5_Example17_ThingSpeak_MQTT/SARA-R5_Example17_ThingSpeak_MQTT.ino new file mode 100644 index 0000000..a48183f --- /dev/null +++ b/examples/SARA-R5_Example17_ThingSpeak_MQTT/SARA-R5_Example17_ThingSpeak_MQTT.ino @@ -0,0 +1,268 @@ +/* + + SARA-R5 Example + =============== + + ThingSpeak (MQTT) + + Written by: Paul Clark + Date: November 14th 2023 + + This example uses the SARA's mobile data connection and MQTT to publish random temperatures on ThingSpeak. + It also subscribes to the same topic (channel) so you can read the data back again! + + See: https://thingspeak.com/ + + And: https://uk.mathworks.com/help/thingspeak/mqtt-basics.html#responsive_offcanvas + + You will need to: + Create a ThingSpeak User Account – https://thingspeak.com/login + Create a new Channel by selecting Channels, My Channels, and then New Channel + Note the Channel ID and copy&paste it into myChannelID below + Click on the Devices drop-down at the top of the screen and select MQTT + Create a new MQTT Device using "Add a new device". Give it a name + Authorize the New Channel you created above, then Add Channel, then Add Device + Copy the Username, Client ID and password into myUsername, myClientID and myPassword below + The random temperature reading will be added to the channel as "Field 1" + + Feel like supporting open source hardware? + Buy a board from SparkFun! + + Licence: MIT + Please see LICENSE.md for full details + +*/ + +#include + +// ThingSpeak via MQTT Publish + +String brokerName = "mqtt3.thingspeak.com"; // MQTT Broker + +const int brokerPort = 1883; // MQTT port (TCP, no encryption) + +String myUsername = "OAAxOjYHIwooJykfCiYoEx0"; + +String myClientID = "OAAxOjYHIwooJykfCiYoEx0"; + +String myPassword = "RqY/6L246tULLVWUzCqJBX/V"; + +String myChannelID = "1225363"; // Public View: https://thingspeak.com/channels/1225363 + +// SARA-R5 + +#include //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_SARA-R5_Arduino_Library + +// Uncomment the next line to connect to the SARA-R5 using hardware Serial1 +#define saraSerial Serial1 + +// Uncomment the next line to create a SoftwareSerial object to pass to the SARA-R5 library instead +//SoftwareSerial saraSerial(8, 9); + +// Create a SARA_R5 object to use throughout the sketch +// Usually we would tell the library which GPIO pin to use to control the SARA power (see below), +// but we can start the SARA without a power pin. It just means we need to manually +// turn the power on if required! ;-D +SARA_R5 mySARA; + +// Create a SARA_R5 object to use throughout the sketch +// We need to tell the library what GPIO pin is connected to the SARA power pin. +// If you're using the MicroMod Asset Tracker and the MicroMod Artemis Processor Board, +// the pin name is G2 which is connected to pin AD34. +// Change the pin number if required. +//SARA_R5 mySARA(34); + +// processMQTTcommandResult is provided to the SARA-R5 library via a +// callback setter -- setMQTTCommandCallback. (See the end of setup()) +void processMQTTcommandResult(int command, int result) +{ + Serial.println(); + Serial.print(F("MQTT Command Result: command: ")); + Serial.print(command); + Serial.print(F(" result: ")); + Serial.print(result); + if (result == 0) + Serial.print(F(" (fail)")); + if (result == 1) + Serial.print(F(" (success)")); + Serial.println(); + + // Get and print the most recent MQTT protocol error + int error_class; + int error_code; + mySARA.getMQTTprotocolError(&error_class, &error_code); + Serial.print(F("Most recent MQTT protocol error: class: ")); + Serial.print(error_class); + Serial.print(F(" code: ")); + Serial.print(error_code); + if (error_code == 0) + Serial.print(F(" (no error)")); + Serial.println(); +} + +void setup() +{ + delay(1000); + + String currentOperator = ""; + + Serial.begin(115200); // Start the serial console + + // Wait for user to press key to begin + Serial.println(F("SARA-R5 Example")); + Serial.println(F("Wait for the SARA NI LED to light up - then press any key to begin")); + + while (!Serial.available()) // Wait for the user to press a key (send any serial character) + ; + while (Serial.available()) // Empty the serial RX buffer + Serial.read(); + + //mySARA.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // For the MicroMod Asset Tracker, we need to invert the power pin so it pulls high instead of low + // Comment the next line if required + mySARA.invertPowerPin(true); + + // Initialize the SARA + if (mySARA.begin(saraSerial, 115200) ) + { + Serial.println(F("SARA-R5 connected!")); + } + else + { + Serial.println(F("Unable to communicate with the SARA.")); + Serial.println(F("Manually power-on (hold the SARA On button for 3 seconds) on and try again.")); + while (1) ; // Loop forever on fail + } + Serial.println(); + + // First check to see if we're connected to an operator: + if (mySARA.getOperator(¤tOperator) == SARA_R5_SUCCESS) + { + Serial.print(F("Connected to: ")); + Serial.println(currentOperator); + } + else + { + Serial.print(F("The SARA is not yet connected to an operator. Please use the previous examples to connect. Or wait and retry. Freezing...")); + while (1) + ; // Do nothing more + } + + // Deactivate the PSD profile - in case one is already active + if (mySARA.performPDPaction(0, SARA_R5_PSD_ACTION_DEACTIVATE) != SARA_R5_SUCCESS) + { + Serial.println(F("Warning: performPDPaction (deactivate profile) failed. Probably because no profile was active.")); + } + + // Load the PSD profile from NVM - these were saved by a previous example + if (mySARA.performPDPaction(0, SARA_R5_PSD_ACTION_LOAD) != SARA_R5_SUCCESS) + { + Serial.println(F("performPDPaction (load from NVM) failed! Freezing...")); + while (1) + ; // Do nothing more + } + + // Activate the PSD profile + if (mySARA.performPDPaction(0, SARA_R5_PSD_ACTION_ACTIVATE) != SARA_R5_SUCCESS) + { + Serial.println(F("performPDPaction (activate profile) failed! Freezing...")); + while (1) + ; // Do nothing more + } + + // Set up the MQTT command callback + mySARA.setMQTTCommandCallback(processMQTTcommandResult); + + // Disable the security profile + mySARA.setMQTTsecure(false); + + // Set Client ID + mySARA.setMQTTclientId(myClientID); + + // Set the broker name and port + mySARA.setMQTTserver(brokerName, brokerPort); + + // Set the user name and password + mySARA.setMQTTcredentials(myUsername, myPassword); + + // Connect + if (mySARA.connectMQTT() == SARA_R5_SUCCESS) + Serial.println(F("MQTT connect: success")); + else + Serial.println(F("MQTT connect: failed!")); + + // The LTE modem has difficulties subscribing/unsubscribing more than one topic at the same time. + // We can only start one operation at a time wait for the URC and add a extra delay before we can + // do the next operation. + // Wait for ~2 seconds + for (int i = 0; i < 200; i++) + { + mySARA.bufferedPoll(); // Keep processing data from the SARA + delay(10); + } + + // Subscribe to the channel topic, so we can read the data back again + String subscribeTopic = "channels/" + myChannelID + "/subscribe/fields/field1"; + if (mySARA.subscribeMQTTtopic(0, subscribeTopic) == SARA_R5_SUCCESS) // QoS = 0 + Serial.println(F("MQTT subscribe: success")); + else + Serial.println(F("MQTT subscribe: failed!")); + + // Wait for ~2 seconds + for (int i = 0; i < 200; i++) + { + mySARA.bufferedPoll(); // Keep processing data from the SARA + delay(10); + } +} + +void loop() +{ + float temperature = ((float)random(2000,3000)) / 100.0; // Create a random temperature between 20 and 30 + + // Send data using MQTT Publish + String Topic = "channels/" + myChannelID + "/publish"; + String DataField = "field1=" + String(temperature) + "&status=MQTTPUBLISH"; + + Serial.println(); + Serial.print(F("Publishing a temperature of ")); + Serial.print(String(temperature)); + Serial.println(F(" to ThingSpeak")); + + // Publish the text message + mySARA.mqttPublishTextMsg(Topic, DataField.c_str(), 0, true); // QoS = 0, retain = true + + // Wait for ~10 seconds + for (int i = 0; i < 1000; i++) + { + mySARA.bufferedPoll(); // Keep processing data from the SARA + delay(10); + } + + // Check for any received data + // The MQTT API does not allow getting the size before actually reading the data. + // So we have to allocate a big enough buffer. + const int MQTT_MAX_MSG_SIZE = 1024; + static uint8_t buf[MQTT_MAX_MSG_SIZE]; + String topic; + int len = -1; + int qos = -1; + if (mySARA.readMQTT(&qos, &topic, buf, MQTT_MAX_MSG_SIZE, &len) == SARA_R5_SUCCESS) + { + if (len > 0) + { + Serial.println(); + Serial.print(F("Subscribed MQTT data: ")); + Serial.write((const char *)buf, len); + Serial.println(); + } + } + + // Wait for ~10 seconds + for (int i = 0; i < 1000; i++) + { + mySARA.bufferedPoll(); // Keep processing data from the SARA + delay(10); + } +} diff --git a/keywords.txt b/keywords.txt index 53ce387..1b23534 100644 --- a/keywords.txt +++ b/keywords.txt @@ -164,12 +164,16 @@ sendHTTPPOSTfile KEYWORD2 nvMQTT KEYWORD2 setMQTTclientId KEYWORD2 setMQTTserver KEYWORD2 +setMQTTcredentials KEYWORD2 setMQTTsecure KEYWORD2 connectMQTT KEYWORD2 disconnectMQTT KEYWORD2 subscribeMQTTtopic KEYWORD2 unsubscribeMQTTtopic KEYWORD2 readMQTT KEYWORD2 +mqttPublishTextMsg KEYWORD2 +mqttPublishBinaryMsg KEYWORD2 +mqttPublishFromFile KEYWORD2 getMQTTprotocolError KEYWORD2 resetSecurityProfile KEYWORD2 configSecurityProfileString KEYWORD2 diff --git a/library.properties b/library.properties index 80b33a0..767ddfd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun u-blox SARA-R5 Arduino Library -version=1.1.8 +version=1.1.9 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=Library for the u-blox SARA-R5 LTE-M / NB-IoT modules with secure cloud

diff --git a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp index 800dcef..490a161 100644 --- a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp @@ -4814,7 +4814,7 @@ SARA_R5_error_t SARA_R5::setSecurityManager(SARA_R5_sec_manager_opcode_t opcode, _debugPort->println(F(" bytes")); } hwWriteData(data.c_str(), dataLen); - err = waitForResponse(SARA_R5_RESPONSE_OK, SARA_R5_RESPONSE_ERROR, SARA_R5_STANDARD_RESPONSE_TIMEOUT*3); + err = waitForResponse(SARA_R5_RESPONSE_OK, SARA_R5_RESPONSE_ERROR, SARA_R5_SECURITY_RESPONSE_TIMEOUT); } diff --git a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h index b743cde..ea1a274 100644 --- a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h +++ b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h @@ -89,6 +89,7 @@ #define SARA_R5_IP_CONNECT_TIMEOUT 130000 #define SARA_R5_POLL_DELAY 1 #define SARA_R5_SOCKET_WRITE_TIMEOUT 10000 +#define SARA_R5_SECURITY_RESPONSE_TIMEOUT 10000 // ## Suported AT Commands // ### General