diff --git a/backend/config.ini b/backend/config.ini index 35d88621..149d17f0 100644 --- a/backend/config.ini +++ b/backend/config.ini @@ -29,8 +29,8 @@ fourcc = MJPG backend = directshow [CAMERA2] -enable = False -device_index = 2 +enable = True +device_index = 1 width = 1280 height = 720 fps = 30 diff --git a/backend/devices/device_coordinator.py b/backend/devices/device_coordinator.py index de3f70d9..6f66d0c6 100644 --- a/backend/devices/device_coordinator.py +++ b/backend/devices/device_coordinator.py @@ -849,12 +849,20 @@ class DeviceCoordinator: self.logger.warning(f"设备 {device_name} 连接丢失") self.stats['device_errors'][device_name] += 1 + if self.stats['reconnect_attempts'][device_name] >= 3: + continue + now = time.time() - if now - self._last_restart_ts[device_name] >= 15.0: + if now - self._last_restart_ts[device_name] >= 50.0: self._last_restart_ts[device_name] = now self.logger.info(f"尝试重连设备: {device_name}") if self.restart_device(device_name): self.stats['device_errors'][device_name] = 0 + self.stats['reconnect_attempts'][device_name] = 0 + else: + self.stats['reconnect_attempts'][device_name] += 1 + if self.stats['reconnect_attempts'][device_name] >= 3: + self.logger.error(f"设备 {device_name} 重连失败已达3次,停止自动重试") except Exception as e: self.logger.error(f"检查设备 {device_name} 状态异常: {e}") diff --git a/backend/devices/device_model.py b/backend/devices/device_model.py index 20d7a110..18e76059 100644 --- a/backend/devices/device_model.py +++ b/backend/devices/device_model.py @@ -33,6 +33,37 @@ class DeviceModel: self.isOpen = False self.callback_method = callback_method self.deviceData = {} + self._battery_ts = 0.0 + + @staticmethod + def _battery_percent_from_reg(reg_value: int) -> int: + try: + v = int(reg_value) + except Exception: + return 0 + if v > 396: + return 100 + if v >= 393: + return 90 + if v >= 387: + return 75 + if v >= 382: + return 60 + if v >= 379: + return 50 + if v >= 377: + return 40 + if v >= 373: + return 30 + if v >= 370: + return 20 + if v >= 368: + return 15 + if v >= 350: + return 10 + if v >= 340: + return 5 + return 0 # region 获取设备数据 Obtain device data # 设置设备数据 Set device data @@ -71,34 +102,59 @@ class DeviceModel: notify_characteristic = None self.logger.info("正在匹配服务...") - services = None - for _ in range(3): + await asyncio.sleep(0.3) + services = [] + for i in range(10): + tmp_services = None get_services = getattr(client, 'get_services', None) if callable(get_services): - services = await get_services() - else: + try: + tmp_services = await get_services() + except Exception: + tmp_services = None + if not tmp_services: backend = getattr(client, "_backend", None) backend_get_services = getattr(backend, "get_services", None) if callable(backend_get_services): - services = await backend_get_services() - else: - services = getattr(client, 'services', None) - if services: + try: + tmp_services = await backend_get_services() + except Exception: + tmp_services = None + if not tmp_services: + tmp_services = getattr(client, 'services', None) + + try: + services = list(tmp_services) if tmp_services else [] + except Exception: + services = [] + + for service in services: + try: + svc_uuid = str(getattr(service, "uuid", "") or "").lower() + except Exception: + svc_uuid = "" + if svc_uuid == str(target_service_uuid).lower(): + self.logger.info(f"匹配到服务: {service}") + self.logger.info("正在匹配特征...") + chars = [] + try: + chars = list(getattr(service, "characteristics", None) or []) + except Exception: + chars = [] + for characteristic in chars: + try: + chr_uuid = str(getattr(characteristic, "uuid", "") or "").lower() + except Exception: + chr_uuid = "" + if chr_uuid == str(target_characteristic_uuid_read).lower(): + notify_characteristic = characteristic + if chr_uuid == str(target_characteristic_uuid_write).lower(): + self.writer_characteristic = characteristic + if notify_characteristic: + break + if notify_characteristic: break - await asyncio.sleep(0.2) - if not services: - services = [] - for service in services: - if service.uuid == target_service_uuid: - self.logger.info(f"匹配到服务: {service}") - self.logger.info("正在匹配特征...") - for characteristic in service.characteristics: - if characteristic.uuid == target_characteristic_uuid_read: - notify_characteristic = characteristic - if characteristic.uuid == target_characteristic_uuid_write: - self.writer_characteristic = characteristic - if notify_characteristic: - break + await asyncio.sleep(0.2 + i * 0.1) if notify_characteristic: self.logger.info(f"匹配到特征: {notify_characteristic}") @@ -110,14 +166,33 @@ class DeviceModel: # 保持连接打开 Keep connected and open try: while self.isOpen: + try: + if not bool(getattr(client, "is_connected", False)): + self.isOpen = False + break + except Exception: + self.isOpen = False + break await asyncio.sleep(1) except asyncio.CancelledError: pass finally: # 在退出时停止通知 Stop notification on exit - await client.stop_notify(notify_characteristic.uuid) + try: + await client.stop_notify(notify_characteristic.uuid) + except Exception: + pass else: - self.logger.warning("未找到匹配的服务或特征") + try: + svc_list = [] + for s in services: + try: + svc_list.append(str(getattr(s, "uuid", "") or "")) + except Exception: + pass + self.logger.warning(f"未找到匹配的服务或特征,可用服务: {svc_list}") + except Exception: + self.logger.warning("未找到匹配的服务或特征") raise RuntimeError("未找到匹配的服务或特征") # 关闭设备 close Device @@ -134,24 +209,41 @@ class DeviceModel: if len(self.TempBytes) == 1 and self.TempBytes[0] != 0x55: del self.TempBytes[0] continue - if len(self.TempBytes) == 2 and self.TempBytes[1] != 0x61: - del self.TempBytes[0] - continue if len(self.TempBytes) == 20: self.processData(self.TempBytes) self.TempBytes.clear() # 数据解析 data analysis def processData(self, Bytes): - if Bytes[1] != 0x61: + if Bytes[1] == 0x61: + AngX = self.getSignInt16(Bytes[15] << 8 | Bytes[14]) / 32768 * 180 + AngY = self.getSignInt16(Bytes[17] << 8 | Bytes[16]) / 32768 * 180 + AngZ = self.getSignInt16(Bytes[19] << 8 | Bytes[18]) / 32768 * 180 + self.set("AngX", round(AngX, 3)) + self.set("AngY", round(AngY, 3)) + self.set("AngZ", round(AngZ, 3)) + self.callback_method(self) + return + + if Bytes[1] == 0x71: + start_reg = int(Bytes[2]) + regs = [] + for i in range(8): + base = 4 + i * 2 + if base + 1 >= len(Bytes): + break + regs.append(int(Bytes[base]) | (int(Bytes[base + 1]) << 8)) + for idx, val in enumerate(regs): + self.set(f"Reg_{start_reg + idx:02X}", val) + if regs and start_reg == 0x64: + raw = int(regs[0]) + self.set("BatteryRaw", raw) + self.set("BatteryVoltage", round(raw / 100.0, 2)) + self.set("BatteryPercent", int(self._battery_percent_from_reg(raw))) + self._battery_ts = time.time() + self.set("BatteryTS", self._battery_ts) + self.callback_method(self) return - AngX = self.getSignInt16(Bytes[15] << 8 | Bytes[14]) / 32768 * 180 - AngY = self.getSignInt16(Bytes[17] << 8 | Bytes[16]) / 32768 * 180 - AngZ = self.getSignInt16(Bytes[19] << 8 | Bytes[18]) / 32768 * 180 - self.set("AngX", round(AngX, 3)) - self.set("AngY", round(AngY, 3)) - self.set("AngZ", round(AngZ, 3)) - self.callback_method(self) # 获得int16有符号数 Obtain int16 signed number @staticmethod @@ -175,6 +267,26 @@ class DeviceModel: # 封装读取指令并向串口发送数据 Encapsulate read instructions and send data to the serial port await self.sendData(self.get_readBytes(regAddr)) + async def readBattery(self, timeout: float = 2.0): + if not bool(self.isOpen): + return None + client = getattr(self, "client", None) + if client is None or not bool(getattr(client, "is_connected", False)): + return None + prev_ts = float(self.deviceData.get("BatteryTS", 0.0) or 0.0) + await self.readReg(0x64) + deadline = time.time() + max(0.1, float(timeout)) + while time.time() < deadline: + cur_ts = float(self.deviceData.get("BatteryTS", 0.0) or 0.0) + if cur_ts > prev_ts: + return { + "raw": self.deviceData.get("BatteryRaw"), + "voltage": self.deviceData.get("BatteryVoltage"), + "percent": self.deviceData.get("BatteryPercent"), + } + await asyncio.sleep(0.05) + return None + # 写入寄存器 Write Register async def writeReg(self, regAddr, sValue): # 解锁 unlock diff --git a/backend/devices/imu_manager.py b/backend/devices/imu_manager.py index 54d61e68..bc781a70 100644 --- a/backend/devices/imu_manager.py +++ b/backend/devices/imu_manager.py @@ -42,7 +42,9 @@ class BleIMUDevice: self._device_model = None self._open_task = None self._main_task = None + self._battery_task = None self._last_update_ts = None + self._last_ble_device = None try: from . import device_model as wit_device_model except Exception: @@ -106,7 +108,8 @@ class BleIMUDevice: 'pitch': self.last_data['roll'] # pitch 对应俯仰 }, 'temperature': self.last_data.get('temperature', 25.0), - 'timestamp': datetime.now().isoformat() + 'timestamp': datetime.now().isoformat(), + 'battery': self.last_data.get('battery'), } return self.apply_calibration(raw) if apply_calibration else raw @@ -155,6 +158,14 @@ class BleIMUDevice: async def _disconnect(self): try: + if self._battery_task is not None and not self._battery_task.done(): + self._battery_task.cancel() + try: + await self._battery_task + except asyncio.CancelledError: + pass + except Exception: + pass if self._device_model is not None: try: self._device_model.closeDevice() @@ -175,9 +186,38 @@ class BleIMUDevice: except Exception: pass finally: + self._battery_task = None self._open_task = None self._device_model = None self._last_update_ts = None + self._connected = False + + async def _battery_poll_loop(self, interval_s: float = 30.0): + try: + await asyncio.sleep(1.0) + while self.running: + dm = self._device_model + if dm is None or not bool(getattr(dm, "isOpen", False)): + await asyncio.sleep(1.0) + continue + try: + battery = await dm.readBattery(timeout=2.0) + except asyncio.CancelledError: + raise + except Exception: + battery = None + if isinstance(battery, dict): + battery_payload = { + "raw": battery.get("raw"), + "voltage": battery.get("voltage"), + "percent": battery.get("percent"), + "timestamp": datetime.now().isoformat(), + } + with self._lock: + self.last_data["battery"] = battery_payload + await asyncio.sleep(max(1.0, float(interval_s))) + except asyncio.CancelledError: + pass async def _connect_and_listen(self): try: @@ -187,46 +227,89 @@ class BleIMUDevice: self.running = False return - async def find_device() -> Optional[Any]: - scan_timeout_s = 30.0 - if self.ble_name: - find_by_name = getattr(BleakScanner, "find_device_by_name", None) - if callable(find_by_name): - try: - device = await find_by_name(self.ble_name, timeout=scan_timeout_s) - if device is not None: - if self.mac_address and (getattr(device, "address", "") or "").lower() != self.mac_address.lower(): - return None - return device - except Exception: - pass - try: - found = await BleakScanner.discover(timeout=scan_timeout_s) - except Exception: - found = [] - if self.ble_name: - for d in found: - if (getattr(d, "name", None) or "") != self.ble_name: - continue - if self.mac_address and (getattr(d, "address", "") or "").lower() != self.mac_address.lower(): - continue - return d - if self.mac_address: - target = self.mac_address.lower() - for d in found: - addr = getattr(d, "address", "") or "" - if addr.lower() == target: + async def find_device(total_timeout_s: float = 30.0) -> Optional[Any]: + if self._last_ble_device is not None: + return self._last_ble_device + + find_by_address = getattr(BleakScanner, "find_device_by_address", None) + find_by_name = getattr(BleakScanner, "find_device_by_name", None) + + deadline = time.time() + max(0.1, total_timeout_s) + attempt = 0 + + async def _match_discover(timeout_s: float) -> Optional[Any]: + try: + found = await BleakScanner.discover(timeout=timeout_s) + except Exception: + found = [] + + if self.mac_address: + target = self.mac_address.lower() + for d in found: + addr = (getattr(d, "address", "") or "").lower() + if addr == target: + return d + + if self.ble_name: + for d in found: + if (getattr(d, "name", None) or "") != self.ble_name: + continue + if self.mac_address and (getattr(d, "address", "") or "").lower() != self.mac_address.lower(): + continue return d - candidates = [d for d in found if (getattr(d, "name", "") or "").startswith("WT")] - if len(candidates) == 1: - return candidates[0] + + candidates = [d for d in found if (getattr(d, "name", "") or "").startswith("WT")] + if len(candidates) == 1: + return candidates[0] + return None + + while time.time() < deadline and self.running: + attempt += 1 + remaining = deadline - time.time() + per_try = min(5.0, max(0.2, remaining)) + + strat = attempt % 3 + device = None + + if strat == 1 and self.ble_name and callable(find_by_name): + try: + device = await find_by_name(self.ble_name, timeout=per_try) + except Exception: + device = None + + if device is None and strat == 2 and self.mac_address and callable(find_by_address): + try: + device = await find_by_address(self.mac_address, timeout=per_try) + except TypeError: + try: + device = await find_by_address(self.mac_address, cb=dict(use_bdaddr=False)) + except Exception: + device = None + except Exception: + device = None + + if device is None: + device = await _match_discover(per_try) + + if device is not None: + if self.mac_address and (getattr(device, "address", "") or "").lower() != self.mac_address.lower(): + device = None + elif self.ble_name and getattr(device, "name", None) not in (None, "") and getattr(device, "name", None) != self.ble_name: + device = None + + if device is not None: + self._last_ble_device = device + return device + + await asyncio.sleep(0.2) + return None while self.running: try: attempt_ts = time.perf_counter() logger.info(f"BLE IMU开始扫描并连接: name={self.ble_name}, mac={self.mac_address}") - device = await find_device() + device = await find_device(total_timeout_s=30.0) if device is None: logger.info(f"BLE IMU扫描未发现设备 (耗时: {(time.perf_counter()-attempt_ts)*1000:.1f}ms)") @@ -236,13 +319,14 @@ class BleIMUDevice: device_addr = getattr(device, "address", None) device_name = getattr(device, "name", None) logger.info(f"BLE IMU发现设备 (耗时: {(time.perf_counter()-attempt_ts)*1000:.1f}ms, address={device_addr}, name={device_name})") + self._last_ble_device = device self._connected = False self._last_update_ts = None self._device_model = self._wit_device_model.DeviceModel("WitMotionBle5.0", device, self._on_device_update) self._open_task = asyncio.create_task(self._device_model.openDevice()) ready = False - ready_timeout_s = 20.0 + ready_timeout_s = 30.0 deadline = time.time() + ready_timeout_s while self.running and time.time() < deadline: if self._open_task is not None and self._open_task.done(): @@ -266,23 +350,42 @@ class BleIMUDevice: continue logger.info(f"BLE IMU连接并开始产出数据 (耗时: {(time.perf_counter()-attempt_ts)*1000:.1f}ms)") + try: + if self._battery_task is None or self._battery_task.done(): + self._battery_task = asyncio.create_task(self._battery_poll_loop(interval_s=30.0)) + except Exception: + pass while self.running and self._open_task is not None and not self._open_task.done(): await asyncio.sleep(1.0) await self._disconnect() self._connected = False + self._last_ble_device = None except asyncio.CancelledError: break except Exception as e: logger.error(f"BLE IMU连接/监听失败: {e}", exc_info=True) self._connected = False + self._last_ble_device = None await asyncio.sleep(2.0) @property def connected(self) -> bool: - return self._connected + dm = self._device_model + if dm is None: + return False + if not bool(getattr(dm, 'isOpen', False)): + return False + client = getattr(dm, 'client', None) + if client is not None: + try: + if not bool(getattr(client, 'is_connected', False)): + return False + except Exception: + return False + return True @property def has_received_data(self) -> bool: @@ -304,7 +407,13 @@ class MockIMUDevice: 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.0, - 'temperature': 25.0 + 'temperature': 25.0, + 'battery': { + "raw": None, + "voltage": None, + "percent": 100, + "timestamp": datetime.now().isoformat(), + }, } self._phase = 0.0 self._last_update_ts = None @@ -352,7 +461,8 @@ class MockIMUDevice: 'pitch': self.last_data['roll'] }, 'temperature': self.last_data.get('temperature', 25.0), - 'timestamp': datetime.now().isoformat() + 'timestamp': datetime.now().isoformat(), + 'battery': self.last_data.get('battery'), } return self.apply_calibration(raw) if apply_calibration else raw @@ -815,8 +925,6 @@ class IMUManager(BaseDevice): self.update_heartbeat() except Exception: self.update_heartbeat() - else: - self.update_heartbeat() return connected if hasattr(self.imu_device, 'ser') and getattr(self.imu_device, 'ser', None): diff --git a/backend/devices/imu_test.py b/backend/devices/imu_test.py index e83716e1..f055ce3a 100644 --- a/backend/devices/imu_test.py +++ b/backend/devices/imu_test.py @@ -4,6 +4,7 @@ import time from statistics import mean import bleak +import device_model async def find_device_by_address(address: str, timeout_s: float): @@ -56,13 +57,105 @@ def parse_args(): parser.add_argument("--runs", type=int, default=10) parser.add_argument("--timeout", type=float, default=30.0) parser.add_argument("--cooldown", type=float, default=0.3) - parser.add_argument("--mode", choices=["mac", "name", "both"], default="both") + parser.add_argument("--mode", choices=["mac", "name", "both", "isopen", "battery"], default="both") return parser.parse_args() async def main(): args = parse_args() + if args.mode == "isopen": + device = await find_device_by_name(args.name, args.timeout) + if device is None: + device = await find_device_by_address(args.address, args.timeout) + if device is None: + print("FAIL: 未发现设备") + return + addr = getattr(device, "address", None) + name = getattr(device, "name", None) + if args.address and addr and addr.lower() != args.address.lower(): + print(f"FAIL: 发现设备地址不匹配 found={addr} expected={args.address}") + return + print(f"FOUND address={addr} name={name}") + + first_frame = asyncio.Event() + + def on_update(dm): + if not first_frame.is_set(): + first_frame.set() + + dm = device_model.DeviceModel("imu_test", device, on_update) + task = asyncio.create_task(dm.openDevice()) + + try: + await asyncio.wait_for(first_frame.wait(), timeout=30.0) + print(f"OPENED isOpen={dm.isOpen} client_connected={bool(getattr(getattr(dm, 'client', None), 'is_connected', False))}") + except Exception: + print(f"OPEN_TIMEOUT isOpen={dm.isOpen} client_connected={bool(getattr(getattr(dm, 'client', None), 'is_connected', False))}") + + while True: + client_connected = bool(getattr(getattr(dm, "client", None), "is_connected", False)) + print(f"STATUS isOpen={dm.isOpen} client_connected={client_connected}") + if not dm.isOpen: + break + await asyncio.sleep(1.0) + + try: + await asyncio.wait_for(task, timeout=5.0) + except Exception: + try: + task.cancel() + except Exception: + pass + print("DONE") + return + + if args.mode == "battery": + device = await find_device_by_name(args.name, args.timeout) + if device is None: + device = await find_device_by_address(args.address, args.timeout) + if device is None: + print("FAIL: 未发现设备") + return + addr = getattr(device, "address", None) + name = getattr(device, "name", None) + if args.address and addr and addr.lower() != args.address.lower(): + print(f"FAIL: 发现设备地址不匹配 found={addr} expected={args.address}") + return + print(f"FOUND address={addr} name={name}") + + first_frame = asyncio.Event() + + def on_update(dm): + if not first_frame.is_set(): + first_frame.set() + + dm = device_model.DeviceModel("imu_test", device, on_update) + task = asyncio.create_task(dm.openDevice()) + + try: + await asyncio.wait_for(first_frame.wait(), timeout=30.0) + print("OPENED") + except Exception: + print("OPEN_TIMEOUT") + + info = await dm.readBattery(timeout=3.0) + print(f"BATTERY {info}") + + try: + dm.closeDevice() + except Exception: + pass + try: + await asyncio.wait_for(task, timeout=5.0) + except Exception: + try: + task.cancel() + except Exception: + pass + print("DONE") + return + if args.mode in ("mac", "both"): await run_trials( "mac", diff --git a/backend/main.py b/backend/main.py index bc44da7e..0fb57305 100644 --- a/backend/main.py +++ b/backend/main.py @@ -270,6 +270,10 @@ class AppServer: self.logger.info('开始初始化设备...') if self.device_coordinator.initialize(): self.logger.info('设备协调器初始化完成') + try: + self.device_coordinator.set_status_change_callback(self._on_device_status_change) + except Exception as e: + self.logger.error(f'注册设备状态变化回调失败: {e}') # 获取设备管理器实例 self.device_managers = self.device_coordinator.get_device_managers() @@ -1969,6 +1973,10 @@ class AppServer: try: self.logger.info(f'开始重启 {device_type} 设备...') + try: + self.broadcast_device_status(device_type, False) + except Exception: + pass # 调用设备协调器的重启方法 with self._get_device_lock(device_type): @@ -1976,6 +1984,10 @@ class AppServer: if success: self.logger.info(f'{device_type} 设备重启成功') + try: + self.broadcast_device_status(device_type, True) + except Exception: + pass # 发送重启成功事件到前端 self.socketio.emit('device_restart_message', { @@ -1986,6 +1998,10 @@ class AppServer: return True else: self.logger.error(f'{device_type} 设备重启失败!') + try: + self.broadcast_device_status(device_type, False) + except Exception: + pass # 发送重启失败事件到前端 self.socketio.emit('device_restart_message', { 'device_type': device_type, @@ -2255,7 +2271,7 @@ def main(): """主函数""" # 解析命令行参数 parser = argparse.ArgumentParser(description='Body Balance Evaluation System Backend') - parser.add_argument('--host', default='localhost', help='Host address to bind to') + parser.add_argument('--host', default='0.0.0.0', help='Host address to bind to') parser.add_argument('--port', type=int, default=5000, help='Port number to bind to') parser.add_argument('--debug', action='store_true', help='Enable debug mode') args = parser.parse_args() diff --git a/config.ini b/config.ini index 8bbec20d..a2a76567 100644 --- a/config.ini +++ b/config.ini @@ -35,7 +35,7 @@ chart_dpi = 300 export_format = csv [SECURITY] -secret_key = f50c705c26a963701a4832ae3d69a091674f587a4b02da8b1c59909c0bd312fe +secret_key = 855842922ac3d1747493bcf40f0b2534387ac6304b903c901cf980e4059d5150 session_timeout = 3600 max_login_attempts = 5 diff --git a/frontend/src/renderer/src/views/Detection.vue b/frontend/src/renderer/src/views/Detection.vue index 7e167529..d2d58a3a 100644 --- a/frontend/src/renderer/src/views/Detection.vue +++ b/frontend/src/renderer/src/views/Detection.vue @@ -83,7 +83,10 @@
-
头部姿态
+
+ 头部姿态 + 电量{{ imuBatteryPercent }}% +
校准 @@ -1230,6 +1233,7 @@ const headlist = ref({ tilt: 0, pitch: 0 }) +const imuBatteryPercent = ref(null) // 开始计时器 const startTimer = () => { if (isRunning.value) return; @@ -1781,6 +1785,14 @@ const IMU_CHANGE_EPS = 0.1 // 小于0.1°的变化忽略 function handleIMUData(data) { try { if (!data) return + + const batteryPercent = data && data.battery && data.battery.percent + if (batteryPercent !== undefined && batteryPercent !== null) { + const v = Number(batteryPercent) + if (!Number.isNaN(v) && Number.isFinite(v)) { + imuBatteryPercent.value = Math.max(0, Math.min(100, Math.round(v))) + } + } // 兼容两种载荷结构: // 1) { rotation, tilt, pitch } @@ -2620,17 +2632,28 @@ function refreshClick(type) { ElMessage.warning(`🚀 发送重启设备请求...`) if (devicesSocket && devicesSocket.connected) { if(type == 'camera1'){ + camera1Status.value = '未连接' devicesSocket.emit('restart_device', { device_type: 'camera1' }) }else if(type == 'camera2'){ + camera2Status.value = '未连接' devicesSocket.emit('restart_device', { device_type: 'camera2' }) }else if(type == 'femtobolt'){ + femtoboltStatus.value = '未连接' devicesSocket.emit('restart_device', { device_type: 'femtobolt' }) }else if(type == 'imu'){ + imuStatus.value = '未连接' devicesSocket.emit('restart_device', { device_type: 'imu' }) }else if(type == 'pressure'){ + pressureStatus.value = '未连接' devicesSocket.emit('restart_device', { device_type: 'pressure' }) }else if(type == 'remote'){ + remoteStatus.value = '未连接' devicesSocket.emit('restart_device', { device_type: 'remote' }) + }else if(type == 'camera'){ + camera1Status.value = '未连接' + camera2Status.value = '未连接' + devicesSocket.emit('restart_device', { device_type: 'camera1' }) + devicesSocket.emit('restart_device', { device_type: 'camera2' }) } } else { console.warn('⚠️ Socket服务未连接,无法重启设备!') @@ -2841,6 +2864,13 @@ function viewClick(e){ font-style: normal; font-size: 14px; } +.imu-battery-percent{ + margin-left: 10px; + font-weight: 400; + font-style: normal; + font-size: 14px; + color: rgba(255, 255, 255, 0.8); +} .body-header-bottombox{ width: 100%; @@ -3653,4 +3683,4 @@ function viewClick(e){ .pop-up-camera-display .el-checkbox__inner:hover{ border-color: #14aaff; } - \ No newline at end of file +