Connection to Cayenne using AT Commands (Telit Modem)


#1

Hi guys,

I am trying to getting started with the IoT stuff and MQTT I want to use a microcontroller + Cellular modem, to send/receive messages uisng UART, But I am not sure where to start, some documentation?

I read about the MQTT specs and I understand the major part about it, but I don’t know how to implement it yet using AT commands, I read about set a TCP socket then send my data to the Server/Broker, I dont know how to do it,

I found this thread Connection via AT Commands but it is still unclear for me

Similar experiencing trying to do it?

Details: My microcontroller is a BL652 a Bluetooth capable and it is not a Linux based device or ESP8266

Regards


#2

hi @Estarrosa welcome to the cayenne community.
i am not sure about BL652 but we have a sample working code for arduino mega and GSM800 module.
AT commands will be similar but you have get it working from this code.

#define dbg
// no need to add the below 3.
char aux_str[100];
const char * __APN      = "";
const char * __usrnm    = "";
const char * __password = "";

unsigned long checksum, rLength;
unsigned long datalength, datalength1, datalength2, datalength4;
unsigned short topiclength;
unsigned short topiclength2;
unsigned short topiclength4;
unsigned char topic[200];
unsigned char topic2[200];
unsigned char topic4[200];

unsigned char encodedByte;
unsigned char encodedByte0;
unsigned char encodedByte1;
unsigned char encodedByte4;
int X;
int X0;
int X1;
int X4;

unsigned short MQTTProtocolNameLength;
unsigned short MQTTClientIDLength;
unsigned short MQTTUsernameLength;
unsigned short MQTTPasswordLength;
unsigned short MQTTTopicLength;

//const char * MQTTHost = "m10.cloudmqtt.com";

const char * MQTTHost = "mqtt.mydevices.com";
const char * MQTTPort = "1883";
const char * MQTTClientID = "CLIENT_ID";
unsigned char MQTTTopic[200] = "v1/USERNAME/things/CLIENT_ID/data/2";
const char * MQTTProtocolName = "MQTT";
const char MQTTLVL = 0x03;
const char MQTTFlags = 0xC2;
const unsigned int MQTTKeepAlive = 60;
const char * MQTTUsername = "USERNAME";
const char * MQTTPassword = "PASSWORD";
const char MQTTQOS = 0x00;
const char MQTTPacketID = 0x0001;

char MQTTTopic2[200] = "v1/USERNAME/things/CLIENT_ID/cmd/2";
char MQTTTopic4[200] = "v1/USERNAME/things/CLIENT_ID/response";

char sim800lreset = 4;

unsigned long lastMillis = 0;
int data1;

//String rc;
char tempChars[250];
//char rc1[50];
char seq[30] = {0};
char str2[30] = {0};
char str3[30] = {0};
char str4[30] = {0};
char str5[30] = {0};
char str6[30] = {0};
int value = 0;

char str[250];
char str1[250];
char strR[250];
char strRR[250];


void setup() {
  Serial.begin(115200);
  Serial2.begin(115200);
  Serial.println(" setup restarting");
  pinMode(5, OUTPUT);
  pinMode(sim800lreset, OUTPUT);
  delay(3000);
  MQTTProtocolNameLength = strlen(MQTTProtocolName);
}

