first commit

This commit is contained in:
Pyhtagodzilla 2025-08-18 02:28:52 +08:00
commit 1615bda1ef
7 changed files with 218 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea/
python/__pycache__/
python/logs/

61
python/config.py Normal file
View File

@ -0,0 +1,61 @@
from pathlib import Path
import toml
from logger import get_log
_log = get_log()
class Config:
config_path = Path("config.toml")
def __init__(self):
if not Config.config_path.exists():
self.create_config_file()
config_content = self.load_config()
broker_settings = config_content.get("broker", {})
self.broker_address = broker_settings.get("address", "pythagodzilla.pw")
self.broker_port = broker_settings.get("port", 1883)
self.broker_username = broker_settings.get("username", "")
self.broker_password = broker_settings.get("password", "")
def create_config_file(self):
"""
"""
default_config = {
"broker": {
"address": "pythagodzilla.pw",
"port": 1883,
"username": "",
"password": ""
}
}
try:
with open(self.config_path, "w", encoding="utf-8") as config_file:
toml.dump(default_config, config_file)
_log.info(f"已创建默认配置文件{Config.config_path}")
except Exception as e:
_log.exception(f"创建配置文件失败: {e}")
def load_config(self):
"""
Load the configuration from the config file.
"""
try:
with open(self.config_path, "r") as config_file:
config = toml.load(config_file)
return config
except FileNotFoundError:
_log.exception(f"配置文件 {self.config_path} 不存在。")
return None
except toml.TomlDecodeError as e:
_log.exception(f"配置文件解析错误: {e}")
return None
except Exception as e:
_log.exception(f"加载配置文件失败: {e}")
return None

5
python/config.toml Normal file
View File

@ -0,0 +1,5 @@
[broker]
address = "pythagodzilla.pw"
port = 1883
username = ""
password = ""

44
python/logger.py Normal file
View File

@ -0,0 +1,44 @@
import logging
from datetime import datetime
from logging.handlers import TimedRotatingFileHandler
from pathlib import Path
def get_log():
"""
"""
logger = logging.getLogger("WildAssistant")
logger.setLevel(logging.DEBUG)
# file log handler
file_handler = TimedRotatingFileHandler(
# filename=f"{datetime.now().strftime(" % Y - % m - %d")}.log"
filename=Path("logs") / f"{datetime.now().strftime("%Y-%m-%d")}.log",
when="midnight",
backupCount=90,
encoding="utf-8",
)
file_handler.setLevel(logging.INFO)
# console log handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
file_formatter = logging.Formatter(
fmt="%(asctime)s - %(name)s - %(filename)10s - %(lineno)4d - %(funcName)10s - %(levelname)8s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
console_formatter = logging.Formatter(
fmt="%(asctime)s - %(levelname)8s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
file_handler.setFormatter(file_formatter)
console_handler.setFormatter(console_formatter)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
return logger

17
python/main.py Normal file
View File

@ -0,0 +1,17 @@
from fastapi import FastAPI
from contextlib import asynccontextmanager
from mqtt_client import client, mqtt_connect, mqtt_disconnect
from logger import get_log
_log = get_log()
@asynccontextmanager
async def lifspan(app: FastAPI):
"""
Application startup and shutdown events.
"""
_log.info("Starting MQTT client...")
await mqtt_connect()
yield
_log.info("Stopping MQTT client...")
await mqtt_disconnect()

87
python/mqtt_client.py Normal file
View File

@ -0,0 +1,87 @@
import json
import paho.mqtt.client as mqtt
from config import Config
from logger import get_log
# 创建一个 MQTT 客户端实例,并指定使用 V2 回调 API
# 这将消除 DeprecationWarning 警告
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
_log = get_log()
topics = [
"test/topic",
"test/topic2",
]
user_data = {
"topics": json.dumps(topics).encode("utf-8"),
}
client.user_data_set(user_data)
# 定义连接成功时的回调函数
def on_connect(client, userdata, flags, rc, properties):
"""
当客户端成功连接到 MQTT 代理时这个函数会被调用
rc (return code) 的值为 0 表示成功
"""
if rc == 0:
_log.info("成功连接到 MQTT 服务器!")
# 订阅一个主题。
# 当连接成功后,客户端会自动重新订阅之前订阅的主题。
topic_list = json.loads(userdata["topics"].decode("utf-8"))
for topic in topic_list:
_log.info(f"订阅主题:{topic}")
client.subscribe(topic)
else:
_log.error(f"连接失败,返回码:{rc}")
# 定义接收到消息时的回调函数
def on_message(client, userdata, msg):
"""
当客户端接收到来自代理的消息时这个函数会被调用
消息内容在 msg.payload 需要解码成字符串
"""
_log.info(f"收到消息来自主题:{msg.topic}")
_log.info(f"消息内容:{msg.payload.decode('utf-8')}")
# 绑定回调函数
client.on_connect = on_connect
client.on_message = on_message
# 连接 MQTT
def mqtt_connect():
"""
"""
_config = Config()
# 设置连接参数
broker_address = _config.broker_address
port = _config.broker_port # MQTT 默认端口
_log.info(f"正在连接{broker_address}:{port}")
try:
client.connect(broker_address, port, 60)
client.loop_start()
except Exception as e:
_log.exception(e)
# 断开 MQTT 连接的函数
def mqtt_disconnect():
"""
停止 MQTT 客户端循环并断开连接
"""
_log.info("正在断开 MQTT 连接...")
client.loop_stop()
client.disconnect()
_log.info("MQTT 连接已断开。")

1
python/requirements.txt Normal file
View File

@ -0,0 +1 @@
paho-mqtt~=2.1.0