【XR806开发板试用】自带mqtt的调试教学

news2024/11/24 14:05:57
  • 1、下载代码
mkdir xr806_openharmony
cd xr806_openharmony
repo init -u ssh://git@gitee.com/openharmony-sig/manifest.git -b OpenHarmony_1.0.1_release --no-repo-verify -m devboard_xr806.xml
repo sync -c
repo forall -c 'git lfs pull'   
**最近仓库在整合,如果下载不了可以去论坛找一下临时仓替换即可**
  • 2、环境配置
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-env-setup.md#/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-env-setup-linux.md
  • 3、编译准备
https://xr806.docs.aw-ol.com/study/soft_compile/

要注意的是教程里面的这一步文件名是错的,要把deconfig替换成defconfig
在这里插入图片描述

之后的make menuconfig这一步不用修改,直接选择save生成.config文件即可

如果出现了替代文字

可以打开
/device/xradio/xr806/xr_shylark/project/image_cfg/readme.md
查看解决教程

或者根据报错代码修改
/device/xradio/xr806/xr_shylark/project/demo/wlan_ble_demo/image/xr806/image/image_wlan_ble.cfg文件
这是我的修改过的cfg文件,可以编译通过
在这里插入图片描述

  • 4、固件烧录
https://xr806.docs.aw-ol.com/study/soft_flash/
根据教程烧录即可,使用波特率921600可以烧录更快

windows下如果烧录时报错,可以跟我这样设置

在这里插入图片描述

  • 5、使用串口进行调试,波特率设置115200,这里使用的是windows下的SSCOM
    在这里插入图片描述

调试时如果不出现消息可以点击,打开串口->重新插拔数据线->按下复位键(XR806右下角)

  • 6、这里使用ubuntu下的mosquito作为服务端
ubuntu安装mosquitto可以参考这个链接
https://www.cnblogs.com/guyk/p/12405938.html
开启mosquito服务
mosquitto -c /etc/mosquitto/mosquitto.conf -d

如果显示1883端口已占用,可以强制结束mosquito后台然后重启服务,这里我使用1884端口
在这里插入图片描述

开启服务后板子就可以连接虚拟机进行操作了,可以在mosquito下进行订阅发布信息
如果想要在windows环境下进行订阅发布,可以下载MQTT.fx工具

http://mqttfx.jensd.de/index.php/download
  • 7、mqtt代码烧录
    XR806文件夹里面,是有很多例程的,这里的代码参考自/device/xradio/xr806/xr_shylark/project/example/mqtt/main.c
#include <stdio.h>
#include "ohos_init.h"
#include "kernel/os/os.h"
#include <string.h>
#include "wifi_device.h"
#include "wifi_hotspot.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"
#define WIFI_DEVICE_CONNECT_AP_SSID "Redmi"
#define WIFI_DEVICE_CONNECT_AP_PSK "00000000"
#define MQTT_DEMO_THREAD_STACK_SIZE (8 * 1024) /* ssl need more stack */
static OS_Thread_t mqtt_demo_thread;
static OS_Thread_t g_main_thread;
static MQTTPacket_connectData mqtt_demo_connectData = MQTTPacket_connectData_initializer;
static Client mqtt_demo_client;
static Network mqtt_demo_network;

#define MQTT_DEMO_CLIENT_ID "mqt"
#define MQTT_DEMO_HOST_NAME "192.168.43.251"
#define MQTT_DEMO_PORT      "1884"
#define MQTT_DEMO_USERNAME  "root"
#define MQTT_DEMO_PASSWORD  ""
#define MQTT_DEMO_TOPIC     "/vo84Hm3xbUj/xr806_senor_set0/data"

#define MQTT_DEMO_BUF_SIZE (2*1024)
#define WIFI_START 1
#define MQTT_DEMO_MSG_TEXT "mqtt demo test"

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);
}

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 */
re:
	ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT);
	if (ret != 0)
		OS_MSleep(500);
		goto re;

	/* subscribe topic */
	ret = mqtt_demo_subscribe(MQTT_DEMO_TOPIC);
	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_TOPIC);
	mqtt_demo_disconnect();
	mqtt_demo_deinit();

	OS_ThreadDelete(&mqtt_demo_thread);
}

