This topic describes how to use the open source Paho MQTT project for embedded C to connect a device to IoT Platform and enable messaging.

Prerequisites

A product and a device are created in an instance in the IoT Platform console. The device certificate and an MQTT endpoint are obtained. The certificate information includes the ProductKey, DeviceName, and DeviceSecret. For more information, see the following topics:

Prepare the development environment

In this example, Ubuntu 16.04-LTS is used to build the development environment. Run the following commands to build the development environment:

sudo apt-get update
sudo apt-get install build-essential git sed cmake

Download the Paho MQTT library for C

Run the following command to clone the Paho MQTT library for C:

git clone https://github.com/eclipse/paho.mqtt.embedded-c.git
Note In this topic, the master branch is used to develop the sample code. The commit ID is 29ab2aa29c5e47794284376d7f8386cfd54c3eed.

The Paho MQTT project for embedded C includes the following sub-projects:

  • MQTTPacket: provides serialization and deserialization of MQTT data packets and some helper functions.
  • MQTTClient: encapsulates the high-level C++ client program that is generated by MQTTPacket.
  • MQTTClient-C: encapsulates the high-level C client program that is generated by MQTTPacket.

    The MQTTClient-C project includes the following directories and files:

    ├── CMakeLists.txt
    ├── samples
    │   ├── CMakeLists.txt
    │   ├── FreeRTOS
    │   └── linux
    ├── src
    │   ├── CMakeLists.txt
    │   ├── FreeRTOS
    │   ├── MQTTClient.c
    │   ├── MQTTClient.h
    │   ├── cc3200
    │   └── linux
    └── test
        ├── CMakeLists.txt
        └── test1.c
    • The samples directory provides sample code for FreeRTOS and Linux systems.
    • The src directory provides sample code to implement MQTTClient and network drivers for porting to FreeRTOS, CC3200, and Linux.

    For more information about the Paho MQTT API, see MQTTClient.h.

