|
|
@@ -30,7 +30,20 @@ from config import (
|
|
|
SOCKETIO_NAMESPACE_STATUS,
|
|
|
SOCKETIO_NAMESPACE_CONTROL,
|
|
|
ERROR_CODES,
|
|
|
- ERROR_MESSAGES
|
|
|
+ ERROR_MESSAGES,
|
|
|
+ DEFAULT_CUSTOMER_ID,
|
|
|
+ DEFAULT_DTU_ID,
|
|
|
+ DTU_HEARTBEAT_INTERVAL,
|
|
|
+ DEFAULT_MQTT_TOPIC_PREFIX,
|
|
|
+ DTU_REGISTRATION_TOPIC,
|
|
|
+ DTU_STATUS_TOPIC,
|
|
|
+ DTU_CONTROL_TOPIC,
|
|
|
+ DTU_RESPONSE_TOPIC,
|
|
|
+ DTU_EVENT_TOPIC,
|
|
|
+ DTU_ALARM_TOPIC,
|
|
|
+ DTU_BROADCAST_TOPIC,
|
|
|
+ MAX_PANELS,
|
|
|
+ MAX_PORTS_PER_PANEL
|
|
|
)
|
|
|
|
|
|
# 配置日志
|
|
|
@@ -78,6 +91,23 @@ forward_serial_to_mqtt = DEFAULT_FORWARD_SERIAL_TO_MQTT
|
|
|
forward_mqtt_to_serial = DEFAULT_FORWARD_MQTT_TO_SERIAL
|
|
|
mqtt_publish_topic = DEFAULT_MQTT_PUBLISH_TOPIC
|
|
|
|
|
|
+# DTU MQTT协议配置(运行时可修改)
|
|
|
+dtu_config = {
|
|
|
+ 'topic_prefix': DEFAULT_MQTT_TOPIC_PREFIX,
|
|
|
+ 'customer_id': DEFAULT_CUSTOMER_ID,
|
|
|
+ 'dtu_id': DEFAULT_DTU_ID,
|
|
|
+ 'firmware_version': 'v1.0.0',
|
|
|
+ 'hardware_version': 'v1.0',
|
|
|
+ 'heartbeat_interval': DTU_HEARTBEAT_INTERVAL,
|
|
|
+ 'enabled': True # 是否启用DTU MQTT协议
|
|
|
+}
|
|
|
+
|
|
|
+# 端口状态追踪(用于事件检测)
|
|
|
+port_state = {} # {panel_id: {port_id: {'last_uid': str, 'expected_uid': str, 'alarm_count': int}}}
|
|
|
+
|
|
|
+# 面板配置(从地址配置模块加载)
|
|
|
+panel_config = {} # {panel_id: {'address': int, 'position': int, 'panel_uid': str}}
|
|
|
+
|
|
|
# 数据存储缓冲区
|
|
|
serial_data_buffer = []
|
|
|
mqtt_data_buffer = []
|
|
|
@@ -219,16 +249,339 @@ def mqtt_status_handler(status):
|
|
|
try:
|
|
|
global mqtt_status
|
|
|
mqtt_status = status
|
|
|
-
|
|
|
+
|
|
|
# 通过WebSocket广播状态变化
|
|
|
socketio.emit('mqtt_status', {
|
|
|
'connected': status
|
|
|
}, namespace=SOCKETIO_NAMESPACE_STATUS)
|
|
|
-
|
|
|
+
|
|
|
logger.info(f"MQTT状态更新: {'已连接' if status else '已断开'}")
|
|
|
+
|
|
|
+ # 如果MQTT连接成功且启用了DTU协议,发送注册消息和订阅控制主题
|
|
|
+ if status and dtu_config.get('enabled'):
|
|
|
+ socketio.sleep(1) # 等待连接稳定
|
|
|
+
|
|
|
+ # 发送DTU注册消息
|
|
|
+ dtu_register()
|
|
|
+
|
|
|
+ # 订阅控制主题
|
|
|
+ control_topic = build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'control')
|
|
|
+ mqtt_client.subscribe(control_topic)
|
|
|
+ logger.info(f"已订阅控制主题: {control_topic}")
|
|
|
except Exception as e:
|
|
|
logger.error(f"处理MQTT状态时出错: {str(e)}")
|
|
|
|
|
|
+
|
|
|
+# ========== DTU MQTT协议处理函数 ==========
|
|
|
+
|
|
|
+def build_dtu_topic(*parts):
|
|
|
+ """构建DTU MQTT主题"""
|
|
|
+ prefix = dtu_config.get('topic_prefix', '线架系统')
|
|
|
+ return '/'.join([prefix] + list(parts))
|
|
|
+
|
|
|
+
|
|
|
+def dtu_register():
|
|
|
+ """发送DTU注册消息"""
|
|
|
+ if not mqtt_client.get_status():
|
|
|
+ logger.warning("MQTT未连接,无法发送注册消息")
|
|
|
+ return False
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 加载面板配置
|
|
|
+ devices = address_config.get_stored_devices()
|
|
|
+ panels = []
|
|
|
+ panel_id = 1
|
|
|
+ for uid_hex, addr in devices.items():
|
|
|
+ panels.append({
|
|
|
+ 'panel_id': f"PANEL_{dtu_config['dtu_id']}_{addr}",
|
|
|
+ 'address': addr,
|
|
|
+ 'position': panel_id
|
|
|
+ })
|
|
|
+ panel_id += 1
|
|
|
+
|
|
|
+ payload = {
|
|
|
+ 'msg_id': f"reg_{int(time.time() * 1000)}",
|
|
|
+ 'timestamp': int(time.time() * 1000),
|
|
|
+ 'dtu_id': dtu_config['dtu_id'],
|
|
|
+ 'type': 'REGISTER',
|
|
|
+ 'payload': {
|
|
|
+ 'firmware_version': dtu_config.get('firmware_version', 'v1.0.0'),
|
|
|
+ 'hardware_version': dtu_config.get('hardware_version', 'v1.0'),
|
|
|
+ 'panel_count': len(panels),
|
|
|
+ 'network_type': 'ethernet',
|
|
|
+ 'signal_strength': None,
|
|
|
+ 'uptime': int(time.time() * 1000), # 简化处理
|
|
|
+ 'panels': panels
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ topic = build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'register')
|
|
|
+ success, msg = mqtt_client.publish(topic, json.dumps(payload))
|
|
|
+
|
|
|
+ if success:
|
|
|
+ logger.info(f"DTU注册消息已发送: {topic}")
|
|
|
+ else:
|
|
|
+ logger.error(f"DTU注册消息发送失败: {msg}")
|
|
|
+
|
|
|
+ return success
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"发送DTU注册消息失败: {str(e)}")
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+def dtu_publish_status(force=False):
|
|
|
+ """发送DTU状态/心跳消息"""
|
|
|
+ if not mqtt_client.get_status() or not dtu_config.get('enabled'):
|
|
|
+ return False
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 统计面板在线状态
|
|
|
+ panel_online = 0
|
|
|
+ panel_offline = 0
|
|
|
+
|
|
|
+ # 检查串口状态
|
|
|
+ serial_st = serial_client.get_status()
|
|
|
+ rs485_status = 'normal' if (isinstance(serial_st, dict) and serial_st.get('connected', False)) else 'error'
|
|
|
+
|
|
|
+ payload = {
|
|
|
+ 'msg_id': f"hbt_{int(time.time() * 1000)}",
|
|
|
+ 'timestamp': int(time.time() * 1000),
|
|
|
+ 'dtu_id': dtu_config['dtu_id'],
|
|
|
+ 'type': 'STATUS',
|
|
|
+ 'payload': {
|
|
|
+ 'cpu_usage': None, # 可后续添加
|
|
|
+ 'memory_usage': None,
|
|
|
+ 'temperature': None,
|
|
|
+ 'network_status': 'online',
|
|
|
+ 'panel_online': panel_online,
|
|
|
+ 'panel_offline': panel_offline,
|
|
|
+ 'screen_connected': False,
|
|
|
+ 'mqtt_connected': mqtt_client.get_status(),
|
|
|
+ 'rs485_status': rs485_status
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ topic = build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'status')
|
|
|
+ success, _ = mqtt_client.publish(topic, json.dumps(payload))
|
|
|
+ return success
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"发送DTU状态消息失败: {str(e)}")
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+def dtu_publish_event(panel_id, port_id, event_type, jumper_uid, previous_jumper_uid=None):
|
|
|
+ """发送端口事件消息"""
|
|
|
+ if not mqtt_client.get_status() or not dtu_config.get('enabled'):
|
|
|
+ return False
|
|
|
+
|
|
|
+ try:
|
|
|
+ payload = {
|
|
|
+ 'msg_id': f"evt_{int(time.time() * 1000)}",
|
|
|
+ 'timestamp': int(time.time() * 1000),
|
|
|
+ 'dtu_id': dtu_config['dtu_id'],
|
|
|
+ 'type': 'EVENT',
|
|
|
+ 'payload': {
|
|
|
+ 'panel_id': panel_id,
|
|
|
+ 'port_id': port_id,
|
|
|
+ 'event_type': event_type,
|
|
|
+ 'event_id': f"evt_{uuid.uuid4().hex[:8]}",
|
|
|
+ 'jumper_uid': jumper_uid,
|
|
|
+ 'previous_jumper_uid': previous_jumper_uid
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ topic = build_dtu_topic(dtu_config['customer_id'], 'patchpanel', dtu_config['dtu_id'], panel_id, 'event')
|
|
|
+ success, _ = mqtt_client.publish(topic, json.dumps(payload))
|
|
|
+
|
|
|
+ if success:
|
|
|
+ logger.info(f"端口事件已发送: {panel_id}:{port_id} - {event_type}")
|
|
|
+
|
|
|
+ return success
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"发送端口事件失败: {str(e)}")
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+def dtu_publish_alarm(panel_id, port_id, alarm_type, expected_jumper_uid, actual_jumper_uid):
|
|
|
+ """发送非法告警消息"""
|
|
|
+ if not mqtt_client.get_status() or not dtu_config.get('enabled'):
|
|
|
+ return False
|
|
|
+
|
|
|
+ try:
|
|
|
+ description = f"端口{port_id}期望跳线{expected_jumper_uid},实际{'未读到' if not actual_jumper_uid else actual_jumper_uid}"
|
|
|
+
|
|
|
+ payload = {
|
|
|
+ 'msg_id': f"alm_{int(time.time() * 1000)}",
|
|
|
+ 'timestamp': int(time.time() * 1000),
|
|
|
+ 'dtu_id': dtu_config['dtu_id'],
|
|
|
+ 'type': 'ALARM',
|
|
|
+ 'payload': {
|
|
|
+ 'panel_id': panel_id,
|
|
|
+ 'port_id': port_id,
|
|
|
+ 'alarm_type': alarm_type,
|
|
|
+ 'severity': 'WARNING',
|
|
|
+ 'expected_jumper_uid': expected_jumper_uid,
|
|
|
+ 'actual_jumper_uid': actual_jumper_uid,
|
|
|
+ 'description': description
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ topic = build_dtu_topic(dtu_config['customer_id'], 'patchpanel', dtu_config['dtu_id'], panel_id, 'alarm')
|
|
|
+ success, _ = mqtt_client.publish(topic, json.dumps(payload))
|
|
|
+
|
|
|
+ if success:
|
|
|
+ logger.warning(f"非法告警已发送: {panel_id}:{port_id} - {alarm_type}")
|
|
|
+
|
|
|
+ return success
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"发送非法告警失败: {str(e)}")
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+def dtu_handle_control(topic, payload):
|
|
|
+ """处理下行控制指令"""
|
|
|
+ try:
|
|
|
+ if not dtu_config.get('enabled'):
|
|
|
+ return
|
|
|
+
|
|
|
+ command = payload.get('payload', {}).get('command')
|
|
|
+ target = payload.get('payload', {}).get('target')
|
|
|
+ params = payload.get('payload', {}).get('params', {})
|
|
|
+
|
|
|
+ logger.info(f"收到控制指令: command={command}, target={target}")
|
|
|
+
|
|
|
+ response_payload = {
|
|
|
+ 'msg_id': payload.get('msg_id'),
|
|
|
+ 'timestamp': int(time.time() * 1000),
|
|
|
+ 'dtu_id': dtu_config['dtu_id'],
|
|
|
+ 'type': 'RESPONSE',
|
|
|
+ 'payload': {
|
|
|
+ 'command': command,
|
|
|
+ 'target': target,
|
|
|
+ 'success': True,
|
|
|
+ 'result': {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ # 处理各命令
|
|
|
+ if command == 'SET_PORT_LED':
|
|
|
+ # 设置端口LED
|
|
|
+ port_id = params.get('port_id')
|
|
|
+ led_mode = params.get('led_mode', 'OFF')
|
|
|
+
|
|
|
+ # LED模式映射
|
|
|
+ led_mode_map = {'OFF': 0, 'BLINK_RED': 1, 'BLINK_GREEN': 2, 'BLINK_BLUE': 3}
|
|
|
+ color = led_mode_map.get(led_mode, 0)
|
|
|
+
|
|
|
+ # 查找设备地址
|
|
|
+ device_address = 1 # 默认
|
|
|
+ for panel_id, cfg in panel_config.items():
|
|
|
+ if panel_id == target:
|
|
|
+ device_address = cfg.get('address', 1)
|
|
|
+ break
|
|
|
+
|
|
|
+ result = modbus_client.set_rgb_led(device_address, port_id, color)
|
|
|
+ response_payload['payload']['success'] = 'error' not in result
|
|
|
+ response_payload['payload']['result'] = result
|
|
|
+
|
|
|
+ elif command == 'QUERY_DTU_STATUS':
|
|
|
+ # 查询DTU状态
|
|
|
+ dtu_publish_status(force=True)
|
|
|
+
|
|
|
+ elif command == 'SYNC_PORT_MAPPING':
|
|
|
+ # 同步单端口期望映射
|
|
|
+ port_id = params.get('port_id')
|
|
|
+ jumper_uid = params.get('jumper_uid')
|
|
|
+
|
|
|
+ if target not in port_state:
|
|
|
+ port_state[target] = {}
|
|
|
+ if port_id not in port_state[target]:
|
|
|
+ port_state[target][port_id] = {'last_uid': None, 'expected_uid': None, 'alarm_count': 0}
|
|
|
+
|
|
|
+ port_state[target][port_id]['expected_uid'] = jumper_uid
|
|
|
+
|
|
|
+ elif command == 'SYNC_ALL_MAPPING':
|
|
|
+ # 批量同步期望映射
|
|
|
+ mappings = params.get('mappings', [])
|
|
|
+ for mapping in mappings:
|
|
|
+ panel_id = mapping.get('panel_id')
|
|
|
+ port_id = mapping.get('port_id')
|
|
|
+ jumper_uid = mapping.get('jumper_uid')
|
|
|
+
|
|
|
+ if panel_id not in port_state:
|
|
|
+ port_state[panel_id] = {}
|
|
|
+ if port_id not in port_state[panel_id]:
|
|
|
+ port_state[panel_id][port_id] = {'last_uid': None, 'expected_uid': None, 'alarm_count': 0}
|
|
|
+
|
|
|
+ port_state[panel_id][port_id]['expected_uid'] = jumper_uid
|
|
|
+
|
|
|
+ elif command == 'REBOOT':
|
|
|
+ # 重启DTU(模拟)
|
|
|
+ response_payload['payload']['result'] = {'message': 'Reboot command received'}
|
|
|
+
|
|
|
+ # 发送响应
|
|
|
+ response_topic = build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'response')
|
|
|
+ mqtt_client.publish(response_topic, json.dumps(response_payload))
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"处理控制指令失败: {str(e)}")
|
|
|
+
|
|
|
+
|
|
|
+# 启动DTU心跳定时器
|
|
|
+def start_dtu_heartbeat():
|
|
|
+ """启动DTU心跳定时任务"""
|
|
|
+ def heartbeat_task():
|
|
|
+ while True:
|
|
|
+ socketio.sleep(dtu_config.get('heartbeat_interval', DTU_HEARTBEAT_INTERVAL))
|
|
|
+ if mqtt_client.get_status() and dtu_config.get('enabled'):
|
|
|
+ dtu_publish_status()
|
|
|
+
|
|
|
+ socketio.start_background_task(target=heartbeat_task)
|
|
|
+
|
|
|
+
|
|
|
+# 修改mqtt_data_handler以处理控制指令
|
|
|
+def mqtt_data_handler_extended(data):
|
|
|
+ """处理MQTT接收的数据(扩展版,含DTU协议)"""
|
|
|
+ try:
|
|
|
+ topic = data.get('topic', '')
|
|
|
+ payload_str = data.get('payload', '')
|
|
|
+
|
|
|
+ # 尝试解析JSON
|
|
|
+ try:
|
|
|
+ payload = json.loads(payload_str) if isinstance(payload_str, str) else payload_str
|
|
|
+ except:
|
|
|
+ payload = payload_str
|
|
|
+
|
|
|
+ # 添加到缓冲区
|
|
|
+ timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
|
|
|
+ mqtt_data_buffer.append({
|
|
|
+ 'timestamp': timestamp,
|
|
|
+ 'topic': topic,
|
|
|
+ 'payload': payload_str
|
|
|
+ })
|
|
|
+ if len(mqtt_data_buffer) > MAX_BUFFER_SIZE:
|
|
|
+ mqtt_data_buffer.pop(0)
|
|
|
+
|
|
|
+ # 通过WebSocket广播
|
|
|
+ socketio.emit('mqtt_data', {
|
|
|
+ 'timestamp': timestamp,
|
|
|
+ 'topic': topic,
|
|
|
+ 'payload': payload_str
|
|
|
+ }, namespace=SOCKETIO_NAMESPACE_DATA)
|
|
|
+
|
|
|
+ # 检查是否是控制指令主题
|
|
|
+ expected_control_topic = build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'control')
|
|
|
+ if topic == expected_control_topic:
|
|
|
+ dtu_handle_control(topic, payload)
|
|
|
+
|
|
|
+ # 转发到串口(如果启用)
|
|
|
+ if forward_mqtt_to_serial and serial_client.get_status():
|
|
|
+ success, msg = serial_client.send_data(payload_str)
|
|
|
+ if not success:
|
|
|
+ logger.warning(f"MQTT数据转发到串口失败: {msg}")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"处理MQTT数据时出错: {str(e)}")
|
|
|
+
|
|
|
# WebSocket事件处理
|
|
|
@socketio.on('connect', namespace=SOCKETIO_NAMESPACE_DATA)
|
|
|
def handle_data_connect():
|
|
|
@@ -490,7 +843,7 @@ def handle_clear_data_buffer(data):
|
|
|
# 设置回调
|
|
|
serial_client.set_data_callback(serial_data_handler)
|
|
|
serial_client.set_status_callback(serial_status_handler)
|
|
|
-mqtt_client.set_data_callback(mqtt_data_handler)
|
|
|
+mqtt_client.set_data_callback(mqtt_data_handler_extended)
|
|
|
mqtt_client.set_status_callback(mqtt_status_handler)
|
|
|
|
|
|
# 设备配置文件路径
|
|
|
@@ -1404,6 +1757,126 @@ def set_all_leds():
|
|
|
# 在 set_rgb_led 中更新 LED 状态追踪
|
|
|
# 不再需要静态文件目录,前端由nginx提供服务
|
|
|
|
|
|
+
|
|
|
+# ========== DTU MQTT协议配置API ==========
|
|
|
+
|
|
|
+@app.route('/api/dtu/config', methods=['GET'])
|
|
|
+def get_dtu_config():
|
|
|
+ """获取DTU配置"""
|
|
|
+ return jsonify({
|
|
|
+ 'success': True,
|
|
|
+ 'data': dtu_config
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+@app.route('/api/dtu/config', methods=['POST'])
|
|
|
+def update_dtu_config():
|
|
|
+ """更新DTU配置"""
|
|
|
+ try:
|
|
|
+ data = request.json
|
|
|
+ old_config = dtu_config.copy()
|
|
|
+
|
|
|
+ # 更新配置项
|
|
|
+ if 'topic_prefix' in data:
|
|
|
+ dtu_config['topic_prefix'] = data['topic_prefix']
|
|
|
+ if 'customer_id' in data:
|
|
|
+ dtu_config['customer_id'] = data['customer_id']
|
|
|
+ if 'dtu_id' in data:
|
|
|
+ dtu_config['dtu_id'] = data['dtu_id']
|
|
|
+ if 'firmware_version' in data:
|
|
|
+ dtu_config['firmware_version'] = data['firmware_version']
|
|
|
+ if 'hardware_version' in data:
|
|
|
+ dtu_config['hardware_version'] = data['hardware_version']
|
|
|
+ if 'heartbeat_interval' in data:
|
|
|
+ dtu_config['heartbeat_interval'] = data['heartbeat_interval']
|
|
|
+ if 'enabled' in data:
|
|
|
+ dtu_config['enabled'] = data['enabled']
|
|
|
+
|
|
|
+ # 如果MQTT已连接且主题配置发生变化,重新订阅
|
|
|
+ if mqtt_status and dtu_config.get('enabled'):
|
|
|
+ old_control_topic = build_dtu_topic(
|
|
|
+ old_config.get('customer_id', DEFAULT_CUSTOMER_ID),
|
|
|
+ 'dtu',
|
|
|
+ old_config.get('dtu_id', DEFAULT_DTU_ID),
|
|
|
+ 'control'
|
|
|
+ )
|
|
|
+ new_control_topic = build_dtu_topic(
|
|
|
+ dtu_config['customer_id'],
|
|
|
+ 'dtu',
|
|
|
+ dtu_config['dtu_id'],
|
|
|
+ 'control'
|
|
|
+ )
|
|
|
+
|
|
|
+ if old_control_topic != new_control_topic:
|
|
|
+ # 取消旧订阅,订阅新主题
|
|
|
+ mqtt_client.unsubscribe(old_control_topic)
|
|
|
+ mqtt_client.subscribe(new_control_topic)
|
|
|
+ logger.info(f"控制主题已更新: {old_control_topic} -> {new_control_topic}")
|
|
|
+
|
|
|
+ # 重新发送注册消息
|
|
|
+ dtu_register()
|
|
|
+
|
|
|
+ return jsonify({
|
|
|
+ 'success': True,
|
|
|
+ 'message': 'DTU配置已更新',
|
|
|
+ 'data': dtu_config
|
|
|
+ })
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"更新DTU配置失败: {str(e)}")
|
|
|
+ return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
+
|
|
|
+
|
|
|
+@app.route('/api/dtu/register', methods=['POST'])
|
|
|
+def manual_dtu_register():
|
|
|
+ """手动触发DTU注册"""
|
|
|
+ try:
|
|
|
+ if not mqtt_status:
|
|
|
+ return jsonify({'success': False, 'message': 'MQTT未连接'}), 400
|
|
|
+
|
|
|
+ success = dtu_register()
|
|
|
+ if success:
|
|
|
+ return jsonify({'success': True, 'message': '注册消息已发送'})
|
|
|
+ else:
|
|
|
+ return jsonify({'success': False, 'message': '注册消息发送失败'}), 500
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"手动触发DTU注册失败: {str(e)}")
|
|
|
+ return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
+
|
|
|
+
|
|
|
+@app.route('/api/dtu/status', methods=['GET'])
|
|
|
+def get_dtu_status():
|
|
|
+ """获取DTU状态"""
|
|
|
+ try:
|
|
|
+ # 获取串口状态
|
|
|
+ serial_st = serial_client.get_status()
|
|
|
+
|
|
|
+ # 获取面板状态
|
|
|
+ devices = address_config.get_stored_devices()
|
|
|
+
|
|
|
+ status = {
|
|
|
+ 'dtu_id': dtu_config.get('dtu_id'),
|
|
|
+ 'mqtt_connected': mqtt_status,
|
|
|
+ 'serial_connected': isinstance(serial_st, dict) and serial_st.get('connected', False),
|
|
|
+ 'dtu_enabled': dtu_config.get('enabled', True),
|
|
|
+ 'topic_prefix': dtu_config.get('topic_prefix'),
|
|
|
+ 'customer_id': dtu_config.get('customer_id'),
|
|
|
+ 'panel_count': len(devices),
|
|
|
+ 'topics': {
|
|
|
+ 'register': build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'register'),
|
|
|
+ 'status': build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'status'),
|
|
|
+ 'control': build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'control'),
|
|
|
+ 'response': build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'response'),
|
|
|
+ 'event': build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'event'),
|
|
|
+ 'alarm': build_dtu_topic(dtu_config['customer_id'], 'dtu', dtu_config['dtu_id'], 'alarm')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return jsonify({'success': True, 'data': status})
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"获取DTU状态失败: {str(e)}")
|
|
|
+ return jsonify({'success': False, 'message': str(e)}), 500
|
|
|
+
|
|
|
+
|
|
|
if __name__ == '__main__':
|
|
|
try:
|
|
|
# 启动前的初始化工作
|