c++tcparduinoserial-communicationgprs

Can't connect or publish to MQTT broker with Arduino and SIM900


I have written a simple sketch to send a connect and publish packet to a cloudMQTT server. I get no errors back from the SIM900 but nothing shows up on the cloudMQTT dashboard.

#include <SoftwareSerial.h>
SoftwareSerial SoftSerial( 9, 10 );

// These varaibles are passed to functionality that generates the connect and publish packets. This code was taken from a sketch written by Ravi Pujar
unsigned int Counter = 0;
unsigned long datalength, CheckSum, RLength;
unsigned short topiclength;
unsigned char topic[30];
char str[250];
unsigned char encodedByte;
int X;
unsigned short MQTTProtocolNameLength;
unsigned short MQTTClientIDLength;
unsigned short MQTTUsernameLength;
unsigned short MQTTPasswordLength;
const char MQTTHost[30] = "hairdresser.cloudmqtt.com";
const char MQTTPort[10] = "18958";
const char MQTTClientID[20] = "ABCDEF";
const char MQTTTopic[30] = "valetron";
const char MQTTProtocolName[10] = "MQIsdp";
const char MQTTLVL = 0x03;
const char MQTTFlags = 0xC2;
const unsigned int MQTTKeepAlive = 60;
const char MQTTUsername[30] = "uroxeeil";
const char MQTTPassword[35] = "ifG3xIxaf5gT";
const char MQTTQOS = 0x00;
const char MQTTPacketID = 0x0001;

unsigned char buffer[ 64 ];
int counter = 0;

void setup() 
{
    // Set the babud rate of both the software serial and hardware serial
    Serial.begin( 19200 );
    SoftSerial.begin( 19200 );

    delay(2000);

    // This section of code sends AT commands to initialize the SIM900
    //-------------- AT INITIALIZATION - This is working fine--------------//
    SoftSerial.write( "\r\nAT\r\n" );

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CIPSHUT\r\n" );

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CIPMUX=0\r\n" );

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CGATT=1\r\n" );

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CSTT=\"myMTN\", \"\", \"\"\r\n" );    

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CIICR\r\n" );

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CIFSR\r\n" );

    delay(3000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);
//-----
    SoftSerial.write( "\r\nAT+CIPSTART=\"TCP\", \"hairdresser.cloudmqtt.com\", \"18958\"\r\n" );

    delay(10000);

    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;

delay(2000);

    //-------------- END OF AT INITIALIZATION --------------//
    //This is where the issue lies

    // Send the connect packet. This code was written by Ravi Pujar

    SoftSerial.write( "\r\nAT+CIPSEND\r\n" );

    delay(3000);
    SoftSerial.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 (X > 0) {
      encodedByte |= 128;
    }
    SoftSerial.write(encodedByte);
    }
    while (X > 0);
    SoftSerial.write(MQTTProtocolNameLength >> 8);
    SoftSerial.write(MQTTProtocolNameLength & 0xFF);
    SoftSerial.print(MQTTProtocolName);
    SoftSerial.write(MQTTLVL); // LVL
    SoftSerial.write(MQTTFlags); // Flags
    SoftSerial.write(MQTTKeepAlive >> 8);
    SoftSerial.write(MQTTKeepAlive & 0xFF);
    SoftSerial.write(MQTTClientIDLength >> 8);
    SoftSerial.write(MQTTClientIDLength & 0xFF);
    SoftSerial.print(MQTTClientID);
    SoftSerial.write(MQTTUsernameLength >> 8);
    SoftSerial.write(MQTTUsernameLength & 0xFF);
    SoftSerial.print(MQTTUsername);
    SoftSerial.write(MQTTPasswordLength >> 8);
    SoftSerial.write(MQTTPasswordLength & 0xFF);
    SoftSerial.print(MQTTPassword);
    SoftSerial.write(0x1A);  

    delay( 2000 );

    // Send the publish packet. This code was written by Ravi Pujar

    SoftSerial.print("\r\nAT+CIPSEND\r\n");
    delay(3000);
    memset(str, 0, 250);
    topiclength = sprintf((char * ) topic, MQTTTopic);
    datalength = sprintf((char * ) str, "%s%u", topic, Counter);
    delay(1000);
    Serial.write(0x30);
    X = datalength + 2;
    do {
    encodedByte = X % 128;
    X = X / 128;
    if (X > 0) {
    encodedByte |= 128;
    }
    SoftSerial.write(encodedByte);
    }
    while (X > 0);
    SoftSerial.write(topiclength >> 8);
    SoftSerial.write(topiclength & 0xFF);
    SoftSerial.print(str);
    SoftSerial.write(0x1A);    
}

void loop() 
{
    // Display any response that has been sent after the first CIPSEND 
    while ( SoftSerial.available() > 0 )
    {
        buffer[ counter++ ] = SoftSerial.read();
        if( counter == 64 ) break;        
    }

    Serial.write( buffer, counter );

    for( int i = 0; i < counter; i++ )
    {
        buffer[ i ] = NULL;
    }
    counter = 0;
}

This is the Serial output:enter image description here

But nothing shows on the cloudMQTT server besides the IP of my device after the tcp connection is established.


