当前位置: 首页 > news >正文

【嵌入式linux开发】智能家居入门5:老版ONENET,多协议接入(QT、微信小程序、HTTP协议、ONENET云平台、旭日x3派)

智能家居入门5(QT、微信小程序、HTTP协议、ONENET云平台、旭日x3派)

    • 前言
    • 一、QT界面设计
    • 二、云平台产品创建与连接
    • 三、下位机端QT代码总览:
    • 四、微信小程序端代码总览
    • 五、板端测试

前言

前四篇智能家居相关文章都是使用STM32作为主控,本篇使用旭日x3派作为主控,这是一款嵌入式linux开发板,运行linux操作系统。本项目在开发板端运行QT,使用http协议与onenet云平台通信,微信小程序作为移动端,可以接收到下位机上传至服务器的数据,也可以下发指令到服务器,开发板端不断获取指令,进而执行指令。界面设置是在QTcreator中进行,相较于代码设计来说更简单,然后是在电脑虚拟机的ubuntu中进行设计和测试,成功之后直接将项目移植到板端即可,这里是因为开发板能直接运行qt,所以可以直接移植项目,如果板端不能直接运行qt的话,就参考正点原子的交叉编译,最好是使用他官方的开发板。

本文使用的是onenet平台的多协议接入,目前对于新用户已经没有这个功能了,然后老用户之前没创建产品的话,现在也创建不了了,所以本篇文章仅给使用多协议接入的小伙伴参考,新版onenet的接入也已经实现,可以到这篇文章参考。


由于本文的目的主要是在linux下实现双向通信和QT练习,所以没有真的连接温湿度传感器等外设。最终现象如下视频所示:

本文中开发板端称为下位机,微信小程序称为上位机,ONENET云平台称为服务器。


环境:
ubuntu20.04
QT5
旭日x3派
微信开发者工具


一、QT界面设计

虚拟机端的QT5安装,直接网上搜,有很多,一般用命令行安装比较快。
这里直接使用视频的方式来简单展示搭建的过程,主要包括:添加资源文件qrc,添加qss样式表,界面设计等。

视频中用到的qss样式表代码参考如下,都给出了注释很好理解:
①QRadiobutton

QRadioButton::indicator{     //设置点击区域的长和宽width:45px;height:30px;
}
QRadioButton::indicator:unchecked{     //设置未点击时的显示图像image: url(:/images/switch_off.png);
}
QRadioButton::indicator:checked{    //设置点击时的显示图像image: url(:/images/switch_on.png);
}

②QWidget

QWidget#widget {              // #特指某个对象,从右上角的类和对象中可以看当前选中的是哪个对象。background-color:rgb(150, 150, 150);        //背景颜色background-image: url(:/images/light.png);    //背景图片background-repeat: no-repeat;    //表示不要应用到子对象上,不设置的话开关里面也会添加一张背景图片background-position: top left;   //显示到左上角border-radius: 18px;    //边框圆角
}

视频中用到的图像,可以到阿里巴巴矢量图标库中找到,下载png图像即可,然后最好将图像大小重新设置成60*60,不然就有问题:
在这里插入图片描述
ps:这里最后设计成自己喜欢的样子就可以了,当然可以不参考我的设计,如果只对通信感兴趣的直接往后看就好了,本文的重点也是在双向通信上。

二、云平台产品创建与连接

1、云平台产品创建

前言中已经提到了多协议接入的问题,这里不再赘述,使用最新物联网组件的小伙伴可以评论区讨论,我看了官方文档的http接入,只看到了数据上传,没有看到获取指令或者数据的部分,是不是新版的onenet中http不支持双向了呢?MQTT协议好像还是和之前差不多的,只是不再是以前的三元组了。

2、云平台连接测试
这部分可以直接参考正点原子的视频,写一个tcp客户端,就可以正常连接云平台了,注意连接的ONENET云平台的IP地址是:183.230.40.33,端口号是:80。
建议直接跟着视频写一下:TCP客户端程序编写,主要是防止后续代码看不懂。