void loop()
{
  Serial.println("restarting");
  if (initTCP()) {
    MQTTConnect();
    readServerResponse("AT+CIPRXGET=2,1024", "OK", "ERROR", 10000);//receive data from n/w
    MQTTsubscribe();
    readServerResponse("AT+CIPRXGET=2,1024", "OK", "ERROR", 10000);//receive data from n/w
    delay(1500);
    while (1) {
      if (Serial2.available() > 0) {
        Serial.println("Reading");
        String rc = Serial2.readString();
        Serial.println(rc);
        char* rc2 = rc.c_str();
        strcpy(tempChars, &rc2[4]);
        char * strtokIndx;
        strtokIndx = strtok(tempChars, "/");
        strcpy(str2, strtokIndx);
        strtokIndx = strtok(NULL, "/");
        strcpy(str3, strtokIndx);
        strtokIndx = strtok(NULL, "/");
        strcpy(str4, strtokIndx);
        strtokIndx = strtok(NULL, "/");
        strcpy(str5, strtokIndx);
        strtokIndx = strtok(NULL, "2");
        strcpy(str6, strtokIndx);
        strtokIndx = strtok(NULL, ",");
        strcpy(seq, strtokIndx);
        strtokIndx = strtok(NULL, ",");
        value = atoi(strtokIndx);
        Serial.print("seq ");
        Serial.println(seq);
        Serial.print("value ");
        Serial.println(value);
        MQTTResponse();
        readServerResponse("AT+CIPRXGET=2,1024", "OK", "ERROR", 10000);
        MQTTupdate();
        readServerResponse("AT+CIPRXGET=2,1024", "OK", "ERROR", 10000);
        Serial2.flush();
        char* rc1 = rc.c_str();
        int len = strlen(&rc1[4]);
        memset(rc1, 0, len + 4);
        Serial.println(len);
        //rc = "";
        delay(1000);

      }


    }
  }
}
int  MQTTConnect() {

  if (sendATcommand2("AT+CIPSEND", ">", "ERROR", 1000)) {
    Serial2.write(0x10);
    MQTTProtocolNameLength = strlen(MQTTProtocolName);
    MQTTClientIDLength = strlen(MQTTClientID);
    MQTTUsernameLength = strlen(MQTTUsername);
    MQTTPasswordLength = strlen(MQTTPassword);
    datalength = MQTTProtocolNameLength + 2 + 4 + MQTTClientIDLength + 2 + MQTTUsernameLength + 2 + MQTTPasswordLength + 2;
    X = datalength;
    do
    {
      encodedByte = X % 128;
      X = X / 128;
      // if there are more data to encode, set the top bit of this byte
      if ( X > 0 ) {
        encodedByte |= 128;
      }

      Serial2.write(encodedByte);
    }
    while ( X > 0 );
    Serial2.write(MQTTProtocolNameLength >> 8);
    Serial2.write(MQTTProtocolNameLength & 0xFF);
    Serial2.write(MQTTProtocolName);

    Serial2.write(MQTTLVL); // LVL
    Serial2.write(MQTTFlags); // Flags
    Serial2.write(MQTTKeepAlive >> 8);
    Serial2.write(MQTTKeepAlive & 0xFF);


    Serial2.write(MQTTClientIDLength >> 8);
    Serial2.write(MQTTClientIDLength & 0xFF);
    Serial2.print(MQTTClientID);


    Serial2.write(MQTTUsernameLength >> 8);
    Serial2.write(MQTTUsernameLength & 0xFF);
    Serial2.print(MQTTUsername);


    Serial2.write(MQTTPasswordLength >> 8);
    Serial2.write(MQTTPasswordLength & 0xFF);
    Serial2.print(MQTTPassword);

    Serial2.write(0x1A);
    if (sendATcommand2("", "SEND OK", "SEND FAIL", 5000)) {
      Serial.println(F("CONNECT PACKET SUCCESS"));
      return 1;
    }
    else return 0;
  }
}


int  MQTTupdate() {
  if (sendATcommand2("AT+CIPSEND", ">", "ERROR", 1000)) {

    Serial.println("Sending");
    memset(str, 0, sizeof(str));
    data1 = value;
    topiclength = sprintf((char*)topic, MQTTTopic);
    datalength1 = sprintf((char*)str, "%s%s%d", topic, "digital_actuator,d=", data1);
    //Serial.println(str);
    //delay(1000);
    //Serial.println(str);
    Serial2.write(0x30);
    X0 = datalength1 + 2;
    do
    {
      encodedByte0 = X0 % 16384;
      X0 = X0 / 16384;
      // if there are more data to encode, set the top bit of this byte
      if ( X0 > 0 ) {
        encodedByte0 |= 16384;
      }
      Serial2.write(encodedByte0);
    }
    while ( X > 0 );
    Serial2.write(topiclength >> 8);
    Serial2.write(topiclength & 0xFF);
    Serial2.print(str);
    Serial.print(str);
    Serial2.write(0x1A);
    if (sendATcommand2("", "SEND OK", "SEND FAIL", 5000)) {
      Serial.println(F("PUBLISH PACKET SENT"));
      return 1;
    }
    else return 0;
  }
}

