smart-home/verify_cloud_alarm_reporting.py

187 lines
7.4 KiB
Python
Raw Normal View History

2026-02-26 09:16:34 +08:00
#!/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()