# 设备端数据上报

# 物模型数据上报

  • 修改 thing_model_demo.c 的三元组信息为设备对应的三元组信息
char *product_key = "KS78JR0J";
char *device_name = "testdemo";
char *secret = "5b28b44337b53ef5261d6335af5c8075";
1
2
3
  • 修改 host 和 port
char *host = "8.136.220.253";
int port = 1883;
1
2
  • 设置重连间隔和重连次数
int reconnect_interval = 10;
int reconnect_time = 3;
1
2
  • 根据已定义好的物模型所对应 TSL 修改 model_id
char *model_id = "test_model_id";
1
  • 根据获取的物模型的 TSL 更改下列参数。

    属性参数修改,根据 web 端生成的物模型描述,如下是属性相关参数,以及相关设置。

"properties": [
    {
      "identifier": "property_a1",
      "is_required": false,
      "data_type": {
        "type": "int"
      }
    },
    {
      "identifier": "property_a2",
      "is_required": false,
      "data_type": {
        "type": "double"
      }
    },
    {
      "identifier": "property_a3",
      "is_required": false,
      "data_type": {
        "type": "text"
      }
    },
    {
      "identifier": "property_b",
      "is_required": false,
      "data_type": {
        "type": "struct",
        "specs": [
          {
            "identifier": "aaaa",
            "data_type": {
              "type": "int"
            }
          },
          {
            "identifier": "bbbb",
            "data_type": {
              "type": "int"
            }
          },
          {
            "identifier": "cccc",
            "data_type": {
              "type": "double"
            }
          }
        ]
      }
    },
    {
      "identifier": "property_c",
      "is_required": false,
      "data_type": {
        "type": "array",
        "specs": {
          "size": 10,
          "item": {
            "type": "int"
          }
        }
      }
    },
    {
      "identifier": "property_d",
      "is_required": false,
      "data_type": {
        "type": "array",
        "specs": {
          "size": 10,
          "item": {
            "type": "double"
          }
        }
      }
    },
    {
      "identifier": "property_e",
      "is_required": false,
      "data_type": {
        "type": "array",
        "specs": {
          "size": 10,
          "item": {
            "type": "text"
          }
        }
      }
    },
    {
      "identifier": "property_f",
      "is_required": false,
      "data_type": {
        "type": "array",
        "specs": {
          "size": 10,
          "item": {
            "type": "struct",
            "specs": [
              {
                "identifier": "asdf",
                "data_type": {
                  "type": "int"
                }
              },
              {
                "identifier": "hjkl",
                "data_type": {
                  "type": "int"
                }
              }
            ]
          }
        }
      }
    }
  ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 原生类型参数设置
int    val_i1     = 0;
int    val_i2     = 0;
char   val_s3[16] = "text";
double val_d4     = 23.7;
double val_d5     = 23.7;
char   val_s6[16] = "1629344092";

// 结构体类型参数设置
emqc_tm_object val_struct[] = {
    { .type = EMQC_TM_INT, "aaaa", .val_i = 0 },
    { .type = EMQC_TM_INT, "bbbb", .val_i = 0 },
    { .type = EMQC_TM_DOUBLE, "cccc", .val_d = 0.0 },
    { .type = EMQC_TM_TERMINATOR, "", .val_o = NULL }
};

// 数组类型参数设置
int *val_arr_int[] = {&val_i1, &val_i2, NULL};
double *val_arr_dou[] = {&val_d4, &val_d5, NULL};
char *val_arr_str[] = {val_s3, val_s6, NULL};

// 结构体数组类型设置
emqc_tm_object val_struct1[] = {
    { EMQC_TM_INT, "asdf", .val_i = 0 },
    { EMQC_TM_INT, "hjkl", .val_i = 0 },
    // 这里是作为结束符必须的
    { EMQC_TM_TERMINATOR, "", .val_o = NULL } 
};

emqc_tm_object val_struct2[] = {
    { EMQC_TM_INT, "asdf", .val_i = 0 },
    { EMQC_TM_INT, "hjkl", .val_i = 0 },
    // 这里是作为结束符必须的
    { EMQC_TM_TERMINATOR, "", .val_o = NULL } 
};

emqc_tm_object *val_arr_struct[] = {
    val_struct1,
    val_struct2,
    NULL // 这里是作为结束符必须的
};

// 最终要上报的数据全部配置到这里
emqc_tm_object property_array[] = {
    { .type = EMQC_TM_INT,  .key = "property_a1", .val_i = 10 },
    { .type = EMQC_TM_DOUBLE,  .key = "property_a2", .val_d = 10.10 },
    { .type = EMQC_TM_STR,  .key = "property_a3", .val_s = val_s6 },
    { .type = EMQC_TM_STRUCT,  .key = "property_b", .val_o = &val_struct },
    { .type = EMQC_TM_ARR_INT,  .key = "property_c", .val_o = &val_arr_int },
    { .type = EMQC_TM_ARR_DOUBLE,  .key = "property_d", .val_o = &val_arr_dou },
    { .type = EMQC_TM_ARR_STR,  .key = "property_e", .val_o = &val_arr_str },
    { .type = EMQC_TM_ARR_STRUCT,  .key = "property_f", .val_o = &val_arr_struct },
    // 这里是作为结束符必须的
    { .type = EMQC_TM_TERMINATOR, .key = "", .val_o = NULL },
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

​ 属性上报函数,响应函数以及属性设置回调。

// 属性上报
void property_post(emqc_tm *tm)
{
    char sfx[] = "property/post";
    char mtd[] = "thing.property.post";
    char topic[EMQC_TM_TOPIC_LEN];

    json_object *jso = emqc_tm_new_payload(mtd, NULL);
    int          i   = 0;
    do {
        if (property_array[i].type == EMQC_TM_TERMINATOR) {
            break;
        }
        emqc_tm_add_post_param(jso, &property_array[i], model_id);
    } while (++i);

    snprintf(topic, EMQC_TM_TOPIC_LEN, TM_FMT, product_key, device_name, sfx);
    log_info("#PUB: %s", topic);
    log_info("#PAYLOAD: %s", json_object_to_json_string(jso));
    emqc_tm_pub(tm, topic, json_object_to_json_string(jso));
    json_object_put(jso);
    return;
}

// 属性响应回调
void *property_post_reply_cb(void *payload)
{
    emqc_tm_trans_object *obj = (emqc_tm_trans_object*) payload;
    if (obj) {
        switch (obj->type) {
            // 符合物模型协议的数据,从这里获取
            case TM_REP:;
                tm_reply *tr = obj->rep;
                log_info("#RECV: id: %s, code: %d, data: %s", tr->id, tr->code, tr->data);
                break;
            // 自定义数据,从这里获取
            case TM_RAW:
                log_info("#RECV: raw_data: %s", obj->raw);
                break;
            default:
                log_err("Error trans type.");
        }
    }
    return NULL;
}

// 属性设置回调
void *property_set_cb(void *payload)
{
    emqc_tm_trans_object *obj = (emqc_tm_trans_object*) payload;
    char *ret = NULL;
    if (obj) {
        switch (obj->type) {
            case TM_REQ:;// 符合物模型协议的数据,从这里获取
                tm_request *tr = obj->req;
                log_info("#RECV: id: %s, version: %s, method: %s, params: %s", tr->id,
                         tr->version, tr->method, tr->params);
                // 设置操作
                json_object *jso_tmp = json_tokener_parse(tr->params);
                emqc_tm_property_set(jso_tmp, property_array, model_id);

                json_object *jso      = json_object_new_object();
                json_object *jso_data = json_object_new_object();
                json_object_object_add(jso, "id", json_object_new_string(tr->id));
                json_object_object_add(jso, "code", json_object_new_int(0));
                json_object_object_add(jso, "data", jso_data);
                ret = zstrdup(json_object_to_json_string(jso));
                json_object_put(jso);
                break;
            case TM_RAW:// 自定义数据,从这里获取
                log_info("#RECV: raw_data: %s", obj->raw);
                break;
            default:
                log_err("Error trans type.");
        }
    }

    return (void *) ret;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

​ 事件参数修改,根据 web 端生成的物模型描述,如下是事件相关参数,以及相关设置。

 "events": [
    {
      "identifier": "events",
      "is_required": false,
      "event_type": "EVENT_TYPE_INFO",
      "output_data": [
        {
          "identifier": "param01",
          "data_type": {
            "type": "array",
            "specs": {
              "size": 10,
              "item": {
                "type": "text"
              }
            }
          }
        }
      ]
    }
  ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
char val_param01_s1[] = "param011";
char val_param01_s2[] = "param012";
char val_param01_s3[] = "param013";
char val_param01_s4[] = "param014";
char val_param01_s5[] = "param015";
char val_param01_s6[] = "param016";
char val_param01_s7[] = "param017";
char val_param01_s8[] = "param018";
char val_param01_s9[] = "param019";

char *param01[] = {
	val_param01_s1,
	val_param01_s2,
	val_param01_s3,
	val_param01_s4,
	val_param01_s5,
	val_param01_s6,
	val_param01_s7,
	val_param01_s8,
	val_param01_s9,
	NULL
 };

char *event_idents[] = {
	"events", // 如果有多个 identifer 顺序添加,最后一个元素一定是 NULL。
	NULL,
};
emqc_tm_object event_array[] = {
	{ .type = EMQC_TM_ARR_STR, .key = "param01", .val_o = &param01 },
	{ .type = EMQC_TM_TERMINATOR, .key = "", .val_o = NULL },
 };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

​ 服务参数修改,根据 web 端生成的物模型描述,如下是服务相关参数,以及相关设置。

 "actions": [
    {
      "identifier": "service01",
      "is_required": false,
      "input_data_param": [
        {
          "identifier": "input_param",
          "data_type": {
            "type": "int"
          }
        }
      ],
      "output_data_param": [
        {
          "identifier": "output_param",
          "data_type": {
            "type": "int"
          }
        }
      ]
    }
  ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char *service_idents[] = {
	"service01",
	NULL,
};
emqc_tm_object service_array[] = {
	{ .type = EMQC_TM_INT, .key = "output_param", .val_i = 0 },
	{ .type = EMQC_TM_TERMINATOR, .key = "", .val_o = NULL },
 };

1
2
3
4
5
6
7
8
9
  • 根据需求定义自己的服务,将自己的服务放到service_cb中,并处理服务服务的错误响应,以下仅为事例。
void *service_cb(void *payload)
{
    emqc_tm_trans_object *obj = (emqc_tm_trans_object*) payload;
    char *       ret     = NULL;
    if (obj) {
        switch (obj->type) {
            // 符合物模型协议的数据,从这里获取
            case TM_REQ:;
                tm_request *tr = obj->req;
                log_info("#RECV: id: %s, version: %s, method: %s, params: %s", tr->id,
                         tr->version, tr->method, tr->params);
                json_object *jso_tmp = json_tokener_parse(tr->params);
                json_object *jso_val = NULL;
                int          val     = 0;

                int i = 0;
                int j = 0;
                while (service_idents[i] != NULL) {
                    if (!strstr(tr->method, service_idents[i])) {
                        do {
                            if (service_array[j].type == EMQC_TM_TERMINATOR) {
                                break;
                            }

                        } while (++j);

                    } else {
                        json_object *jso      = json_object_new_object();
                        json_object *jso_data = json_object_new_object();
                        do {
                            if (service_array[j].type == EMQC_TM_TERMINATOR) {
                                break;
                            }

                            // 这里可以加具体的操作。
                            // 根据输入计算输出。
                            emqc_tm_add_service_param(jso_data, service_array[j].key,
                                                      &service_array[j]);
                        } while (++j);

                        json_object_object_add(jso, "id", json_object_new_string(tr->id));
                        json_object_object_add(jso, "code", json_object_new_int(0));
                        json_object_object_add(jso, "data", jso_data);
                        ret = zstrdup(json_object_to_json_string(jso));
                        json_object_put(jso);
                        break;
                    }
                    i++;
                    j++;
                }
                break;
            // 自定义数据,从这里获取
            case TM_RAW:
                log_info("#RECV: raw_data: %s", obj->raw);
                break;
            default:
                log_err("Error trans type.");
        }
    }
    return (void *) ret;
}Z
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  • 设备属性获取并设置相应的回调。
// 获取期望属性函数,可在设备启动时,或重连是调用
void get_desire(emqc_tm *tm) {
  // 修改希望获取属性的 key
    const char *keys[] = {"key_xxx", "key_xxx", "key_xxx"};
    char        sfx[]  = "property/desired/get";
    char        topic[EMQC_TM_TOPIC_LEN];

    snprintf(topic, EMQC_TM_TOPIC_LEN, TM_FMT, product_key, device_name, sfx);
    log_info("#PUB: %s", topic);
    json_object *jso = emqc_tm_new_payload("thing.property.desired.get", NULL);
  // 修改 key 的个数
    emqc_tm_add_get_desired_param(jso, (const char **) keys, 3, model_id);
    emqc_tm_pub(tm, topic, json_object_to_json_string(jso));
    json_object_put(jso);
    return;
}

// 回调函数
void *desire_get_reply_cb(void *payload)
{
    emqc_tm_trans_object *obj = (emqc_tm_trans_object*) payload;
    if (obj) {
        switch (obj->type) {
            // 符合物模型协议的数据,从这里获取
            case TM_REP:;
                tm_reply *tr = obj->rep;
                log_info("#RECV: id: %s, code: %d, data: %s", tr->id, tr->code, tr->data);
                break;
            // 自定义数据,从这里获取
            case TM_RAW:
                log_info("#RECV: raw_data: %s", obj->raw);
                break;
            default:
                log_err("Error trans type.");
        }
    }
    return NULL;
}

// 设置回调函数
emqc_tm_set_dft_cb(tm, TM_CB_DESIRED_GET_REPLY, desire_get_reply_cb);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  • 清除设备属性并设置响应的回调。
// 清除期望属性
void clear_desire(emqc_tm *tm) {
    char          topic[EMQC_TM_TOPIC_LEN];
    char          sfx[] = "property/desired/delete";
    del_des_param ddp[] = {{"WF", NULL}, {"Power", "1"}};

    snprintf(topic, EMQC_TM_TOPIC_LEN, TM_FMT, product_key, device_name, sfx);
    log_info("#PUB: %s", topic);
    json_object *jso = emqc_tm_new_payload("thing.property.desired.delete", NULL);
    emqc_tm_add_del_desired_param(jso, ddp, 2, NULL);
    emqc_tm_pub(tm, topic, json_object_to_json_string(jso));
    json_object_put(jso);
    return;
}

// 回调函数
void *desire_delete_reply_cb(void *payload)
{
    emqc_tm_trans_object *obj = (emqc_tm_trans_object*) payload;
    if (obj) {
        switch (obj->type) {
            case TM_REP:;
                tm_reply *tr = obj->rep;
                log_info("#RECV: id: %s, code: %d, data: %s", tr->id, tr->code, tr->data);
                break;
            case TM_RAW:
                log_info("#RECV: raw_data: %s", obj->raw);
                break;
            default:
                log_err("Error trans type.");
        }
    }
    return NULL;
}

// 设置回调函数
emqc_tm_set_dft_cb(tm, TM_CB_DESIRED_DEL_REPLY, desire_delete_reply_cb);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  • 到此,我们的物模型就修改完毕,重新编译,既可以上报数据了。

# 设备影子数据上报

  • 同物模型相同首先要修改三元组信息以及 host 地址和端口号

  • 通过 sdk 提供的一些设置函数,设置三元组,以及对应的回调函数

emqc_ds *ds = emqc_ds_new();

emqc_set_secret(ds->handle, secret);
emqc_set_product_key(ds->handle, product_key);
emqc_set_device_name(ds->handle, device_name);
// 设置回调处理函数
emqc_ds_set_get_callback(ds, get_payload_call);
emqc_ds_set_generic_callback(ds, generic_payload_call);
emqc_ds_set_control_callback(ds, control_payload_call);
// 设置回调函数
emqc_ds_set_reconnect(ds, interval, times);

// 初始化已设置的参数
emqc_ds_init(ds, host, port);
rc = emqc_ds_connect(ds, 60, 1);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 设置请求的 body
serv_req *re_update = new_request();
emqc_ds_state st = DESIRED;
char *key = "test"
char *t2[] = {"11","22","33","44","55"};
add_param_arr(re_update, key, t2, STR, 5, st); 
1
2
3
4
5

可以通过 add_param 系列函数添加不同类型的数据,如下:

int add_param_null(serv_req *request, const char *key, emqc_ds_state s);
int add_param_int(serv_req *request, const char *key, int val, emqc_ds_state s);
int add_param_str(serv_req *request, const char *key, const char *val, emqc_ds_state s);
int add_param_arr(serv_req *request, const char *key, void *val, TAG type, int len, emqc_ds_state s);
1
2
3
4
  • 请求数据构建好以后,我们可以调用对应的方法向服务器发送请求:
emqc_ds_asyn_update(ds, re_update);
1

请求函数包括以下几种;

EMQC_ERR_CODE emqc_ds_asyn_get(emqc_ds *handle);
EMQC_ERR_CODE emqc_ds_asyn_update(emqc_ds *handle, serv_req *resquest);
EMQC_ERR_CODE emqc_ds_asyn_delete(emqc_ds *handle, serv_req *request);
1
2
3
  • 最后,我们释放资源
emqc_disconnect(ds->handle);
emqc_ds_destroy(ds);
1
2