无法使用 Arduino 和 SIM900 连接或发布到 MQTT 代理

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

我写了一个简单的草图来向 cloudMQTT 服务器发送连接和发布数据包。我没有从 SIM900 返回任何错误,但 cloudMQTT 仪表板上没有任何显示。

#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;
}

这是串行输出:

但是在建立tcp连接后,除了我设备的IP外,cloudMQTT服务器上没有任何显示。

所以在尝试连接到 cloudMQTT 服务器时它不起作用,但是当我连接到我的 MQTT 服务器或测试 MQTT 服务器时,它起作用了。云 mqttServer 使用的协议 (MQIsdp) 与普通 MQTT 服务器使用的标准 MQTT 协议相对应,这一定存在问题。我对连接数据包进行了更改,以便它指定 MQTT 协议并将 TCP 连接指向测试服务器 ( test.mosquitto.org ),现在我可以成功连接和发布。

对于刚开始尝试将 Arduino 与 SIM900(GPRS/GSM 模块)等模块连接到 MQTT 服务器的任何人,我建议您全面了解标准 AT 命令(至与服务器建立牢固的 TCP 连接),如何编译将通过 GPRS 模块从 Arduino 发送的数据包,最后我建议不要使用任何您尚未编写的代码来实现此目的。学习如何用AT命令建立TCP连接,然后学习如何通过自己编译字节数组并发送来编译和发送连接数据包。一旦您了解了客户端和服务器之间的数据包和通信,MQTT 世界就是您的牡蛎。

您可以使用此代码作为指导,但请尽量编写您自己的代码:

#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;
}