Solution

  • So it was not working when trying to connect to the cloudMQTT server, but when I connected to my MQTT server or the test MQTT server, it worked. There must be an issue dealing with the protocol that the cloud mqttServer uses (MQIsdp) as apposed to the standard MQTT protocol that a normal MQTT server utilizes. I made a change to the connect packet so that it specified the MQTT protocol and pointed the TCP connection to the test server ( test.mosquitto.org ) and I can now Connect and Publish successfully.

    For anyone who is just starting out with trying to interface an Arduino with a module like a SIM900 ( GPRS/GSM module ) to a MQTT server, I suggest you grasp a full understanding of standard AT Commands ( To establish a solid TCP connection to server ), how to compile the packets that will be sent through the GPRS module from the Arduino and lastly I suggest not using any code you have not written to achieve this. Learn how to establish the TCP connection with AT commands, then learn how to compile and send a connect packet by compiling the byte array yourself and sending it. Once you understand the packets and the communication between the client and the server, the MQTT world is your oyster.

    You can use this code as a guideline but please try write as much of your own as possible:

    #include <SoftwareSerial.h>
    SoftwareSerial SoftSerial( 9, 10 );
    
    // Go Look up the structure of MQTT packets and from there you will learn how to compile these
    byte connectPacket[ 19 ] = 
    { 
       0x10, 0x11, 0x00, 0x04, 0x4D, 0x51, 0x54, 0x54, 0x04, 0x02, 0x00, 0x3C, 0x00, 0x05, 0x54, 0x32, 0x54, 0x49, 0x44
    };
    
    byte publishPacket[ 26 ] = 
    {
      0x30, 0x18, 0x00, 0x0E, 0x54, 0x32, 0x54, 0x5F, 0x54, 0x6F, 0x70, 0x69, 0x63, 0x5F, 0x44, 0x65, 0x6D, 0x6F, 0x54, 0x65, 0x6D, 0x70, 0x3A, 0x20, 0x33, 0x30 
    };
    
    unsigned char buffer[ 64 ];
    int counter = 0;
    
    // Simple function to send an AT command and see its response
    void sendAtCommandWithResponse( char message[] )
    {
       SoftSerial.write( message );
    
       delay(3000);
    
       while ( SoftSerial.available() > 0 )
       {
           buffer[ counter++ ] = SoftSerial.read();
           if( counter == 64 ) break;        
       }
    
       Serial.write( buffer, counter );
    
       for( int i = 0; i < counter; i++ )
       {
           buffer[ i ] = NULL;
       }
       counter = 0;
    }
    
    void setup() 
    {
       Serial.begin( 19200 );
       SoftSerial.begin( 19200 );
    
       delay(10000);
    
       // -- Configure the SIM900 and establish the TCP connection to the server
    
       sendAtCommandWithResponse( "\r\nAT\r\n" );
    
       delay(2000);
       //-----
    
       sendAtCommandWithResponse( "\r\nAT+CIPSHUT\r\n" );
    
       delay(2000);
       //-----
    
       sendAtCommandWithResponse( "\r\nAT+CIPMUX=0\r\n" );
    
       delay(2000);
       //-----
    
       sendAtCommandWithResponse( "\r\nAT+CGATT=1\r\n" );    
    
       delay(2000);
       //-----
    
       sendAtCommandWithResponse( "\r\nAT+CSTT=\"myMTN\", \"\", \"\"\r\n" );    
    
       delay(2000);
       //-----
    
       sendAtCommandWithResponse( "\r\nAT+CIICR\r\n" );
    
       delay(2000);
       //-----
    
       sendAtCommandWithResponse( "\r\nAT+CIFSR\r\n" );
    
       delay(2000);
       //-----
    
       SoftSerial.write( "\r\nAT+CIPSTART=\"TCP\", \"test.mosquitto.org\", \"1883\"\r\n" );    
    
       delay(10000);
       //-----
    
       while ( SoftSerial.available() > 0 )
       {
           buffer[ counter++ ] = SoftSerial.read();
           if( counter == 64 ) break;        
       }
    
       Serial.write( buffer, counter );
    
       for( int i = 0; i < counter; i++ )
       {
           buffer[ i ] = NULL;
       }
       counter = 0;
    
       delay(2000);
       //-----
    
       // -- Send the connect packet 
       sendAtCommandWithResponse( "\r\nAT+CIPSEND\r\n" );
    
       delay(3000);
    
       SoftSerial.write( connectPacket, sizeof( connectPacket ) );
       // This tells the SIM900 to send the packet
       SoftSerial.write(0x1A); 
    
       delay(3000);
    
       // -- Send the publish packet
       sendAtCommandWithResponse( "\r\nAT+CIPSEND\r\n" );
    
       delay(3000);
    
       SoftSerial.write( publishPacket, sizeof( publishPacket ) );     
       // This tells the SIM900 to send the packet
       SoftSerial.write(0x1A);  
    }
    
    void loop() 
    {
       while ( SoftSerial.available() > 0 )
       {
           buffer[ counter++ ] = SoftSerial.read();
           if( counter == 64 ) break;        
       }
    
       Serial.write( buffer, counter );
    
       for( int i = 0; i < counter; i++ )
       {
           buffer[ i ] = NULL;
       }
       counter = 0;
    }