Hey everybody,
First post, so let me know if I need to work on anything for the future.
Project setup:
Board: MKR NB 1500
ublox firmware: A.02.16
Power source: Adafruit bq24074 solar/Li Ion charger to 6600mAH Li Ion with 9W 6V solar panel.
Sensor: Ratiometric 0-4.5V pressure transducer with voltage divider to scale output to 0-3V.
Backend: HTTP Post request through Google Cloud Platform.
SIM: Soracom Io
Fleet size: Over 20 boards
Objective: Transmit a sensor reading every minute from a remote location. My backend is set up to subset tables based on SimID and generate reports.
Situation:
The MKR board goes offline after 5-10 days of successful transmission despite above average signal qualities with AT+CSQ. The board, charger and sensor still outputs voltage, but the modem goes offline. The only way to restart transmission is a power cycle, which is unrealistic in remote locations.
I have tested the following:
- A permanent USB power source produces the same outcome.
- No sensor. Simple analog pin read still results in the board going offline.
- Arduino support informed me to move my sketches to Arduino IoT Cloud, where I removed my manual AT commands on resets and focused on their ArduinoCloud.update() function to solve any modem issues - same outcome.
- I have attached a hybrid sketch that involved their .update() function with a simple modem reset based on the AT+CEREG? response- this lasted 8 days of transmission before going offline. I have left the boolean flags.
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
#include <MKRNB.h>
#include "thingProperties.h"
#define NB_TIMEOUT 60 * 1000UL
const char server[] = "funnel.soracom.io";
const int port = 80;
NBClient client;
NBModem modem;
GPRS gprs;
NB nbAccess;
HttpClient httpClient = HttpClient(client, server, port);
// connection state
bool connected = false;
bool restart = false;
// Publish interval
long previousMillis = 0;
long interval = 60000; // transmit every minute
void setup() {
initProperties();
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
nbAccess.setTimeout(NB_TIMEOUT);
gprs.setTimeout(NB_TIMEOUT);
SerialSARA.begin(115200);
delay(10);
SerialSARA.println("AT+CFUN=0");
delay(10);
SerialSARA.println("AT+UMNOPROF=2"); //AT&T profile.
delay(10);
SerialSARA.println("AT+CFUN=15");
delay(2000);
}
void connectNB() {
Serial.println(F("Attempting to connect to cellular network"));
bool connected= false;
bool restart = false;
while(!connected) {
if ((nbAccess.begin(PINNUMBER, GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == NB_READY) && (gprs.attachGPRS() == GPRS_READY)) {
Serial.println(F("NB Success"));
connected = true;
} else {
Serial.println(F("NB Connection Failed"));
restart = true;
delay(500);
}
}
}
void post_data(String postData) {
Serial.println(F("POST Request"));
httpClient.beginRequest();
httpClient.post("/");
httpClient.sendHeader("Content-Type", "application/json");
httpClient.sendHeader("Content-Length", postData.length());
httpClient.beginBody();
httpClient.print(postData);
httpClient.endRequest();
delay(5000);
}
void verifyConnection() {
if (nbAccess.isAccessAlive()){
connected = true;
}
else{
connected = false;
Serial.println(F("Restart"));
nbAccess.shutdown();
connectNB();
}
}
void loop() {
ArduinoCloud.update();
delay(5000);
verifyConnection();
unsigned long currentMillis = millis();
// Enforce accurate interval
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
// Construct the JSON data to send
StaticJsonDocument<200> payload;
int ptval = analogRead(A1);
float pvolt = ptval * (3.3f / 1023.0f);
payload["pdigi"] = ptval;
payload["pvolt"] = pvolt;
int battval = analogRead(ADC_BATTERY);
float voltage = battval * 3.3f / 1023.0f / 1.2f * (1.2f + 0.33f);
payload["vbatt"] = voltage;
String ICCID = modem.getICCID();
payload["SimID"] = ICCID;
int unixTime = nbAccess.getTime();
payload["unixTime"] = unixTime;
char jsonBuffer[512];
serializeJson(payload, jsonBuffer);
post_data(jsonBuffer);
}
}
Any feedback on the sketch above to help eliminate this modem disconnect issue is greatly appreciated. The JSON construction and sending is based off recommendations on soraom github repos to send to their backend service - I was wondering if such a set up is causing a memory leak.
Arduino support informed me they are working on a fix for their modem stabilities and the reintroduction of OTA sketch uploads for the MKR NB 1500 - which is attractive for me as my fleet will be in remote areas.