This article describes how to use the open source Paho MQTT project for embedded C to connect and communicate with IoT Platform.

Prerequisites

A product and a device are created in the IoT Platform console.The device certificate information including ProductKey, DeviceName, and DeviceSecret is obtained. For more information, see the following articles:

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 The master branch is used to develop the sample code in this article. The commit ID is 29ab2aa29c5e47794284376d7f8386cfd54c3eed.

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

  • MQTTPacket: provides serialization and deserialization of MQTT data packets and some helper functions.
  • MQTTClient: encapsulates the high-level C++ client program generated by MQTTPacket.
  • MQTTClient-C: encapsulates the high-level C client program 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 the code for 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.

    • Syntax
      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 parameter is used to identify the device in IoT Platform.
      deviceName const char * The DeviceName of the device. This parameter is used to identify the device in IoT Platform.
      deviceSecret const char * The DeviceSecret of the device. This parameter is used to identify the device in IoT Platform.
    • 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 The function is implemented.
      -1 The function failed to be implemented.
  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 used to establish an MQTT connection with IoT Platform.

    This section provides the development instructions and sample code.

    • Call the aiotMqttSign() function to obtain 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 edited in Step 2 to ../paho.mqtt.embedded-c/MQTTClient-C/samples/linux and then compile the project.

Sample code

You can use the sample code to connect with IoT Platform.

  1. Download the demo package and decompress it.
    The following files are obtained:
    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 the username, password, and clientId parameters.
    aiot_c_demo.c This file contains the logic code that is used to connect 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".

      Replace cn-shanghai in the code with the ID of the region where your device resides. For more information about region IDs, see Regions and zones.

  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 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.