AutoHotKey V2: Выполнение HTTP-запроса при событии PBT_APMSUSPEND иногда не удается. Windows не дает достаточно времени, чтобы что-либо сделать перед переходом в спящий режим.

Вопрос или проблема

Я пытаюсь автоматизировать выключение моего miniDSP Flex, когда я ставлю компьютер в спящий режим (или гибернацию), если miniDSP в данный момент включен. Скрипт ниже отправляет HTTP-запрос на обучающий пульт через его API, когда я ставлю компьютер в спящий режим (если miniDSP включен). Пульт затем переключает питание моего miniDSP, отправляя обученный ИК-сигнал.

Я пробовал слушать событие PBT_APMSUSPEND. К сожалению, это не всегда работает: Windows не дает скрипту достаточно времени, чтобы сделать что-то полезное. HTTP-запрос на выключение моего miniDSP иногда не выполняется до того, как компьютер переходит в спящий режим. Когда я возобновляю работу компьютера, запрос отправляется, в результате чего miniDSP выключается после возобновления.

Я уже пробовал перенести запрос состояния питания miniDSP вне функции-обработчика PBT_APMSUSPEND, потому что проверка, включен ли miniDSP, с помощью minidsp-rs занимает слишком много времени. Даже с этим HTTP-запрос иногда не завершается до сна.

Есть ли какие-либо обходные пути? Или есть другой способ автоматизировать выключение miniDSP?

Еще одним решением, которое может сработать, может стать установка новой горячей клавиши, которая выключает miniDSP, а затем переводит систему в спящий режим. Я должен помнить, чтобы ставить компьютер в спящий режим только с помощью этой горячей клавиши.

К сожалению, minidsp-rs, похоже, не имеет команды для выключения miniDSP.

MiniDSPExe := "C:\miniDSP\minidsp.exe"
MiniDSPTurnedOn := false
RemoURL := "http://192.168.50.73/messages"
RemoRequestBody := FileRead("toggle_power.json")

LogFile := "C:\miniDSPAutoToggler\MiniDSPAutoToggler.log"

WHR := ComObject("WinHttp.WinHttpRequest.5.1")

WM_POWERBROADCAST := 0x218
PBT_APMSUSPEND := 4

; file log
flog(params*){
    ts := FormatTime(, "yyyy-MM-dd HH:mm:ss.") substr(A_TickCount,-3)

    for ,param in params
      message .= param . " "
    FileAppend ts " " message "`n", LogFile
}

flog("Запуск miniDSPAutoToggler.ahk")

_WM_POWERBROADCAST(wParam, lParam, msg, hwnd) {
    Critical(1000)
    flog "wParam " wParam
    if (wParam = PBT_APMSUSPEND) {
        flog "Система переходит в спящий режим"
        ToggleMiniDSP(false)
    }
}

LogMiniDSPState() {
    flog "miniDSP включен: " MiniDSPTurnedOn
}

RefreshMiniDSPState() {
    global MiniDSPTurnedOn
    exitCode := RunWait(MiniDSPExe, , "Hide")
    MiniDSPTurnedOn := exitCode == 0
    LogMiniDSPState()
}

ToggleMiniDSP(turnOn) {
    global MiniDSPTurnedOn
    if (MiniDSPTurnedOn != turnOn) {
        WHR.Open("POST", remoURL, false)
        WHR.SetRequestHeader("X-Requested-With", "local")
        WHR.Send(remoRequestBody)
        status := WHR.Status
        if (status = 200) {
            flog "Успешно отправлен HTTP-запрос к Nature Remo"
        } else {
            flog "HTTP-запрос к remo завершился с кодом состояния " status
        }
    } else {
        flog "miniDSP уже в желаемом состоянии питания"
    }

    MiniDSPTurnedOn := turnOn
    LogMiniDSPState()

    return true
}

RefreshMiniDSPState()
SetTimer(RefreshMiniDSPState, 60000)

OnMessage(WM_POWERBROADCAST, _WM_POWERBROADCAST)

Ответ или решение

Ваша задача по автоматизации отключения устройства miniDSP Flex перед переходом компьютера в спящий режим действительно является интересной и требует тонкого подхода, так как обработка событий отказа от питания в Windows может не предоставлять достаточного времени для завершения HTTP-запросов. Рассмотрим более детально, как можно улучшить работу вашего скрипта на AutoHotKey V2, чтобы устранить описанную вами проблему.

Проблема

