[arduino] Connecting SIM800 to IoT hub

andrew blance 1 Reputation point
2021-11-18T12:17:41.457+00:00

Hey all,
I have a SIM800h gsm unit, and a Arduino MKRZERO. I hope to connect this to Azure IoT hub, using Shared Access Signatures. The device is registered in the IoT hub, and I can grab an access signature from the azure iot vscode extension. Originally, I was using the MKRGSM1400, and libraries associated with that, however, we found these were unreliable and unable to connect constantly. Therefore, we moved to the MKRZERO and sim800

Now, I am using the TinyGSM and PubSubClient libraries for this. My Sim800 has R13.08 hardware. The code I am using is based on the tinyGSM examples, and looks like:

// Select your modem:
#define TINY_GSM_MODEM_SIM800

// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial

// Set serial for AT commands (to the module)
// Use Hardware Serial on Mega, Leonardo, Micro
#ifndef __AVR_ATmega328P__
#define SerialAT Serial1

// or Software Serial on Uno, Nano
#else
#include <SoftwareSerial.h>
SoftwareSerial SerialAT(2, 3);  // RX, TX
#endif

// See all AT commands, if wanted
// #define DUMP_AT_COMMANDS

// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon

// Range to attempt to autobaud
// NOTE:  DO NOT AUTOBAUD in production code.  Once you've established
// communication, set a fixed baud rate using modem.setBaud(#).
#define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 115200

// Add a reception delay, if needed.
// This may be needed for a fast processor at a slow baud rate.
// #define TINY_GSM_YIELD() { delay(2); }

// Define how you're planning to connect to the internet.
// This is only needed for this example, not in other code.
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false

// set GSM PIN, if any
#define GSM_PIN ""

// Your GPRS credentials, if any
const char apn[]      = "uk.lebara.mobi";
const char gprsUser[] = "wap";
const char gprsPass[] = "wap";

// Your WiFi connection credentials, if applicable
const char wifiSSID[] = "YourSSID";
const char wifiPass[] = "YourWiFiPass";

// MQTT details
const char* broker = "XXXX.azure-devices.net";
const char* mqtt_user = "XXXXXX.azure-devices.net/Arduino";
const char* mqtt_pass = "SharedAccessSignature sr=YYYYYYYYYY";

const char* topicInit      = "GsmClientTest/init";

const char* topicLed =  "devices/Arduino/messages/devicebound/#";
const char* topicLedStatus       = "devices/Arduino/messages/events/";

#include <TinyGsmClient.h>
#include <PubSubClient.h>

#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm        modem(debugger);
#else
TinyGsm        modem(SerialAT);
#endif
TinyGsmClient  client(modem);
PubSubClient  mqtt(client);

#define LED_PIN 13
int ledStatus = LOW;

uint32_t lastReconnectAttempt = 0;

void mqttCallback(char* topic, byte* payload, unsigned int len) {
  SerialMon.print("Message arrived [");
  SerialMon.print(topic);
  SerialMon.print("]: ");
  SerialMon.write(payload, len);
  SerialMon.println();

  // Only proceed if incoming message's topic matches
  if (String(topic) == topicLed) {
    ledStatus = !ledStatus;
    digitalWrite(LED_PIN, ledStatus);
    mqtt.publish(topicLedStatus, ledStatus ? "1" : "0");
  }
}

boolean mqttConnect() {
  SerialMon.print("Connecting to ");
  SerialMon.print(broker);

  // Connect to MQTT Broker
 // boolean status = mqtt.connect("GsmClientTest");

  // Or, if you want to authenticate MQTT:
  boolean status = mqtt.connect("Arduino", mqtt_user, mqtt_pass);

  if (status == false) {
    SerialMon.println(" fail");
    return false;
  }
  SerialMon.println(" success");
  mqtt.publish(topicLedStatus, "GsmClientTest started");
  mqtt.subscribe(topicLed);
  return mqtt.connected();
}


