Trouble using Cayenne with Adafruit FONA (SIM800-based GSM module)


#1

Greetings,

From a review of past forum posts, it seems there is no existing support for accessing Cayenne using the Adafruit FONA or other GSM modules. It seemed like it would be easy enough to implement this through Adafruit’s own FONA-friendly MQTT library, but I am running into a problem.

When I attempt to start the MQTT connection, it appears to send an appropriate connection string, which looks like this:

MQTT , $[my client ID]$[my username]([my password]

But the Cayenne server does not respond, and so the request times out.

If I leave off the client ID, I get a valid connection packet back from the server, but data I send does not show up in the target widget.

The same code – with different credentials, of course – works fine on adafruit.io.

The code is below. I’d appreciate any insight. I’d also love to see what came through at the server end; some transparency there would be really helpful as I go through this process.

#include "Adafruit_FONA.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_FONA.h"
#include <SoftwareSerial.h>

#define FONA_RST 4
#define FONA_RX  5
#define FONA_TX  6
#define FONA_KEY 7

SoftwareSerial fonaSerial = SoftwareSerial(FONA_TX, FONA_RX);
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

#define CAYENNE_SERVER      "mqtt.mydevices.com"
#define CAYENNE_SERVERPORT  1883
#define CAYENNE_USERNAME    "57eadfa57-57a11ed-c0a1e5ced"		//	Fake news, sad!
#define CAYENNE_PASSWORD    "f01ded-5a1ad"						//	Fake news, sad!
#define CAYENNE_CLIENTID    "c0ded-5eac0a575"					//	Fake news, sad!


uint8_t txfailures = 0;

//  MQTT connection object.
Adafruit_MQTT_FONA mqtt(&fona, CAYENNE_SERVER, CAYENNE_SERVERPORT, CAYENNE_CLIENTID, CAYENNE_USERNAME, CAYENNE_PASSWORD);

//  Publish object. Note MQTT paths for Cayenne follow the form: <username>/things/<client_id>/data/<channel_number>
Adafruit_MQTT_Publish datapoint = Adafruit_MQTT_Publish(&mqtt, "v1/" CAYENNE_USERNAME "/things/" CAYENNE_CLIENTID "/data/1");



void setup() {
  Serial.begin(57600);
  Serial.println(F("\nFONA Cayenne code demo"));
  fonaOn();
}



void loop() {
  delay(5000);
  MQTT_connect();
  delay(5000);

  if(! mqtt.ping()) {
    Serial.println(F("MQTT Ping failed."));
  }

  char* publishString = "242";

  Serial.print(F("\nSending value: "));
  Serial.print(publishString);
  Serial.print("...");
  if (! datapoint.publish(publishString)) {
    Serial.println(F("Failed"));
    txfailures++;
  } else {
    Serial.println(F("Published."));
    txfailures = 0;
  }
  delay(5000);
}



void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);  // wait 5 seconds
  }
  Serial.println("MQTT Connected.");
}



boolean fonaOn() {
  fonaSerial.begin(4800);                      //  Open a serial interface to FONA
  
  /*if(fona.sendCheckReply(F("AT"), F("OK")) == false) {*/   //  If the FONA is off...
    Serial.print(F("Powering FONA on..."));
    digitalWrite(FONA_KEY, LOW);  //  ...pulse the Key pin low...
    delay(2000);
    digitalWrite(FONA_KEY, HIGH);        //  ...and then return it to high
    Serial.println(F(" done."));
  //}
  
  Serial.println(F("Initializing FONA..."));
  
  if(fona.begin(fonaSerial) == false) {        //  Start the FONA on serial interface
    Serial.println(F("FONA not found. Check wiring and power."));
    return false;
  }
  else {
    Serial.print(F("FONA online. "));
    
    unsigned long gsmTimeout = millis() + 30000;
    boolean gsmTimedOut = false;

    Serial.print(F("Waiting for GSM network... "));
    while(1) {
      byte network_status = fona.getNetworkStatus();
      if(network_status == 1 || network_status == 5) break;
      
      if(millis() >= gsmTimeout) {
        gsmTimedOut = true;
        break;
      }
      
      delay(250);
    }

    if(gsmTimedOut == true) {
      Serial.println(F("timed out. Check SIM card, antenna, and signal."));
      return false;
    }
    else {
      Serial.println(F("done."));
    }

    //  RSSI is a measure of signal strength -- higher is better; less than 10 is worrying
    byte rssi = fona.getRSSI();
    Serial.print(F("RSSI: "));
    Serial.println(rssi);

    delay(3000);    //  Give the network a moment

    //fona.setGPRSNetworkSettings(F("cellcard"));    //  Set APN to your local carrier

    if(rssi > 5) {
      if(fona.enableGPRS(true) == false) {
        //  Sometimes enableGPRS() returns false even though it succeeded
        if(fona.GPRSstate() != 1) {
          for(byte GPRSattempts = 0; GPRSattempts < 5; GPRSattempts++) {
            Serial.println(F("Trying again..."));
            delay(2000);
            fona.enableGPRS(true);
            
            if(fona.GPRSstate() == 1) {
              Serial.println(F("GPRS is on."));
              break;
            }
            else {
              Serial.print(F("Failed to turn GPRS on... "));
            }
          }
        }
      }
    }
    else {
            Serial.println(F("Can't transmit, network signal strength is poor."));
            gsmTimedOut = true;
    }

    return true;
  }
}

#2

I’ve never used an Adafruit FONA so anything from me is just a guess. The only thing that looks a little off to me is the line below. That may very well be a valid way to concatenate a string but I’ve never seen it done that way.

Adafruit_MQTT_Publish datapoint = Adafruit_MQTT_Publish(&mqtt, "v1/" CAYENNE_USERNAME "/things/" CAYENNE_CLIENTID "/data/1");

try:
Adafruit_MQTT_Publish datapoint = Adafruit_MQTT_Publish(&mqtt, "v1/" + CAYENNE_USERNAME + "/things/" + CAYENNE_CLIENTID + "/data/1");


#3

Thank you for the suggestion.

My code does not generally get this far; it seems to be failing to make an MQTT connection to the server in the first place. To be specific, I believe it is connecting to the server, because on my dashboard I get a “last data packet sent” message with an appropriate timestamp, but because on the device’s end I get no reply to the connection packet and no data appears, I suspect the Client ID is not passing correctly. Further, when I connect without attempting to pass the Client ID in the connection packet, I get a confirmed MQTT connection, though the data does not appear in the channel.

However, I gave this a try; I was not able to get your suggested method to compile in the Arduino IDE, but I manually created the path so that no concatenation was necessary. This did not have an obvious effect. FWIW, the concatenation method in my code does work in connecting to adafruit.io.

Thanks.