利用百度物联网MQTT平台远程在线聊天室的实现,使用自带GUI,并通过Pyinstaller进行exe打包
一、项目简介
XIBI(随便取的)是一个简单的聊天工具,通过MQTT协议实现消息的发布和订阅。你可以通过它和连接到同一个MQTT服务器的其他小伙伴聊天。当然,你也可以把它当作一个学习MQTT协议的练手项目。
主要功能:
-
连接MQTT服务器:输入昵称,点击连接按钮,就可以加入聊天室。
-
发送消息:在输入框里输入你想说的话,按下回车键或者点击发送按钮,消息就会发送到所有连接到服务器的客户端。
-
接收消息:当其他用户发送消息时,你会实时收到并显示在聊天框中。
-
语音播报:收到新消息时,系统会用语音提醒你,让你不错过任何一条“撩人”的消息。
二、代码解析
1. 导入必要的库
paho.mqtt.client:用于MQTT通信。
tkinter:用于创建图形用户界面(GUI)。
pyttsx3:用于文本转语音,提醒你有新消息。
import paho.mqtt.client as mqtt
import tkinter as tk
from tkinter import scrolledtext
import random
import json
import datetime # 导入 datetime 模块以获取当前时间
import pyttsx3 # 文本转语音库
2. 初始化文本转语音引擎
这里设置了语音的语速和音量,你可以根据自己的喜好调整。
engine = pyttsx3.init()
engine.setProperty("rate", 1000) # 语速
engine.setProperty("volume", 1.0) # 音量 (0.0 到 1.0)
3. MQTT配置
这里配置了MQTT服务器的地址、端口、主题(最好发布和订阅一样,后续只需要通过id来避免自己的消息就好)以及设备的名称和密钥。你可以根据自己的MQTT服务器进行修改。
BROKER = "auyppwt.iot.gz.baidubce.com" # 接入点地址
PORT = 1883 # 端口
TOPIC_PUB = "自己设计的主题" # 发布主题
TOPIC_SUB = "自己设计的主题" # 订阅主题
DEVICE_NAME = "百度云物联网平台获得" # 设备名称
DEVICE_SECRET = "百度云物联网平台获得" # 设备密钥
4. 生成随机昵称
为了防止你忘记输入昵称,贴心地为你生成了一个随机的昵称,比如“Xibi123456”。这个其实是client_id,为了避免出现两个客户端重复的情况,但是也可以修改为自己喜欢的,当然和自己的小伙伴聊天应该是不会重复的。
def generate_random_name():
return str(random.randint(100, 9999999))
5. 获取当前时间
每条消息都会带上时间戳,方便你查看消息的发送时间。
def get_current_time():
now = datetime.datetime.now()
return now.strftime("[%H:%M:%S]")
6. MQTT连接回调
这个没什么好说的就是当成功连接到MQTT服务器时,系统会提示你“成功连接Xibi!请开始聊天吧”。如果连接失败,会显示错误代码。
def on_connect(client, userdata, flags, rc, properties=None):
if rc == 0:
insert_output_box("成功连接Xibi!\n请开始聊天吧\n", "system")
client.subscribe(TOPIC_SUB, qos=1)
else:
insert_output_box(f"连接失败,错误代码:{rc}\n", "error")
7. MQTT消息接收回调
当收到消息时,系统会解析消息内容并显示在聊天框中。如果是你自己发送的消息,系统会自动忽略。这个就是因为发布和订阅的是一个主题,所以如果id一样就不会显示内容。后续实现一对一聊天也可以通过id来判断。
def on_message(client, userdata, msg):
try:
payload = json.loads(msg.payload.decode('utf-8'))
id = payload.get("id", "未知设备")
content = payload.get("str", "")
if id == client_id_entry.get():
return
insert_output_box(f"{get_current_time()} {id}: {content}\n", "received")
engine.say("收到一条新消息")
engine.runAndWait()
except json.JSONDecodeError:
insert_output_box(f"{get_current_time()} 官方提示: {msg.payload.decode('utf-8')}\n", "received")
engine.say("收到一条新消息")
engine.runAndWait()
except Exception as e:
insert_output_box(f"{get_current_time()} 解析消息失败: {e}\n", "error")
8. 连接和断开MQTT服务器
连接和断开MQTT服务器的逻辑都在这里。连接成功后,昵称输入框会被禁用,按钮文本会变成“断开连接”。剩下的就是一些逻辑处理。
def connect_mqtt():
global client
client_id = client_id_entry.get()
if not client_id:
insert_output_box("请输入昵称后连接!\n", "error")
return
client = mqtt.Client(client_id=client_id)
client.username_pw_set(DEVICE_NAME, DEVICE_SECRET)
client.on_connect = on_connect
client.on_message = on_message
try:
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
insert_output_box(f"{get_current_time()} 正在连接...(昵称: {client_id})\n", "system")
client_id_entry.config(state=tk.DISABLED)
connect_button.config(text="断开连接", command=disconnect_mqtt)
except Exception as e:
insert_output_box(f"{get_current_time()} 连接失败: {e}\n", "error")
def disconnect_mqtt():
global client
if client:
client.loop_stop()
client.disconnect()
insert_output_box(f"{get_current_time()} 已断开与Xibi的连接。\n", "system")
client_id_entry.config(state=tk.NORMAL)
connect_button.config(text="连接", command=connect_mqtt)
9. 发送消息
发送消息的逻辑很简单,输入消息后按下回车键或者点击发送按钮,消息就会发送到MQTT服务器。会采用JSON格式发送,处理收到的消息也会按照JSON格式解析。
def send_message():
if not client:
insert_output_box("请先连接XIBI!\n", "error")
return
message = input_box.get()
if not message:
insert_output_box("请输入消息!\n", "error")
return
try:
payload = {
"id": client_id_entry.get(),
"str": message
}
client.publish(TOPIC_PUB, json.dumps(payload), qos=1)
insert_output_box(f"{get_current_time()} {payload['id']}: {payload['str']}\n", "sent")
input_box.delete(0, tk.END)
except Exception as e:
insert_output_box(f"{get_current_time()} 发送失败: {e}\n", "error")
10. GUI界面
GUI界面使用了tkinter
库,界面简洁明了,功能齐全。你可以通过输入框输入消息,按下回车键或者点击发送按钮发送消息。
root = tk.Tk()
root.title("XIBI(线上交友)")
root.geometry("500x400")
root.resizable(False, False)
client_id_label = tk.Label(root, text="昵称(不能中文):")
client_id_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
client_id_entry = tk.Entry(root, width=30)
client_id_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
client_id_entry.insert(0, 'Xibi'+generate_random_name())
connect_button = tk.Button(root, text="连接", command=connect_mqtt, width=10)
connect_button.grid(row=0, column=2, padx=5, pady=5, sticky="e")
output_box = scrolledtext.ScrolledText(root, width=60, height=20, font=("微软雅黑", 10), state=tk.DISABLED)
output_box.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")
output_box.tag_config("sent", foreground="green")
output_box.tag_config("received", foreground="blue")
output_box.tag_config("system", foreground="gray")
output_box.tag_config("error", foreground="red")
input_box = tk.Entry(root, width=50)
input_box.grid(row=2, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
input_box.bind("<Return>", on_enter_key)
send_button = tk.Button(root, text="发送", command=send_message, width=10)
send_button.grid(row=2, column=2, padx=5, pady=5, sticky="e")
root.grid_columnconfigure(1, weight=1)
root.grid_rowconfigure(1, weight=1)
root.mainloop()
if client:
client.loop_stop()
client.disconnect()
三、总结
通过这个项目,你不仅可以学习到如何使用Python和MQTT协议进行通信,还可以打造一个属于自己的线上交友工具。当然,XIBI只是一个简单的示例,你可以根据自己的需求进行扩展,比如添加私聊功能、表情包支持等等。如果有什么问题,欢迎在评论区留言,我会尽力解答。
1.全部代码
import paho.mqtt.client as mqtt
import tkinter as tk
from tkinter import scrolledtext
import random
import json
import datetime # 导入 datetime 模块以获取当前时间
import pyttsx3 # 文本转语音库
# 初始化文本转语音引擎
engine = pyttsx3.init()
# 设置语音属性
engine.setProperty("rate", 1000) # 语速
engine.setProperty("volume", 1.0) # 音量 (0.0 到 1.0)
# MQTT 配置
BROKER = "auyppwt.iot.gz.baidubce.com" # 接入点地址
PORT = 1883 # SSL端口
TOPIC_PUB = "xx" # 发布主题
TOPIC_SUB = "xx" # 订阅主题
DEVICE_NAME = "xxx" # 设备名称
DEVICE_SECRET = "xxxx" # 设备密钥
# 全局变量
client = None
# 生成三位随机数作为初始名字
def generate_random_name():
return str(random.randint(100, 9999999))
# 获取当前时间并格式化为 [HH:MM:SS] 格式
def get_current_time():
now = datetime.datetime.now()
return now.strftime("[%H:%M:%S]")
# MQTT 连接回调
def on_connect(client, userdata, flags, rc, properties=None):
if rc == 0:
insert_output_box("成功连接Xibi!\n请开始聊天吧\n", "system")
# 连接成功后订阅主题
client.subscribe(TOPIC_SUB, qos=1)
else:
insert_output_box(f"连接失败,错误代码:{rc}\n", "error")
# MQTT 消息接收回调
def on_message(client, userdata, msg):
try:
# 解析 JSON 消息
payload = json.loads(msg.payload.decode('utf-8'))
id = payload.get("id", "未知设备") # 获取 id,默认为 "未知设备"
content = payload.get("str", "") # 获取 str,默认为空
# 如果接收到的 id 与当前客户端的 id 相同,则忽略
if id == client_id_entry.get():
return
# 显示接收到的消息,并添加时间
insert_output_box(f"{get_current_time()} {id}: {content}\n", "received")
engine.say("收到一条新消息")
engine.runAndWait()
except json.JSONDecodeError:
# 如果消息不是 JSON 格式,直接显示原始内容
insert_output_box(f"{get_current_time()} 官方提示: {msg.payload.decode('utf-8')}\n", "received")
engine.say("收到一条新消息")
engine.runAndWait()
except Exception as e:
insert_output_box(f"{get_current_time()} 解析消息失败: {e}\n", "error")
# 连接按钮点击事件
def connect_mqtt():
global client
client_id = client_id_entry.get() # 获取连接名字
if not client_id:
insert_output_box("请输入昵称后连接!\n", "error")
return
# 创建 MQTT 客户端
client = mqtt.Client(client_id=client_id)
client.username_pw_set(DEVICE_NAME, DEVICE_SECRET)
client.on_connect = on_connect
client.on_message = on_message
try:
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
insert_output_box(f"{get_current_time()} 正在连接...(昵称: {client_id})\n", "system")
# 连接成功后,禁用输入框并更改按钮文本
client_id_entry.config(state=tk.DISABLED)
connect_button.config(text="断开连接", command=disconnect_mqtt)
except Exception as e:
insert_output_box(f"{get_current_time()} 连接失败: {e}\n", "error")
# 断开连接按钮点击事件
def disconnect_mqtt():
global client
if client:
client.loop_stop()
client.disconnect()
insert_output_box(f"{get_current_time()} 已断开与Xibi的连接。\n", "system")
# 断开连接后,启用输入框并更改按钮文本
client_id_entry.config(state=tk.NORMAL)
connect_button.config(text="连接", command=connect_mqtt)
# 发送消息
def send_message():
if not client:
insert_output_box("请先连接XIBI!\n", "error")
return
message = input_box.get() # 获取输入框内容
if not message:
insert_output_box("请输入消息!\n", "error")
return
try:
# 构造 JSON 格式的消息
payload = {
"id": client_id_entry.get(), # 连接名字
"str": message # 输入的内容
}
client.publish(TOPIC_PUB, json.dumps(payload), qos=1) # 发布 JSON 消息
# 在输出框中显示发送的内容(解析后的格式),并添加时间
insert_output_box(f"{get_current_time()} {payload['id']}: {payload['str']}\n", "sent")
input_box.delete(0, tk.END) # 清空输入框
except Exception as e:
insert_output_box(f"{get_current_time()} 发送失败: {e}\n", "error")
# 回车键发送消息
def on_enter_key(event):
send_message()
# 创建主窗口
root = tk.Tk()
root.title("XIBI(线上交友)")
root.geometry("500x400") # 固定窗口大小
root.resizable(False, False) # 禁止调整窗口大小
# 连接名字输入框
client_id_label = tk.Label(root, text="昵称(不能中文):")
client_id_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
client_id_entry = tk.Entry(root, width=30)
client_id_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
client_id_entry.insert(0, 'Xibi'+generate_random_name()) # 初始名字为三位随机数
# 连接按钮
connect_button = tk.Button(root, text="连接", command=connect_mqtt, width=10)
connect_button.grid(row=0, column=2, padx=5, pady=5, sticky="e")
# 输出框
output_box = scrolledtext.ScrolledText(root, width=60, height=20, font=("微软雅黑", 10), state=tk.DISABLED) # 初始状态为不可编辑
output_box.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")
# 设置消息颜色
output_box.tag_config("sent", foreground="green") # 发送的消息为绿色
output_box.tag_config("received", foreground="blue") # 接收的消息为蓝色
output_box.tag_config("system", foreground="gray") # 系统消息为灰色
output_box.tag_config("error", foreground="red") # 错误消息为红色
# 封装插入内容的函数
def insert_output_box(text, tag=None):
output_box.config(state=tk.NORMAL) # 临时设置为可编辑
output_box.insert(tk.END, text, tag) # 插入内容
output_box.config(state=tk.DISABLED) # 恢复为不可编辑
output_box.see(tk.END) # 滚动到底部
# 输入框
input_box = tk.Entry(root, width=50)
input_box.grid(row=2, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
input_box.bind("<Return>", on_enter_key) # 绑定回车键事件
# 发送按钮
send_button = tk.Button(root, text="发送", command=send_message, width=10)
send_button.grid(row=2, column=2, padx=5, pady=5, sticky="e")
# 配置网格布局权重
root.grid_columnconfigure(1, weight=1) # 使中间列(输入框)可以扩展
root.grid_rowconfigure(1, weight=1) # 使输出框所在行可以扩展
# 运行主循环
root.mainloop()
# 断开连接
if client:
client.loop_stop()
client.disconnect()
2.运行截图
下图就是聊天界面,这相当于是一个群聊软件,只要拥有该客户端的人都能进来聊天。所以你们分享软件的时候需要注意。当然后续我会根据反馈情况,增加私聊功能。
3.打包为exe
接下来就是最重要的了,代码写好之后只能在你自己的电脑上运行,所以我们需要一个打包工具,把这个代码打包为exe格式的文件,就可以分享给小伙伴了。
我推荐使用Pyinstaller进行打包,相比于其它打包方式更简单。具体下载过程可以查看下方博客,我就不详细解释了(如果需要我可以出一期)。
用 Pyinstaller 模块将 Python 程序打包成 exe 文件(全网最全面最详细,万字详述)_pyinstaller打包-CSDN博客
当下载完之后通过下方命令就能获得所需要的
Pyinstaller -F -w -p site-packages包的位置 -i 图标.ico 文件.py
好了,今天的分享就到这里,希望大家喜欢!如果你觉得这篇文章对你有帮助,别忘了点赞、收藏和分享哦!我们下期再见!👋
作者:wss2210