目录
巴法云云平台官网
巴法云云平台搭建
- 进入巴法云平台登录注册
- 点击TCP设备云
- 在最右边输入框中输入主题名,主题命名并无强制性要求,也可以参考主题类型命名说明:
比如我们这里将主题命名为ledtest,点击新建主题
创建成功后可以看到下面出现了一个主题
TCP简介
TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议,传输层协议常用的有TCP和UDP,像常见的http协议或mqtt协议,都是在TCP上传输的,TCP用途广泛,一般可以联网的设备,都支持TCP协议传输。
订阅、发布简介
通俗的来讲,订阅、发布是两种不同的信号
订阅:订阅某一个主题,订阅之后,就可以收到发往该主题的消息。
发布:向某个主题发送消息。
例如:当某个设备订阅了主题“X”,这时向主题“X”发送的任何消息,设备都可以收到,因为设备已经订阅上了该主题。
直接上干货!
代码示例
wifi_sta_connect.c
- /*
- * Copyright (c) 2022 Hunan OpenValley Digital Industry Development 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 "securec.h"
- #include "cmsis_os2.h"
- #include "ohos_init.h"
- #include "wifi_device.h"
- #include "lwip/ip4_addr.h"
- #include "lwip/netif.h"
- #include "lwip/netifapi.h"
- #include "wifi_error_code.h"
-
- #define DEF_TIMEOUT 15
- #define ONE_SECOND 1
- #define SELECT_WLAN_PORT "wlan0"
- #define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_OPEN
- #define STD_TIMEZONE_OFFSET (+8)
- #define OD_DELAY_100 100
- #define OD_DELAY_200 200
-
- static int g_staScanSuccess = 0;
- static int g_ConnectSuccess = 0;
- static int ssid_count = 0;
- static WifiErrorCode wifi_error;
- static WifiEvent g_wifiEventHandler = {0};
- static int wifi_sta_init_state = 0;
- int sock_fd;
- int addr_length;
- const int timeZone = 8;
-
- static void WiFiInit(void);
- static void WaitScanResult(void);
- static int WaitConnectResult(void);
- static void OnWifiScanStateChangedHandler(int state, int size);
- static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info);
- static void OnHotspotStaJoinHandler(StationInfo *info);
- static void OnHotspotStateChangedHandler(int state);
- static void OnHotspotStaLeaveHandler(StationInfo *info);
-
- void DisableWIFI(void)
- {
- DisableWifi();
- }
-
- static void OnHotspotStaJoinHandler(StationInfo *info)
- {
- (void)info;
- printf("STA join AP\n");
- return;
- }
-
- static void OnHotspotStaLeaveHandler(StationInfo *info)
- {
- (void)info;
- printf("HotspotStaLeave:info is null.\n");
- return;
- }
-
- static void OnHotspotStateChangedHandler(int state)
- {
- printf("HotspotStateChanged:state is %d.\n", state);
- return;
- }
-
- static void WiFiInit(void)
- {
- printf("<--Wifi Init-->\r\n");
- g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;
- g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;
- g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
- g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
- g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
- wifi_error = RegisterWifiEvent(&g_wifiEventHandler);
- if (wifi_error != WIFI_SUCCESS)
- {
- printf("register wifi event fail!\r\n");
- }
- else
- {
- printf("register wifi event succeed!\r\n");
- }
- }
-
- static void OnWifiScanStateChangedHandler(int state, int size)
- {
- (void)state;
- if (size > 0)
- {
- ssid_count = size;
- g_staScanSuccess = 1;
- }
- return;
- }
-
- static int result;
- int WifiConnect(const char *ssid, const char *psk)
- {
- WifiScanInfo *info = NULL;
- unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
- static struct netif *g_lwip_netif = NULL;
- WifiDeviceConfig select_ap_config = {0};
- osDelay(OD_DELAY_200);
- printf("<--System Init-->\r\n");
- WiFiInit();
- if (EnableWifi() != WIFI_SUCCESS)
- {
- printf("EnableWifi failed, wifi_error = %d\n", wifi_error);
- return -1;
- }
- if (IsWifiActive() == 0)
- {
- printf("Wifi station is not actived.\n");
- return -1;
- }
- info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
- if (info == NULL)
- {
- printf("faild to create wifiscanInfo.\n");
- return -1;
- }
- do
- {
- ssid_count = 0;
- g_staScanSuccess = 0;
- Scan();
- WaitScanResult();
- wifi_error = GetScanInfoList(info, &size);
- } while (g_staScanSuccess != 1);
- strcpy_s(select_ap_config.ssid, sizeof(select_ap_config.ssid), ssid);
- printf("[%s][%s] \r\n", select_ap_config.ssid, select_ap_config.preSharedKey);
- select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE;
- if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS)
- {
- if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1)
- {
- printf("WiFi connect succeed!\r\n");
- wifi_sta_init_state = 1;
- }
- }
- osDelay(OD_DELAY_100);
- return 0;
- }
-
- static int WaitConnectResult(void)
- {
- int ConnectTimeout = DEF_TIMEOUT;
- while (ConnectTimeout > 0)
- {
- sleep(1);
- ConnectTimeout--;
- if (g_ConnectSuccess == 1)
- {
- printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout));
- break;
- }
- }
- if (ConnectTimeout <= 0)
- {
- printf("WaitConnectResult:timeout!\n");
- return 0;
- }
- return 1;
- }
-
- static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info)
- {
- (void)info;
- if (state > 0)
- {
- g_ConnectSuccess = 1;
- printf("callback function for wifi connect\r\n");
- }
- else
- {
- g_ConnectSuccess = 0;
- printf("connect wifi_error, please check password, state:%d, try connect again\r\n", state);
- esp_wifi_connect();
- }
- return;
- }
-
- static void WaitScanResult(void)
- {
- int scanTimeout = DEF_TIMEOUT;
- while (scanTimeout > 0)
- {
- sleep(ONE_SECOND);
- scanTimeout--;
- if (g_staScanSuccess == 1)
- {
- printf("WaitScanResult:wait success[%d]s\n", (DEF_TIMEOUT - scanTimeout));
- break;
- }
- }
- if (scanTimeout <= 0)
- {
- printf("WaitScanResult:timeout!\n");
- }
- }
wifi_sta_example.c
- /*
- * Copyright (c) 2022 Hunan OpenValley Digital Industry Development 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 "securec.h"
- #include "cmsis_os2.h"
- #include "ohos_run.h"
- #include "lwip/sockets.h"
- #include "lwip/ip_addr.h"
- #include "wifi_device.h"
-
- #include <string.h>
-
- #define OPEN_WIFI_NAME "test"
- // #define SERVER_IP "192.168.31.67"
- #define SERVER_IP "119.91.109.180"
- #define SERVER_PORT 8344
- #define OD_DELAY_1000 1000
- #define OD_DELAY_100 100
- #define RECV_LEN 511
- #define STACK_SIZE 4096
- #define PRIORITY 25
-
- osThreadId_t wifi_test_id = NULL;
-
- void wifi_test(void)
- {
- int sock = -1;
- struct sockaddr_in client_addr;
- char recv_data[512] = {0};
- int recv_data_len;
- WifiConnect(OPEN_WIFI_NAME);
- printf("start wifi_test test\r\n");
- while (1)
- {
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0)
- {
- printf("Socket error\n");
- osDelay(OD_DELAY_100);
- continue;
- }
- memset_s(&(client_addr), sizeof(client_addr), 0, sizeof(client_addr));
- client_addr.sin_family = AF_INET;
- client_addr.sin_port = htons(SERVER_PORT);
- client_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
- printf("try connect to server " SERVER_IP " :%d \n", SERVER_PORT);
- if (connect(sock, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) == -1)
- {
- closesocket(sock);
- osDelay(OD_DELAY_1000);
- continue;
- }
- printf("Connect to tcp server successful!\n");
- write(sock, "cmd=1&uid=4e2a189d769e4511bd5885742aa3edcb&topic=ledtest\r\n", strlen("cmd=1&uid=4e2a189d769e4511bd5885742aa3edcb&topic=ledtest\r\n"));
- while (1)
- {
- recv_data_len = recv(sock, recv_data, RECV_LEN, 0);
- if (recv_data_len <= 0)
- {
- break;
- }
- else
- {
- recv_data[recv_data_len] = '\0';
- printf("recv: %s\n", recv_data);
- }
- }
- }
- }
-
- static void wifi_test_example(void)
- {
- osThreadAttr_t attr;
- attr.name = "wifi_test";
- attr.attr_bits = 0U;
- attr.cb_mem = NULL;
- attr.cb_size = 0U;
- attr.stack_mem = NULL;
- attr.stack_size = STACK_SIZE;
- attr.priority = PRIORITY;
- wifi_test_id = osThreadNew((osThreadFunc_t)wifi_test, NULL, &attr);
- if (wifi_test_id == NULL)
- {
- printf("Failed to create wifi_test thread!\n");
- }
- }
-
- OHOS_APP_RUN(wifi_test_example);
BUILD.gn
- # Copyright (c) 2022 Hunan OpenValley Digital Industry Development 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("//kernel/liteos_m/liteos.gni")
-
- module_name = get_path_info(rebase_path("."), "name")
- kernel_module(module_name) {
- sources = [
- "wifi_sta_example.c",
- "wifi_sta_connect.c"
- ]
- include_dirs = [
- "//foundation/communication/wifi_lite/interfaces/wifiservice",
- "//device/board/esp/esp32/liteos_m/hals/driver/wifi_lite"
- ]
- }
移植步骤
移植本代码中有几个部分需要注意:
- 所连接的热点必须是开放的2.4G热点(没有密码)
修改连接热点名方法:将wifi_sta_example.c中OPEN_WIFI_NAME的宏定义修改为热点名即可
- 参考巴法云平台接入文档 - TCP协议中 接口地址应是:
但经笔者测试,直接填入"bemfa.com"无法连接上该服务器,推测是无法进行DNS解析,所以我们直接连接IP地址,可以通过cmd打开windows终端 - ping bemfa.com查看域名对应的IP地址
- 巴法云提供的TCP服务器是基于订阅/发布(简化版MQTT)的服务,我们可以通过向服务器发送命令的方式对主题进行订阅与发布。
巴法云TCP客户端接入详解
命令字段说明
cmd:消息类型
- cmd=1 时为订阅消息,当设备发送一次此消息类型,之后就可以收到发往该主题的消息
-
- cmd=2 时为发布消息,向订阅该主题的设备发送消息
-
- cmd=3 是订阅消息,和cmd=1相同,并且会拉取一次已发送过的消息
-
- cmd=7 是获取时间,获取当前北京时间
-
- cmd=9 为遗嘱消息,拉取一次已经发送的消息
uid:用户私钥
可在控制台获取
topic:用户主题
可以在控制台创建主题,格式为英文或数字,相当于设备标识
msg: 为消息体
用户想要发送到某个主题的数据
符号说明
- \r\n: 为回车换符,每条指令后都需要有回车换行。
- &: 为连接符,各字段间用'&'隔离。
心跳说明
- 发送任意数据 为心跳消息,包括上述指令也算是心跳,但要以回车换行结尾。
- 心跳消息是告诉服务器设备还在线,建议60秒发送一次,超过65秒未发送心跳会掉线。
订阅主题
订阅主题,单次最多订阅八个主题
cmd=1&uid=xxxxxxxxxxxxxxxxxxxxxxx&topic=xxx1,xxx2,xxx3,xxx4\r\n
正常返回:
cmd=1&res=1
发布
cmd=2&uid=xxxxxxxxxxxxxxxxxxxxxxx&topic=light002&msg=off\r\n
正常返回:
cmd=2&res=1
订阅主题,并获取一条历史消息
cmd=3&uid=xxxxxxxxxxxxxxxxxxxxxxx&topic=light002\r\n
正常返回:
cmd=3&uid=xxxxxxxxxxxxxxxxxxxxxxx&topic=light002&msg=on
获取一次时间
cmd=7&uid=xxxxxxxxxxxxxxxxxxxxxxx&type=1\r\n
正常返回:
2021-06-11 16:39:27
- type=1 获取当前日期和时间,例如:2021-06-11 17:20:54
-
- type=2 获取当前时间,例如:17:20:54
-
- type=3 获取当前时间戳,例如:1623403325
获取一次已发消息
cmd=9&uid=7d54f85af42976ee3c2693e6xxxxxxxx&topic=light002\r\n
正常返回:
cmd=9&uid=xxxxxxxxxxxxxxxxxxxxxxx&topic=light002&msg=on
发送心跳
ping\r\n
正常返回:
cmd=0&res=1
发送任意数据,并以\r\n结尾,都为心跳消息,包括上述发布、订阅指令也都算是心跳。 心跳消息是告诉服务器设备还在线,建议60秒发送一次,超过65秒未发送心跳会掉线。
set 指令
推送消息时:主题名后加/set推送消息,表示向所有订阅这个主题的设备们推送消息,假如推送者自己也订阅了这个主题,消息不会被推送给它自己,以防止自己推送的消息被自己接收。 例如向主题 light002推送数据,可为 light002/set 。
示例:
cmd=2&uid=4d9ec352e0376f2110a0c601a2857225&topic=light002/set&msg=on
up 指令
推送消息时:主题名后加/up推送消息,表示只更新云端数据,不进行任何推送。 例如向主题 light002推送数据,可为light002/up。
示例:
cmd=2&uid=4d9ec352e0376f2110a0c601a2857225&topic=light002/up&msg=on
app 指令
订阅时:主题名后加/app订阅主题,不会占用设备在线状态,即不会显示设备在线,可用于app、小程序等订阅时使用。
示例:
cmd=1&uid=4d9ec352e0376f2110a0c601a2857225&topic=light002/app
编译并烧录
在源码根目录下使用hb工具对写好的代码进行编译
选择mini级系统
同理 产品选择esp公司下的esp32
选择完毕后在源码根目录下执行hb build -f 进行编译
编译完成后会有如下界面,并且编译后的代码固件位于:out\esp32\esp32
使用烧录软件进行烧录:
点击start,等待烧录完成
实验现象
按下ESP32开发板上的EN键,即可观察到实验现象:
可以看到我们已经成功连接上TCP服务器,我们打开云平台查看是否有客户端对主题ledtest进行了订阅
我们尝试在云平台进行手动发布信息:hello openharmony!
在串口助手上成功打印出了该信息
后续大家自行将手动发布信息改成使用命令的方式进行发布即可!订阅相同主题的设备都可以收到发布的信息!
本项目代码已上传至gitee:ESP32_Oh: ESP32移植Openharmony
评论记录:
回复评论: