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

Prerequisites

Products and devices are created in IoT Platform.

For more information, see Create a product and Create a device.

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 C language version of the Paho MQTT library:

git clone https://github.com/eclipse/paho.mqtt.embedded-c.git
Note The master branch is used to develop the demo in this example. 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 additional 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 APIs, visit MQTTClient.h.

Connect to IoT Platform

  1. Click aiot_mqtt_signal.c to obtain the source code provided by Alibaba Cloud to calculate the MQTT connection parameters.

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

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

      Calculates the username, password, and clientId parameters for MQTT connections to IoT Platform.

    • Input parameters
      Parameter Type Description
      productKey const char * The ProductKey of the product to which the device belongs. It can be used to identify the device in IoT Platform.
      deviceName const char * The DeviceName of the device. It can be used to identify the device in IoT Platform.
      deviceSecret const char * The DeviceSecret of the device. It can be 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.
    • Return codes
      Return code Description
      0 Success
      -1 Failure
  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 calculate the parameters that are used to establish an MQTT connection to IoT Platform.

    This section provides the development instructions and sample code.

    • Call the aiotMqttSign() function to calculate the connection parameters clientId, username, and password.
      #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 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.

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

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

    • Subscribe to a topic to obtain 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 Communication methods.

  3. Copy the aiot_mqtt_signal.c file and the file edited in Step 2 to ../paho.mqtt.embedded-c/MQTTClient-C/samples/linux and then compile the project.

Demo

Connect the demo to IoT Platform.

  1. Download the demo package and decompress it.
    After the decompression, you can obtain the files described in the following table.
    .
    +-- aiot_c_demo.c
    +-- aiot_mqtt_sign.c
    File Description
    aiot_mqtt_sign.c This file contains the code that is used to calculate the parameters for establishing an MQTT connection to IoT Platform. When you run the aiot_c_demo.c file, the aiotMqttSign() function is called to calculate the connection parameters username, password, and clientId.
    aiot_c_demo.c This file contains the logic code that is used to establish a connection and exchange messages between the device and 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"
    • Replace the domain name in the code char *host = EXAMPLE_PRODUCT_KEY".iot-as-mqtt.cn-shanghai.aliyuncs.com" with "${EXAMPLE_PRODUCT_KEY}.iot-as-mqtt.cn-shanghai.aliyuncs.com".

      In the domain name, replace the ${EXAMPLE_PRODUCT_KEY} variable with the ProductKey of the product to which the device belongs. You can log on to the IoT Platform console to obtain the ProductKey on the Device Details page of the device.

      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 edited 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 to obtain the executable program 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 the content of the modified 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. After the compilation, run the following command in the /paho.mqtt.embedded-c/build.paho directory to run the program:
        . /MQTTClient-C/samples/linux/aiot_c_demo
    • Use the build.sh file.
      1. Replace the content of the build.sh file in the /paho.mqtt.embedded-c/MQTTClient-C/samples/linux directory with the following code:
        cp .. /../src/MQTTClient.c .
        sed -e 's/""/"MQTTLinux.h"/g' .. /../src/MQTTClient.h > MQTTClient.h
        gcc \
            -o aiot_c_demo \
            -I .. /../src -I .. /../src/linux -I .. /.. /.. /MQTTPacket/src \
            aiot_mqtt_sign.c aiot_c_demo.c \
            MQTTClient.c \
            .. /../src/linux/MQTTLinux.c \
            .. /.. /.. /MQTTPacket/src/MQTTFormat.c \
            .. /.. /.. /MQTTPacket/src/MQTTPacket.c \
            .. /.. /.. /MQTTPacket/src/MQTTDeserializePublish.c \
            .. /.. /.. /MQTTPacket/src/MQTTConnectClient.c \
            .. /.. /.. /MQTTPacket/src/MQTTSubscribeClient.c \
            .. /.. /.. /MQTTPacket/src/MQTTSerializePublish.c \
            .. /.. /.. /MQTTPacket/src/MQTTConnectServer.c \
            .. /.. /.. /MQTTPacket/src/MQTTSubscribeServer.c \
            .. /.. /.. /MQTTPacket/src/MQTTUnsubscribeServer.c \
            .. /.. /.. /MQTTPacket/src/MQTTUnsubscribeClient.c
      2. After the modification, run the ./build.sh command in the current directory to compile the project.

        After the compilation, the aiot_c_demo executable file is generated.

      3. Run the ./aiot_c_demo command to run the file.
    After the file is run, you can view the local logs about the connection to IoT Platform.
    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
    ...

    In the IoT Platform console, you can view the device status and logs.

    • Choose Devices > Devices. You can view that the status of the device is Online.
    • Choose Maintenance > Device Log. You can view the Device Activity Analysis and Upstream Analysis 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 about the error codes that may be returned by IoT Platform, see Troubleshooting.