Вы столкнулись с трудностью: при переходе системы в спящий режим время выполнения вашего скрипта недостаточно для отправки HTTP-запроса, что приводит к тому, что комманда на отключение устройства miniDSP выполняется только после пробуждения системы. Это происходит из-за того, что Windows обрабатывает переход в спящий режим очень быстро, и ваш скрипт не успевает завершить запрос.

Потенциальные Решения

  1. Изменение Стратегии Обработки Событий:
    Вместо того чтобы обрабатывать явное событие PBT_APMSUSPEND, вы можете рассмотреть вариант с использованием таймера, который будет контролировать состояние miniDSP перед потенциальным переходом системы в спящий режим. Это позволило бы разделить логику проверки состояния устройства и отправку запроса.

  2. Использование асинхронной отправки запросов:
    Модифицируйте ваш HTTP-запрос так, чтобы он выполнялся асинхронно. Это можно реализовать с помощью Async функций, что позволило бы избежать блокировок на время выполнения запросов.

  3. Создание Горячей Клавиши для Управления:
    Как вы упомянули в своем вопросе, создание отдельной горячей клавиши для отключения miniDSP перед переходом в спящий режим может стать хорошим решением. Этот подход предполагает выполнение двух команд под единым триггером, что устраняет необходимость ожидания ответа от системы при получении события PBT_APMSUSPEND.

    ^j:: ; Control + J для отключения миниDSP и перехода в сон
       RefreshMiniDSPState() ; Проверка состояния
       if (MiniDSPTurnedOn) {
           ToggleMiniDSP(false) ; Отключение миниDSP
           Sleep(500) ; Небольшая пауза для завершения запроса
       }
       Sleep(1000) ; Небольшая задержка для успеха выполнения команды
       Sleep, 1000 ; может быть и степенями в другой подход
       Send {LWin Down}{u Down}{u Up}{LWin Up} ; команды для перехода в сон
  4. Логирование и Отладка:
    Убедитесь, что ваше логирование достаточно детально. Если запрос завершается неудачно, важно отслеживать это и вносить изменения в код. Вы можете улучшить сообщение о статусе, например, дополнить его более детальными данными.

Оптимизация вашего скрипта

Вот обновленная версия скрипта, которая учитывает вышеперечисленные рекомендации:

MiniDSPExe := "C:\miniDSP\minidsp.exe"
MiniDSPTurnedOn := false
RemoURL := "http://192.168.50.73/messages"
RemoRequestBody := FileRead("toggle_power.json")

LogFile := "C:\miniDSPAutoToggler\MiniDSPAutoToggler.log"

WHR := ComObject("WinHttp.WinHttpRequest.5.1")

WM_POWERBROADCAST := 0x218
PBT_APMSUSPEND := 4

flog(params*) {
    ts := FormatTime(, "yyyy-MM-dd HH:mm:ss.") substr(A_TickCount, -3)
    for param in params
        message .= param . " "
    FileAppend ts " " message "`n", LogFile
}

flog("Started miniDSPAutoToggler.ahk")

WM_POWERBROADCAST(wParam, lParam) {
    if (wParam = PBT_APMSUSPEND) {
        flog "The system is entering a suspended state"
        ToggleMiniDSP(false)
    }
}

ToggleMiniDSP(turnOn) {
    global MiniDSPTurnedOn
    if (MiniDSPTurnedOn != turnOn) {
        WHR.Open("POST", RemoURL, false)
        WHR.SetRequestHeader("X-Requested-With", "local")
        WHR.Send(RemoRequestBody)
        if (WHR.Status = 200) {
            flog "Successfully sent HTTP request"
        } else {
            flog "HTTP request failed with status code: " WHR.Status
        }
    }
    MiniDSPTurnedOn := turnOn
}

RefreshMiniDSPState() {
    global MiniDSPTurnedOn
    exitCode := RunWait(MiniDSPExe, , "Hide")
    MiniDSPTurnedOn := (exitCode == 0)
}

OnMessage(WM_POWERBROADCAST, WM_POWERBROADCAST)
SetTimer(RefreshMiniDSPState, 60000)

return

Заключение

Способы решения вашей проблемы разнообразны, и каждая выделенная стратегия имеет свои особенности. Я рекомендую протестировать предложенные модификации и проследить за логами, чтобы убедиться, что ваш скрипт работает стабильно и соответствует вашим требованиям. Используя предложенные методы, вы сможете эффективно управлять состоянием вашего miniDSP Flex перед переходом компьютера в спящий режим.

Оцените материал
Добавить комментарий

Капча загружается...