三、下位机端QT代码总览:

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QRadioButton>
#include <QDebug>
#include <QTimer>
//日期时间
#include <QDateTimeEdit>
#include <QTimeEdit>
#include <QDateEdit>
//tcp客户端通过http协议连接云服务器
#include <QTcpSocket>
#include <QJsonObject>
#include <QByteArray>
#include <QJsonDocument>
#include "QHostAddress"
#include <QJsonArray>
#include <QJsonValue>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();bool deng_flag = 0;int last_mainkongtiaoValue;const char *str[4] = {"POST /devices/1188390993/datapoints HTTP/1.1","api-key:=4T1J3khTpmZO99YYNDHvM5EZiI=","Host:api.heclouds.com",""};QString getbtnRequest = "GET /devices/1188390993/datastreams/ HTTP/1.1\r\napi-key:=4T1J3khTpmZO99YYNDHvM5EZiI=\r\nHost:api.heclouds.com\r\n\r\n" ;private:Ui::MainWindow *ui;QDateTimeEdit *dateTimeEdit;QTimer *timer;QTcpSocket *tcpsocket;private slots:void onRadioButtonToggled(bool checked);//五个radiobuttonvoid onRadioButton2Toggled(bool checked);void onRadioButton3Toggled(bool checked);void onRadioButton4Toggled(bool checked);void onRadioButton5Toggled(bool checked);void updateDateTimeEdit();//刷新日期时间,上传数据至云服务器void receiveMessage();//tcp相关void mStateChange(QAbstractSocket::SocketState);void on_pushButton_clicked();void on_pushButton_2_clicked();};
#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//tcp客户端通过http连接云服务器this->setWindowTitle("智能家居");tcpsocket = new QTcpSocket(this);connect(tcpsocket, SIGNAL(readyRead()), this, SLOT(receiveMessage()));connect(tcpsocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),this, SLOT(mStateChange(QAbstractSocket::SocketState)));connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(on_pushButton_clicked()));connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(on_pushButton_2_clicked()));//显示当前的时间和日期dateTimeEdit = new QDateTimeEdit(QDateTime::currentDateTime(),this);dateTimeEdit->setGeometry(50,400, 200, 40);timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &MainWindow::updateDateTimeEdit);timer->start(1000);//下面是按钮对应的信号与槽连接connect(ui->radioButton,SIGNAL(toggled(bool)), this, SLOT(onRadioButtonToggled(bool)));connect(ui->radioButton_2,SIGNAL(toggled(bool)), this, SLOT(onRadioButton2Toggled(bool)));connect(ui->radioButton_3,SIGNAL(toggled(bool)), this, SLOT(onRadioButton3Toggled(bool)));connect(ui->radioButton_4,SIGNAL(toggled(bool)), this, SLOT(onRadioButton4Toggled(bool)));connect(ui->radioButton_5,SIGNAL(toggled(bool)), this, SLOT(onRadioButton5Toggled(bool)));
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::receiveMessage()
{QString response = tcpsocket->readAll();qDebug() << "接收到服务器下发消息" << endl;// 提取 JSON 部分int jsonStartIndex = response.indexOf('{');QString jsonString = response.mid(jsonStartIndex);// 解析 JSONQJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());QJsonObject jsonObject = jsonResponse.object();QJsonArray dataArray = jsonObject["data"].toArray();for (const QJsonValue &value : dataArray){QJsonObject obj = value.toObject();if (obj["id"].toString() == "led_ctl"){int ledCtlValue = obj["current_value"].toInt();//qDebug() << "LED Control Value:" << ledCtlValue;// 可以在这里处理 ledCtlValue,如更新 UI 显示if(ledCtlValue == 0){ui->textBrowser->append("手机控制关闭客厅灯");ui->radioButton->setText("客厅灯|离线");ui->radioButton->setChecked(0);}else if(ledCtlValue == 1){ui->textBrowser->append("手机控制打开客厅灯");ui->radioButton->setText("客厅灯|在线");ui->radioButton->setChecked(1);}}else if (obj["id"].toString() == "mainroom_kongtiao"){int mainkongtiaoValue = obj["current_value"].toInt();bool ischecked = ui->radioButton_3->isChecked();if((ischecked == 1) && (mainkongtiaoValue ==0)){ui->textBrowser->append("手机控制关闭主卧空调");ui->radioButton_3->setText("空调|离线");ui->radioButton_3->setChecked(0);}else if((ischecked == 0) && (mainkongtiaoValue ==1)){ui->textBrowser->append("手机控制打开主卧空调");ui->radioButton_3->setText("空调|在线");ui->radioButton_3->setChecked(1);}}}
}void MainWindow::mStateChange(QAbstractSocket::SocketState state)
{switch (state) {case QAbstractSocket::UnconnectedState:ui->textBrowser->append("因某种原因与服务端连接断开,尝试重连");qDebug() << "因某种原因与服务端连接断开,尝试重连" << endl;tcpsocket->connectToHost(QHostAddress("183.230.40.33"),80);ui->pushButton->setEnabled(true);ui->pushButton_2->setEnabled(false);break;case QAbstractSocket::ConnectedState:qDebug() << "已连接服务器" << endl;ui->textBrowser->append("已连接服务端");ui->pushButton->setEnabled(false);ui->pushButton_2->setEnabled(true);break;default:break;}
}//开启关闭客厅灯
void MainWindow::onRadioButtonToggled(bool checked)
{if (checked) {ui->radioButton->setText("客厅灯|在线");//deng_flag = 1;qDebug() << "客厅灯打开" << endl;} else {ui->radioButton->setText("客厅灯|离线");//deng_flag = 0;qDebug() << "客厅灯关闭" << endl;}
}//场景选择:居家
void MainWindow::onRadioButton2Toggled(bool checked)
{if (checked) {qDebug() << "居家模式已打开" << endl;} else {qDebug() << "居家模式已关闭" << endl;}
}//开启关闭主卧空调
void MainWindow::onRadioButton3Toggled(bool checked)
{if (checked) {ui->radioButton_3->setText("空调|在线");qDebug() << "主卧空调打开" << endl;} else {ui->radioButton_3->setText("空调|离线");qDebug() << "主卧空调关闭" << endl;}
}//场景选择:暂时出门
void MainWindow::onRadioButton4Toggled(bool checked)
{if (checked) {//ui->radioButton_3->setForegroundRole();qDebug() << "暂时出门模式已打开" << endl;} else {//ui->radioButton_3->setText("空调|离线");qDebug() << "暂时出门模式已关闭" << endl;}
}//场景选择:出远门
void MainWindow::onRadioButton5Toggled(bool checked)
{if (checked) {qDebug() << "出远门模式已打开" << endl;} else {qDebug() << "出远门模式已关闭" << endl;}
}void MainWindow::on_pushButton_clicked()
{tcpsocket->connectToHost(QHostAddress("183.230.40.33"),80);
}void MainWindow::on_pushButton_2_clicked()
{tcpsocket->disconnectFromHost();
}//定时器刷新时间、上传数据至服务器、刷新本地显示数据
void MainWindow::updateDateTimeEdit() {static int flag = 0;dateTimeEdit->setDateTime(QDateTime::currentDateTime());//请求设备数据,这里会读回来所有的数据,比如温适度和数据流模板QByteArray getbtnRequestBytes = getbtnRequest.toUtf8();if(tcpsocket->state() == QAbstractSocket::ConnectedState) {tcpsocket->write(getbtnRequestBytes);//qDebug() << "请求已发送" << endl;;} else {ui->textBrowser->append("请先连接服务端");//qDebug() << "请先连接服务器" << endl;;}if(flag == 10){ui->label_6->setText("14度");ui->label_8->setText("70");ui->label_10->setText("9.7 ppm");QJsonObject postData;postData["temp"] = 14;postData["humi"] = 70;QJsonDocument jsonDoc(postData);QByteArray jsonData = jsonDoc.toJson(QJsonDocument::Compact);// 计算请求体的长度int contentLength = jsonData.size();// 构建HTTP请求QString httpRequestString ="POST /devices/1188390993/datapoints?type=3 HTTP/1.1\r\n""api-key:=4T1J3khTpmZO99YYNDHvM5EZiI=\r\n"  // 请注意api-key的值需要是您的实际API密钥"Host: api.heclouds.com\r\n""Content-Length: " + QString::number(contentLength) + "\r\n"  // 设置正确的内容长度"\r\n"  // 请求头和请求体之间的空行+ QString(jsonData)  // 添加JSON请求体;QByteArray httpRequest(httpRequestString.toUtf8());if(tcpsocket->state() == QAbstractSocket::ConnectedState) {tcpsocket->write(httpRequest);qDebug() << "请求已发送" << endl;} else {ui->textBrowser->append("请先连接服务端");//qDebug() << "请先连接服务器" << endl;;}flag = 0;}flag++;
}

只要简单学过QT,上述的代码都能看懂,并不是直接复制就能用,如果自己画的ui界面和我的不一样,那就要改代码,有兴趣的可以私聊拿原项目。

四、微信小程序端代码总览

有用的目录格式如下:
在这里插入图片描述
各部分的代码如下,注意只测试了温度和湿度,其他的想加很简单(微信小程序直接使用的b站up的代码:彼岸有光我们有船):
index.js:

Page({data: {temp:0},// 事件处理函数getinfo(){var that = thiswx.request({url: "https://api.heclouds.com/devices/1188390993/datapoints",   //将请求行中的数字换成自己的设备IDheader: {"api-key": "=4T1J3khTpmZO99YYNDHvM5EZiI="},method: "GET",success: function (e) {console.log("获取成功",e)that.setData({temp:e.data.data.datastreams[0].datapoints[0].value,humi:e.data.data.datastreams[2].datapoints[0].value,})console.log("temp==",that.data.temp),console.log("humi==",that.data.humi)}});},kai:function(){let data={"datastreams": [  {"id": "led_ctl","datapoints":[{"value": 1}]},//led是数据流的名称,value是要传上去的数值]	}//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/devices/1188390993/datapoints',header: {'content-type': 'application/json','api-key':'=4T1J3khTpmZO99YYNDHvM5EZiI='},method: 'POST',data: JSON.stringify(data),//data数据转换成JSON格式success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},guan:function(){let data={"datastreams": [  {"id": "led_ctl","datapoints":[{"value": 0}]},//led是数据流的名称,value是要传上去的数值]	}//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/devices/1188390993/datapoints',header: {'content-type': 'application/json','api-key':'=4T1J3khTpmZO99YYNDHvM5EZiI='},method: 'POST',data: JSON.stringify(data),//data数据转换成JSON格式success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},kaikong:function(){let data={"datastreams": [  {"id": "mainroom_kongtiao","datapoints":[{"value": 1}]},//led是数据流的名称,value是要传上去的数值]	}//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/devices/1188390993/datapoints',header: {'content-type': 'application/json','api-key':'=4T1J3khTpmZO99YYNDHvM5EZiI='},method: 'POST',data: JSON.stringify(data),//data数据转换成JSON格式success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},guankong:function(){let data={"datastreams": [  {"id": "mainroom_kongtiao","datapoints":[{"value": 0}]},//led是数据流的名称,value是要传上去的数值]	}//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/devices/1188390993/datapoints',header: {'content-type': 'application/json','api-key':'=4T1J3khTpmZO99YYNDHvM5EZiI='},method: 'POST',data: JSON.stringify(data),//data数据转换成JSON格式success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},onLoad() {var that = thissetInterval(function(){that.getinfo()},5000)}})

index.wxml:

<view class="userinfo"><image class="img" src="../images/温度 .png"></image><text>温度:{{temp}}℃</text> 
</view><view class="userinfo"><image class="img" src="../images/湿度.png"></image><text>湿度:{{humi}}%</text> 
</view><view class="userinfo"><image class="img" src="../images/甲烷.png"></image><text>天然气:{{gas_ch4}}PPM</text> 
</view><view class="userinfo"><image class="img" src="../images/可燃气体.png"></image><text>可燃气体:{{ranqi}}PPM</text> 
</view><button type="primary" style="margin-top: 20px;" bindtap="kai">开灯</button>
<button type="warn" bindtap="guan">关灯</button><button type="primary" style="margin-top: 20px;" bindtap="kaikong">开主卧空调</button>
<button type="warn" bindtap="guankong">关主卧空调</button>

index.wxss:

/**index.wxss**/
.userinfo {display: flex;flex-direction: column;align-items: center;color: rgb(141, 10, 10);font-size: 15px;
}.img {width: 100rpx;height: 100rpx;
}.usermotto {margin-top: 200px;
}

index.json:

{"usingComponents": {}
}

也是非常简单,比起qt还要更简单,简单看看就能看懂。愉快的测试即可。

五、板端测试

虚拟机端代码跑通之后其实就可以到板子上跑了。直接远程登录开发板,然后安装QT5:

sudo apt-get install qt5-default qt5-qmake qtcreator

随后将项目拷贝至任意目录下,打开qtcreator,然后打开项目,即可运行。

相关文章:

【嵌入式linux开发】智能家居入门5:老版ONENET,多协议接入(QT、微信小程序、HTTP协议、ONENET云平台、旭日x3派)

智能家居入门5&#xff08;QT、微信小程序、HTTP协议、ONENET云平台、旭日x3派&#xff09; 前言一、QT界面设计二、云平台产品创建与连接三、下位机端QT代码总览&#xff1a;四、微信小程序端代码总览五、板端测试 前言 前四篇智能家居相关文章都是使用STM32作为主控&#xf…...

软考-软件设计师(程序设计语言习题)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...

「C++系列」vector 容器

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能教程 文章目录 一、vector 容器1. 基本特性2. 基本操作3. 注意事项 二、应用场景1. 应用场景2. 案例案例一&#xff1…...

梯度的概念

梯度 机器学习中&#xff0c;梯度下降法&#xff0c;牛顿法都会用到梯度概念 对于一元函数&#xff0c;梯度可以看成导数 对于多元函数&#xff0c;梯度可以看成偏导数 如果多元函数包含N个自变量&#xff1a; x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1​,x2​,...,x…...

低代码开发:机遇与挑战并存的技术革新

近年来&#xff0c;随着数字化转型的加速&#xff0c;低代码开发平台如雨后春笋般涌现&#xff0c;承诺让非专业人士也能快速构建应用程序。这种新兴技术正在挑战传统软件开发模式&#xff0c;引发了IT行业的广泛讨论。低代码平台是提高效率的利器&#xff0c;还是降低了编程门…...

Linux之RabbitMQ集群部署

RabbitMQ 消息中间件 1、消息中间件 消息(message)&#xff1a; 指在服务之间传送的数据。可以是简单的文本消息&#xff0c;也可以是包含复杂的嵌入对象的消息 消息队列(message queue): 指用来存放消息的队列&#xff0c;一般采用先进先出的队列方式&#xff0c;即最先进入的…...

【JAVA CORE_API】Day19 多线程API(2)、多线程并发安全问题、同步

多线程API 进程和线程 进程&#xff1a;进程就像是一个程序在电脑里运行时的一个实例。你可以把它想象成一个独立的小工人&#xff0c;专门负责完成某项任务&#xff08;比如打开浏览器、播放音乐&#xff09;。每个进程都有自己独立的资源&#xff08;比如内存&#xff09;和…...

最新Windows 11 23H2精简版,免费获取!稳定流畅!

今日&#xff0c;系统之家小编给大家带来了2024最新的Windows11 23H2精简版系统&#xff0c;该版本系统经过适度地优化与精简&#xff0c;保留大部分功能&#xff0c;完全能满足日常使用需求&#xff0c;兼容性非常出色&#xff0c;无需担心应用程序出现闪退问题。大家可以通过…...

PostgreSQL SELECT 语句:深入解析与实例应用

PostgreSQL SELECT 语句:深入解析与实例应用 PostgreSQL 是一款功能强大的开源关系数据库管理系统,它以稳定性、可靠性以及支持高级功能而著称。在 PostgreSQL 中,SELECT 语句是最基本也是最重要的查询语句之一,用于从数据库表中检索数据。本文将详细介绍 SELECT 语句的用…...

【自然语言处理】 构建文本对话系统

构建文本对话系统的框架如下&#xff1a; 根据聊天系统目的功用的不同&#xff0c;可分成三大类型&#xff1a; 闲聊式机器人&#xff1a;较有代表性的有微软小冰、微软小娜、苹果的 Siri、小 i 机器人等&#xff0c;主要以娱乐为目的。 **知识问答型机器人&#xff1a;**知识…...

java: 程序包org.slf4j不存在

当在Java项目中遇到“程序包org.slf4j不存在”的错误时&#xff0c;这通常意味着你的项目没有正确地包含SLF4J&#xff08;Simple Logging Facade for Java&#xff09;的库。SLF4J是一个Java的日志门面&#xff08;Facade&#xff09;&#xff0c;它允许你在后端使用不同的日志…...

图片转PDF怎么转?教你3种快捷方便的jpg转pdf方法

图片文件以及PDF文档已经是我们工作当中不可或缺的一部分&#xff0c;我们在一些商务合作的场景下经常需要把拍摄下来的合同、企划书、画册等图片内容转换为PDF格式后再发送&#xff0c;这样能够极大程度的保证文件的安全性&#xff0c;那么图片应该如何转换成PDF文件呢?今天来…...

数据防泄密软件如何防止数据泄密?七大措施筑起数据安全壁垒

数据防泄密软件通过集成多种安全防护技术&#xff0c;旨在全面保护企业数据的安全性和保密性。以安企神软件为例&#xff0c;其实现全面防泄密的方式主要包括以下7个方面&#xff0c;为企业筑起数据安全壁垒。 1. 透明加密技术 安企神软件采用先进的透明加密技术&#xff0c;确…...

GNU/Linux - systemd介绍

systemd官网&#xff1a; System and Service Manager systemd systemd Github地址&#xff1a; https://github.com/systemd/systemd 首次发布 2010年3月30日 System and Service Manager systemd 是一套 Linux 系统的基本构件。它提供了一个系统和服务管理器&#xff0c;作为…...

如何理解递归

在二叉树的题目中&#xff0c;我们难免会用到递归方法&#xff0c;递归思想很简单&#xff0c;但运用起来却因为抽象而难以理解。 理解递归的关键在于认识到它是一种解决问题的方法&#xff0c;允许函数直接或间接地调用自身。以下是对递归的概述以及如何理解它的几个要点&…...

Spring Cache sync属性

在Spring Cache中&#xff0c;Cacheable注解用于标记一个方法&#xff0c;使其返回值可以被缓存。sync属性是Spring 4.3引入的一个新特性&#xff0c;用于控制缓存的同步行为。 sync 属性 sync属性的默认值是false&#xff0c;表示异步缓存。如果将sync设置为true&#xff0c…...

【Unity】通用GM QA工具 运行时数值修改 命令行 测试工具

GM工具使用: GM工具通常用于游戏运行时修改数值(加钱/血量)、解锁关卡等&#xff0c;用于快速无死角测试游戏。一个通用型GM工具对于游戏项目是非常实用且必要的&#xff0c;但通用不能向易用妥协&#xff0c;纯命令行GM门槛太高&#xff0c;对QA不友好。 这类运行时命令行工具…...

[Spring] Spring原理(SpringBoot完结)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

python | rq,一个无敌的 关于Redis 的Python 库!

本文来源公众号“python”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;rq&#xff0c;一个无敌的 Python 库&#xff01; 大家好&#xff0c;今天为大家分享一个无敌的 Python 库 - rq。 Github地址&#xff1a;https://githu…...

Redis的缓存淘汰策略

1. 查看Redis 最大的占用内存 打开redis配置文件, 设置maxmemory参数&#xff0c;maxmemory 是bytes字节类型, 注意转换 2. Redis默认内存多少可以用 注意: 在64bit系统下&#xff0c; maxmemory 设置为 0 表示不限制Redis内存使用 3. 一般生产上如何配置 一般推荐Redis 设置内…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...