Small project: Reliable and fault-tolerant modem start sequence

Hi there (At least on reply :sunglasses:

I can't share the whole sketch, it's over 4000 lines so far..

What i found out meanwhile:

  • Never use the modem. method to communicate direct with the modem, this leads to internal conflicts (probably memory leak) after a while. Instead:
    In the setup: SerialSARA.begin(115200);
    Then (Example with soft reset): SerialSARA.println("AT+CFUN=15");
  • Install the latest firmware, it's a little voodoo but i made it with 3 MKR1500
  • I use GitHub - 256dpi/arduino-mqtt: MQTT library for Arduino as mqtt lib
  • Mr. zbelding, a hardcore coder is not using the mkrnb lib. This could be a reasonable decision.
    His collected experiences can be found here:
    Sketch to http post to thingspeak and what I have learned so far
  • The main problem is losing the socket to the mosquitto broker. The modem answer only with ERROR while trying to establish a new socket. In this case only a PIN reset for the modem and a cpu reset helps. I would appreciate finding a more elegant method....
    The problem is that the modem is a sensitive diva and whatever you use to communicate with the modem (MKRNB or homemade like zbelding), at the end you are shouting AT commands..
  • I stay with the mkrnb lib and have the whole thing with mosquitto now reasonably stable.

I made the following change in the mkrnb lib because my MQTT messages are larger than 256 and i feel better to send this message in one push through the socket then in two..based on superstition...

My start sequence is:


int gsm_conn_counter = 0;
  do {

    if ((nbAccess.begin(PINNUMBER) == NB_READY) &&
        (gprs.attachGPRS() == GPRS_READY)) {
      modemconnected = true;
     print("Mobile Uplink Ready!");
      delay(1000);
      break;
    }

    else
    {
     print("Mobile Uplink Not Ready!");
      delay(2000);
   print("Trying to uplink again..");
      delay(2000);
      Serial.print("gsm_conn_counter");
      gsm_conn_counter ++;
      Serial.print(gsm_conn_counter);
    }
  }
  while (gsm_conn_counter == 2);

  if (gsm_conn_counter == 2)
  {
   print("Start without Network..");
    delay(2000);
  }

My MQTT Watchdog is:

 static unsigned long delayStarttime;
  unsigned long currentTime = millis();


  if  (modemconnected == true)
  {
    if (client.connected() == 0) {
      mqtt_con_counter++;
      if (mqtt_con_counter > 20) // Reboot after 20 attemps
      {
   
        SerialSARA.println("AT+CFUN=15");
        delay(1000);
        // NEVER EVER use RESET_N
        Serial.println("Modem resetting...");
        digitalWrite(SARA_RESETN, HIGH);
        pinMode(SARA_RESETN, OUTPUT);
        delay(12000);
        pinMode(SARA_RESETN, INPUT);
        Serial.println("Modem reset");
        delay(3000);
        digitalWrite(SARA_PWR_ON, HIGH);
        pinMode(SARA_PWR_ON, OUTPUT);
        delay(3000);
        pinMode(SARA_PWR_ON, INPUT);
        Serial.println("Modem off");

        // Board reset
        NVIC_SystemReset();
      }

      //
      if (mqtt_con_counter > 5) //After 5 attemps modem soft reset
      {
        net.stop();
        net.flush();
        delay(200);
        Serial.println("AT+CFUN=15");
        SerialSARA.println("AT+CFUN=15");
        delay(1000);
      }
      client.begin("mqqt server", net);
      client.setOptions(180, true, 1200);

      Serial.println("Neuer MQTT Broker Verbindunsversuch, Nr:");
      Serial.print(mqtt_con_counter);
      client.connect("client name", "group", "password");

      delay(1000);
      if (client.connected() == 1) { // Falls verbunden , Zähler auf null setzen
        mqtt_con_counter = 0;
      }
      //  client.setOptions(120, true, 2000);
      client.subscribe("/mqtt channel name");
    }
  }

// Send a mqtt msg all minutes
  if (currentTime - delayStarttime >= 60000UL) //dev 1min = 60000 5 min =300000 15 min 90000

  {
    delayStarttime = currentTime;

    if ((Cloud == 1) && (modemconnected == true))
    {
      if (client.connected() == 1)
      {
        mqtt_con_counter = 0;
        mqtt_msg = "Message to publish";
        client.publish("/channel", mqtt_msg);

      }
      delay(20);
      //client.loop();   I DO NO LOOP BECAUSE I ONLY SEND DATA
      Serial.print("Last MQTTerror: ");
      Serial.println(client.lastError());
      Serial.print("Last MQTT Return code: ");
      Serial.println(client.returnCode());
    }
  }
}

Ergo: the wooden hammer method....but working for weeks now. Sometimes there is a reset i don't know exactly why. It must be the network.

Nice to have:

  • More elegant way to reset the communication with the MQTT broker
  • Check SIM routine to pass if there is no SIM inserted
  • I've never tested what happens when i lose and regain mobile signal. A proper routine to reconnect would be nice if neccesary.