修正了设备未连接的状态错误

This commit is contained in:
root 2025-08-17 17:39:04 +08:00
parent 50a0fe8641
commit 4e89ab6107
7 changed files with 168 additions and 18 deletions

View File

@ -41,6 +41,9 @@ class BaseDevice(ABC):
self._socketio = None
self._last_heartbeat = time.time()
# 状态变化回调
self._status_change_callbacks = []
# 设备状态信息
self._device_info = {
'name': device_name,
@ -133,6 +136,53 @@ class BaseDevice(ABC):
socketio: SocketIO实例
"""
self._socketio = socketio
def add_status_change_callback(self, callback):
"""
添加状态变化回调函数
Args:
callback: 回调函数接收参数 (device_name, is_connected)
"""
if callback not in self._status_change_callbacks:
self._status_change_callbacks.append(callback)
def remove_status_change_callback(self, callback):
"""
移除状态变化回调函数
Args:
callback: 要移除的回调函数
"""
if callback in self._status_change_callbacks:
self._status_change_callbacks.remove(callback)
def _notify_status_change(self, is_connected: bool):
"""
通知状态变化
Args:
is_connected: 连接状态
"""
for callback in self._status_change_callbacks:
try:
callback(self.device_name, is_connected)
except Exception as e:
self.logger.error(f"状态变化回调执行失败: {e}")
def set_connected(self, is_connected: bool):
"""
设置连接状态并触发回调
Args:
is_connected: 连接状态
"""
old_status = self.is_connected
self.is_connected = is_connected
# 只有状态真正改变时才触发回调
if old_status != is_connected:
self._notify_status_change(is_connected)
def emit_data(self, event: str, data: Any, namespace: Optional[str] = None):
"""

View File

@ -316,6 +316,13 @@ class IMUManager(BaseDevice):
if use_real_device:
self.logger.info(f"使用真实IMU设备 - 端口: {self.port}, 波特率: {self.baudrate}")
self.imu_device = RealIMUDevice(self.port, self.baudrate)
# 检查真实设备是否连接成功
if self.imu_device.ser is None:
self.logger.error(f"IMU设备连接失败: 无法打开串口 {self.port}")
self.is_connected = False
self.imu_device = None
return False
else:
self.logger.info("使用模拟IMU设备")
self.imu_device = MockIMUDevice()

View File

@ -15,7 +15,7 @@ backup_interval = 24
max_backups = 7
[CAMERA]
device_index = 3
device_index = 0
width = 1280
height = 720
fps = 30

View File

@ -198,6 +198,12 @@ class AppServer:
'imu': IMUManager(self.socketio, self.config_manager),
'pressure': PressureManager(self.socketio, self.config_manager)
}
# 为每个设备添加状态变化回调
for device_name, manager in self.device_managers.items():
if manager and hasattr(manager, 'add_status_change_callback'):
manager.add_status_change_callback(self._on_device_status_change)
self.logger.info('设备管理器初始化完成')
# 初始化设备协调器
@ -933,6 +939,9 @@ class AppServer:
self.logger.info('设备命名空间客户端连接')
emit('status', {'message': '设备命名空间连接成功'}, namespace='/devices')
# 连接时发送当前所有设备的状态
self.broadcast_all_device_status()
@self.socketio.on('disconnect', namespace='/devices')
def handle_devices_disconnect():
self.logger.info('设备命名空间客户端断开连接')
@ -1047,6 +1056,11 @@ class AppServer:
# 输出启动结果摘要
successful_devices = [name for name, success in device_results.items() if success]
# 广播设备状态更新
for device_name, success in device_results.items():
self.broadcast_device_status(device_name, success)
if successful_devices:
self.logger.info(f'成功启动的设备: {", ".join(successful_devices)}')
if failed_devices:
@ -1076,13 +1090,54 @@ class AppServer:
manager.stop_streaming()
manager.disconnect()
self.logger.info(f'{device_name}设备已停止')
# 广播设备状态为未连接
self.broadcast_device_status(device_name, False)
except Exception as e:
self.logger.error(f'停止{device_name}设备失败: {e}')
# 即使停止失败也广播为未连接状态
self.broadcast_device_status(device_name, False)
self.logger.info('设备数据推送已停止')
except Exception as e:
self.logger.error(f'停止设备数据推送失败: {e}')
def broadcast_device_status(self, device_name: str, is_connected: bool):
"""广播单个设备状态"""
if self.socketio:
try:
status_data = {
'device_type': device_name,
'status': is_connected,
'timestamp': datetime.now().isoformat()
}
self.socketio.emit('device_status', status_data, namespace='/devices')
self.logger.info(f'广播设备状态: {device_name} -> {"已连接" if is_connected else "未连接"}')
except Exception as e:
self.logger.error(f'广播设备状态失败: {e}')
def broadcast_all_device_status(self):
"""广播所有设备状态"""
for device_name, manager in self.device_managers.items():
if manager is not None:
try:
# 检查设备是否连接使用is_connected属性
is_connected = hasattr(manager, 'is_connected') and getattr(manager, 'is_connected', False)
self.broadcast_device_status(device_name, is_connected)
except Exception as e:
self.logger.error(f'检查{device_name}设备状态失败: {e}')
self.broadcast_device_status(device_name, False)
def _on_device_status_change(self, device_name: str, is_connected: bool):
"""
设备状态变化回调函数
Args:
device_name: 设备名称
is_connected: 连接状态
"""
self.logger.info(f'设备状态变化: {device_name} -> {"已连接" if is_connected else "未连接"}')
self.broadcast_device_status(device_name, is_connected)
def _detection_worker(self, detection_id, duration):

