Hey! I have an arduino that gathers accelerometer data, and sends it up to the cloud. As I want to be constantly taking readings, it would be preferable to have all GSM connection commands run asynchronously, as to not block any data taking.
Is this possible on the Arduino GSM MKR 1400? My code, at the moment, seems to "block" at the GSM parts. Is there a method to ensure the connection is made, and data sent over GSM, async? Is blocking behaviour a limitation of the device?
I've attached my code below, though it may not be necessary. Its heavily based on one of the Arduino Cloud Provider examples.
#include <ArduinoBearSSL.h>
#include <ArduinoECCX08.h>
#include <utility/ECCX08SelfSignedCert.h>
#include <ArduinoMqttClient.h>
#include <MKRGSM.h>
#include "SparkFunLIS3DH.h"
#include "Wire.h"
#include "SPI.h"
#include "arduino_secrets.h"
/////// Enter your sensitive data in arduino_secrets.h
const char pinnumber[] = SECRET_PINNUMBER;
const char gprs_apn[] = SECRET_GPRS_APN;
const char gprs_login[] = SECRET_GPRS_LOGIN;
const char gprs_password[] = SECRET_GPRS_PASSWORD;
const char broker[] = SECRET_BROKER;
String deviceId = SECRET_DEVICE_ID;
GSM gsmAccess;
GPRS gprs;
GSMClient gsmClient; // Used for the TCP socket connection
BearSSLClient sslClient(gsmClient); // Used for SSL/TLS connection, integrates with ECC508
MqttClient mqttClient(sslClient);
LIS3DH myIMU; //Default constructor is I2C, addr 0x19.
unsigned long lastMillis = 0;
void setup() {
Serial.begin(9600);
while (!Serial);
if (!ECCX08.begin()) {
Serial.println("No ECCX08 present!");
while (1);
}
// reconstruct the self signed cert
ECCX08SelfSignedCert.beginReconstruction(0, 8);
ECCX08SelfSignedCert.setCommonName(ECCX08.serialNumber());
ECCX08SelfSignedCert.endReconstruction();
// Set a callback to get the current time
// used to validate the servers certificate
ArduinoBearSSL.onGetTime(getTime);
// Set the ECCX08 slot to use for the private key
// and the accompanying public certificate for it
sslClient.setEccSlot(0, ECCX08SelfSignedCert.bytes(), ECCX08SelfSignedCert.length());
// Set the client id used for MQTT as the device id
mqttClient.setId(deviceId);
// Set the username to "<broker>/<device id>/api-version=2018-06-30" and empty password
String username;
username += broker;
username += "/";
username += deviceId;
username += "/api-version=2018-06-30";
mqttClient.setUsernamePassword(username, "");
myIMU.begin();
}
void loop() {
Serial.println("Beginning this read loop");
// gonna grab x,y,z from accelo
// drop it in array
int minute_array[960][3];
int i =0;
while (i < 960) {
//Get all parameters
float X = myIMU.readFloatAccelX();
int x = int(X*100000); // make an int to save space?
float Y = myIMU.readFloatAccelY();
int y = int(Y*100000);
float Z = myIMU.readFloatAccelZ();
int z = int(Z*100000);
int acc[] = {x, y, z};
for(int j=0; j<3; j++) {
minute_array[i][j] = acc[j];
}
i++;
delay(250);
}
Serial.println("Ending this read loop");
Serial.println("Beginning loop send");
azureTime(minute_array);
Serial.println("Ending loop's send");
}
void azureTime(int message[][3]) {
if (gsmAccess.status() != GSM_READY || gprs.status() != GPRS_READY) {
connectGSM();
}
if (!mqttClient.connected()) {
// MQTT client is disconnected, connect
connectMQTT();
}
// poll for new MQTT messages and send keep alives
mqttClient.poll();
publishMessage(message);
}
unsigned long getTime() {
// get the current time from the cellular module
return gsmAccess.getTime();
}
void connectGSM() {
Serial.println("Attempting to connect to the cellular network");
while ((gsmAccess.begin(pinnumber) != GSM_READY) ||
(gprs.attachGPRS(gprs_apn, gprs_login, gprs_password) != GPRS_READY)) {
// failed, retry
Serial.print(".");
delay(1000);
}
Serial.println("You're connected to the cellular network");
Serial.println();
}
void connectMQTT() {
Serial.print("Attempting to MQTT broker: ");
Serial.print(broker);
Serial.println(" ");
while (!mqttClient.connect(broker, 8883)) {
// failed, retry
Serial.print(".");
Serial.print(gsmAccess.getTime());
Serial.println(mqttClient.connectError());
delay(5000);
if (gsmAccess.status() != GSM_READY || gprs.status() != GPRS_READY) {
connectGSM();
}
}
Serial.println();
Serial.println("You're connected to the MQTT broker");
Serial.println();
// subscribe to a topic
mqttClient.subscribe("devices/" + deviceId + "/messages/devicebound/#");
}
void publishMessage(int message[][3]) {
Serial.println("Publishing message");
// max buffer size on a message is 256 bytes
// need to send results in chunks
// send message, the Print interface can be used to set the message contents
// this sets up message 1
mqttClient.beginMessage("devices/" + deviceId + "/messages/events/");
for(int n=0; n<960; n++) {
// send every 3 messages together
if (n>0 && n%3==0){
mqttClient.print(" / ");
mqttClient.print(getTime());
mqttClient.endMessage();
mqttClient.beginMessage("devices/" + deviceId + "/messages/events/");
}
for(int m=0; m<3; m++) {
mqttClient.print(message[n][m]);
mqttClient.print(",");
// Serial.println(message[n][m]);
}
}
// this finalises the last message of the batch
mqttClient.print(" / ");
mqttClient.print(getTime());
mqttClient.endMessage();
}