From ba6ec56cee13388d53e57f4960f87dfa407b6c48 Mon Sep 17 00:00:00 2001 From: Fridayssheep <18313899771@163.com> Date: Wed, 11 Feb 2026 15:16:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=20=E4=BF=AE=E5=A4=8D=E4=BA=86=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4=E5=AF=B9=E8=AF=9D=E6=A1=86=E6=93=8D=E4=BD=9C=E7=9A=84?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=9C=A8=E7=82=B9=E5=87=BB=E6=97=B6=E8=A2=AB?= =?UTF-8?q?=E9=87=8D=E7=BD=AE=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atx/executor.rs | 7 +++++++ src/atx/types.rs | 2 +- src/web/handlers/mod.rs | 1 + web/src/components/AtxPopover.vue | 31 +++++++++++++++++++------------ web/src/views/ConsoleView.vue | 8 ++++++-- web/src/views/SettingsView.vue | 4 ++-- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/atx/executor.rs b/src/atx/executor.rs index 80ddab3d..d45af70d 100644 --- a/src/atx/executor.rs +++ b/src/atx/executor.rs @@ -258,6 +258,7 @@ impl AtxKeyExecutor { /// Pulse Serial relay async fn pulse_serial(&self, duration: Duration) -> Result<()> { + info!("Pulse serial relay on {} pin {}", self.config.device, self.config.pin); // Turn relay on self.send_serial_relay_command(true)?; @@ -272,13 +273,19 @@ impl AtxKeyExecutor { /// Send Serial relay command using cached handle fn send_serial_relay_command(&self, on: bool) -> Result<()> { + // user config pin should be 1 for most LCUS modules (A0 01 01 A2) + // if user set 0, it will send A0 00 01 A1 which might not work let channel = self.config.pin as u8; // LCUS-Type Protocol + // Frame: [StopByte(A0), Channel, State, Checksum] // Checksum = A0 + channel + state let state = if on { 1 } else { 0 }; let checksum = 0xA0u8.wrapping_add(channel).wrapping_add(state); + // Example for Channel 1: + // ON: A0 01 01 A2 + // OFF: A0 01 00 A1 let cmd = [0xA0, channel, state, checksum]; let mut guard = self.serial_handle.lock().unwrap(); diff --git a/src/atx/types.rs b/src/atx/types.rs index e0cc0848..8e3060f9 100644 --- a/src/atx/types.rs +++ b/src/atx/types.rs @@ -33,7 +33,7 @@ pub enum AtxDriverType { Gpio, /// USB HID relay module UsbRelay, - /// Serial/COM port relay (LCUS type) + /// Serial/COM port relay (taobao LCUS type) Serial, /// Disabled / Not configured None, diff --git a/src/web/handlers/mod.rs b/src/web/handlers/mod.rs index ea0d077f..7321d7bf 100644 --- a/src/web/handlers/mod.rs +++ b/src/web/handlers/mod.rs @@ -2641,6 +2641,7 @@ pub async fn atx_power( State(state): State>, Json(req): Json, ) -> Result> { + tracing::info!("Received ATX power request: action={}", req.action); let atx_guard = state.atx.read().await; let atx = atx_guard .as_ref() diff --git a/web/src/components/AtxPopover.vue b/web/src/components/AtxPopover.vue index 3d70fe78..23483494 100644 --- a/web/src/components/AtxPopover.vue +++ b/web/src/components/AtxPopover.vue @@ -33,7 +33,9 @@ const activeTab = ref('atx') // ATX state const powerState = ref<'on' | 'off' | 'unknown'>('unknown') -const confirmAction = ref<'short' | 'long' | 'reset' | null>(null) +// Decouple action data from dialog visibility to prevent race conditions +const pendingAction = ref<'short' | 'long' | 'reset' | null>(null) +const confirmDialogOpen = ref(false) // WOL state const wolMacAddress = ref('') @@ -56,15 +58,21 @@ const powerStateText = computed(() => { } }) +function requestAction(action: 'short' | 'long' | 'reset') { + pendingAction.value = action + confirmDialogOpen.value = true +} + function handleAction() { - if (confirmAction.value === 'short') emit('powerShort') - else if (confirmAction.value === 'long') emit('powerLong') - else if (confirmAction.value === 'reset') emit('reset') - confirmAction.value = null + console.log('[AtxPopover] Confirming action:', pendingAction.value) + if (pendingAction.value === 'short') emit('powerShort') + else if (pendingAction.value === 'long') emit('powerLong') + else if (pendingAction.value === 'reset') emit('reset') + confirmDialogOpen.value = false } const confirmTitle = computed(() => { - switch (confirmAction.value) { + switch (pendingAction.value) { case 'short': return t('atx.confirmShortTitle') case 'long': return t('atx.confirmLongTitle') case 'reset': return t('atx.confirmResetTitle') @@ -73,14 +81,13 @@ const confirmTitle = computed(() => { }) const confirmDescription = computed(() => { - switch (confirmAction.value) { + switch (pendingAction.value) { case 'short': return t('atx.confirmShortDesc') case 'long': return t('atx.confirmLongDesc') case 'reset': return t('atx.confirmResetDesc') default: return '' } }) - // MAC address validation const isValidMac = computed(() => { const mac = wolMacAddress.value.trim() @@ -169,7 +176,7 @@ if (savedHistory) { variant="outline" size="sm" class="w-full justify-start gap-2 h-8 text-xs" - @click="confirmAction = 'short'" + @click="requestAction('short')" > {{ t('atx.shortPress') }} @@ -179,7 +186,7 @@ if (savedHistory) { variant="outline" size="sm" class="w-full justify-start gap-2 h-8 text-xs text-orange-600 hover:text-orange-700 hover:bg-orange-50 dark:hover:bg-orange-950" - @click="confirmAction = 'long'" + @click="requestAction('long')" > {{ t('atx.longPress') }} @@ -189,7 +196,7 @@ if (savedHistory) { variant="outline" size="sm" class="w-full justify-start gap-2 h-8 text-xs text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-950" - @click="confirmAction = 'reset'" + @click="requestAction('reset')" > {{ t('atx.reset') }} @@ -247,7 +254,7 @@ if (savedHistory) { - + {{ confirmTitle }} diff --git a/web/src/views/ConsoleView.vue b/web/src/views/ConsoleView.vue index b4c19bae..81517d3b 100644 --- a/web/src/views/ConsoleView.vue +++ b/web/src/views/ConsoleView.vue @@ -1310,15 +1310,19 @@ function openTerminalInNewTab() { // ATX actions async function handlePowerShort() { + console.log('[ConsoleView] Handling power short press') try { - await atxApi.power('short') + const res = await atxApi.power('short') + console.log('[ConsoleView] Power short API result:', res) await systemStore.fetchAtxState() - } catch { + } catch (e) { + console.error('[ConsoleView] Power short API failed:', e) // ATX action failed } } async function handlePowerLong() { + console.log('[ConsoleView] Handling power long press') try { await atxApi.power('long') await systemStore.fetchAtxState() diff --git a/web/src/views/SettingsView.vue b/web/src/views/SettingsView.vue index b42eb114..41cf21c7 100644 --- a/web/src/views/SettingsView.vue +++ b/web/src/views/SettingsView.vue @@ -930,6 +930,7 @@ async function saveAtxConfig() { driver: atxConfig.value.power.driver, device: atxConfig.value.power.device || undefined, pin: atxConfig.value.power.pin, + active_level: atxConfig.value.power.active_level, baud_rate: atxConfig.value.power.baud_rate, }, reset: { @@ -937,8 +938,7 @@ async function saveAtxConfig() { device: atxConfig.value.reset.device || undefined, pin: atxConfig.value.reset.pin, active_level: atxConfig.value.reset.active_level, - baud_rate: atxConfig.value.reset.baud_rate - active_level: atxConfig.value.reset.active_level, + baud_rate: atxConfig.value.reset.baud_rate, }, led: { enabled: atxConfig.value.led.enabled,