Tuya IoT Core SDK for C

Last Updated on : 2024-06-24 03:23:14download

Tuya IoT Core SDK for C supports the Tuya-defined device model, aiming to help developers to connect their proprietary hardware to the Tuya Developer Platform.

Feature description

Tuya IoT Core SDK provides APIs to implement basic services including device activation, bidirectional data exchange between the cloud and devices, and OTA updates. The SDK is independent of platforms and operating systems (OS), and it can run on a single-tasking operating system. If your devices support the TCP/IP protocol stack, you can develop with this SDK to connect your devices to the platform.

Procedure

Step 1: Download the SDK

Download IoT Core SDK from GitHub.

The following describes the structure of the SDK directory:

Files Description
certs Private keys, device certificates, and server-side CA root certificates.
docs Development documentation.
libraries External dependencies including MQTT client, HTTP client, and Mbed TLS.
interface The SDK function API, which is required to port to your platform.
include SDK APIs.
src Source code.
platform Adapters.
utils Common tools.
examples Routines.

Step 2: Configure device information

To get the platform authorization, you need to create a product on the Tuya Developer Platform. Add the product and authorization information to your code to enable cloud connectivity. The following steps show how to configure device information.

  1. Log in to the Tuya Developer Platform.

  2. Click Create.

    Tuya IoT Core SDK for C

  3. Click By Business Type > Smart Industry > Industrial Gateway.

    Tuya IoT Core SDK for C

  4. Choose TuyaLink Solution for Smart Mode and complete the required information to create a product.

    Tuya IoT Core SDK for C
  5. In Function Definition, click Add and complete the parameter fields to create a custom function.

    Tuya IoT Core SDK for C
  6. In Device Development, select and download the SDK and click Next.

    Tuya IoT Core SDK for C
  7. Request the free license and click Register Device. The device information will appear on the screen after registration.

    Tuya offers two free licenses for debugging purposes.

    Tuya IoT Core SDK for C
  8. Add the device information to the examples/subdevice_basic_demo/subdevice_basic_demo.c file. Build and run the program. Then, your device can connect to the cloud. For more information about the build process, see the following Build and run the demo.

    Tuya IoT Core SDK for C
    const char productId[] = "rwosj58aaqjk **** ";
    const char deviceId[] = "6c95875d0f5ba69607 **** ";
    const char deviceSecret[] = " ******************* ";
    

    You need to purchase licenses to register devices and get device information comprised of ProductId, DeviceId, and DeviceSecret.

Step 3: Build and run the program in Ubuntu

This section uses Ubuntu as an example to show you how to build and run the program. The build processes also apply to Debian system.

  1. Install make and other dependencies.

    sudo apt-get install make cmake
    
  2. Navigate to the SDK directory. Create a build folder and navigate to the created directory. Run cmake .. to generate a build system. Then run make to compile the project. The generated binary files are stored in the bin folder of your project.

    mkdir build && cd build
    cmake ..
    make
    
  3. Navigate to the bin folder and run the demo. The SDK contains the basic sample code for communication, such as code for sub-device management.

    ./bin/subdevice_basic_demo
    
  4. View log files.

    If you see MQTT client connected, your device is successfully connected to the cloud.

    Tuya IoT Core SDK for C

  5. Go back to the Tuya Developer Platform and refresh the Device Status. You will find it is Online.

    Tuya IoT Core SDK for C

