Last active
July 11, 2024 18:19
-
-
Save todbot/5cd232e16c7a67bd2172d6719f8a8518 to your computer and use it in GitHub Desktop.
Sleep a Windows box with CircuitPython using USB HID
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-FileCopyrightText: Copyright (c) 2023 Tod Kurt | |
# | |
# SPDX-License-Identifier: MIT | |
""" | |
`sleepy_keys` | |
============= | |
HID System Control Powerdown / Sleep / Wake device helper library | |
* Author(s): Tod Kurt | |
Implementation Notes | |
-------------------- | |
**Software and Dependencies:** | |
* Adafruit CircuitPython firmware for the supported boards: | |
https://github.com/adafruit/circuitpython/releases | |
**Reference:*** | |
* "Input Device Class Power Management Reference Specification, v. 2.0 " | |
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/Inpmspc.rtf | |
* "HID Usage Tables, section 4.5.1" | |
https://www.usb.org/document-library/hid-usage-tables-14 | |
""" | |
import time | |
import usb_hid | |
from adafruit_hid import find_device | |
def device(report_id: int = 4) -> usb_hid.Device: | |
"""Create a `usb_hid.Device` for System Control Power buttons | |
:param int report_id: The report ID to use for the device. | |
""" | |
return usb_hid.Device( | |
# fmt: off | |
report_descriptor=bytes(( | |
0x05, 0x01, # Usage Page (Generic Desktop Ctrls) | |
0x09, 0x80, # Usage (Sys Control) | |
0xA1, 0x01, # Collection (Application) | |
0x85, 0x04, # Report ID (4) | |
0x75, 0x02, # Report Size (2) | |
0x95, 0x01, # Report Count (1) | |
0x15, 0x01, # Logical Minimum (1) | |
0x25, 0x03, # Logical Maximum (3) | |
0x09, 0x82, # Usage (Sys Sleep) | |
0x09, 0x81, # Usage (Sys Power Down) | |
0x09, 0x83, # Usage (Sys Wake Up) | |
0x81, 0x60, # Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State) | |
0x75, 0x06, # Report Size (6) | |
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0xC0, # End Collection | |
)), | |
# fmt: on | |
usage_page=0x01, | |
usage=0x80, | |
report_ids=(report_id,), | |
in_report_lengths=(1,), | |
out_report_lengths=(0,), | |
) | |
powerdown_report = bytes( (0x81, ) ) # powerdown | |
sleep_report = bytes( (0x82, ) ) # sleep | |
wakeup_report = bytes( (0x83, ) ) # wake | |
class SleepyKeys: | |
"""Send System Control Power HID reports""" | |
def __init__(self, devices): | |
"""Create a SleepyKeys object that will send System Control HID reports. | |
Devices can be a list of devices that includes a keyboard device or a keyboard device | |
itself. A device is any object that implements ``send_report()``, ``usage_page`` and | |
``usage``. | |
""" | |
self._device = find_device(devices, usage_page=0x01, usage=0x80) | |
def send_powerdown(self): | |
"""From the spec: | |
Should send usage “System Power Down” when the button is | |
pressed to power down the system. The system power policy manager | |
will look up the POWER button action in the current power policy | |
(by default, shutdown) and take that action. | |
""" | |
self._device.send_report( powerdown_report ) | |
def send_sleep(self): | |
"""From the spec: | |
Should send usage “System Sleep” when the button is pressed to put | |
the system to sleep. The system power policy manager will look up | |
the SLEEP button action in the current power policy | |
(by default, sleep) and take that action. | |
""" | |
self._device.send_report( sleep_report ) | |
def send_wakeup(self): | |
"""From the spec: | |
Should send usage “System Wake Up” when the SLEEP button is pressed | |
again to wake up the system. | |
""" | |
self._device.send_report( wakeup_report ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-FileCopyrightText: Copyright (c) 2023 Tod Kurt | |
""" | |
Demo of SleepyKeys -- boot.py | |
""" | |
import usb_hid | |
import sleepy_keys | |
sleep_keys_device = sleepy_keys.device() | |
usb_hid.enable( (usb_hid.Device.KEYBOARD, | |
usb_hid.Device.MOUSE, | |
usb_hid.Device.CONSUMER_CONTROL, | |
sleep_keys_device) ) | |
print("enabled sleep keys") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-FileCopyrightText: Copyright (c) 2023 Tod Kurt | |
""" | |
Demo of SleepyKeys on Adafruit MacroPad RP2040 -- code.py | |
""" | |
import time, board, keypad | |
import usb_hid | |
from adafruit_hid.keyboard import Keyboard | |
from adafruit_hid.keycode import Keycode | |
import sleepy_keys | |
sleep_keys = sleepy_keys.SleepyKeys(usb_hid.devices) | |
kbd = Keyboard(usb_hid.devices) | |
key_pins = [getattr(board, "KEY%d" % (num + 1)) for num in range(12)] | |
keys = keypad.Keys(key_pins, value_when_pressed=False, pull=True) | |
print("ready to go, press bottom keys to go to sleep") | |
while True: | |
event = keys.events.get() | |
if event: | |
key_number = event.key_number | |
print("key:", key_number, event.pressed) | |
if event.pressed: | |
if key_number in (9,10,11): # bottom three keys | |
print("sleeping... ") | |
sleep_keys.send_sleep() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment