本文以C Link SDK中的Demo文件./demos/data_model_basic_demo.c为例,介绍如何调用Link SDK的API,使设备可使用物模型的功能。
背景信息
步骤一:初始化
步骤二:配置功能
调用aiot_dm_setopt,配置以下功能。
步骤三:上报属性
设备建立MQTT连接后,调用aiot_dm_send,向物联网平台发送属性消息。要发送的属性消息,通过aiot_dm_msg_t结构体,存放于指定位置,作为aiot_dm_send的入参。
ICA标准数据格式(Alink JSON)
透传/自定义格式
步骤四:设置属性
您可以调用物联网平台的云端API SetDeviceProperty或SetDevicesProperty,向设备发送属性设置指令。设备端调用aiot_mqtt_recv接收该指令,根据回调函数demo_dm_recv_handler
的设置,执行对应处理。
您可以参考以下内容,编写回调函数的处理逻辑:
-
注意事项:
-
接收的消息作为类型aiot_dm_recv_handler_t的入参,通过aiot_dm_recv_t结构体存放于您指定的位置。
- 不同的设备数据格式,其接收的设置属性指令内容,所在的字段如下表所示:
设备数据格式 接收的消息中的字段 说明 ICA标准数据格式(Alink JSON) recv->data.property_set.params
与Alink格式数据中params的值一致,更多信息,请参见属性消息。
透传/自定义格式 recv->data.raw_data
设备端需解析数据,更多信息,请参见透传/自定义格式的消息。
-
-
建议的处理逻辑:
- 更新设备属性。
- 上报更新后的属性。
-
示例代码的处理逻辑:
示例代码仅打印接收的消息,如需演示上报设置的属性,请取消示例代码中
TODO
下代码的注释符号(/*
和*/
),查看效果。- ICA标准数据格式(Alink JSON)
static void demo_dm_recv_property_set(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata) { printf("demo_dm_recv_property_set msg_id = %ld, params = %.*s\r\n", (unsigned long)recv->data.property_set.msg_id, recv->data.property_set.params_len, recv->data.property_set.params); /* TODO: 以下代码演示如何对物联网平台的属性设置指令进行应答, 您可取消注释查看演示效果 */ /* { aiot_dm_msg_t msg; memset(&msg, 0, sizeof(aiot_dm_msg_t)); msg.type = AIOT_DMMSG_PROPERTY_SET_REPLY; msg.data.property_set_reply.msg_id = recv->data.property_set.msg_id; msg.data.property_set_reply.code = 200; msg.data.property_set_reply.data = "{}"; int32_t res = aiot_dm_send(dm_handle, &msg); if (res < 0) { printf("aiot_dm_send failed\r\n"); } } */ }
- 透传/自定义格式
static void demo_dm_recv_raw_data(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata) { printf("demo_dm_recv_raw_data raw data len = %d\r\n", recv->data.raw_data.data_len); /* TODO: 以下代码演示如何发送二进制格式数据, 如需使用,需在物联网平台部署对应的数据透传脚本。 */ /* { aiot_dm_msg_t msg; uint8_t raw_data[] = {0x01, 0x02}; memset(&msg, 0, sizeof(aiot_dm_msg_t)); msg.type = AIOT_DMMSG_RAW_DATA; msg.data.raw_data.data = raw_data; msg.data.raw_data.data_len = sizeof(raw_data); aiot_dm_send(dm_handle, &msg); } */ }
- ICA标准数据格式(Alink JSON)
步骤五:上报事件
设备建立MQTT连接后,调用aiot_dm_send,向物联网平台发送事件消息。要发送的事件消息,通过aiot_dm_msg_t结构体,存放于指定位置,作为aiot_dm_send的入参。
根据以下不同的设备数据格式类型,为上报事件,编写代码。
- 如果您的设备数据格式为透传/自定义格式,设备上报事件与上报属性的接口一致,具体流程,请参见步骤三中的上报透传/自定义格式的消息。
- 如果您的设备数据格式为ICA标准数据格式(Alink JSON),设备端代码编写的流程,请参见下文。
步骤六:调用服务
您可以调用物联网平台的云端API InvokeThingService或InvokeThingsService,向设备发送调用服务的指令。设备端调用aiot_mqtt_recv接收该指令,根据回调函数demo_dm_recv_handler
的设置,执行对应处理。
您可以参考以下内容,编写回调函数的处理逻辑:
-
注意事项:
-
接收的消息作为类型aiot_dm_recv_handler_t的入参,通过aiot_dm_recv_t结构体存放于您指定的位置。
- 不同的设备数据格式,其接收的调用服务指令内容,所在的字段如下表所示:
设备数据格式 同步消息的字段 异步消息的字段 说明 ICA标准数据格式(Alink JSON) recv->data.sync_service_invoke
recv->data.async_service_invoke
字段中数据的格式与Alink格式数据中params的值一致,更多信息,请参见服务消息。 透传/自定义格式 recv->data.raw_data
recv->data.raw_service_invoke
需自行上传解析脚本,解析指令内容。更多信息,请参见透传/自定义格式的消息。
- 如果您定义的回调函数不对调用服务指令做应答,自行编写应答处理逻辑函数时,请确保应答消息中的以下信息与物联网平台请求中的该参数值一致。
- 同步:
rrpc_id
和msg_id
- 异步:
msg_id
- 同步:
- 向物联网平台返回服务的应答报文时,需注意超时时间:
- 同步:接收同步服务消息后,请在8秒内做出应答。否则,即使设备端已收到消息,也视其失败。
- 异步:您可根据业务需要,自定义异步调用超时的代码逻辑。物联网平台未对此做限制。
-
-
建议的处理逻辑:
- 执行服务指令。
- 向物联网平台返回服务的应答报文。
-
示例代码的处理逻辑:
示例代码仅打印接收的消息,如需演示上报设置的属性,请取消示例代码中
TODO
下代码的注释符号(/*
和*/
),查看效果。- ICA标准数据格式(Alink JSON)
- 同步:
static void demo_dm_recv_sync_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata) { printf("demo_dm_recv_sync_service_invoke msg_id = %ld, rrpc_id = %s, service_id = %s, params = %.*s\r\n", (unsigned long)recv->data.sync_service_invoke.msg_id, recv->data.sync_service_invoke.rrpc_id, recv->data.sync_service_invoke.service_id, recv->data.sync_service_invoke.params_len, recv->data.sync_service_invoke.params); /* TODO: 以下代码演示如何对来自物联网平台的同步调用服务进行应答。 */ { aiot_dm_msg_t msg; memset(&msg, 0, sizeof(aiot_dm_msg_t)); msg.type = AIOT_DMMSG_SYNC_SERVICE_REPLY; msg.data.sync_service_reply.rrpc_id = recv->data.sync_service_invoke.rrpc_id; msg.data.sync_service_reply.msg_id = recv->data.sync_service_invoke.msg_id; msg.data.sync_service_reply.code = 200; msg.data.sync_service_reply.service_id = "SetLightSwitchTimer"; msg.data.sync_service_reply.data = "{}"; int32_t res = aiot_dm_send(dm_handle, &msg); if (res < 0) { printf("aiot_dm_send failed\r\n"); } } }
- 异步:
static void demo_dm_recv_async_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata) { printf("demo_dm_recv_async_service_invoke msg_id = %ld, service_id = %s, params = %.*s\r\n", (unsigned long)recv->data.async_service_invoke.msg_id, recv->data.async_service_invoke.service_id, recv->data.async_service_invoke.params_len, recv->data.async_service_invoke.params); /* TODO: 以下代码演示如何对来自物联网平台的异步调用服务进行应答, 您可取消注释查看演示效果。 */ /* { aiot_dm_msg_t msg; memset(&msg, 0, sizeof(aiot_dm_msg_t)); msg.type = AIOT_DMMSG_ASYNC_SERVICE_REPLY; msg.data.async_service_reply.msg_id = recv->data.async_service_invoke.msg_id; msg.data.async_service_reply.code = 200; msg.data.async_service_reply.service_id = "ToggleLightSwitch"; msg.data.async_service_reply.data = "{\"dataA\": 20}"; int32_t res = aiot_dm_send(dm_handle, &msg); if (res < 0) { printf("aiot_dm_send failed\r\n"); } } */ }
- 同步:
- 透传/自定义格式
- 二进制异步服务调用的处理逻辑,与二进制设置属性的接口一致。具体操作,请参见自定义Topic数据解析。
- 二进制同步服务调用的处理逻辑,示例代码如下:
static void demo_dm_recv_raw_sync_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata) { printf("demo_dm_recv_raw_sync_service_invoke raw sync service rrpc_id = %s, data_len = %d\r\n", recv->data.raw_service_invoke.rrpc_id, recv->data.raw_service_invoke.data_len); /* TODO: 以下代码演示如何对来自物联网平台的同步调用服务进行应答, 您可取消注释查看演示效果 */ /* { aiot_dm_msg_t msg; uint8_t raw_data[] = {0x01, 0x02}; memset(&msg, 0, sizeof(aiot_dm_msg_t)); msg.type = AIOT_DMMSG_RAW_SERVICE_REPLY; msg.data.raw_service_reply.rrpc_id = recv->data.raw_service_invoke.rrpc_id; msg.data.raw_data.data = raw_data; msg.data.raw_data.data_len = sizeof(raw_data); aiot_dm_send(dm_handle, &msg); } */ }
- ICA标准数据格式(Alink JSON)
步骤七:断开连接
MQTT接入常应用于长连接的设备,程序通常不会运行至此。
例程的主线程任务为配置参数并成功建立连接。连接建立后,主线程可进入休眠。
调用aiot_mqtt_disconnect,向物联网平台发送断开连接的报文,然后断开网络连接。
res = aiot_mqtt_disconnect(mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_disconnect failed: -0x%04X\n", -res);
return -1;
}
步骤八:退出程序
调用aiot_dm_deinit,销毁data-model
客户端实例,释放资源。
res = aiot_dm_deinit(&dm_handle);
if (res < STATE_SUCCESS) {
printf("aiot_dm_deinit failed: -0x%04X\n", -res);
return -1;
}