Zephyr连入阿里云物联网平台--使用

Creative Commons
本作品采用知识共享署名

本文说明如何使用移植在zephyr上使用Link Kit SDK开发物联网应用

移植一文中说明了如何将阿里云的link kit sdk移植到zephyr,这里我们更进一步使用link kit sdk在zephyr开发一个应用,用于发布本地的温度和湿度到阿里云,并订阅阿里云上收到的温度和湿度到本地。

云端

云端主要是增加功能定义,在阿里云物联网平台上点击”产品->功能定义”,在自定义功能中”添加功能”,如下图
add
点击添加功能后会弹出功能框,如下图
addmenu
这里我添加了湿度和温度两个,类型,取值,步长都根据实际device来设置,标识符唯一标示功能的字符串,在device端会用到,如下图
t
h

设备端

设备端使用Zephyr的驱动获取温湿度,再通过阿里云SDK将温湿度送到云端

主程序

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
void main(void)
{
int res = 0;
int loop_cnt = 0;
iotx_mqtt_param_t mqtt_params;

//获取DHT11的device handle,方便之后从DHT11读取温湿度
struct device *dev = device_get_binding("DHT11");
printk("dev %p name %s\n", dev, dev->config->name);

//因为使用的是ethernet连入网络,因此初始化ethernet
struct net_if *iface = net_if_get_default();
ethernet_init(iface);

//读取连入阿里云的鉴权信息
HAL_GetProductKey(DEMO_PRODUCT_KEY);
HAL_GetDeviceName(DEMO_DEVICE_NAME);
HAL_GetDeviceSecret(DEMO_DEVICE_SECRET);

EXAMPLE_TRACE("mqtt example");

//可以根据实际情况设置iotx_mqtt_param_t,这里只设置
memset(&mqtt_params, 0x0, sizeof(mqtt_params));
mqtt_params.handle_event.h_fp = example_event_handle;

// 初始化MQTT
pclient = IOT_MQTT_Construct(&mqtt_params);
if (NULL == pclient) {
EXAMPLE_TRACE("MQTT construct failed");
return -1;
}

//订阅信息
res = example_subscribe(pclient);
if (res < 0) {
IOT_MQTT_Destroy(&pclient);
return -1;
}

//每40s获取一次本地温湿度并发布到云端
while (1) {
if (0 == loop_cnt % 200) {
sensor_sample_fetch(dev); //从dh11读取数据
sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); //读取温度
sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity); //读取湿度
example_publish(pclient); //发布
}

IOT_MQTT_Yield(pclient, 200);

loop_cnt += 1;
}

return 0;
}

发布

注意其payload,已json数据的形式将温度和湿度通过IOT_MQTT_Publish_Simple发送到云端

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
int example_publish(void *handle)
{
int res = 0;

//Topic模板
const char *fmt = "/sys/%s/%s/thing/event/property/post";
char *topic = NULL;
int topic_len = 0;

//Payload模板
char *payload = "{\
\"id\": %d,\
\"params\": {\
\"TargetTemperature\": %d,\
\"Humidity\": %d\
},\
\"method\": \"thing.event.property.post\"}";

topic_len = strlen(fmt) + strlen(DEMO_PRODUCT_KEY) + strlen(DEMO_DEVICE_NAME) + 1;
topic = HAL_Malloc(topic_len);
if (topic == NULL) {
EXAMPLE_TRACE("memory not enough");
return -1;
}
memset(topic, 0, topic_len);
//准备topic数据
HAL_Snprintf(topic, topic_len, fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);


memset(acPayload, 0, 128);
//准备payload数据,温度,湿度
HAL_Snprintf(acPayload, 128, payload, idnumber++, temp.val1, humidity.val1);

EXAMPLE_TRACE("Topic %s\n", topic);
EXAMPLE_TRACE("Payload %s\n", acPayload);

//
res = IOT_MQTT_Publish_Simple(0, topic, IOTX_MQTT_QOS0, acPayload, strlen(acPayload));
if (res < 0) {
EXAMPLE_TRACE("publish failed, res = %d", res);
HAL_Free(topic);
return -1;
}

HAL_Free(topic);
return 0;
}

topic

使用云端已定义好的topic,如图
POST
对照加入topic模板,其中字符串分别对应的是product key和device name

1
2
const char *fmt = "/sys/%s/%s/thing/event/property/post";
HAL_Snprintf(topic, topic_len, fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);

Payload

