187 lines
7.4 KiB
Python
187 lines
7.4 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
验证ESP32云端报警上报功能
|
||
通过模拟云端服务器来测试ESP32的上报功能
|
||
"""
|
||
|
||
import socket
|
||
import threading
|
||
import json
|
||
import time
|
||
from datetime import datetime
|
||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||
import urllib.parse
|
||
|
||
class CloudAlarmHandler(BaseHTTPRequestHandler):
|
||
"""模拟云端报警接收服务器"""
|
||
|
||
received_alarms = []
|
||
|
||
def do_POST(self):
|
||
"""处理POST请求"""
|
||
if self.path == '/device-alarms':
|
||
try:
|
||
# 读取请求体
|
||
content_length = int(self.headers.get('Content-Length', 0))
|
||
post_data = self.rfile.read(content_length)
|
||
|
||
# 解析JSON数据
|
||
alarm_data = json.loads(post_data.decode('utf-8'))
|
||
|
||
# 检查设备密钥
|
||
device_key = self.headers.get('X-Device-Key')
|
||
expected_key = "39dc753bd0cb19da5050a2f0edf932f851f5b21b90a6d06ecf9a28d81079a0a6"
|
||
|
||
print(f"\n📨 收到ESP32报警上报:")
|
||
print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||
print(f"设备密钥: {device_key}")
|
||
print(f"报警数据: {json.dumps(alarm_data, indent=2, ensure_ascii=False)}")
|
||
|
||
if device_key == expected_key:
|
||
# 保存报警数据
|
||
alarm_data['received_at'] = datetime.now().isoformat()
|
||
CloudAlarmHandler.received_alarms.append(alarm_data)
|
||
|
||
# 返回成功响应
|
||
response = {
|
||
"code": 200,
|
||
"message": "报警上报成功",
|
||
"data": {
|
||
"alarmId": len(CloudAlarmHandler.received_alarms),
|
||
"receivedAt": alarm_data['received_at']
|
||
}
|
||
}
|
||
|
||
self.send_response(200)
|
||
self.send_header('Content-Type', 'application/json')
|
||
self.end_headers()
|
||
self.wfile.write(json.dumps(response).encode('utf-8'))
|
||
|
||
print(f"✅ 报警接收成功! 总计收到 {len(CloudAlarmHandler.received_alarms)} 个报警")
|
||
else:
|
||
# 设备密钥错误
|
||
self.send_response(401)
|
||
self.send_header('Content-Type', 'application/json')
|
||
self.end_headers()
|
||
error_response = {"code": 401, "message": "设备密钥验证失败"}
|
||
self.wfile.write(json.dumps(error_response).encode('utf-8'))
|
||
print(f"❌ 设备密钥验证失败")
|
||
|
||
except Exception as e:
|
||
print(f"❌ 处理报警数据时出错: {e}")
|
||
self.send_response(500)
|
||
self.send_header('Content-Type', 'application/json')
|
||
self.end_headers()
|
||
error_response = {"code": 500, "message": f"服务器内部错误: {str(e)}"}
|
||
self.wfile.write(json.dumps(error_response).encode('utf-8'))
|
||
else:
|
||
# 其他路径返回404
|
||
self.send_response(404)
|
||
self.end_headers()
|
||
|
||
def do_GET(self):
|
||
"""处理GET请求"""
|
||
if self.path == '/health':
|
||
self.send_response(200)
|
||
self.send_header('Content-Type', 'application/json')
|
||
self.end_headers()
|
||
response = {"status": "ok", "message": "模拟云端服务器运行正常"}
|
||
self.wfile.write(json.dumps(response).encode('utf-8'))
|
||
else:
|
||
self.send_response(404)
|
||
self.end_headers()
|
||
|
||
def log_message(self, format, *args):
|
||
"""禁用默认日志输出"""
|
||
pass
|
||
|
||
def start_mock_cloud_server(port=36988):
|
||
"""启动模拟云端服务器"""
|
||
try:
|
||
server = HTTPServer(('0.0.0.0', port), CloudAlarmHandler)
|
||
print(f"🌐 模拟云端服务器启动成功")
|
||
print(f"监听地址: http://0.0.0.0:{port}")
|
||
print(f"报警接收端点: http://0.0.0.0:{port}/device-alarms")
|
||
print("=" * 50)
|
||
server.serve_forever()
|
||
except Exception as e:
|
||
print(f"❌ 启动模拟云端服务器失败: {e}")
|
||
|
||
def trigger_esp32_alarm():
|
||
"""尝试触发ESP32报警(通过接触传感器)"""
|
||
print("\n🔥 触发ESP32报警指导:")
|
||
print("=" * 40)
|
||
print("请执行以下操作之一来触发报警:")
|
||
print("1. 用手指接触热成像传感器表面")
|
||
print("2. 用打火机或热源靠近传感器")
|
||
print("3. 快速移动热源触发异常升温")
|
||
print("4. 等待系统自动检测")
|
||
print("=" * 40)
|
||
print("触发报警后,ESP32应该会自动上报到模拟云端服务器")
|
||
|
||
def monitor_received_alarms():
|
||
"""监控接收到的报警"""
|
||
print("\n📊 报警监控中...")
|
||
last_count = 0
|
||
|
||
while True:
|
||
current_count = len(CloudAlarmHandler.received_alarms)
|
||
if current_count > last_count:
|
||
print(f"\n🚨 新报警通知! 总计: {current_count}")
|
||
for i in range(last_count, current_count):
|
||
alarm = CloudAlarmHandler.received_alarms[i]
|
||
print(f"报警 #{i+1}:")
|
||
print(f" 设备ID: {alarm.get('physicalUid')}")
|
||
print(f" 标题: {alarm.get('title')}")
|
||
print(f" 级别: {alarm.get('level')}")
|
||
print(f" 温度: {alarm.get('temp')}°C")
|
||
print(f" 消息: {alarm.get('message')}")
|
||
print(f" 发生时间: {datetime.fromtimestamp(alarm.get('occurredAtMs', 0)/1000)}")
|
||
print(f" 接收时间: {alarm.get('received_at')}")
|
||
last_count = current_count
|
||
|
||
time.sleep(2) # 每2秒检查一次
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("🧪 ESP32云端报警上报功能验证")
|
||
print("=" * 50)
|
||
print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||
print("=" * 50)
|
||
|
||
# 启动模拟云端服务器(在后台线程中)
|
||
server_thread = threading.Thread(target=start_mock_cloud_server, daemon=True)
|
||
server_thread.start()
|
||
|
||
# 等待服务器启动
|
||
time.sleep(2)
|
||
|
||
# 显示触发指导
|
||
trigger_esp32_alarm()
|
||
|
||
# 开始监控报警
|
||
try:
|
||
monitor_received_alarms()
|
||
except KeyboardInterrupt:
|
||
print(f"\n\n🎯 测试结果总结:")
|
||
print("=" * 30)
|
||
print(f"总共接收到报警: {len(CloudAlarmHandler.received_alarms)} 个")
|
||
|
||
if CloudAlarmHandler.received_alarms:
|
||
print("✅ ESP32云端报警上报功能正常!")
|
||
print("\n📋 接收到的报警列表:")
|
||
for i, alarm in enumerate(CloudAlarmHandler.received_alarms):
|
||
print(f"{i+1}. {alarm.get('title')} - {alarm.get('level')} - {alarm.get('temp')}°C")
|
||
else:
|
||
print("⚠️ 未接收到任何报警")
|
||
print("可能的原因:")
|
||
print("1. ESP32未连接到网络")
|
||
print("2. CloudAlarmReporter模块未正确初始化")
|
||
print("3. 报警未被触发")
|
||
print("4. 网络配置问题")
|
||
|
||
print(f"\n💡 如果测试成功,说明ESP32能够正确上报报警到云端!")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|