美文网首页物联网
中国电信天翼物联网平台CTWing学习笔记(1)——设备接入(T

中国电信天翼物联网平台CTWing学习笔记(1)——设备接入(T

作者: Leung_ManWah | 来源:发表于2022-03-30 18:10 被阅读0次

    一、平台简介

    天翼物联网平台(AIoT) 是中国电信倾力打造的智能终端汇聚、应用开发运行服务和轻量级应用提供的物联网平台,旨在降低物联网应用开发的准入门槛,降低智能硬件的接入门槛,提供端到端的解决方案,服务于终端开发商、个人极客开发者、能力提供商、应用开发商以及集团内部各生态圈。

    官网主页:https://www.ctwing.cn/
    帮助中心:https://www.ctwing.cn/czlks/11#see

    平台架构:

    二、Demo体验与SDK下载

    2.1 创建产品及设备

    产品信息如下:


    安全类型:
    • 一机一密:每个设备都有一个不同的特征串
    • 一型一密:同款产品下每个设备都使用同一个特征串



      添加设备如下:


    2.2 SDK下载及修改

    SDK下载:
    https://www.ctwing.cn/sbjr/72#/callback

    从平台获取接入 IP 和端口,设备 ID,认证信息:



    然后根据实际获取到的设备 ID,特征串修改 ctiot_tcp_sdk\sample\demo\demo.cctiot_test_init() 的设备 ID和特征串。
    ctiot_status ctiot_test_init()
    {
      char* ip = "180.106.148.146";
      int port  = 8996;
      char* deviceId = "1517035889860492192091928466";
      char* passWord = "AqUFr6ntTFDFZUvAO1jELbIz8h3v6yHzH7hEBsKNxrY";
      char* verSion = "1.0";
      int certmode = 0;
      
      printf("server IP: %s\nserver Port: %d\ndeviceid: %s\npassword: %s\nversion:%s\ncertMode: %d\n",ip, port, deviceId, passWord, verSion, certmode);
      ctiot_init(&c, ip, port, deviceId, passWord, verSion, certmode);
    }
    

    2.3 SDK编译及运行程序对接平台测试

    将修改完的 SDK 工程文件夹 ctiot_tcp_sdk 放入 Linux 运行环境中 ,进入 ctiot_tcp_sdk/sample/demo 目录,执行 make 命令,系统自动编译生成可执行文件,运行程序 tcp_client

    2.3.1 设备登录

    输入'l''L' 登录:


    平台查看终端已在线:

    注:若60秒内同一ip建链、断链次数超过30次,将停止该ip连接2小时。

    2.3.2 数据上报

    输入's''S' 进行数据上报:


    在平台进行数据查看,可看到数据已上报:

    可看到上报的两条数据:

    对于透传产品,平台对上报的业务数据进行 Base64编码 处理,进行解码后:

    2.3.3 指令下发

    平台执行指令下发(对于透传产品,平台对下行指令做透传处理,支持字符串和十六进制两种数据类型):


    平台可查看指令下发日志,可看到下发已成功:


    终端查看指令下发成功:

    三、TCP协议接口介绍

    帮助文档:https://www.ctwing.cn/sbjr/67#see

    3.1 接口地址

    通信协议 地址 端口 说明
    TCP tcp.ctwing.cn 8996 TCP非加密接口
    支持ipv4和ipv6接入

    3.2 消息格式

    应用层数据报文以1个字节的类型字段作为分割,平台支持登录、心跳、上下行业务数据等消息类型。消息携带的参数必须包含两个字节的参数长度。

    根据数据报文内容分为:

    • 透传设备(对于透传产品,平台对上报的业务数据进行 Base64编码 处理,可以在产品的数据查看页面查看上报的数据内容,也可以通过订阅推送的方式,北向应用订阅设备数据变化通知,平台将上报的数据推送给北向应用。)
    消息类型 类型描述 消息格式 备注
    0x01 登录请求 0x01 +deviceId_length(2字节) +deviceId +password_length(2字节) +password +version_length(2字节) +version deviceId是由产品ID和设备编号拼接而成的字符串; password由平台生成,在设备管理业务可以查看; version固定1.0
    0x02 上行数据报文 0x02 +数据长度(2字节) +业务数据
    0x03 下行数据报文 0x03 +数据长度(2字节) +业务数据
    0x04 心跳 0x04 平台心跳周期为5分钟,设备需在5分钟内发送心跳报文
    0x05 登录响应 0x05+结果码(2字节) 登录结果: 0 成功 1 未知错误 2 设备未注册 3 设备认证失败 4 设备已登录
    0x06 心跳响应 0x06 平台回复终端心跳的响应
    • 非透传设备(对于非透传产品,平台 根据物模型对上报的业务数据进行解析,可以在产品的数据查看页面查看上报的数据内容,也可以通过订阅推送的方式,北向应用订阅设备数据变化通知,平台将上报的数据推送给北向应用。)
    消息类型 类型描述 消息格式 备注
    0x01 登录请求 0x01 +deviceId_length(2字节) +deviceId +password_length(2字节) +password +version_length(2字节) +version deviceId是由产品ID和设备编号拼接而成的字符串; password由平台生成,在设备管理业务可以查看; version固定1.1 业务数据非透传格式遵循物模型,上下行业务数据需要响应。
    0x02 上行数据报文 0x02+数据长度(2字节)+msgid(2字节)+serviceid(2字节)+param1+params2+param3+…… 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,由终端分配;serviceId:平台分配的服务ID;param:平台服务包含的属性
    0x82 上行数据报文 0x82+数据长度(2字节)+msgid(2字节)+结果码(2字节) 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,跟上行报文中msgid对应;结果码:0-成功、1-报文解析失败
    0x03 下行数据报文 0x03+数据长度(2字节)+msgid(2字节)+serviceId(2字节)+param1+param2+param3+…… 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,由平台分配;serviceId:平台分配的服务ID;param:平台服务包含的属性(参数)注:msgid字段即为指令的taskId
    0x83 下行数据响应 0x83+数据长度(2字节)+msgid(2字节)+结果码(2字节)+serviceId(2字节)+param1+param2+param3+…… 数据长度:从msgid开始,到报文结尾的长度;msgid:报文标识,对应下行指令中的msgid;结果码:0-成功,不带serviceId和参数;1-成功,带serviceId和参数;2-下行数据处理失败,不带serviceId和参数
    0x04 心跳 0x04 平台心跳周期为5分钟,设备需在5分钟内发送心跳报文
    0x05 登录响应 0x05+结果码(2字节) 登录结果: 0 成功 1 未知错误 2 设备未注册 3 设备认证失败 4 设备已登录
    0x06 心跳响应 0x06 平台回复终端心跳的响应

    3.3 业务数据交互流程

    3.3.1 设备登录


    设备登录需要携带 deviceIdpasswordversion 字段,AEP对设备进行认证,认证通过 0x05 消息类型返回成功的响应(响应码为:0),认证失败将失败原因通过响应码带给设备。
    • 透传设备
      deviceId:10013378001
      password:7Sfv-b_HDbLDyJ_K-0SkWqRGd-GE-b3rZp-upOr1kSU
      version:1.0
    登录请求编码为(16进制):
    • 登录报文标识符:0x01
    • deviceId_length:0x000b
    • deviceId:0x3130303133333738303031
    • password_length:0x002b
    • password:0x375366762d625f4844624c44794a5f4b2d30536b57715247642d47452d6233725a702d75704f72316b5355
    • version_length:0x0003
    • version:0x312e30
    

    登录请求的完整报文为:01000b 3130303133333738303031 002b 375366762d625f4844624c44794a5f4b2d30536b57715247642d47452d6233725a702d75704f72316b5355 0003 312e30

    • 非透传设备
      deviceId:10013378001
      password:7Sfv-b_HDbLDyJ_K-0SkWqRGd-GE-b3rZp-upOr1kSU
      version:1.1
    登录请求编码为(16进制):
    • 登录报文标识符:0x01
    • deviceId_length:0x000b
    • deviceId:0x 3130303133333738303031
    • password_length:0x002b
    • password:0x375366762d625f4844624c44794a5f4b2d30536b57715247642d47452d6233725a702d75704f72316b5355
    • version_length:0x0003
    • version:0x312e31
    

    登录请求的完整报文为:01 000b 3130303133333738303031 002b 375366762d625f4844624c44794a5f4b2d30536b57715247642d47452d6233725a702d75704f72316b5355 0003 312e31

    3.3.2 上行数据


    设备以 0x02 消息类型上报数据,非透传设备平台解析后会以 0x82 回复响应结果。
    • 透传设备
      业务数据:"hello"
    上行数据编码为(16进制):
    • 上行报文标识符:0x02
    • payload_length:0x0005
    • payload:0x68656c6c6f
    

    上行数据报文完整报文为:02 0005 68656c6c6f

    • 非透传设备
      物模型如下:
    服务类型 服务标识 服务ID 属性顺序 属性标识符 属性类型 属性长度
    数据上报 up 1 1 data0 无符号整型 2
    2 data1 定长字符串 5
    3 data2 变长字符串 /

    服务类型、服务标识、服务ID所在位置:



    属性顺序、属性标识符、属性类型所在位置:


    上行数据编码为(16进制):
    • 上行报文标识符:0x02
    • payload_length:0x0012
    • msgId: 0x0001
    • serviced: 0x0001
    • payload:
      – data0:0x0064(100)
      – data1:0x68656C6C6F(hello)
      – data2:0x0005 776F726C64(world)[包含两个字节的长度0005]
    

    上行数据完整报文为:02 0012 0001 0001 0064 68656C6C6F 0005776F726C64

    上行数据响应报文编码为:
    • 上行响应标识符:0x82
    • payload_length:0x0004
    • msgId: 0x0001
    • 结果码: 0x0000
    

    上行数据响应报文为:82 0004 0001 0000

    3.3.3 下行数据


    平台以 0x03 消息类型下发指令,非透传设备需以 0x83 回复指令执行结果。

    注意:tcp透传没有指令缓存机制,若设备离线指令直接丢弃,不会下发,非透传有缓存机制,收到指令后若不进行回复,在指令ttl有效期内如果设备重新上线,指令会重新下发。

    • 透传设备
      业务数据:"turn off"
    下行数据编码为(16进制):
    • 下行报文标识符:0x03
    • payload_length:0x0008
    • payload:0x7475726e206f6666
    

    下行数据完整报文为:03 0008 7475726e206f6666

    • 非透传设备
      物模型如下:
    服务类型 服务标识 服务ID 参数顺序 参数标识符 参数类型 参数长度
    指令下发 dn 8001 1 cmd 定长字符串 5
    指令下发响应 rsp 9001 1 time 定长字符串 5
    下行指令编码为(16进制):
    • 下行报文标识符:0x03
    • payload_length:0x0009
    • msgId: 0x0001
    • serviced: 0x1f41
    • payload:
      – cmd:0x68656C6C6F(hello)
    

    下行指令完整报文为:03 0009 0001 1f41 68656c6c6f

    msgid为1,需要在响应中带回

    指令响应编码为:
    • 下行响应标识符:0x83
    • payload_length:0x000b
    • msgId: 0x0001
    • 结果码: 0x0001
    • serviced: 0x2329
    • payload:
      – cmd:0x776F726C64 (world)
    

    下行指令响应的完整包文为:83 000b 0001 0001 2329 776F726C64

    3.3.4 心跳


    设备需要周期性(5分钟以内)发送心跳报文来保持业务层会话。
    心跳编码为(16进制):
    • 心跳标识符:0x04
    

    心跳的完整包文为:04

    四、自定义接口函数

    由于原来SDK是Linux平台的程序,为了更适用于嵌入式终端程序,这里我修改成几个接口函数。

    4.1 ctiot_tcp.c

    /*********************************************************************
     * INCLUDES
     */
    #include <stdio.h>
    #include <string.h>
    
    #include "ctiot_tcp.h"
    
    static ctiot_status ctiot_varify_parameters(uint8_t *deviceId, uint8_t *password, uint8_t *version);
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief 初始化终端信息
     @param clientInfo -[out] 终端信息
     @param deviceId -[in] 设备ID
     @param password -[in] 特征串
     @param version -[in] 版本
     @return 无
    */
    ctiot_status CTIOT_Init(clientinfo_t *clientInfo, uint8_t *deviceId, uint8_t *password, uint8_t *version)
    {
        if(CTIOT_ERROR == ctiot_varify_parameters(deviceId, password, version))
        {
            return CTIOT_ERROR;
        }
        clientInfo->deviceIdLen = strlen(deviceId);
        clientInfo->deviceId = strdup(deviceId);
        clientInfo->passwordLen = strlen(password);
        clientInfo->password = strdup(password);
        clientInfo->versionLen = strlen(version);
        clientInfo->version = strdup(version);
    
        return CTIOT_SUCCESS;
    }
    
    /**
     @brief 登录CTWing平台
     @param pMsg -[out] 消息
     @param pMsgLen -[out] 消息长度
     @param pDeviceId -[in] 设备ID
     @return 无
    */
    void CTIOT_Login(clientinfo_t *context)
    {
        uint8_t *pMsg = NULL;
        uint16_t msgLen = 0;
        if(CTIOT_SUCCESS != CTIOT_Encode_Login_Para(&pMsg, &msgLen, context))
        {
            iopen_debug_print("Login encode failed!\n");
        }
        Socket_SendBytes(pMsg, msgLen);
        free(pMsg);
        pMsg = NULL;   
    }
    
    /**
     @brief 下行数据报文处理
     @param pMsg -[in&out] 消息
     @param pMsgLen -[in&out] 消息长度
     @return 无
    */
    void CTIOT_Command_MsgHandler(char *pMsg, uint32_t *pMsgLen)
    {
        uint8_t msgType = 0;
        uint8_t payloadLength[2] = {0};
        uint8_t msgId[2] = {0};
        uint8_t serviced[2] = {0};
    
        msgType = pMsg[0];
        memcpy(payloadLength, pMsg + 1, 2);
        memcpy(msgId, pMsg + 1+2, 2);
        memcpy(serviced, pMsg + 1+2+2, 2);
    
        switch(msgType)
        {
        case DOWNSTREAM_MESSAGE:                                            // 下行数据报文标识符
            for(int i = 0; i < *pMsgLen; i++)
            {
                print("socket msg:%02x\n", pMsg[i]);
            }
            CTIOT_Command_Response(msgId);
            break;
    
        case LOGIN_ACK:                                                     // 注册ACK报文标识符
            if(pMsg[2] != CTIOT_LOGIN_FAILED || pMsg[2] != CTIOT_DEVICE_AUTH_FAILED)
            {
                // 登录成功
            }
            break;
    
        case HEARTBEAT_ACK:                                                 // 心跳ACK报文标识符
            // 心跳成功
            break;
        
        default:
            break;
        }
    }
    
    /**
     @brief 封装登录请求
     @param ptrStream -[out] 请求消息
     @param ptrLen -[out] 请求消息长度
     @param data -[in] 需要上传的数据
     @param dataLen -[in] 需要上传的数据长度
     @return 状态码
    */
    ctiot_status CTIOT_Encode_Login_Para(uint8_t **ptrStream, uint16_t *ptrLen, clientinfo_t *context)
    {
        ctiot_status ret = CTIOT_SUCCESS;
        *ptrLen = 0;
        *ptrLen = 7 + context->deviceIdLen + context->passwordLen + context->versionLen;
        uint32_t i = 0,j = 0;
    
        *ptrStream = (uint8_t *)malloc(*ptrLen);
        if(ptrStream == NULL)
        {
            ret = CTIOT_ERROR;
            goto exit;
        }
    
        //message type
        (*ptrStream)[0] = LOGIN_MESSAGE;i++;
    
        //deviceId
        (*ptrStream)[i++] = (context->deviceIdLen)>>8;
        (*ptrStream)[i++] = (context->deviceIdLen)>>0;
        for(j = 0; j < context->deviceIdLen; j++)
        {
            (*ptrStream)[i++] = (context->deviceId[j]);
        }
    
        //password
        (*ptrStream)[i++] = (context->passwordLen)>>8;
        (*ptrStream)[i++] = (context->passwordLen)>>0;
        for(j = 0; j < context->passwordLen; j++)
        {
            (*ptrStream)[i++] = (context->password[j]);
        }
    
        //version
        (*ptrStream)[i++] = (context->versionLen)>>8;
        (*ptrStream)[i++] = (context->versionLen)>>0;
        for(j = 0; j < context->versionLen; j++)
        {
            (*ptrStream)[i++] = (context->version[j]);
        }
    
        if(*ptrLen != i)
        {
            ret = CTIOT_ERROR;
            iopen_debug_print("*ptrLen error\n");
            goto exit;
        }
    
    exit:
        return ret;
    }
    
    /**
     @brief 封装上行数据报文
     @param ptrStream -[out] 上报消息
     @param ptrLen -[out] 上报消息长度
     @param data -[in] 需要上传的数据
     @param dataLen -[in] 需要上传的数据长度
     @return 状态码
    */
    ctiot_status CTIOT_Encode_Updata_Para(uint8_t **ptrStream, uint16_t *ptrLen, uint8_t *data, uint16_t dataLen)
    {
        ctiot_status ret = CTIOT_SUCCESS;
        *ptrLen = 0;
        *ptrLen = 3 + dataLen;
        uint32_t i = 0,j = 0;
    
        *ptrStream = (uint8_t *)malloc(*ptrLen);
        if(ptrStream == NULL)
        {
            ret = CTIOT_ERROR;
            goto exit;
        }
    
        //message type
        (*ptrStream)[0] = UPSTREAM_MESSAGE;i++;
    
        //upstream data
        (*ptrStream)[i++] = dataLen>>8;
        (*ptrStream)[i++] = dataLen>>0;
        for(j = 0; j < dataLen; j++)
        {
            (*ptrStream)[i++] = (data[j]);
        }
    
        if(*ptrLen != i)
        {
            ret = CTIOT_ERROR;
            iopen_debug_print("*ptrLen error\n");
            goto exit;
        }
    
    exit:
        return ret;
    }
    
    /**
     @brief 封装下行数据响应
     @param ptrStream -[out] 指令响应消息
     @param ptrLen -[out] 指令响应消息长度
     @param data -[in] 需要上传的数据
     @param dataLen -[in] 需要上传的数据长度
     @return 状态码
    */
    ctiot_status CTIOT_Encode_Command_Response_Para(uint8_t **ptrStream, uint16_t *ptrLen, uint8_t *data, uint16_t dataLen)
    {
        ctiot_status ret = CTIOT_SUCCESS;
        *ptrLen = 0;
        *ptrLen = 3 + dataLen;
        uint32_t i = 0,j = 0;
    
        *ptrStream = (uint8_t *)malloc(*ptrLen);
        if(ptrStream == NULL)
        {
            ret = CTIOT_ERROR;
            goto exit;
        }
    
        //message type
        (*ptrStream)[0] = DOWNSTREAM_MESSAGE_ACK;i++;
    
        //upstream data
        (*ptrStream)[i++] = dataLen>>8;
        (*ptrStream)[i++] = dataLen>>0;
        for(j = 0; j < dataLen; j++)
        {
            (*ptrStream)[i++] = (data[j]);
        }
    
        if(*ptrLen != i)
        {
            ret = CTIOT_ERROR;
            iopen_debug_print("*ptrLen error\n");
            goto exit;
        }
    
    exit:
        return ret;    
    }
    
    /**
     @brief 保持心跳
     @param 无
     @return 无
    */
    void CTIOT_Keep_Alive(void)
    {
        uint8_t ping[1] = {PING_MESSAGE};
        Socket_SendBytes(ping, sizeof(ping));  // 改成自己的socket发送函数
    }
    
    /**
     @brief 指令响应
     @param pMsgId -[in] 消息ID
     @return 无
    */
    void CTIOT_Command_Response(uint8_t *pMsgId)
    {
        uint8_t *pMsg = NULL;
        uint16_t msgLen = 0;
        //                      msgid      result
        uint8_t data[4] = {0x00, 0x01, 0x00, 0x00};
        memcpy(data, pMsgId, 2);
        CTIOT_Encode_Command_Response_Para(&pMsg, &msgLen, data, sizeof(data));
        Socket_SendBytes(pMsg, msgLen);
        free(pMsg);
        pMsg = NULL;
    }
    
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief 校验参数
     @param deviceId -[in] 设备ID
     @param password -[in] 特征串
     @param version -[in] 版本
     @return 状态码
    */
    static ctiot_status ctiot_varify_parameters(uint8_t *deviceId, uint8_t *password, uint8_t *version)
    {
        ctiot_status ret = CTIOT_SUCCESS;
        if(deviceId == NULL || password == NULL || version == NULL)
        {
            ret = CTIOT_ERROR;
            iopen_debug_print("Init paramter error!\n");
        }
        return ret;
    }
    
    /****************************************************END OF FILE****************************************************/
    

    4.2 ctiot_tcp.h

    注意:请修改以下地方 PRODUCT_IDPASSWORDVERSIONCTIOT_Keep_Alive() 中的socket发送函数,CTIOT_Command_Msghandler()中进行数据接收处理。

    #ifndef _CTIOT_TCP_H_
    #define _CTIOT_TCP_H_
    
    /*********************************************************************
     * INCLUDES
     */
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define PRODUCT_ID              "10005081"                                      // 产品ID,根据实际修改
    #define PASSWORD                "WbYvOBP6Zx73gy1o7pqviKkK8EDYFNjsDNJA1I34_oo"   // 特征串,根据实际修改
    #define VERSION                 "1.1"                                           // 协议版本,透传设备改成1.0,非透传设备为1.1
    
    #define PRODUCT_ID_LEN          8       // 产品ID长度
    #define ICCID_LEN               20      // 设备编号长度
    
    /*********************************************************************
     * TYPEDEFS
     */
    typedef enum
    {
        LOGIN_MESSAGE = 0x01,               //!<注册报文标识符
        UPSTREAM_MESSAGE = 0x02,            //!<上行数据报文标识符
        DOWNSTREAM_MESSAGE = 0x03,          //!<下行数据报文标识符
        PING_MESSAGE = 0x04,                //!<心跳报文标识符
        LOGIN_ACK = 0x05,                   //!<注册ACK报文标识符
        HEARTBEAT_ACK = 0x06,               //!<心跳ACK报文标识符
        UPSTREAM_MESSAGE_ACK = 0x82,        //!<上行数据ACK报文标识符
        DOWNSTREAM_MESSAGE_ACK = 0x83,      //!<下行数据ACK报文标识符
    } message_type_e;
    
    typedef struct client
    {
        uint16_t deviceIdLen;               //!<deviceid长度
        uint8_t *deviceId;                  //!<deviceid
        uint16_t passwordLen;               //!<password长度
        uint8_t *password;                  //!<password
        uint16_t versionLen;                //!<version长度
        uint8_t *version;                   //!<version
    } clientinfo_t;
    
    typedef enum
    {
        CTIOT_ERROR = -1,                   //!<错误
        CTIOT_SUCCESS = 0,                  //!<成功
        CTIOT_LOGIN_FAILED = 1,             //!<登录未知错误
        CTIOT_DEVICE_UNREGISTERED = 2,      //!<设备未注册
        CTIOT_DEVICE_AUTH_FAILED = 3,       //!<设备认证失败
        CTIOT_DEVICE_HAVE_LOGINED = 4,      //!<设备已登录
    
        CTIOT_READ_PACKET_NONE = 999,       //!<未读取到数据
    } ctiot_status;
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void CTIOT_Command_Msghandler(char *pMsg, uint32_t *pMsgLen);
    ctiot_status CTIOT_Init(clientinfo_t *clientInfo, uint8_t *deviceId, uint8_t *password, uint8_t *version);
    ctiot_status CTIOT_Encode_Login_Para(uint8_t **ptrStream, uint16_t *ptrLen, clientinfo_t *context);
    ctiot_status CTIOT_Encode_Updata_Para(uint8_t **ptrStream, uint16_t *ptrLen, uint8_t *data, uint16_t dataLen);
    ctiot_status CTIOT_Encode_Command_Response_Para(uint8_t **ptrStream, uint16_t *ptrLen, uint8_t *data, uint16_t dataLen);
    void CTIOT_Login(clientinfo_t *context);
    void CTIOT_Keep_Alive(void);
    void CTIOT_Command_Response(uint8_t *pMsgId);
    
    #endif /* _CTIOT_TCP_H_ */
    

    4.3 使用方法

    • 初始化终端信息
      在这里设备ID我采取的是产品ID+iccid的形式,实际应用中把你的设备编号替换iccid的内容。
    #include "ctiot_tcp.h"
    
    static clientinfo_t s_clientInfo = {0};
    
    char iccidString[21] = {0};
    GetIccid(iccidString);
    char deviceId[PRODUCT_ID_LEN + ICCID_LEN + 1] = {0};
    sprintf(deviceId, "%s%s", PRODUCT_ID, iccidString);
    char *pPassword = PASSWORD;
    char *pVersion = VERSION;
    
    CTIOT_Init(&s_clientInfo, deviceId, pPassword, pVersion);
    
    • 登录
    CTIOT_Login(&s_clientInfo);
    
    • 数据上报
      • msgid:0x00 0x01 可变可不变,按实际需求
      • serviced:0x00 0x03 即服务ID为3,按实际情况修改
      • data:0x01 这里为无符号整型1字节的属性,按实际情况修改
      • Socket_SendBytes():修改成你字节的socket发送函数
    uint8_t *pMsg = NULL;
    uint16_t msgLen = 0;
    //                       msgid    serviced  data
    uint8_t data[5] = {0x00, 0x01, 0x00, 0x03, 0x01};
    CTIOT_Encode_Updata_Para(&pMsg, &msgLen, data, sizeof(data));
    Socket_SendBytes(pMsg, msgLen);
    free(pMsg);
    pMsg = NULL;
    
    • 心跳
      设备需要周期性(5分钟以内)发送心跳报文来保持业务层会话。
    CTIOT_Keep_Alive();
    
    • 指令下发、登录响应、心跳响应

    注意:tcp透传没有指令缓存机制,若设备离线指令直接丢弃,不会下发,非透传有缓存机制,收到指令后若不进行回复,在指令ttl有效期内如果设备重新上线,指令会重新下发。

    int recvDataLen = Socket_Receive(recvDataBuf);                  // 接收服务器数据
    if(recvDataLen > 0)
    {
        CTIOT_Command_MsgHandler(recvDataBuf, &recvDataLen);
    }
    
    • 指令响应
    void CTIOT_Command_MsgHandler(char *pMsg, uint32_t *pMsgLen)
    {
        uint8_t msgType = 0;
        uint8_t payloadLength[2] = {0};
        uint8_t msgId[2] = {0};
        uint8_t serviced[2] = {0};
    
        msgType = pMsg[0];
        memcpy(payloadLength, pMsg + 1, 2);
        memcpy(msgId, pMsg + 1+2, 2);
        memcpy(serviced, pMsg + 1+2+2, 2);
    
        switch(msgType)
        {
        case DOWNSTREAM_MESSAGE:                                            // 下行数据报文标识符
            CTIOT_Command_Response(msgId);                                  // 指令响应
            break;
        ···
        ···
        default:
            break;
    }
    

    • 由 Leung 写于 2022 年 3 月 30 日

    • 参考:电信平台对接CTWing具体实现流程

    相关文章

      网友评论

        本文标题:中国电信天翼物联网平台CTWing学习笔记(1)——设备接入(T

        本文链接:https://www.haomeiwen.com/subject/nbivjrtx.html