HarmonyOS小熊派 | HarmonyOS WiFi编程开发--MQTT协议开发
BearPi-HM_Nano开发板WiFi编程开发——MQTT协议开发
本示例将演示如何在BearPi-HM_Nano开发板上使用MQTT协议
编译调试
下载MQTT消息代理工具Mosquitto
点击下载Mosquitto 工具
下载后双击安装包,安装工具,安装完毕后,打开电脑设备管理器,在“服务”中开启mosquitto服务。
修改安装路径下的mosquitto.conf文件 修改515行附近代码
修改216行附近代码,其中192.168.0.173
为自己的电脑的IP地址
下载Eclipse Paho MQTT 工具
点击下载Eclipse Paho MQTT 工具
解压缩后,双击paho.exe,打开后的Eclipse Paho UI开始界面,点击上图中的 十字图标,就能新建一个MQTT的客户端的连接,如下图所示
输入正确的MQTT服务端的连接地址,比如,本例中的连接地址是tcp://localhost:1883,然后点击“连接”按钮,这个时候,如果MQTT服务端没有设置密码(默认情况是没有密码的)的话,这个时候,我们就能看到连接得到状态是“已连接”,如下图所示:
这个时候我们就能订阅消息了。选择“订阅”下方的绿色十字图标,就可以输入订阅的主题(topic)的名字,比如我们设置主题名称为
“pubtopic”,并点击 “订阅”按钮,如下图所示
修改对接IP
将代码中对接的IP修改为电脑在命令行窗口里输入 ipconfig
查询的电脑的本地IP
项目结构目录:
yuchuan@yuchuan:~/MasterData/SharedData/MasterHarmonyOSCode/HarmonyOSCode/applications/sample/BearPi/BearPi-HM_Nano/sample/D5_YuchuanIoTMQTT$ tree
.
├── BUILD.gn
├── include
│ └── wifi_connect.h
├── src
│ └── wifi_connect.c
└── yuchuanIoTMQTT.c
2 directories, 4 files
yuchuan@yuchuan:~/MasterData/SharedData/MasterHarmonyOSCode/HarmonyOSCode/applications/sample/BearPi/BearPi-HM_Nano/sample/D5_YuchuanIoTMQTT$
yuchuanIoTMQTT.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_connect.h"
#include "MQTTClient.h"
#define WIFI_ACCOUNT "886699"
#define WIFI_PASSWD "te11from"
#define _PORT_ 8888
Network network;
static unsigned char sendBuff[1000];
static unsigned char readBuff[1000];
/* 订阅消息的回调函数 */
void messageHandlerCallback(MessageData *data)
{
printf("Message MQTT substopic %.*s : %.*s\r\n", data->topicName->lenstring.len, data->topicName->lenstring.data, data->message->payloadlen, data->message->payload);
}
/* YuchuanIoTMQTT 任务函数入口 */
static void yuchuanIoTMQTTTask(void)
{
MQTTClient client;
int rc, count = 0;
// 连接WIFI
wifiConnect(WIFI_ACCOUNT, WIFI_PASSWD);
printf("Starting IoT MQTT...\r\n");
NetworkInit(&network);
printf("NetworkConnet ......\r\n");
begin:
NetworkConnect(&network, "10.81.234.13", _PORT_);
printf("MQTT Client Init...\r\n");
// DLLExport void MQTTClientInit(MQTTClient* client, Network* network, unsigned int command_timeout_ms, unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size);
MQTTClientInit(&client, &network, 2000, sendBuff, sizeof(sendBuff), readBuff, sizeof(readBuff));
MQTTString clientId = MQTTString_initializer;
clientId.cstring = "YuchuanHuayingMQTT";
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.clientID = clientId;
data.willFlag = 0;
data.MQTTVersion = 3;
data.keepAliveInterval = 0;
data.cleansession = 1;
printf("MQTT Connect......\r\n");
// DLLExport int MQTTConnect(MQTTClient* client, MQTTPacket_connectData* options);
rc = MQTTConnect(&client, &data);
if (rc != 0)
{
printf("MQTT Connect : %d.\r\n", rc);
NetworkDisconnect(&network);
// DLLExport int MQTTDisconnect(MQTTClient* client);
MQTTDisconnect(&client);
osDelay(200);
goto begin;
}
printf("MQTTSubscribe:...\r\n");
// DLLExport int MQTTSubscribe(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler);
rc = MQTTSubscribe(&client, "substopic", 2, messageHandlerCallback);
if (rc != 0)
{
printf("MQTT Subscribe : %d.\r\n", rc);
osDelay(200);
goto begin;
}
while (++count)
{
MQTTMessage message;
char payload[30];
message.qos = 2;
message.retained = 0;
message.payload = payload;
sprintf(payload, "message number %d.", count);
message.payloadlen = strlen(payload);
// DLLExport int MQTTPublish(MQTTClient* client, const char*, MQTTMessage*);
if ((rc = MQTTPublish(&client, "pubtopic", &message)) != 0)
{
printf("Return Code From MQTT Publish is %d.\r\n", rc);
NetworkDisconnect(&network);
// DLLExport int MQTTDisconnect(MQTTClient* client);
MQTTDisconnect(&client);
goto begin;
}
osDelay(50);
}
}
/* MQTT 入口函数 */
static void yuchuanIoTMQTTEntry(void)
{
osThreadAttr_t threadAttr;
threadAttr.attr_bits = 0U;
threadAttr.cb_mem = NULL;
threadAttr.cb_size = 0U;
threadAttr.stack_mem = NULL;
threadAttr.stack_size = 10240;
threadAttr.priority = osPriorityNormal;
threadAttr.name = "YuchuanIoTMQTTTask";
if (osThreadNew((osThreadFunc_t)yuchuanIoTMQTTTask, NULL, &threadAttr) == NULL)
{
printf("Falied To Create YuchuanIoTMQTTTask.\r\n");
}
}
APP_FEATURE_INIT(yuchuanIoTMQTTEntry);
src/wifi_connect.c
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "wifi_error_code.h"
#include "lwip/api_shell.h"
#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#define DEF_TIMEOUT 15
#define ONE_SECOND 1
#define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK
#define SELECT_WLAN_PORT "wlan0"
WifiErrorCode errorCode;
WifiEvent wifiEventHandler = {0};
static int ssid_count = 0;
static int staScanSuccess = 0;
static int staConnectSuccess = 0;
/* WiFi 站点改变扫描的回调函数 */
static void OnWifiScanStateChangedCallBack(int state, int size)
{
if (size > 0)
{
ssid_count = size;
staScanSuccess = 1;
}
printf("WiFi CallBack Function Is Success Scan:%d ,%d.\r\n", state, size);
return;
}
/* WiFi 连接改变的回调函数 */
static void OnWifiConnectionChangedCallBack(int state, WifiLinkedInfo *info)
{
if (info == NULL)
{
printf("OnWifiConnectionChangedCallBack: info is null state is %d.\r\n", state);
}
else
{
if (state == WIFI_STATE_AVALIABLE)
{
staConnectSuccess = 1;
}
else
{
staConnectSuccess = 0;
}
}
}
/* WiFi 加入站点的回调函数 */
static void OnHotspotStaJoinCallBack(StationInfo *info)
{
(void)info;
printf("OnHotspotStaJoinCallBack: Sta Join AP.\r\n");
return;
}
/* WiFi 离开站点的回调函数 */
static void OnHotspotStaLeaveCallBack(StationInfo *info)
{
(void)info;
printf("OnHotspotStaLeaveCallBack: info is null.\r\n");
return;
}
/* WiFi 状态改变的回调函数 */
static void OnHotspotStateChangedCallBack(int state)
{
printf("OnHotspotStateChangedCallBack: state is %d.\r\n", state);
return;
}
/* 初始化WIFI */
static void wifiInit(void)
{
printf(">>>WiFi Init Start ......\r\n");
/** Scan state change */
// void (*OnWifiScanStateChanged)(int state, int size);
wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedCallBack;
/** Connection state change */
// void (*OnWifiConnectionChanged)(int state, WifiLinkedInfo* info);
wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedCallBack;
/** Station connected */
// void (*OnHotspotStaJoin)(StationInfo* info);
wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinCallBack;
/** Station disconnected */
// void (*OnHotspotStaLeave)(StationInfo* info);
wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveCallBack;
/** Hotspot state change */
// void (*OnHotspotStateChanged)(int state);
wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedCallBack;
// 注册 WiFi 事件
/**
* @brief Registers a callback for a specified Wi-Fi event.
*
* The registered callback will be invoked when the Wi-Fi event defined in {@link WifiEvent} occurs. \n
*
* @param event Indicates the event for which the callback is to be registered.
* @return Returns {@link WIFI_SUCCESS} if the callback is registered successfully; returns an error code defined
* in {@link WifiErrorCode} otherwise.
* @since 1.0
* @version 1.0
*/
// WifiErrorCode RegisterWifiEvent(WifiEvent* event);
errorCode = RegisterWifiEvent(&wifiEventHandler);
if (errorCode == WIFI_SUCCESS)
{
printf("Register WiFi Event Successed!!!\r\n");
}
else
{
printf("Register WiFi Event Falied And ErrorCode is %d.\r\n", errorCode);
}
}
/* 等待扫描结果的函数 */
static void waitScanResult(void)
{
int scanTimeOut = DEF_TIMEOUT;
while (scanTimeOut > 0)
{
sleep(ONE_SECOND);
scanTimeOut--;
if (staScanSuccess == 1)
{
printf("waitScanResult: WiFi Scan Result Is Success[%d]s.\r\n", (DEF_TIMEOUT - scanTimeOut));
break;
}
}
if (scanTimeOut <= 0)
{
printf("waitScanResult: WiFi Scan Result TimeOut.\r\n");
}
}
/* 等待连接结果的函数 */
static int waitConnectResult(void)
{
int connectTimeOut = DEF_TIMEOUT;
while (connectTimeOut > 0)
{
sleep(ONE_SECOND);
connectTimeOut--;
if (staConnectSuccess == 1)
{
printf("waitConnectResult: WiFi Connect Result Is Success[%d]s.\r\n", (DEF_TIMEOUT - connectTimeOut));
break;
}
}
if (connectTimeOut <= 0)
{
printf("waitConnectResult: WiFi Connect TimeOut.\r\n");
return 0;
}
return 1;
}
/* 连接 WIFI 的API接口 */
int wifiConnect(const char *ssid, const char *psk)
{
WifiScanInfo *info = NULL;
unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
static struct netif *lwipNetIf = NULL;
// 延迟2s连接
osDelay(200);
printf(">>>System Init WiFi ......\r\n");
// 初始化WIFI
wifiInit();
// 使能WiFi
/**
* @brief Enables the station mode.
*
* @return Returns {@link WIFI_SUCCESS} if the station mode is enabled; returns an error code defined in
* {@link WifiErrorCode} otherwise.
* @since 1.0
* @version 1.0
*/
// WifiErrorCode EnableWifi(void);
if (EnableWifi() != WIFI_SUCCESS)
{
printf("Enable WiFi Falied, Error Code Is %d.\r\n", errorCode);
return -1;
}
// 判断WiFi 是否激活
/**
* @brief Checks whether the station mode is enabled.
*
* @return Returns {@link WIFI_STA_ACTIVE} if the station mode is enabled; returns {@link WIFI_STA_NOT_ACTIVE}
* otherwise.
* @since 1.0
* @version 1.0
*/
// int IsWifiActive(void);
if (IsWifiActive() != WIFI_STA_ACTIVE)
{
printf("WiFi Station Is No Active.\r\n");
return -1;
}
// 分配内存空间,保存WiFi信息
info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
if (info == NULL)
{
return -1;
}
// 轮询查找WiFi列表
do
{
// 重置标志
ssid_count = 0;
staScanSuccess = 0;
// 开始扫描
/**
* @brief Starts a Wi-Fi scan.
*
* @return Returns {@link WIFI_SUCCESS} if the Wi-Fi scan is started; returns an error code defined in
* {@link WifiErrorCode} otherwise.
* @since 1.0
* @version 1.0
*/
// WifiErrorCode Scan(void);
Scan();
// 等待扫描结果
waitScanResult();
// 获取扫描结果列表
/**
* @brief Obtains an array of hotspots detected in a Wi-Fi scan.
*
* The array of hotspots can be obtained only after the Wi-Fi scan is complete. \n
*
* @param result Indicates the array of hotspots detected in a Wi-Fi scan. The array is requested and released by the
* caller. The value must be greater than or equal to {@link WIFI_SCAN_HOTSPOT_LIMIT}.
* @param size Indicates the size of the array.
* @return Returns {@link WIFI_SUCCESS} if the array of hotspots detected in the Wi-Fi scan is obtained; returns an
* error code defined in {@link WifiErrorCode} otherwise.
* @since 1.0
* @version 1.0
*/
// WifiErrorCode GetScanInfoList(WifiScanInfo* result, unsigned int* size);
errorCode = GetScanInfoList(info, &size);
} while (staScanSuccess != 1);
// 打印WiFi信息列表
printf("**********YuchuanHuaying WiFi Info List Start**********\r\n");
for (uint8_t i = 0; i < ssid_count; i++)
{
printf("no:%03d, ssid:%-30s, rssi:%5d\r\n", i + 1, info[i].ssid, info[i].rssi / 100);
}
printf("******************YuchuanHuaying End*******************\r\n");
// 连接指定的WiFi热点
for (uint8_t i = 0; i < ssid_count; i++)
{
if (strcmp(ssid, info[i].ssid) == 0)
{
int result;
printf("Select:%3d wireless, Waiting...\r\n", i + 1);
// 拷贝要连接的热点信息
WifiDeviceConfig selectWiFiAPConfig = {0};
strcpy(selectWiFiAPConfig.ssid, info[i].ssid);
strcpy(selectWiFiAPConfig.preSharedKey, psk);
selectWiFiAPConfig.securityType = SELECT_WIFI_SECURITYTYPE;
/**
* @brief Adds a specified hotspot configuration for connecting to a hotspot.
*
* This function generates a <b>networkId</b>. \n
*
* @param config Indicates the hotspot configuration to add.
* @param result Indicates the generated <b>networkId</b>. Each <b>networkId</b> matches a hotspot configuration.
* @return Returns {@link WIFI_SUCCESS} if the specified hotspot configuration is added; returns an error code defined
* in {@link WifiErrorCode} otherwise.
* @since 1.0
* @version 1.0
*/
// WifiErrorCode AddDeviceConfig(const WifiDeviceConfig* config, int* result);
if (AddDeviceConfig(&selectWiFiAPConfig, &result) == WIFI_SUCCESS)
{
/**
* @brief Connects to a hotspot matching a specified <b>networkId</b>.
*
* Before calling this function, call {@link AddDeviceConfig} to add a hotspot configuration. \n
*
* @param networkId Indicates the <b>networkId</b> matching the target hotspot.
* @return Returns {@link WIFI_SUCCESS} if the hotspot is connected; returns an error code defined in
* {@link WifiErrorCode} otherwise.
* @since 1.0
* @version 1.0
*/
// WifiErrorCode ConnectTo(int networkId);
if (ConnectTo(result) == WIFI_SUCCESS && waitConnectResult() == 1)
{
printf("WiFi Connect Successed.\r\n");
/**
* @ingroup Threadsafe_Network_Interfaces
* @brief
* This thread-safe interface is called when to find interface
*/
// struct netif *netifapi_netif_find(const char *name);
lwipNetIf = netifapi_netif_find(SELECT_WLAN_PORT);
break;
}
}
}
if (i == ssid_count - 1)
{
printf("Error: No WiFi as expected.\r\n");
while (1)
osDelay(100);
}
}
// 启动DHCP
if (lwipNetIf)
{
dhcp_start(lwipNetIf);
printf("Begain To DHCP.\r\n");
}
// 等待DHCP
for (;;)
{
if (dhcp_is_bound(lwipNetIf) == ERR_OK)
{
printf("<--YuchuanHuaying DHCP state:OK -->\r\n");
// 打印获取到的IP信息
/**
* @ingroup Threadsafe_Network_Interfaces
* @brief
* This API is used to call all netif related APIs in a thread safe manner. The netif related APIs must be
* of prototype to receive only struct netif* as argument and return type can of type err_t or void. You
* must pass either viodfunc or errtfunc.
*
* @param[in] netif Indicates the network interface to be passed as argument.
* @param[in] voidfunc Callback with return type of void, will be called if errtfunc is NULL.
* @param[in] errtfunc Callback with return type of err_t.
*
* @returns
* 0 : On success. \n
* Negative value : On failure.
*
* @note
* The prototype for netifapi_void_fn and netifapi_errt_fn are as follows:\n
* typedef void (*netifapi_void_fn)(struct netif *netif); \n
* typedef err_t (*netifapi_errt_fn)(struct netif *netif); \n
*/
// err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,netifapi_errt_fn errtfunc);
netifapi_netif_common(lwipNetIf, dhcp_clients_info_show, NULL);
break;
}
printf("<--YuchuanHuaying DHCP state:Inprogress -->\r\n");
osDelay(100);
}
osDelay(100);
return 0;
}
include/wifi_connect.h
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __WIFI_CONNECT_H__
#define __WIFI_CONNECT_H__
int wifiConnect(const char *ssid, const char *psk);
#endif /* __WIFI_CONNECT_H__ */
//applications/sample/BearPi/BearPi-HM_Nano/sample/D5_YuchuanIoTMQTT/BUILD.gn
static_library("yuchuanIoTMQTT"){
sources = [
"yuchuanIoTMQTT.c",
"src/wifi_connect.c",
]
include_dirs = [
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//kernel/liteos_m/kal/cmsis",
"//utils/native/lite/include",
"include",
"//third_party/cJSON",
]
deps = [
"//third_party/paho_mqtt:pahomqtt_static",
]
}
修改 BUILD.gn 文件
修改 applications\sample\BearPi\BearPi-HM_Nano
路径下 BUILD.gn 文件,指定 yuchuanIoTMQTT 参与编译。
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/lite/config/component/lite_component.gni")
lite_component("sample") {
features = [
#"A1_kernal_thread:thread_example",
#"A2_kernel_timer:timer_example",
#"A3_kernel_event:event_example",
#"A4_kernel_mutex:mutex_example",
#"A5_kernel_semaphore:semaphore_example",
#"A6_kernel_message:message_example",
#"B1_basic_led_blink:led_example",
#"B2_basic_button:button_example",
#"B3_basic_pwm_led:pwm_example",
#"B4_basic_adc:adc_example",
#"B5_basic_i2c_nfc:i2c_example",
#"B6_basic_uart:uart_example",
#"C1_e53_sf1_mq2:e53_sf1_example",
#"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
#"C3_e53_sc1_pls:e53_sc1_example",
#"C4_e53_sc2_axis:e53_sc2_example",
#"C5_e53_is1_infrared:e53_is1_example",
#"D1_iot_wifi_ap:wifi_ap",
#"D2_iot_wifi_sta_connect:wifi_sta_connect",
#"D3_iot_udp_client:udp_client",
#"D4_iot_tcp_server:tcp_server",
#"D5_iot_mqtt:iot_mqtt",
#"D6_iot_cloud_oc:oc_mqtt",
#"D7_iot_cloud_onenet:onenet_mqtt",
#"D8_iot_cloud_oc_smoke:cloud_oc_smoke",
#"D9_iot_cloud_oc_light:cloud_oc_light",
#"D10_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
#"D11_iot_cloud_oc_infrared:cloud_oc_infrared",
#"D12_iot_cloud_oc_agriculture:cloud_oc_agriculture",
#"D13_iot_cloud_oc_gps:cloud_oc_gps",
#"D3_YuchuanIoTUDPClient:yuchuanUDPClient",
#"D3_YuchuanUDP:yuchuanUDP",
#"D4_YuchuanTCPServer:yuchuanTCPServer",
#"D3_YuchuanUDPServer:yuchuanUDPServer",
#"D4_YuchuanTCPClient:yuchuanTCPClient",
"D5_YuchuanIoTMQTT:yuchuanIoTMQTT"
]
}
示例代码编译烧录代码后,按下开发板的RESET按键,Eclipse Paho MQTT 工具上会接收到开发板发布的消息。
往开发板发送一条消息主题为“substopic”,内容为“Hello HarmoayOS!”的MQTT消息。然后点击“发布”按钮,这个时候,我们就能看到消息已经发送成功。
且开发板的串口上也打印出接收消息成功的信息。
- 点赞
- 收藏
- 关注作者
评论(0)