static void MainThread(void *arg){
#if WIFI_START == 1
	wifi_scan_connect();
#endif
}

int main(void)
{
	if(OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK){
		printf("[ERR] Create MainThread Failed\n");
	}
	if (OS_ThreadCreate(&mqtt_demo_thread, "mqtt_demo_thread", mqtt_demo_fun, NULL,
			                OS_THREAD_PRIO_APP,
			                4 * 1024) != OS_OK) {
		printf("[ERR] Create MainThread Failed\n");
	}
	
}
SYS_RUN(main);
#define WIFI_DEVICE_CONNECT_AP_SSID "Redmi"
#define WIFI_DEVICE_CONNECT_AP_PSK "00000000"
  • 在这里可以设置XR806连接的wifi SSID和密码
#define MQTT_DEMO_CLIENT_ID "mqt"
#define MQTT_DEMO_HOST_NAME "192.168.43.251"
#define MQTT_DEMO_PORT      "1884"
#define MQTT_DEMO_USERNAME  "root"
#define MQTT_DEMO_PASSWORD  ""
#define MQTT_DEMO_TOPIC     "/vo84Hm3xbUj/xr806_senor_set0/data"

  • 这里的HOST_NAME根据你的虚拟机ip进行修改,查看虚拟机ip可以使用ifconfig -a进行查看,另外我的虚拟机网络选择的是直接复制物理网络连接状态

  • MQTT_DEMO_TOPIC为你订阅的主题,可以随便设置,订阅的时候代码做出相应修改即可

  • MQTT_DEMO_USERNAME是刚才在mosquito配置的账号root

wifi_scan_connect()
  • 这个函数是连接wifi,连接wifi后mqtt就可以连接上虚拟机的服务端
int main(void)
{
	if(OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK){
		printf("[ERR] Create MainThread Failed\n");
	}
	if (OS_ThreadCreate(&mqtt_demo_thread, "mqtt_demo_thread", mqtt_demo_fun, NULL,
			                OS_THREAD_PRIO_APP,
			                4 * 1024) != OS_OK) {
		printf("[ERR] Create MainThread Failed\n");
	}
	
}
  • 这个是main函数,创建两个线程,一个连接wifi一个,连接mqtt

要注意的是使用SYS_RUN的时候要包含这个头文件,否则编译出错

#include "ohos_init.h"

在这里插入图片描述

  • 可以看到只有一个mqtt文件夹和main.c文件,非常简单

在这里插入图片描述

  • 这个是ohosdemo目录下的BUILD.gn

在这里插入图片描述

  • 这个是mqtt目录下的BUILD.gn
    包含wifi头文件和mqtt头文件即可

  • 8、编译文件

执行hb build -f//首次编译加-f,之后不用
执行 
 sudo cp ~/xr806_openharmony/device/xradio/xr806/xr_skylark/out/xr_system.img /home/用户名/

将编译后的xr_system.img复制到用户目录

最后进行烧录即可运行mqtt,我使用的是安卓手机开wifi给电脑和XR806连接,虚拟机复制物理网络同时运行mosquito,mqtt连接上mosquito即可进行订阅和发布

使用mosquitto订阅XR806的消息
mosquitto_sub -h 192.168.43.251 -p 1884 "你设置的主题名字" -u "root"
使用mosquitto给XR806发布消息
mosquitto_pub -h 192.168.43.251 -p 1884 "你设置的主题名字" -m "想要给XR806发的消息" -u "root"
  • 要注意的是-p选项填你在mosquito.conf文件设置的端口,-h选项填你的服务端ip地址,在这里是我的ubuntu的ip地址

成功进行mqtt连接后就可以进行wifi和mqtt的学习了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1588906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件设计师-基础知识科目-算法设计与分析8