int  MQTTResponse() {
  if (sendATcommand2("AT+CIPSEND", ">", "ERROR", 1000)) {

    Serial.println("Sending response");
    memset(strRR, 0, sizeof(strRR));
    topiclength4 = sprintf((char*)topic4, MQTTTopic4);
    datalength4 = sprintf((char*)str4, "%s%s%s", topic4, "ok,", seq);
    //Serial.println(str);
    //delay(1000);
    //Serial.println(str);
    Serial2.write(0x30);
    X4 = datalength4 + 2;
    do
    {
      encodedByte4 = X4 % 16384;
      X4 = X4 / 16384;
      // if there are more data to encode, set the top bit of this byte
      if ( X4 > 0 ) {
        encodedByte4 |= 16384;
      }
      Serial2.write(encodedByte4);
    }
    while ( X4 > 0 );
    Serial2.write(topiclength4 >> 8);
    Serial2.write(topiclength4 & 0xFF);
    Serial2.print(str4);
    Serial.print(str4);
    Serial2.write(0x1A);
    if (sendATcommand2("", "SEND OK", "SEND FAIL", 5000)) {
      Serial.println(F("PUBLISH PACKET SENT"));
      return 1;
    }
    else return 0;
  }
}
void MQTTsubscribe() {

  if (sendATcommand2("AT+CIPSEND", ">", "ERROR", 1000)) {

    memset(str1, 0, 250);
    topiclength2 = strlen(MQTTTopic2);
    datalength2 = 2 + 2 + topiclength2 + 1;
    delay(1000);

    Serial2.write(0x82);
    X1 = datalength2;
    do
    {
      encodedByte1 = X1 % 16384;
      X1 = X1 / 16384;
      // if there are more data to encode, set the top bit of this byte
      if ( X1 > 0 ) {
        encodedByte1 |= 16384;
      }
      Serial2.write(encodedByte1);
    }
    while ( X > 0 );
    Serial2.write(MQTTPacketID >> 8);
    Serial2.write(MQTTPacketID & 0xFF);
    Serial2.write(topiclength2 >> 8);
    Serial2.write(topiclength2 & 0xFF);
    Serial2.print(MQTTTopic2);
    Serial.println(MQTTTopic2);
    Serial2.write(MQTTQOS);

    Serial2.write(0x1A);
    if (sendATcommand2("", "SEND OK", "SEND FAIL", 5000)) {
      Serial.println(F("SUBSCRIBE PACKET SENT"));
      return 1;
    }
    else return 0;
  }


}

//connection and esponse
int8_t readServerResponse(char* ATcommand, char* expected_answer1, char* expected_answer2, unsigned int timeout) {
  unsigned long nowMillis = millis();
  Serial2.println(ATcommand);
  delay(3000);

  if (Serial2.available()) {
    while (char(Serial.read()) != 0x24) {
      if ((millis() - nowMillis) > 2000) {
        Serial.println("NO DATA RECEIVED FROM REMOTE");
        break;
      }
    }
    nowMillis = (millis());
    while (Serial2.available()) {
      Serial.print(char(Serial2.read()));
    }
  }

}


int8_t sendATcommand2(char* ATcommand, char* expected_answer1, char* expected_answer2, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialize the string

  delay(100);

  Serial2.flush();
  Serial2.println(ATcommand);    // Send the AT command
  //if(strstr(ATcommand, "AT+CIPSEND")!=NULL) Serial2.write(0x1A);

#ifdef dbg
  Serial.println(ATcommand);    // Send the AT command
#endif

  x = 0;
  previous = millis();

  // this loop waits for the answer
  do {
    // if there are data in the UART input buffer, reads it and checks for the asnwer
    if (Serial2.available() != 0) {
      response[x] = Serial2.read();
      x++;
      // check if the desired answer 1  is in the response of the module
      if (strstr(response, expected_answer1) != NULL)
      {
        answer = 1;
        while (Serial.available()) {
          response[x] = Serial2.read();
          x++;
        }
      }
      // check if the desired answer 2 is in the response of the module
      else if (strstr(response, expected_answer2) != NULL)
      {
        answer = 2;
        while (Serial.available()) {
          response[x] = Serial2.read();
          x++;
        }
      }

    }
  }
  // Waits for the asnwer with time out
  while ((answer == 0) && ((millis() - previous) < timeout));
#ifdef dbg
  Serial.println(response);
#endif
  return answer;
}
/////////////////////


int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[500];
  unsigned long previous;
  char* str;
  uint8_t index = 0;

  memset(response, '\0', 100);    // Initialize the string

  delay(100);

  while ( Serial2.available() > 0) Serial2.read();   // Clean the input buffer

  Serial2.println(ATcommand);    // Send the AT command
#ifdef dbg
  Serial.println(ATcommand);    // Send the AT command