View File

@ -0,0 +1,5 @@
<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="#323232"/>
<rect x="10" y="10" width="280" height="180" fill="none" stroke="#666" stroke-width="2" stroke-dasharray="5,5"/>
<text x="150" y="105" font-family="Arial, sans-serif" font-size="18" fill="#999" text-anchor="middle">无图片</text>
</svg>

After

Width:  |  Height:  |  Size: 360 B

View File

@ -58,12 +58,12 @@
身体姿态
</div>
</div>
<div :style="{ color: videoStatus == '已连接' ? '#00CC33' : '#808080' }" style="font-size: 14px;">
{{ videoStatus }}</div>
<div :style="{ color: femtoboltStatus == '已连接' ? '#00CC33' : '#808080' }" style="font-size: 14px;">
{{ femtoboltStatus }}</div>
</div>
<div style="display: flex;justify-content: center;height: 100%;padding-top: 0px;">
<!-- 使用深度相机视频流替换静态图片 -->
<img :src="depthCameraImgSrc || '@/assets/posture.png'" alt="深度相机视频流"
<img :src="(femtoboltStatus === '已连接' && depthCameraImgSrc) ? depthCameraImgSrc : noImageSvg" alt="深度相机视频流"
style="width: 100%;height: calc(100% - 10px);object-fit:contain;background:#323232;">
</div>
</div>
@ -199,7 +199,7 @@
</div>
</div>
<div style="position: relative;width: 300px;height: 300px;">
<img :src="footImgSrc" style="width: 300px;height: 300px;" alt="">
<img :src="(pressureStatus === '已连接' && footImgSrc) ? footImgSrc : noImageSvg" style="width: 300px;height: 300px;" alt="">
<div class="xline"></div>
<div class="yline"></div>
</div>
@ -328,12 +328,11 @@
视频
</div>
</div>
<div :style="{ color: videoStatus == '已连接' ? '#00CC33' : '#808080' }" style="font-size: 14px;">{{
videoStatus }}</div>
<div :style="{ color: cameraStatus == '已连接' ? '#00CC33' : '#808080' }" style="font-size: 14px;">{{ cameraStatus }}</div>
</div>
</div>
<!-- 使用img元素显示视频流优化的Data URL方案 -->
<img :src="rtspImgSrc" alt=""
<img :src="(cameraStatus === '已连接' && rtspImgSrc) ? rtspImgSrc : noImageSvg" alt=""
style="width: 100%;height: calc(100% - 80px);object-fit:contain;background:#323232;" />
</div>
</div>
@ -497,6 +496,7 @@ import Header from '@/views/Header.vue'
import { useAuthStore } from '../stores/index.js'
import * as echarts from 'echarts'
import { getBackendUrl, patientAPI } from '../services/api.js'
import noImageSvg from '@/assets/no-image.svg'
const authStore = useAuthStore()
const router = useRouter()
const route = useRoute()
@ -672,9 +672,14 @@ const chartoption = ref({
}
]
})
const videoStatus = ref('未连接')
const pressureStatus = ref('未连接')
const imuStatus = ref('未连接')
//
const cameraStatus = ref('未连接') //
const femtoboltStatus = ref('未连接') // (FemtoBolt)
const imuStatus = ref('未连接') // IMU
const pressureStatus = ref('未连接') //
// videoStatuscameraStatus
const videoStatus = computed(() => cameraStatus.value)
//
const seconds = ref(0);
const isRunning = ref(false);
@ -902,9 +907,6 @@ function connectWebSocket() {
//
devicesSocket.on('connect', () => {
console.log('🔗 设备命名空间连接成功')
videoStatus.value = '已连接'
imuStatus.value = '已连接'
pressureStatus.value = '已连接'
//
devicesSocket.emit('subscribe_device', { device_type: 'camera' })
@ -918,7 +920,9 @@ function connectWebSocket() {
devicesSocket.on('disconnect', () => {
console.log('🔗 设备命名空间断开连接')
videoStatus.value = '未连接'
//
cameraStatus.value = '未连接'
femtoboltStatus.value = '未连接'
imuStatus.value = '未连接'
pressureStatus.value = '未连接'
})
@ -963,6 +967,34 @@ function connectWebSocket() {
console.error('❌ 设备数据推送错误:', data.message)
}
})
//
devicesSocket.on('device_status', (data) => {
console.log('📱 设备状态更新:', data)
const { device_type, status } = data
const statusText = status ? '已连接' : '未连接'
switch (device_type) {
case 'camera':
cameraStatus.value = statusText
console.log(`📷 相机状态: ${statusText}`)
break
case 'femtobolt':
femtoboltStatus.value = statusText
console.log(`🔍 深度相机状态: ${statusText}`)
break
case 'imu':
imuStatus.value = statusText
console.log(`🧭 IMU状态: ${statusText}`)
break
case 'pressure':
pressureStatus.value = statusText
console.log(`⚖️ 压力传感器状态: ${statusText}`)
break
default:
console.warn('⚠️ 未知设备类型:', device_type)
}
})
} catch (error) {
console.error('💥 连接异常:', error.message)
@ -1023,8 +1055,9 @@ function disconnectWebSocket() {
console.log('🔗 统一设备命名空间连接已断开')
}
//
videoStatus.value = '未连接'
//
cameraStatus.value = '未连接'
femtoboltStatus.value = '未连接'
imuStatus.value = '未连接'
pressureStatus.value = '未连接'
}

View File

@ -23,7 +23,7 @@ export default defineConfig({
}
},
server: {
port: 3002,
port: 3000,
host: '0.0.0.0',
// 开发服务器配置
cors: true,