Arduino gets stuck and have to reflash to get started

I am using the following code on Arduino MKR1500, where the device connects to a MQTT broker and publishes ADC value. This code runs for some time (example 3-5 mins) and then gets stuck. Even if I reset it, it does not get started with trying to connect to internet. I have to reflash it to get it working again. Can you please let me know what could be causing that issue?

/*
  Adapted from ArduinoMqttClient - WiFi Simple Receive Callback
  This example connects to a MQTT broker and subscribes to a single topic.
  When a message is received it prints the message to the serial monitor,
  it uses the callback functionality of the library.
  This example also publishes a sensor value to a separate topic
  The circuit:
  - Arduino MKR 1000, MKR 1010 or Uno WiFi Rev.2 board
  This example code is in the public domain.
*/

#include <ArduinoMqttClient.h>
#include <MKRNB.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[]     = "";

// MQTT Broker and Port
const char broker[] = "test.mosquitto.org"; //
int        port     = 1883;

// Pub/Sub Topics - Make it something unique since we are using a public broker
const char subscribeTopic[]  = "test";
const char publishTopic[]  = "test";

// To connect with SSL/TLS:
// 1) Change NBClient to NBSSLClient.
// 2) Change port value from 1883 to 8883.
// 3) Change broker value to a server with a known SSL/TLS root certificate 
//    flashed in the WiFi module.

NBClient client;
GPRS gprs;
NB nbAccess;
MqttClient mqttClient(client);

int LED = 6; // Onboard LED

// Publish interval
long previousMillis = 0; 
long interval = 11000;

void setup() {

  pinMode(LED, OUTPUT); // Set built in LED pinMode
  
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // attempt to connect to GSM and GPRS:
  Serial.print("Attempting to connect to GSM and GPRS");
   // connection state
  bool connected = false;

  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) {
    if ((nbAccess.begin(PINNUMBER) == NB_READY) &&
        (gprs.attachGPRS() == GPRS_READY)) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("You're connected to the network");
  Serial.println();

  // You can provide a unique client ID, if not set the library uses Arduino-millis()
  
  // Each client can have a unique client ID
  // mqttClient.setId("clientId");

  // You can provide a username and password for authentication
  // mqttClient.setUsernamePassword("username", "password");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }

  Serial.println("You're connected to the MQTT broker!");
  Serial.println();

  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);

  Serial.print("Subscribing to topic: ");
  Serial.println(subscribeTopic);
  Serial.println();

  // subscribe to a topic
  mqttClient.subscribe(subscribeTopic);

  // topics can be unsubscribed using:
  // mqttClient.unsubscribe(topic);

  Serial.print("Waiting for messages on topic: ");
  Serial.println(subscribeTopic);
  Serial.println();
}

void loop() {
  unsigned long currentMillis = millis(); 
  
  // call poll() regularly to allow the library to receive MQTT messages and
  // send MQTT keep alives which avoids being disconnected by the broker
  mqttClient.poll();

  // Enforce Interval
  if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;

        // Call a function that handles publishing message
        publishSensorVal();
      
  }
}

void publishSensorVal() {
    // read the first Analog pin
    int sensorVal = analogRead(0);     
    String speak = "The sensor val is " + String(sensorVal);
    
    // Publish our sensor value to the publish topic
    mqttClient.beginMessage(publishTopic);
    mqttClient.print(speak);
    mqttClient.endMessage();
}

void handleCommand(String cmd) {
  if (cmd == "on"){
    digitalWrite(LED, HIGH);
  }else if(cmd == "off"){
    digitalWrite(LED, LOW);
  }
}

void onMqttMessage(int messageSize) {
  // we received a message, print out the topic and contents
  Serial.println("Received a message with topic '");
  Serial.print(mqttClient.messageTopic());
  Serial.print("', length ");
  Serial.print(messageSize);
  Serial.println(" bytes:");

  // We want to read each character into a useable String
  String content = "";
  char character;
  
  // use the Stream interface to print the contents
  while (mqttClient.available()) {
    character = (char)mqttClient.read();
    content.concat(character);
  }

  handleCommand(content); // This function does something with our incoming string

  Serial.println(content);
  Serial.println(); Serial.println(); // double spacing
}

You have embedded debug prints, so at what point in the output print does it freeze?

It published the adc values in the serial monitor for a few min and then it will get stuck without any error. I checked the device manager to check if the USB still shows up there and it was(just to ensure that it is not a bad connection or bad cable).

It's probably the String class crashing because of memory fragmentation.

1 Like

In loop(), you need to test if the MQTT broker is still connected.

I have two functions that I call from setup() and loop():

// =====  mqttReconnect =====
void mqttReconnect() {
  //mqttConnect
  //Make sure we stay connected to the mqtt broker
  if (!client.connected()) {
    mqttConnect();
  }
  if (!client.loop()) {
    client.connect(hostName);
  }
}

//=====  mqttConnect =====
void mqttConnect() {
  client.setServer(mqttServer, mqttPort); //Call the setServer method
  while (!client.connected()) {
    Serial.print(F("MQTT connecting..."));
    if (client.connect(hostName)) {
      Serial.println(F("connected"));

      client.setCallback(callback);
      
      //Subscriptions:
      client.subscribe(cmndTopic);
      Serial.print(F("Subscribing to "));
      Serial.println(cmndTopic);
    } else {
      Serial.print(F("failed, rc="));
      Serial.print(client.state());
      Serial.println(F("- trying again in 5-seconds."));
      delay(5000);
    }
  }
}

In setup, I call
mqttConnect();
in loop I call
mqttReconnect(); //Make sure we stay connected to the mqtt broker

1 Like

Hi @SteveMann : is that code available on github, so I can adopt the code and work on it

Here is my current project that uses MQTT

Download the whole zip, then look in src. Both lid and tail use MQTT.

1 Like

Thanks @SteveMann!!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.