【XR806开发板试用】基于MQTT与Cjson库的花式点灯
-
一、项目介绍
久闻openharmony大名,一直没有机会接触,感谢极术社区和全志社区的这次活动,让我能够了解并上手这个系统。
openhamony 1.1的内核是基于liteos内核系统进行构建的,liteos作为物联网系统,结合xr806小型开发板,特别适合用于构建iot项目,同时openharmony拥有丰富的中间件,使得开发变得容易,因此考虑结合mqtt与cjson这两个iot开发过程中必不可少的两项技术来进行花式点灯。
二、环境准备
mqtt系统搭建
MQTT协议作为一种轻量、简单、开放和易于实现的协议,由服务端与客户端构成,客户端负责发布与订阅消息,服务端则负责完成客户端的管理与设备间的信息交互。本项目中就是通过云服务器来实现pc与开发板间的交互。
1.1、客户端(开发板)
本项目使用所提供的开发包中的mqtt例程进行改写的,该例程调用Eclipse Paho MQTT开发库进行编写,使用MQTTClient-C库,将开发板作为客户端。可以在该目录下找到例程。
harmony\device\xradio\xr806\xr\_skylark\project\example\mqtt
1.2、客户端(PC)
本项目中使用MQTT.fx软件来作为PC的客户端,MQTT.fx是一款也是基于Eclipse Paho库的软件,通过配置后与服务端进行交互。主界面如下图所示,通过添加服务器的地址来与服务器进行交互。
1.3、服务端
本项目中服务端使用阿里云服务器进行mqtt服务端搭建,有云服务器的小伙伴可以参考这篇文章。
https://blog.csdn.net/qq\_45168614/article/details/107183583
没有云服务可以使用阿里云或者腾讯云的提供的物联网服务,也提供了mqtt服务器的功能,并且功能更加强大。
mqtt服务端的界面如下图所示。
三、代码编写
main.c代码如下:
/* * Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include "ohos_init.h" #include "kernel/os/os.h" #include <string.h> #include "wifi_device.h" #include "wifi_hotspot.h" #include "cjson/cJSON.h" #include "common/framework/platform_init.h" #include "net/wlan/wlan.h" #include "common/framework/net_ctrl.h" #include "net/mqtt/MQTTClient-C/MQTTClient.h" #include "iot_gpio.h" //(8) #define MQTT_DEMO_THREAD_STACK_SIZE (8 * 1024) /* ssl need more stack */ static OS_Thread_t mqtt_demo_thread; static OS_Thread_t blink_thread; static MQTTPacket_connectData mqtt_demo_connectData = MQTTPacket_connectData_initializer; static Client mqtt_demo_client; static Network mqtt_demo_network; #define WIFI_DEVICE_CONNECT_AP_SSID "xtg2018" //填写wifi名称 #define WIFI_DEVICE_CONNECT_AP_PSK "xtg2018" //填写wifi密码 #define MQTT_DEMO_CLIENT_ID "IOT control" #define MQTT_DEMO_HOST_NAME "xxx.xxx.xxx.xxx" //填写mqtt服务器地址 #define MQTT_DEMO_PORT "1883" #define MQTT_DEMO_USERNAME "easitmickly" //填写mqtt用户名 #define MQTT_DEMO_PASSWORD "" //填写mqtt密码 #define MQTT_DEMO_TOPIC "/vo84Hm3xbUj/xr806_senor_set0/data" #define MQTT_DEMO_TOPIC2 "/vo84Hm3xbUj/xr806_senor_set1/data" #define GPIO_ID_PA21 21 #define MQTT_DEMO_BUF_SIZE (2*1024) #define MQTT_DEMO_MSG_TEXT "mqtt demo test" static OS_Thread_t g_main_thread; void wifi_scan_connect(){ if(WIFI_SUCCESS != EnableWifi()){ printf("Error:wifi enable fail!\n"); return; } if(WIFI_SUCCESS != Scan()){ printf("Error:wifi scan fail!\n"); } printf("WIFI SCAN STARTED!\n"); OS_Sleep(3); WifiScanInfo scan_result[30]; unsigned int scan_num = 30; if(WIFI_SUCCESS != GetScanInfoList(scan_result, &scan_num)){ printf("Error: get scan result fail!\n"); return; } printf("Scan successful,you've got:\n"); for(int i = 0;i < scan_num;i++){ printf("SSID: %s ",scan_result[i].ssid); printf("RSSI: %d",scan_result[i].rssi); } printf("Scan End \n"); const char ssid_want_connect[] = WIFI_DEVICE_CONNECT_AP_SSID; const char psk[] = WIFI_DEVICE_CONNECT_AP_PSK; printf("Connecting..."); if(WIFI_STA_ACTIVE == IsWifiActive()){ printf("Wifi is active.\n"); } OS_Sleep(1); WifiDeviceConfig config = {0}; int netId = 0; int i; for(i = 0;i < scan_num;i++){ if(0 == strcmp(scan_result[i].ssid, ssid_want_connect)){ memcpy(config.ssid, scan_result[i].ssid, WIFI_MAX_SSID_LEN); memcpy(config.bssid, scan_result[i].bssid, WIFI_MAC_LEN); strcpy(config.preSharedKey, psk); config.securityType = scan_result[i].securityType; config.wapiPskType = WIFI_PSK_TYPE_ASCII; config.freq = scan_result[i].frequency; break; } } if(i >= scan_num){ printf("Error: No SSID SET FOUND!\n"); return; } printf("Found Correct SSID in Scan List!\n"); if(WIFI_SUCCESS != AddDeviceConfig(&config, &netId)){ printf("Error: Add Device config failed!\n"); return; } printf("Add Device Config successful!\n"); if(WIFI_SUCCESS != ConnectTo(netId)){ printf("Error: Connect to Wifi FAILED!\n"); return; } printf("Connect to %s successful!\n",config.ssid); OS_Sleep(3); } static int mqtt_demo_init(void) { char *send_buf; char *recv_buf; /* init client id */ mqtt_demo_connectData.clientID.cstring = MQTT_DEMO_CLIENT_ID; /* init keep alive interval */ mqtt_demo_connectData.keepAliveInterval = 30; // 30s /* enable session reuse */ mqtt_demo_connectData.cleansession = 0; /* set mqtt version */ mqtt_demo_connectData.MQTTVersion = 4; //Version of MQTT 3.1.1 /* send/recv buffer must free when mqtt deinit */ send_buf = malloc(MQTT_DEMO_BUF_SIZE); if (send_buf == NULL) { printf("no memory\n"); return -1; } recv_buf = malloc(MQTT_DEMO_BUF_SIZE); if (recv_buf == NULL) { free(send_buf); printf("no memory\n"); return -1; } /* init network */ NewNetwork(&mqtt_demo_network); /* init mqtt client object */ MQTTClient(&mqtt_demo_client, &mqtt_demo_network, 6000, (unsigned char *)send_buf, MQTT_DEMO_BUF_SIZE, (unsigned char *)recv_buf, MQTT_DEMO_BUF_SIZE); /** * set will function, when this client disconnect, * server will sent the message to every client in MQTT_DEMO_TOPIC */ mqtt_demo_connectData.willFlag = 1; mqtt_demo_connectData.will.topicName.cstring = MQTT_DEMO_TOPIC; mqtt_demo_connectData.will.message.cstring = "I am disconnected"; mqtt_demo_connectData.will.retained = 0; mqtt_demo_connectData.will.qos = 0; /* set username and password */ mqtt_demo_connectData.username.cstring = MQTT_DEMO_USERNAME; mqtt_demo_connectData.password.cstring = MQTT_DEMO_PASSWORD; return 0; } static int mqtt_demo_connect(char *host_name, char *host_port) { int ret = -1; /* need connect the server in tcp level first, if use ssl, use TLSConnectNetwork() */ ret = ConnectNetwork(&mqtt_demo_network, host_name, atoi(host_port)); if (ret != 0) { printf("mqtt connect faild, ret:%d, host:%s, port:%s\n", ret, host_name, host_port); goto exit; } /* if tcp level connected, then connect mqtt level */ ret = MQTTConnect(&mqtt_demo_client, &mqtt_demo_connectData); if (ret != 0) { printf("mqtt connect faild, ret:%d\n", ret); /* disconnect the tcp level */ mqtt_demo_network.disconnect(&mqtt_demo_network); goto exit; } printf("mqtt connected\n"); exit: return ret; } static void mqtt_demo_msg_cb(MessageData *data) { printf("get a message, topic: %.*s, msg: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data, data->message->payloadlen, (char *)data->message->payload); parse_json((char *)data->message->payload); } void Led_blink(void *arg) { int *pinter = (int *)arg; int inter = *pinter; printf("transport inter is %d\n", *pinter); while(1) { IoTGpioSetOutputVal(GPIO_ID_PA21, 0); OS_MSleep(1000 * inter); IoTGpioSetOutputVal(GPIO_ID_PA21, 1); OS_MSleep(1000 * inter); } } int parse_json(char *s) { cJSON *root = cJSON_Parse(s); if(!root) { printf("get root faild !\n"); return -1; } cJSON *js_list = cJSON_GetObjectItem(root, "list"); if(!js_list) { printf("no list!\n"); return -1; } printf("list type is %d\n",js_list->type); cJSON *pin = cJSON_GetObjectItem(js_list, "pin style"); if(!pin) { printf("No pin style!\n"); return -1; } printf("pin style is %s\n",pin->valuestring); cJSON *inter = cJSON_GetObjectItem(js_list, "inter"); if(!inter) { printf("no inter!\n"); return -1; } printf("inter is %d\n",inter->valueint); if(pin) { OS_ThreadDelete(&blink_thread); if (0 == strcmp(pin->valuestring, "open")) { IoTGpioSetOutputVal(GPIO_ID_PA21, 1); } else if(0 == strcmp(pin->valuestring, "close")) { IoTGpioSetOutputVal(GPIO_ID_PA21, 0); } else if(0 == strcmp(pin->valuestring, "blink")) { if(inter) { if(OS_ThreadCreate(&blink_thread, "BlinkThread", Led_blink, &inter->valueint, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) { printf("[ERR] Create BlinkThread Failed\n"); } } } else { printf("unknown pin style\n"); } } if(root) cJSON_Delete(root); return 0; } static int mqtt_demo_subscribe(char *topic) { int ret = -1; if (mqtt_demo_client.isconnected) { /* set the message callback */ ret = MQTTSubscribe(&mqtt_demo_client, topic, 0, mqtt_demo_msg_cb); if (ret != 0) printf("mqtt subscribe faild ret:%d\n", ret); } return ret; } static int mqtt_demo_unsubscribe(char *topic) { int ret = -1; if (mqtt_demo_client.isconnected) { ret = MQTTUnsubscribe(&mqtt_demo_client, topic); if (ret != 0) printf("mqtt unsubscribe faild, ret:%d\n", ret); } return ret; } static int mqtt_demo_publish(char *topic, char *msg) { int ret = -1; MQTTMessage message; memset(&message, 0, sizeof(message)); message.qos = 0; message.retained = 0; /* disable retain the message in server */ message.payload = msg; message.payloadlen = strlen(msg); ret = MQTTPublish(&mqtt_demo_client, topic, &message); if (ret != 0) printf("mqtt publish faild, ret:%d\n", ret); return ret; } static int mqtt_demo_disconnect(void) { int ret = -1; if (mqtt_demo_client.isconnected) { /* need disconnect mqtt level first */ ret = MQTTDisconnect(&mqtt_demo_client); if (ret != 0) printf("mqtt disconnect fail, ret:%d\n", ret); /* then disconnect tcp level */ mqtt_demo_network.disconnect(&mqtt_demo_network); } return ret; } static void mqtt_demo_deinit(void) { if (mqtt_demo_client.buf) { free(mqtt_demo_client.buf); mqtt_demo_client.buf = NULL; } if (mqtt_demo_client.readbuf) { free(mqtt_demo_client.readbuf); mqtt_demo_client.readbuf = NULL; } } static void mqtt_demo_fun(void *arg) { int ret; int reconnect_times = 0; /* mqtt init */ mqtt_demo_init(); /* mqtt connect */ ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT); if (ret != 0) goto exit; /* subscribe topic */ ret = mqtt_demo_subscribe(MQTT_DEMO_TOPIC2); if (ret != 0) goto exit; while (1) { /* publish message to topic */ mqtt_demo_publish(MQTT_DEMO_TOPIC, MQTT_DEMO_MSG_TEXT); ret = MQTTYield(&mqtt_demo_client, 300); if (ret != 0) { printf("mqtt yield err, ret:%d\n", ret); reconnect: printf("mqtt reconnect\n"); mqtt_demo_disconnect(); ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT); if (ret != 0) { reconnect_times++; if (reconnect_times > 5) goto exit; OS_MSleep(5000); //5s goto reconnect; } } OS_MSleep(1000); //1s } exit: mqtt_demo_unsubscribe(MQTT_DEMO_TOPIC2); mqtt_demo_disconnect(); mqtt_demo_deinit(); OS_ThreadDelete(&mqtt_demo_thread); } static void MainThread(void *arg) { wifi_scan_connect(); } int main(void) { IoTGpioInit(GPIO_ID_PA21); IoTGpioSetDir(GPIO_ID_PA21, IOT_GPIO_DIR_OUT); if(OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) { printf("[ERR] Create MainThread Failed\n"); } OS_MSleep(10000); //10s if (OS_ThreadCreate(&mqtt_demo_thread, "mqtt_demo_thread", mqtt_demo_fun, (void *)NULL, OS_THREAD_PRIO_APP, MQTT_DEMO_THREAD_STACK_SIZE) != OS_OK) { printf("[ERR] Create MainThread Failed\n"); } } SYS_RUN(main);
build文件如下:
import("//device/xradio/xr806/liteos_m/config.gni") static_library("app_mqtt") { configs = [] sources = [ "main.c", ] cflags = board_cflags include_dirs = board_include_dirs include_dirs += [ ".", "//kernel/liteos_m/kernel/arch/include", "//base/iot_hardware/peripheral/interfaces/kits", "//utils/native/lite/include", "//foundation/communication/wifi_lite/interfaces/wifiservice", "//device/xradio/xr806/xr_skylark/include/cjson", "//device/xradio/xr806/xr_skylark/project" ] }
main.c代码使用mqtt例程与wifi例程中提供的函数,并调用cjson库。
if(OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) { printf("[ERR] Create MainThread Failed\n"); } OS_MSleep(10000); //10s if (OS_ThreadCreate(&mqtt_demo_thread, "mqtt_demo_thread", mqtt_demo_fun, (void *)NULL, OS_THREAD_PRIO_APP, MQTT_DEMO_THREAD_STACK_SIZE) != OS_OK) { printf("[ERR] Create MainThread Failed\n"); }
main函数中首先对led端口进行初始化,然后初始化wifi,延时10s使得wifi连接网络,最后进行mqtt连接。
int parse_json(char *s) { cJSON *root = cJSON_Parse(s); if(!root) { printf("get root faild !\n"); return -1; } cJSON *js_list = cJSON_GetObjectItem(root, "list"); if(!js_list) { printf("no list!\n"); return -1; } printf("list type is %d\n",js_list->type); cJSON *pin = cJSON_GetObjectItem(js_list, "pin style"); if(!pin) { printf("No pin style!\n"); return -1; } printf("pin style is %s\n",pin->valuestring); cJSON *inter = cJSON_GetObjectItem(js_list, "inter"); if(!inter) { printf("no inter!\n"); return -1; } printf("inter is %d\n",inter->valueint); if(pin) { if (0 == strcmp(pin->valuestring, "open")) { IoTGpioSetOutputVal(GPIO_ID_PA21, 1); } else if(0 == strcmp(pin->valuestring, "close")) { IoTGpioSetOutputVal(GPIO_ID_PA21, 0); } else if(0 == strcmp(pin->valuestring, "blink")) { if(inter) { if(OS_ThreadDelete(&blink_thread)) { printf("[ERR] Create OS_ThreadDelete BlinkThread Failed\n"); } if(OS_ThreadCreate(&blink_thread, "BlinkThread", Led_blink, &inter->valueint, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) { printf("[ERR] Create BlinkThread Failed\n"); } } } else { printf("unknown pin style\n"); } } if(root) cJSON_Delete(root); return 0; }
parse_json函数对接受到的json消息进行解析,消息体中包含两个参数:点灯类型和跳动间隔。消息体如下:
{"list":{"pin style":"blink","inter":3}}
pin style有三个参数:open、close和blink,而inter参数则在blink状态生效。当pin style参数为blink时,将进入Led_blink线程,循环点灯。
#四、效果展示
服务端展示的两个客户端状态如图所示:
pc端收到的开发板消息如下图:
开发板显示消息如下:
==================================================================== Hello! OpenHarmony! System tag : OpenHarmony 1.1.2_LTS ==================================================================== use default flash chip mJedec 0x0 [FD I]: mode: 0x10, freq: 96000000Hz, drv: 0 [FD I]: jedec: 0x0, suspend_support: 1 mode select:e [2022-01-22 13:28:55.546]# RECV ASCII> wlan information =================================================== firmware: version : R0-XR_C07.08.52.65_02.84 May 27 2021 11:41:33-Y02.84 buffer : 8 driver: version : XR_V02.05 mac address: in use : 0c:6d:88:3d:34:01 in use : 0c:6d:88:3d:34:02 ==================================================================== wlan mode:a [VFS INF] SPIFFS mount success. platform information =============================================== XR806 SDK v1.2.0 Jan 19 2022 20:05:38 heap space [0x229344, 0x247c00), size 125116 cpu clock 160000000 Hz HF clock 40000000 Hz sdk option: XIP : enable INT LF OSC : enable SIP flash : enable mac address: efuse : 80:74:84:05:b9:0e in use : 0c:6d:88:3d:34:01 ==================================================================== IoTGpioInit port0, pin21 [net INF] no need to switch wlan mode 0 WIFI SCAN STARTED! [2022-01-22 13:28:56.088]# RECV ASCII> [net INF] msg <wlan scan success> [2022-01-22 13:28:58.579]# RECV ASCII> Scan successful,you've got: SSID: xtgy2018 RSSI: 122SSID: LUCIO_Wi-Fi5 RSSI: 42SSID: ChinaNet-KFVB6L RSSI: 38SSID: TP-LINK_shc RSSI: 34SSID: CMCC-V5xN RSSI: 32SSID: ziroom501 RSSI: 26SSID: ChinaNet-UnjV RSSI: 22SSID: ChinaNet-aDhv RSSI: 6SSID: CMCC-FSU6 RSSI: -2SSID: 201 RSSI: -6SSID: RSSI: -16SSID: CMCC-d5Nj RSSI: -20Scan End Connecting...Wifi is active. [2022-01-22 13:28:59.593]# RECV ASCII> Found Correct SSID in Scan List! Add Device Config successful! [net INF] no need to switch wlan mode 0 [2022-01-22 13:29:00.354]# RECV ASCII> en1: Trying to associate with cc:2d:21:86:4b:01 (SSID='xtg2018' freq=2437 MHz) Connect to xtgy2018 successful! [2022-01-22 13:29:00.512]# RECV ASCII> en1: Associated with cc:2d:21:86:4b:01 en1: WPA: Key negotiation completed with cc:2d:21:86:4b:01 [PTK=CCMP GTK=TKIP] en1: CTRL-EVENT-CONNECTED - Connection to cc:2d:21:86:4b:01 completed [id=0 id_str=] [net INF] msg <wlan connected> [net INF] netif is link up [net INF] start DHCP... [2022-01-22 13:29:01.401]# RECV ASCII> [net INF] netif (IPv4) is up [net INF] address: 192.168.0.128 [net INF] gateway: 192.168.0.1 [net INF] netmask: 255.255.255.0 [net INF] msg <network IPv6 state> [2022-01-22 13:29:02.398]# RECV ASCII> [net INF] IPv6 addr state change: 0x0 --> 0x1 [net INF] msg <> [2022-01-22 13:29:04.396]# RECV ASCII> WAR drop=1117, fctl=0x00d0. [2022-01-22 13:29:05.536]# RECV ASCII> hiview init success. console init success [2022-01-22 13:29:05.631]# RECV ASCII> mqtt connected [2022-01-22 13:29:14.784]# RECV ASCII> get a message, topic: /vo84Hm3xbUj/xr806_senor_set1/data, msg: {"list":{"pin style":"blink","inter":3}} list type is 64 pin style is blink inter is 3 [os E] OS_ThreadDelete():110, handle 0 transport inter is 3
可以从消息中看出已经连接上了wifi与mqtt服务器,并接受到了从pc端发送的消息,视频演示如下:
https://www.bilibili.com/video/BV12q4y1A7zM
可以看出已经达到想要的效果。感谢阅读!感兴趣可以交流,谢谢。~~~~
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号