Connect the client to IoT Platform

  1. Click aiot_mqtt_sign.c and copy the source code that is provided by Alibaba Cloud to obtain the MQTT connection parameters. Then, create the aiot_mqtt_sign.c file on premises and paste the code to the file.

    The aiot_mqtt_signal.c file defines the aiotMqttSign() function.

    • Definition:
      int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
                       char clientId[150], char username[65], char password[65]);
    • Description

      This class is used to obtain the following MQTT connection parameters: username, password, and clientid.

    • Input parameters:
      Parameter Type Description
      productKey const char * The ProductKey of the product to which the device belongs. This ProductKey is used to identify the device in the IoT Platform console.
      deviceName const char * The DeviceName of the device. This DeviceName is used to identify the device in the IoT Platform console.
      deviceSecret const char * The DeviceSecret of the device. This DeviceSecret is used to identify the device in the IoT Platform console.
    • Output parameters:
      Parameter Type Description
      username char * The username that is used to establish the MQTT connection.
      password char * The password that is used to establish the MQTT connection.
      clientId char * The ID of the MQTT client.
    • Response codes
      Response code Description
      0 Success
      -1 Failed
  2. Add a program file that can connect a device to IoT Platform.

    You must write a program to call the aiotMqttSign() function in the aiot_mqtt_sign.c file to obtain the parameters that are required to establish an MQTT connection to IoT Platform.

    This section provides the development instructions and sample code.

    • Call the aiotMqttSign() function to initialize the clientId, username, and password parameters.
      #define EXAMPLE_PRODUCT_KEY            "a11xsrW****"
      #define EXAMPLE_DEVICE_NAME            "paho_****"
      #define EXAMPLE_DEVICE_SECRET       "Y877Bgo8X5owd3lcB5wWDjryNPoB****"
      
      extern int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
                              char clientId[150], char username[65], char password[65]);
      
      /* invoke aiotMqttSign to generate mqtt connect parameters */
      char clientId[150] = {0};
      char username[65] = {0};
      char password[65] = {0};
      
      if ((rc = aiotMqttSign(EXAMPLE_PRODUCT_KEY, EXAMPLE_DEVICE_NAME, EXAMPLE_DEVICE_SECRET, clientId, username, password) < 0)) {
          printf("aiotMqttSign -%0x4x\n", -rc);
          return -1;
      }
      printf("clientid: %s\n", clientId);
      printf("username: %s\n", username);
      printf("password: %s\n", password);
    • Connect the client to IoT Platform.

      Perform the following operations:

      • Call the NetworkInit() and NetworkConnect() functions to establish a TCP connection.
      • Call the MQTTClientInit() function to initialize the MQTT client.
      • Configure the MQTTPacket_connectData structure that contains the MQTT connection parameters.

      Sample code:

      /* network init and establish network to aliyun IoT platform */
      NetworkInit(&n);
      rc = NetworkConnect(&n, host, port);
      printf("NetworkConnect %d\n", rc);
      
      /* init mqtt client */
      MQTTClientInit(&c, &n, 1000, buf, sizeof(buf), readbuf, sizeof(readbuf));
      
      /* set the default message handler */
      c.defaultMessageHandler = messageArrived;
      
      /* set mqtt connect parameter */
      MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
      data.willFlag = 0;
      data.MQTTVersion = 3;
      data.clientID.cstring = clientId;
      data.username.cstring = username;
      data.password.cstring = password;
      data.keepAliveInterval = 60;
      data.cleansession = 1;
      printf("Connecting to %s %d\n", host, port);
      
      rc = MQTTConnect(&c, &data);
      printf("MQTTConnect %d, Connect aliyun IoT Cloud Success!\n", rc);
    • Publish messages.

      Call the MQTTPublish() function to publish messages in the custom format to the specified custom topic.

      For more information about topics, see What is a topic?.

      char *pubTopic = "/"EXAMPLE_PRODUCT_KEY"/"EXAMPLE_DEVICE_NAME"/user/update";
      int cnt = 0;
      unsigned int msgid = 0;
      while (!toStop)
      {
          MQTTYield(&c, 1000);    
      
          if (++cnt % 5 == 0) {
              MQTTMessage msg = {
                  QOS1,
                  0,
                  0,
                  0,
                  "Hello world",
                  strlen("Hello world"),
              };
              msg.id = ++msgid;
              rc = MQTTPublish(&c, pubTopic, &msg);
              printf("MQTTPublish %d, msgid %d\n", rc, msgid);
          }
      }
    • Subscribe to a topic to receive messages from IoT Platform.
      void messageArrived(MessageData* md)
      {
          MQTTMessage* message = md->message;
      
          printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
          printf("%.*s\n", (int)message->payloadlen, (char*)message->payload);
      }
      
      char *subTopic = "/"EXAMPLE_PRODUCT_KEY"/"EXAMPLE_DEVICE_NAME"/user/get";
      
      printf("Subscribing to %s\n", subTopic);
      rc = MQTTSubscribe(&c, subTopic, 1, messageArrived);
      printf("MQTTSubscribe %d\n", rc);

    For more information about the communication methods of devices, servers, and IoT Platform, see Overview.

  3. Copy the aiot_mqtt_signal.c file and the file that is modified in Step 2 to ../paho.mqtt.embedded-c/MQTTClient-C/samples/linux. Then, compile the project.

Sample code

