first commit
This commit is contained in:
commit
1615bda1ef
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.idea/
|
||||||
|
python/__pycache__/
|
||||||
|
python/logs/
|
61
python/config.py
Normal file
61
python/config.py
Normal 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
5
python/config.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[broker]
|
||||||
|
address = "pythagodzilla.pw"
|
||||||
|
port = 1883
|
||||||
|
username = ""
|
||||||
|
password = ""
|
44
python/logger.py
Normal file
44
python/logger.py
Normal 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
17
python/main.py
Normal 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
87
python/mqtt_client.py
Normal 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
1
python/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
paho-mqtt~=2.1.0
|
Loading…
x
Reference in New Issue
Block a user