八、算法设计与分析&#xff1a; 常见算法&#xff1a; 回溯方法&#xff1a; 用深度优先的探索问题的解空间。应用场景&#xff1a;N皇后问题。&#xff08;背&#xff09; 分支界限法&#xff1a; 用广度优先的探索问题的解空间&#xff0c;采用的是分支界限法算法设计策…

【数据库】PostgreSQL源码编译安装方式与简单配置(v16.2)

PostgreSQL源码编译安装方式与简单配置&#xff08;v16.2&#xff09; 一、PostgreSQL安装基本介绍1.1 几种PostgreSQL的安装方式1.2 删除原有的PostgreSQL1.3 编译安装过程简介 二、源码编译安装方式详情2.1 下载源代码2.2 编译安装运行 configure执行 make执行 make install …

监控服务zabbix的部署

监控服务zabbix部署 文章目录 监控服务zabbix部署1. zabbix介绍2. zabbix特点3. zabbix配置文件4. 部署zabbix4.1apache安装4.2mysql安装php安装(yum方式)4.3php安装&#xff08;源码方式&#xff09;4.4配置apache代理4.5zabbix安装4.6zabbix服务端配置4.7zabbix服务端web界面…

Python应用|获取矢量数据的多边形个数

import geopandas as gpd #首先导入geopandas包# 读取Shapefile文件 shp_file "E:\python\china" gdf gpd.read_file(shp_file)# 获取多边形个数 num_polygons len(gdf)print("Number of polygons:", num_polygons) 图1|输出结果

淄博、哈尔滨、天水…社交媒体助推下的网红城市能“长红”吗?

烧烤卷饼带火山东传统工业小镇淄博&#xff1b; 冰雪狂欢让东北的哈尔滨在寒冬爆火&#xff1b; 一碗麻辣烫让西北天水小城变“网红”…… 在刚刚过去的清明假期&#xff0c;甘肃天水可谓是“热辣滚烫”&#xff0c;在春暖花开时节&#xff0c;迎来了属于它的春天。而被人们逐…

QT:QMainWindow、ui界面、资源文件的添加、信号和槽

1.练习&#xff1a;使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(…

【STL】栈(stack)

笔者在做下面这道题的时候想到用栈&#xff0c;但写的很麻烦 代码&#xff1a; #include<bits/stdc.h> using namespace std; #define MAXC 255 typedef int SElemType; typedef struct StackNode {SElemType data;struct StackNode *next; }StackNode,*LinkStack; bool…

LiveNVR监控流媒体Onvif/RTSP功能-概览负载统计展示取流中、播放中、录像中点击柱状图快速定位相关会话

LiveNVR概览负载统计展示取流中、播放中、录像中点击柱状图快速定位相关会话 1、负载信息说明2、快速定位会话3、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、负载信息说明 实时展示取流中、播放中、录像中等使用数目 取流中&#xff1a;当前拉流到平台的实时通道数目播放中&am…

天诚物联网锁亮相福州南京沈阳西安展会,与您见证AIoT行业发展

目光灼灼&#xff0c;步履不辍。自4月1日第七届CCLE中国教育后勤展览会一别&#xff0c;全场景AIoT解决方案服务商——江苏新巢天诚智能技术有限公司&#xff08;以下简称“天诚”&#xff09;打造的校园物联网锁软硬一体化解决方案获得了诸多准意向代理商、集成商同仁们的咨询…

人形机器人行业报告:AI赋能人形机器人开启产业化元年

今天分享的是人形机器人专题系列深度研究报告&#xff1a;《AI赋能&#xff0c;人形机器人开启产业化元年》。 &#xff08;报告出品方&#xff1a;国泰君安证券&#xff09; 报告共计&#xff1a;56页 要点 通用性是人形机器人商业化的关键&#xff0c;AI大模型赋能加速机…

蓝桥杯 每日2题 day5