这里将报温度和湿度已Json格式上报
模板如下:

1
2
3
4
5
6
7
char *payload = "{\
\"id\": %d,\
\"params\": {\
\"TargetTemperature\": %d,\
\"Humidity\": %d\
},\
\"method\": \"thing.event.property.post\"}";

对应的value可根据情况定义,代码中是顺序增加的.
温度和湿度的key从前面提到的在云端的“标识符”来,对应的value就是想要上报的温度和湿度
method将topic的device name的string对应转换而来,thing/event/property/post -> thing.event.property.post 这点必须匹配,否则上报数据会出错
实例:

1
"id": 1,"params": {"TargetTemperature": 29,"Humidity": 29},"method": "thing.event.property.post"}

云端显示的示例在概览一文有贴出,这里贴出一下device端的log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
uart:~$ publish
example_publish|116 :: Topic /sys/a10Bd3A14DDC/4Z3Oeud7Sh5cod49oo2U/thing/event/property/post

example_publish|117 :: Payload {"id": 1,"params": {"TargetTemperature": 29,"Humidity": 29},"method": "thing.event.property.post"}


> {
> "id": 1,
> "params": {
> "TargetTemperature": 29,
> "Humidity": 29
> },
> "method": "thing.event.property.post"
> }

订阅

device订阅也很简单,下面代码示例订阅user/get topic内容,当收到云端发布的信息后,将数据打印出来

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
void example_message_arrive(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
iotx_mqtt_topic_info_t *topic_info = (iotx_mqtt_topic_info_pt) msg->msg;

switch (msg->event_type) {
case IOTX_MQTT_EVENT_PUBLISH_RECEIVED:
/* print topic name and topic message */
EXAMPLE_TRACE("Message Arrived:");
EXAMPLE_TRACE("Topic : %.*s", topic_info->topic_len, topic_info->ptopic);
EXAMPLE_TRACE("Payload: %.*s", topic_info->payload_len, topic_info->payload);
EXAMPLE_TRACE("\n");
break;
default:
break;
}
}

int example_subscribe(void *handle)
{
int res = -1;
const char *fmt = "/%s/%s/user/get";
char *topic = NULL;
int topic_len = 0;

topic_len = strlen(fmt) + strlen(DEMO_PRODUCT_KEY) + strlen(DEMO_DEVICE_NAME) + 1;
topic = HAL_Malloc(topic_len);
if (topic == NULL) {
EXAMPLE_TRACE("memory not enough");
return -1;
}
memset(topic, 0, topic_len);
HAL_Snprintf(topic, topic_len, fmt, DEMO_PRODUCT_KEY, DEMO_DEVICE_NAME);

//订阅信息
res = IOT_MQTT_Subscribe(handle, topic, IOTX_MQTT_QOS0, example_message_arrive, NULL);
if (res < 0) {
EXAMPLE_TRACE("subscribe failed");
HAL_Free(topic);
return -1;
}

HAL_Free(topic);
return 0;
}

topic

使用云端已定义好的topic,如图
get
和上面代码自行对应不再详述

云端发布

点击Topic的发布消息,在弹出的对话框中发布数据,如图
Send
发布成功后device端可以收到数据,log如下

1
2
3
4
5
example_event_handle|132 :: msg->event_type : 12
example_message_arrive|052 :: Message Arrived:
example_message_arrive|053 :: Topic : /a10Bd3AmDDC/4Z0Oeud7Sh4cod49oo2U/user/get
example_message_arrive|054 :: Payload: Hello half coder!!
example_message_arrive|055 ::

其它

测试过程中有zephyr网络用一会就不通的情况,原因是NET_PKG和BUF给小了,增大即可

1
2
3
4
CONFIG_NET_PKT_RX_COUNT=34
CONFIG_NET_PKT_TX_COUNT=34
CONFIG_NET_BUF_RX_COUNT=34
CONFIG_NET_BUF_TX_COUNT=34

后记

终于将zephyr接入阿里云收尾,主要是将云端和device串起来并了解zephyr上使用阿里云物联网SDK, 更深入的内容是MQTT/阿里云物联网SDK的使用相关,就不再深入研究了。

参考

https://code.aliyun.com/edward.yangx/public-docs/wikis/user-guide/linkkit/Quick_Start#%E4%BB%A5MQTT%20Topic%E7%BC%96%E7%A8%8B%E6%96%B9%E5%BC%8F%E6%8E%A5%E5%85%A5%E8%AE%BE%E5%A4%87