Sample application

  1. Instantiate and initialize a device object tuya_iot_client_t to assign initial values, such as product ID (PID) and authorization information, for this object.

    /* instantiate the client */
    tuya_mqtt_context_t* client = &client_instance;
    
    /* initialize the client */
    ret = tuya_mqtt_init(client, &(const tuya_mqtt_config_t) {
        .host = "m2.tuyacn.com",
        .port = 8883,
        .cacert = tuya_cacert_pem,
        .cacert_len = sizeof(tuya_cacert_pem),
        .device_id = deviceId,
        .device_secret = deviceSecret,
        .keepalive = 60,
        .timeout_ms = 2000,
        .on_connected = on_connected,
        .on_disconnect = on_disconnect,
        .on_messages = on_messages
    });
    
  2. Define event callbacks in the application layer, used to receive the event notifications from the SDK, such as the data point (DP) data from the cloud or cloud connection status.

    /* Tuya SDK event callback */
    void on_messages(tuya_mqtt_context_t* context, void* user_data, const tuyalink_message_t* msg)
    {
        TY_LOGI("on message id:%s, type:%d, code:%d", msg->msgid, msg->type, msg->code);
        switch (msg->type) {
            case THING_TYPE_MODEL_RSP:
                TY_LOGI("Model data:%s", msg->data_string);
                break;
    
            case THING_TYPE_PROPERTY_SET:
                TY_LOGI("property set:%s", msg->data_string);
                break;
    
            case THING_TYPE_PROPERTY_REPORT_RSP:
                break;
    
            default:
                break;
        }
    printf("\r\n");
    }
    
  3. Start TuyaOS SDK service.

    ret = tuya_mqtt_connect(client);
    // TuyaOS SDK service tasks such as handling data and keepalive mechanism.
    
  4. Loop the following function to create threads for the underlying Link SDK client.

    tuya_mqtt_loop(client);
    
  5. Define the data reporting function and call the function to report data to the cloud. The following example shows how a connected device reports some data to the cloud. You can alter the code to meet your specific data reporting needs.

     void on_connected(tuya_mqtt_context_t* context, void* user_data)
    {
    TY_LOGI("on connected");
    
    /* data model test code */
    tuyalink_thing_data_model_get(context, NULL);
    tuyalink_thing_desired_get(context, NULL, "[\"power\"]");
    tuyalink_thing_property_report(context, NULL, "{\"power\":    {\"value\":1234,\"time\":1631708204231}}");
    tuyalink_thing_property_report_with_ack(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
    tuyalink_thing_event_trigger(context, NULL, "{\"eventCode\":\"boom\",\"eventTime\":1626197189630,\"outputParams\":{\"param1\":100}}");
    tuyalink_thing_batch_report(context, "{\"msgId\":\"45lkj3551234001\",\"time\":1626197189638,\"sys\":{\"ack\":1},\"data\":{\"properties\":{\"power\":{\"value\":11,\"time\":1626197189638}},\"events\":{\"boom\":{\"outputParams\":    {\"param1\":\"10\"},\"eventTime\":1626197189001}}}}");
    }
    
    /* Report data to the cloud */
    /* data model code */
    tuyalink_thing_data_model_get(context, NULL);
    tuyalink_thing_desired_get(context, NULL, "[\"power\"]");
    tuyalink_thing_property_report(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
    tuyalink_thing_property_report_with_ack(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
    tuyalink_thing_event_trigger(context, NULL, "{\"eventCode\":\"boom\",\"eventTime\":1626197189630,\"outputParams\":{\"param1\":100}}");
    tuyalink_thing_batch_report(context, "{\"msgId\":\"45lkj3551234001\",\"time\":1626197189638,\"sys\":{\"ack\":0},\"data\":{\"properties\":{\"power\":{\"value\":11,\"time\":1626197189638}},\"events\":{\"boom\":{\"outputParams\":{\"param1\":\"10\"},\"eventTime\":1626197189001}}}}");}
    /* subdevice code */
    tuyalink_subdevice_bind(context, "[{\"productId\":\"jtwe4q9jrs0bbc8q\",\"nodeId\":\"123456\",\"clientId\":\"123455asdf\"}]");
    tuyalink_subdevice_bind_login(context, "[\"6c17c5ba952143f592b8g1\",\"6c41626e5cea758aees0ik\"]");
    tuyalink_subdevice_bind_logout(context, "[\"6c17c5ba952143f592b8g1\"]");
    tuyalink_subdevice_topo_add(context, "[{\"productId\":\"jtwe4q9jrs0bbc8q\",\"deviceId\":\"6c17c5ba952143f592b8g1\",\"sign\":\"366508ed895644e70a3006bdef2dbe77ef73e18a\",\"signMethod\":\"hmacSha1\",\"timestamp\":\"1636989480\"}]");
    tuyalink_subdevice_topo_delete(context,"[\"6c41626e5cea758aees0ik\"]");
    tuyalink_subdevice_topo_get(context);
    

Device debugging

When a device is connected to the MQTT server and goes online, you can debug the device on the Tuya Developer Platform.

  1. Click the Online Debugging tab and select a device. Enter the DeviceID of the online device to show the collection of the defined data points (DPs).

    Tuya IoT Core SDK for C
  2. The right screen shows the device logs in real time.

    Tuya IoT Core SDK for C
  3. You can click Get to request the current device data.

    Tuya IoT Core SDK for C
  4. You can click Set to change the property value. The payload data will be displayed in the log on the right screen. You can also view the payload in the local log file.

    Tuya IoT Core SDK for C

API description

SDK initialization

Interface Description
Function prototype int tuya_mqtt_init(tuya_mqtt_context_t* context, const tuya_mqtt_config_t* config);
Features Device Initialization
Input parameter
  • context: The handle to device management.
  • config: Initial device configuration.
Output parameter None
Return value See common error codes.

Start services

Interface Description
Function prototype int tuya_mqtt_connect(tuya_mqtt_context_t* context);
Features Start SDK services.
Input parameter context: The handle to device management.
Output parameter None
Return value See common error codes.

Stop services

Interface Description
Function prototype int tuya_mqtt_disconnect(tuya_mqtt_context_t* context);
Features Stop SDK services.
Input parameter context: The handle to device management.
Output parameter None
Return value See common error codes.

Run in background

Interface Description
Function prototype int tuya_mqtt_loop(tuya_mqtt_context_t* context);
Features The SDK services run in the background.
Input parameter context: The handle to device management.
Output parameter None
Return value See common error codes.
Notes Call this function in the main loop.

Get device model

Interface Description
Function prototype int tuyalink_thing_data_model_get(tuya_mqtt_context_t* context, const char* device_id);
Features Call this function to get the device model.
Input parameter
  • context: The handle to device management.
  • device_id: Device ID.
Output parameter None
Return value See common error codes.

Report device properties

Interface Description
Function prototype int tuyalink_thing_property_report(tuya_mqtt_context_t* context, const char* device_id, const char* data);
Features Report device properties
Input parameter
  • context: The handle to device management.
  • device_id: Device ID.
Output parameter None
Return value See common error codes.

Report device properties (with ACK)

Interface Description
Function prototype int tuyalink_thing_property_report_with_ack(tuya_mqtt_context_t* context, const char* device_id, const char* data);
Features Call this function to report device properties and wait for an acknowledgment from the cloud.
Input parameter
  • context: The handle to device management.
  • device_id: Device ID.
  • data: The property value.
Output parameter None
Return value See common error codes.

Respond to device events

Interface Description
Function prototype int tuyalink_thing_event_trigger(tuya_mqtt_context_t* context, const char* device_id, const char* data);
Features Respond to device events
Input parameter
  • context: The handle to device management.
  • device_id: Device ID.
  • data: The event data.
Output parameter None
Return value See common error codes.

Report data in bulk

Interface Description
Function prototype int tuyalink_thing_batch_report(tuya_mqtt_context_t* context, const char* data);
Features The device reports status data to the cloud in bulk.
Input parameter
  • context: The handle to device management.
  • data: The data.
Output parameter None
Return value See common error codes.

Bind sub-devices

Interface Description
Function prototype int tuyalink_subdevice_bind(tuya_mqtt_context_t* context, const char* data);
Features Bind sub-devices
Input parameter
  • context: The handle to device management.
  • data: The data.
Output parameter None
Return value See common error codes.

Sub-device goes online

Interface Description
Function prototype int tuyalink_subdevice_bind_login(tuya_mqtt_context_t* context, const char* data);
Features Sub-device goes online
Input parameter
  • context: The handle to device management.
  • data: The data.
Output parameter None
Return value See common error codes.

Sub-device goes offline

Interface Description
Function prototype int tuyalink_subdevice_bind_logout(tuya_mqtt_context_t* context, const char* data);
Features Sub-device goes offline
Input parameter
  • context: The handle to device management.
  • data: The data.
Output parameter None
Return value See common error codes.

Add topology for sub-devices

Interface Description
Function prototype int tuyalink_subdevice_topo_add(tuya_mqtt_context_t* context, const char* data);
Features Add topology for sub-devices
Input parameter
  • context: The handle to device management.
  • data: The data.
Output parameter None
Return value See common error codes.

Delete topology for sub-devices

Interface Description
Function prototype int tuyalink_subdevice_topo_delete(tuya_mqtt_context_t* context, const char* data);
Features Delete topology for sub-devices
Input parameter
  • context: The handle to device management.
  • data: The data.
Output parameter None
Return value See common error codes.

Get topology for sub-devices

Interface Description
Function prototype int tuyalink_subdevice_topo_get(tuya_mqtt_context_t* context);
Features Get topology for sub-devices
Input parameter context: The handle to device management.
Output parameter None
Return value See common error codes.

Example

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "cJSON.h"
#include "tuya_cacert.h"
#include "tuya_log.h"
#include "tuya_error_code.h"
#include "system_interface.h"
#include "mqtt_client_interface.h"
#include "tuyalink_core.h"

const char productId[] = "3jbcpefnn1jxxxxx";
const char deviceId[] = "6ced2aa564727c01xxxxx";
const char deviceSecret[] = "ac5d367db39xxxxx";

tuya_mqtt_context_t client_instance;

void on_connected(tuya_mqtt_context_t* context, void* user_data)
{
    TY_LOGI("on connected");

    /* data model test code */
    tuyalink_thing_data_model_get(context, NULL);
    tuyalink_thing_desired_get(context, NULL, "[\"power\"]");
    tuyalink_thing_property_report(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
    tuyalink_thing_property_report_with_ack(context, NULL, "{\"power\":{\"value\":1234,\"time\":1631708204231}}");
    tuyalink_thing_event_trigger(context, NULL, "{\"eventCode\":\"boom\",\"eventTime\":1626197189630,\"outputParams\":{\"param1\":100}}");
    tuyalink_thing_batch_report(context, "{\"msgId\":\"45lkj3551234001\",\"time\":1626197189638,\"sys\":{\"ack\":0},\"data\":{\"properties\":{\"power\":{\"value\":11,\"time\":1626197189638}},\"events\":{\"boom\":{\"outputParams\":{\"param1\":\"10\"},\"eventTime\":1626197189001}}}}");
}

void on_disconnect(tuya_mqtt_context_t* context, void* user_data)
{
    TY_LOGI("on disconnect");
}

void on_messages(tuya_mqtt_context_t* context, void* user_data, const tuyalink_message_t* msg)
{
    TY_LOGI("on message id:%s, type:%d, code:%d", msg->msgid, msg->type, msg->code);
    switch (msg->type) {
        case THING_TYPE_MODEL_RSP:
            TY_LOGI("Model data:%s", msg->data_string);
            break;

        case THING_TYPE_PROPERTY_SET:
            TY_LOGI("property set:%s", msg->data_string);
            break;

        case THING_TYPE_PROPERTY_REPORT_RSP:
            break;

        default:
            break;
    }
    printf("\r\n");
}

int main(int argc, char** argv)
{
    int ret = OPRT_OK;

    tuya_mqtt_context_t* client = &client_instance;

    ret = tuya_mqtt_init(client, &(const tuya_mqtt_config_t) {
        .host = "m2.tuyacn.com",
        .port = 8883,
        .cacert = tuya_cacert_pem,
        .cacert_len = sizeof(tuya_cacert_pem),
        .device_id = deviceId,
        .device_secret = deviceSecret,
        .keepalive = 60,
        .timeout_ms = 2000,
        .on_connected = on_connected,
        .on_disconnect = on_disconnect,
        .on_messages = on_messages
    });
    assert(ret == OPRT_OK);

    ret = tuya_mqtt_connect(client);
    assert(ret == OPRT_OK);

    for (;;) {
        /* Loop to receive packets, and handles client keepalive */
        tuya_mqtt_loop(client);
    }

    return ret;
}