碎碎念&#xff1a;哦哈呦&#xff0c;到第二天也是哦哈哟&#xff0c;&#xff0c;学前缀和差分学了半天&#xff01;day6堂堂连载&#xff01; 0.单词分析 14.单词分析 - 蓝桥云课 (lanqiao.cn) 关于这题就差在input前加一个sorted&#xff0c;记录一下下。接下来就是用字…

jenkins+git+maven+nodejs安装(linux系统)

前文已经安装完成sonarqube和Sonar Scanner了&#xff0c;接下来可以开始jenkins了 jenkins安装 命令&#xff08;版本为 2.440&#xff09; wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo wget https://pkg.jenkins.io/redh…

golangci-lint 报错

File is not gci-ed with --skip-generated -s standard,default (gci) golangci-lint 报错上面的错解决办法&#xff1a; 1. 文件换行需要换成"LF" 而不是"CRLF" ---->>> 我用的goland IDE&#xff0c;随便在这个文件删除一个空行&#xff…

《手把手教你》系列基础篇之2-python+ selenium自动化测试-打开和关闭浏览器(详细)

1. 简介 本节介绍如何初始化一个webdriver实例对象driver&#xff0c;然后打开和关闭firefox浏览器。要用selenium打开fiefox浏览器。首先需要去下载一个driver插件geckodriver.exe&#xff0c; 下载地址https://github.com/mozilla/geckodriver/releases&#xff0c;下载好这…

爬虫现在还有那么吃香嘛?

Python 作为一种广泛应用的编程语言&#xff0c;在 Web 开发、大数据开发、人工智能开发和嵌入式开发等领域都有着重要的应用。 Python 的易学性、清晰性和可移植性等特点使它得到很多技术人士的喜爱。对于数据科学和机器学习领域的程序员来说&#xff0c;Python 提供了强大的…

并发编程-线程安全:volatile、Lock、synchronized、CAS、ABA、AQS

并发编程-线程安全 1、volatile 关键字1.1 作用1.2 底层实现原理 2、synchronized2.2 synchronized 用法2.2 synchronized 和 volatile 的区别 3、Lock3.1 Lock 和 synchronized 的区别3.2 ReentrantLock 和 synchronized 的区别 4、CAS4.1 CAS 执行流程4.2 ABA问题 5、AQS&…

2024最火的情感短视频素材在哪下载?这里有几个素材网站可以下载

在这个看似无边无际的短视频海洋中&#xff0c;我就像那个手握罗盘、脚踏破旧木筏的勇敢航海家&#xff0c;时刻准备着发现新大陆。而我的罗盘&#xff0c;就是那些能够指引我找到珍稀素材的网站。让我带你领略一下我的航海日记吧。九才素材网&#xff1a; 九才素材网提供了丰…

大数据dolphinscheduler 本地容器化安装

Minio 容器安装 docker run -p 9000:9000 -p 9090:9090 --name minio -d -e "MINIO_ACCESS_KEYminioadmin" -e "MINIO_SECRET_KEYminioadmin" -v D:\SF\DOCKER\minio\data:/data -v D:\SF\DOCKER\minio\config:/root/.minio minio/minio server /da…

全国电影(广州)交易会暨第25届全国优秀影片推介会盛大召开

4月10日&#xff0c;全国电影&#xff08;广州&#xff09;交易会暨第25届全国优秀影片推介会在广州增城召开。作为2024年第一场电影全行业会议&#xff0c;该会议受到行业内外广泛关注和响应&#xff0c;被视为新一年度电影市场“晴雨表”和“风向标”。会议以“聚合电影行业内…

利用Python的Pyttsx3库实现离线文字转语音(TTS)功能

项目中需要一个语言模块&#xff0c;之前用微软的TTS其实挺好用的&#xff0c;但是不开源&#xff0c;离线也不好整&#xff0c;打算找个轻量化的&#xff0c;然后发现&#xff0c;Python里Pyttsx3库已经能完美实现我的需求了 Pyttsx3 Pyttsx3是一个Python库&#xff0c;用于…