You can run the sample code to connect to IoT Platform.

  1. Download the demo package and decompress it.
    The following files are obtained:
    Certificate file Description
    aiot_mqtt_sign.c This file contains the code that is used to obtain the MQTT connection parameters. When you run the aiot_c_demo.c file, the aiotMqttSign() function is called to obtain values of the username, password, and clientId parameters.
    aiot_c_demo.c This file contains the logic code that is used to connect to and communicate with IoT Platform.
  2. In the aiot_c_demo.c file, replace the device information with your device information.
    • Replace the values of the EXAMPLE_PRODUCT_KEY, EXAMPLE_DEVICE_NAME, and EXAMPLE_DEVICE_SECRET parameters with your device certificate information.
      #define EXAMPLE_PRODUCT_KEY            "The ProductKey of the product" 
      #define EXAMPLE_DEVICE_NAME            "The DeviceName of the device" 
      #define EXAMPLE_DEVICE_SECRET          "The DeviceSecret of the device"
    • Modify the endpoint in char *host = EXAMPLE_PRODUCT_KEY".iot-as-mqtt.cn-shanghai.aliyuncs.com".

      For more information about the endpoints of public instances and Enterprise Edition instances and the formats of the endpoints, see View the endpoint of an instance.

  3. Move the aiot_mqtt_signal.c and aiot_c_demo.c files to the ../paho.mqtt.embedded-c/MQTTClient-C/samples/linux directory of the Paho project.
  4. Compile the project and run the program.

    You can compile the project by using one of the following methods:

    • Use the CMake tool.
      1. Add aiot_c_demo.c and aiot_mqtt_signal.c to the CMakeLists.txt file in the /paho.mqtt.embedded-c/MQTTClient-C/samples/linux directory.

        The following code shows how to modify the CMakeLists.txt file.

        add_executable(
          stdoutsubc
          stdoutsub.c
        )
        
        add_executable(
          aiot_c_demo
          aiot_c_demo.c
          aiot_mqtt_sign.c
        )
        
        target_link_libraries(stdoutsubc paho-embed-mqtt3cc paho-embed-mqtt3c)
        target_include_directories(stdoutsubc PRIVATE "../../src" "../../src/linux")
        target_compile_definitions(stdoutsubc PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
        
        target_link_libraries(aiot_c_demo paho-embed-mqtt3cc paho-embed-mqtt3c)
        target_include_directories(aiot_c_demo PRIVATE "../../src" "../../src/linux")
        target_compile_definitions(aiot_c_demo PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
      2. Go back to the /paho.mqtt.embedded-c directory and run the following command to compile the project.
        mkdir build.paho
        cd build.paho
        cmake ..
        make
      3. Go to the /paho.mqtt.embedded-c/build.paho directory and run the following command to run the program:
        ./MQTTClient-C/samples/linux/aiot_c_demo
    • Use the build.sh file.
      1. Open the build.sh file in the /paho.mqtt.embedded-c/MQTTClient-C/samples/linux directory.
      2. In the build.sh file, replace stdoutsub.c with aiot_mqtt_sign.c aiot_c_demo.c, and -o stdoutsub with -o aiot_c_demo. Then, save the build.sh file.
      3. Go to the /paho.mqtt.embedded-c/MQTTClient-C/samples/linux directory and run the ./build.sh command.

        After the compilation, the aiot_c_demo executable file is generated.

      4. Run the ./aiot_c_demo command to run the file.
    After you run the file, the following local logs are generated:
    clientid: paho_mqtt&a11xsrW****|timestamp=2524608000000,_v=sdk-c-1.0.0,securemode=3,signmethod=hmacsha256,lan=C|
    username: paho_mqtt&a11xsrW****
    password: 36E955DC3D9D012EF62C80657A29328B1CFAE6186C611A17DC7939FAB637****
    NetworkConnect 0
    Connecting to a11xsrW****.iot-as-mqtt.cn-shanghai.aliyuncs.com 443
    MQTTConnect 0, Connect aliyun IoT Cloud Success!
    Subscribing to /a11xsrW****/paho_mqtt/user/get
    MQTTSubscribe 0
    MQTTPublish 0, msgid 1
    MQTTPublish 0, msgid 2
    MQTTPublish 0, msgid 3
    MQTTPublish 0, msgid 4
    MQTTPublish 0, msgid 5
    ...

    Log on to the IoT Platform console. View device status and logs.

    • Choose Devices > Devices. You can find that the status of the device is Online.
    • Choose Maintenance > Device Log. Then, click the Cloud run log or Device local log tab to view logs. For more information, see IoT Platform logs and Local device logs.

Error codes

If a device fails to establish an MQTT connection to IoT Platform, you can troubleshoot the issue based on the error code. For more information, see Troubleshooting.