void setup() {
  // Set console baud rate
  SerialMon.begin(115200);
  delay(10);

  pinMode(LED_PIN, OUTPUT);

  // !!!!!!!!!!!
  // Set your reset, enable, power pins here
  // !!!!!!!!!!!

  SerialMon.println("Wait...");

  // Set GSM module baud rate
  TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
  // SerialAT.begin(9600);
  delay(6000);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println("Initializing modem...");
  modem.restart();
  // modem.init();

  String modemInfo = modem.getModemInfo();
  SerialMon.print("Modem Info: ");
  SerialMon.println(modemInfo);

#if TINY_GSM_USE_GPRS
  // Unlock your SIM card with a PIN if needed
  if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
#endif

#if TINY_GSM_USE_GPRS && defined TINY_GSM_MODEM_XBEE
  // The XBee must run the gprsConnect function BEFORE waiting for network!
  modem.gprsConnect(apn, gprsUser, gprsPass);
#endif

  SerialMon.print("Waiting for network...");
  if (!modem.waitForNetwork()) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }

#if TINY_GSM_USE_GPRS
  // GPRS connection parameters are usually set after network registration
  SerialMon.print(F("Connecting to "));
  SerialMon.print(apn);
  if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
    SerialMon.println(" fail");
    delay(10000);
    return;
  }
  SerialMon.println(" success");

  if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
#endif

  // MQTT Broker setup
  mqtt.setServer(broker, 8883);
  mqtt.setCallback(mqttCallback);
}

void loop() {
  // Make sure we're still registered on the network
  if (!modem.isNetworkConnected()) {
    SerialMon.println("Network disconnected");
    if (!modem.waitForNetwork(180000L, true)) {
      SerialMon.println(" fail");
      delay(10000);
      return;
    }
    if (modem.isNetworkConnected()) {
      SerialMon.println("Network re-connected");
    }

#if TINY_GSM_USE_GPRS
    // and make sure GPRS/EPS is still connected
    if (!modem.isGprsConnected()) {
      SerialMon.println("GPRS disconnected!");
      SerialMon.print(F("Connecting to "));
      SerialMon.print(apn);
      if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
        SerialMon.println(" fail");
        delay(10000);
        return;
      }
      if (modem.isGprsConnected()) { SerialMon.println("GPRS reconnected"); }
    }
#endif
  }

  if (!mqtt.connected()) {
    SerialMon.println("=== MQTT NOT CONNECTED ===");
    // Reconnect every 10 seconds
    uint32_t t = millis();
    if (t - lastReconnectAttempt > 10000L) {
      lastReconnectAttempt = t;
      if (mqttConnect()) { lastReconnectAttempt = 0; }
    }
    delay(100);
    return;
  }

  if (millis && modem.isNetworkConnected() && mqtt.connected()) {
    // Publish a message every second
    if (millis() % 1000 == 0) {
      SerialMon.println("sending message!");
      mqtt.publish(topicLedStatus, "hello :)");
    }
  }

  mqtt.loop();
}

I believe I have set the correct port, broker and using mqtt.connect correctly. However, when I upload this code to my arduino, I get stuck in the in the loop entering mqttConnect(), with the output:

Connecting to XXXX.azure-devices.net[651883] ### Closed:  0
 fail

The arduino does manage to connect to the network successfully and can connect to other MQTT brokers and send/receive messages to/from them. I do not attempt to handle any SSL certificates, though I don’t believe this should be an issue, as I am using symmetric key/ SAS security for connecting. I can attach the SIM800 directly into my PC and, using PuTTY, send AT commands to it. Through this I have verified that SSL does work on my board (ie. the command AT+SSLOPT=1,1 does not result in an error)

Does anyone have any suggestions on what may be causing this behaviour? I can provide more/less code, or run more debugging if asked. thanks.

Azure IoT
Azure IoT
A category of Azure services for internet of things devices.
378 questions
Azure IoT Hub
Azure IoT Hub
An Azure service that enables bidirectional communication between internet of things (IoT) devices and applications.
1,115 questions
Azure IoT SDK
Azure IoT SDK
An Azure software development kit that facilitates building applications that connect to Azure IoT services.
208 questions
{count} votes

1 answer

Sort by: Most helpful
  1. António Sérgio Azevedo 7,661 Reputation points Microsoft Employee
    2021-11-22T17:57:54.467+00:00

    I am not aware of that github repo and I do not have a sim800h to test this. For example MXChip is Arduino-compatible board. The initial repo is outdated but it used Arduino: https://github.com/azure-samples/mxchip-iot-devkit-get-started/tree/master/ . Now MXChip is running with Azure RTOS: https://github.com/azure-rtos/getting-started/tree/master/MXChip/AZ3166