#endif


  x = 0;
  previous = millis();

  // this loop waits for the answer
  do {
    if (Serial2.available() != 0) {
      // if there are data in the UART input buffer, reads it and checks for the asnwer
      response[x] = Serial2.read();
      //Serial2.print(response[x]);
      x++;
      // check if the desired answer  is in the response of the module
      if (strstr(response, expected_answer) != NULL)
      {
        answer = 1;

      }
    }
  }
  // Waits for the asnwer with time out
  while ((answer == 0) && ((millis() - previous) < timeout));

#ifdef dbg
  Serial.println(response);    // Send the AT command
#endif
  return answer;
}





//void updateTime() {
//  sendATcommand("AT+CCLK?", "OK", 2000);
//}


int initTCP() {

  //resetModem();
  sendATcommand2("ATE0", "OK", "ERROR", 2000);
  sendATcommand2("ATE0", "OK", "ERROR", 2000);

  delay(2000);


  Serial.println(F("Connecting to the network..."));

  while ( sendATcommand2("AT+CREG?", "+CREG: 0,1", "+CREG: 0,5", 1000) == 0 );
  delay(2000);


  if (sendATcommand2("AT+CIPMUX=0", "OK", "ERROR", 1000) == 1)      // Selects Single-connection mode

  {
    if (sendATcommand2("AT+CIPRXGET=2", "OK", "ERROR", 1000) == 1) { //RECEIVE DATA manually FROM THE REMOTE SERVER
      int8_t answer = 0;

      delay(1000);

      if (!(sendATcommand2("AT+CIPMODE=0", "OK", "ERROR", 1000) ))return 0;//srt non transparent mode for data sending
      delay(500);
      if (!(sendATcommand2("AT+CIPSRIP=0", "OK", "ERROR", 1000) ))return 0;//Do not show the prompt during receiving data from server
      delay(500);
      while (sendATcommand("AT+CGATT?", "+CGATT: 1", 5000) == 0 );
      delay(1000);

      // Waits for status IP INITIAL
      while (sendATcommand("AT+CIPSTATUS", "INITIAL", 5000) == 0 );
      delay(1000);

      snprintf(aux_str, sizeof(aux_str), "AT+CSTT=\"%s\",\"%s\",\"%s\"", __APN, __usrnm, __password);

      // Sets the APN, user name and password
      if (sendATcommand2(aux_str, "OK",  "ERROR", 30000) == 1)
      {

        // Waits for status IP START
        if (sendATcommand("AT+CIPSTATUS", "START", 500)  == 0 )
          delay(3000);

        // Brings Up Wireless Connection
        if (sendATcommand2("AT+CIICR", "OK", "ERROR", 30000) == 1)
        {

          // Waits for status IP GPRSACT
          while (sendATcommand("AT+CIPSTATUS", "GPRSACT", 500)  == 0 );
          delay(3000);

          // Gets Local IP Address
          if (sendATcommand2("AT+CIFSR", ".", "ERROR", 10000) == 1)
          {

            // Waits for status IP STATUS
            while (sendATcommand("AT+CIPSTATUS", "IP STATUS", 500)  == 0 );
            //delay(5000);
            delay(5000);

            Serial.println(F("Opening TCP"));
            snprintf(aux_str, sizeof(aux_str), "AT+CIPSTART=\"TCP\",\"%s\",\"%s\"", MQTTHost, MQTTPort);

            // Opens a TCP socket
            if (sendATcommand2(aux_str, "OK\r\n\r\nCONNECT", "CONNECT FAIL", 30000) == 1)
            {

              // Serial.println(F("Connected"));
              return 1;

            }

            else
            {
              Serial.println(F("Error opening the connection"));
              Serial.println(F("UNABLE TO CONNECT TO SERVER "));
              return 0;

            }

          }
          else
          {
            Serial.println(F("ERROR GETTING IP ADDRESS "));
            return 0;

          }
        }
        else
        {
          Serial.println(F("ERROR BRINGING UP WIRELESS CONNECTION"));
          return 0;
        }
      }
      else {
        Serial.println(F("Error setting the APN"));
        return 0;
      }


    }
    else
    {
      Serial.println(F("Error setting CIPRXGET"));
      return 0;
    }


  }
}  

*NOTE: This code does not handle error and stop working. Also parseing is done manually.


#3

@shramiksalgaonkar Thanks a lot that is an excellent starting point for me. As far I see at the moment I have to adapt the SimCom module AT commands to the Telit one (probable easy). Does it requires some extra headers? I can’t see any for the MQTT stuff.


#4

this the format of connect packet
Book2 - Copy.csv (9.8 KB)