ESP32-S3 Wake-on-LAN Alternative: Wake a PC Over Wi-Fi with USB HID (Geekble Nano)

ESP32-S3 Project

Wake a Sleeping PC Over Wi-Fi
Building an ESP32-S3 USB HID WOL Device

A hands-on build log for waking a Windows PC that doesn't support Wake-on-LAN, by turning an ESP32-S3 into a USB keyboard and triggering it remotely over Wi-Fi.

ESP32-S3 Geekble Nano USB HID Wi-Fi Arduino IDE Wake-on-LAN
Progress
Buy board
Unbox
Arduino IDE
Board Package
Blink
USB HID
Wi-Fi
HTTP Server
Wake API
Wake from sleep ✓
Introduction

Project Overview & How It Works

The Limits of Traditional Wake-on-LAN

Wake-on-LAN (WOL) is a technology for remotely powering on a PC over a network. But WOL comes with an important prerequisite.

WOL's requirement: the device sending the Magic Packet and the target PC must be on the same wired network. A router, server, NAS, or some other wired device is required. Wi-Fi alone can't reliably deliver a WOL signal.

On top of that, USB wired-LAN adapters are often labeled as WOL-capable but don't actually work in practice. This is especially true on Windows installed on Mac hardware via Boot Camp or virtualization, where WOL on the built-in or USB NIC barely works at all — driver and firmware support simply isn't there.

This Project's Approach

This project routes around WOL entirely. The key insight is that keystrokes from a USB input device — like a Logitech USB receiver — can wake a PC even from sleep. So the plan is to make the ESP32-S3 act as a USB keyboard, and when it receives an HTTP request over Wi-Fi, send a Shift keypress to wake the PC from sleep.

Why this approach works: no wired network or extra server needed — all you need is Wi-Fi. Just hit one URL from a phone or remote PC connected to the same router, and that's it.

Parts Cost

The one part that makes this all possible is the Geekble Nano ESP32-S3. It runs about $7–8 USD on Coupang (Korean marketplace), or roughly $4–5 USD on AliExpress. If you've already bought a "WOL-capable" USB NIC that just won't work, this approach is far more reliable.

📱 Phone / Remote PC
Open http://esp32.local/wake in a browser
Wi-Fi (local network)
ESP32-S3 (Geekble Nano)
Receives the HTTP request → sends a USB HID Shift keypress
USB HID Keyboard (virtual)
Windows PC wakes up ✓
Then connect remotely via RDP, etc.
Key point: the ESP32-S3 has built-in USB OTG, so it can implement a USB HID device (keyboard/mouse) entirely in software — no separate USB controller chip needed.
Chapter 1

Meet the Geekble Nano ESP32-S3

The star of this project is the Geekble Nano ESP32-S3. It's an ESP32-S3 board in almost the exact same form factor as an Arduino Nano, and its hardware-level USB HID support makes it a perfect fit for this project.

Key Specs

ItemDetail
SoCESP32-S3FH4R2
CPUDual Core Xtensa LX7, 240 MHz
Flash4 MB
PSRAM2 MB
ConnectivityWi-Fi 802.11 b/g/n, Bluetooth 5.0 (BLE)
USBUSB OTG (USB-C) — HID / CDC support
SizeArduino Nano-compatible form factor

Why the ESP32-S3?

Built-in USB HID
Built-in USB CDC
Built-in Wi-Fi
Bluetooth 5.0
Dual Core 240MHz
Arduino support
Arduino Nano-sized

Built-in USB HID means it can act as a keyboard or mouse without a separate USB controller (e.g. an ATmega16U2). With Wi-Fi built in as well, it single-handedly covers every requirement this project needs.

Chapter 2

Unboxing

The package contents are simple. Open the box and all you find is the Geekble Nano board itself.

ESP32 packaging
▲ As packaged
ESP32 board front
▲ Board, front side
ESP32 board back
▲ Board, back side — the GPIO pinout is silkscreened right on it, which is handy

Front side

The front side has the following laid out:

USB-C port
BOOT button
RESET button
ESP32-S3FH4R2

Back side

The back side has the GPIO pinout silkscreened on it, so you don't need to memorize pin numbers or dig up a datasheet. If you've used an Arduino Nano before, you can put that experience to use directly since it's the same size.

Tip: before buying, make sure it's specifically an ESP32-S3 board. Plain ESP32 or ESP32-S2 boards may differ in USB HID support. This project specifically requires an ESP32-S3.
Chapter 3

Installing Arduino IDE

The ESP32-S3 is officially supported by Arduino IDE 2.x. Download the latest version from the official site.

https://www.arduino.cc/en/software

On Windows, just download the Windows Installer and install it like any other program.

Driver installation — important!

The first time you launch Arduino IDE, a Windows driver install prompt appears. In this project, the Adafruit Industries LLC driver install prompt showed up.

You must install it. Skip it and the ESP32 board may not be recognized as a port later on.
Arduino IDE first launch and driver install screen
▲ The driver install screen that appears the first time you launch Arduino IDE
Additional Boards Manager URLs setting
▲ The Additional Boards Manager URLs settings screen
Chapter 4

Installing the ESP32 Board Package

Arduino IDE only supports AVR boards (like the Arduino Uno) out of the box. To use the ESP32-S3, you need to add Espressif's Board Package separately.

Step 1 — Add the Boards Manager URL

File → Preferences (or Ctrl+,), then
add the URL below to Additional Boards Manager URLs.

https://espressif.github.io/arduino-esp32/package_esp32_index.json

If you already have another URL there, just add this one on a new line.

Installing the ESP32 board package
▲ Search "esp32" in Boards Manager, then install esp32 by Espressif Systems

Step 2 — Install the board package

Click the Boards Manager icon (the chip icon) in the left sidebar and type esp32 into the search box.
Find esp32 by Espressif Systems and click Install. Installation can take a few minutes.

Version tip: unless you have a specific reason not to, just install the latest stable version. No need to restart the IDE afterward.

Step 3 — Select the board

Select Tools → Board → ESP32 Arduino → ESP32S3 Dev Module.
The Geekble Nano doesn't have a dedicated board definition, but the ESP32S3 Dev Module setting works most reliably.

Board selection
▲ Tools → Board → selecting ESP32S3 Dev Module

Step 4 — Select the COM port

Tools → Port, then select the newly-appeared COM port (e.g. COM10).

COM port selection
▲ Selecting the ESP32's COM port under Tools → Port
Port not showing up? Try re-plugging the USB cable and clicking into the IDE window to refresh. Also confirm your cable actually supports data (a charge-only cable won't work).
Chapter 5

Blink Test — Your First Upload

Once the board is configured, the first thing to do is upload Blink. It's a trivial LED-blinking sketch, but succeeding at this step proves in one shot that the hardware, driver, board settings, and upload path are all working correctly.

The Geekble Nano's built-in LED pin

The silkscreen on the back of the Geekble Nano marks D13 = GPIO48 as the built-in LED. The default Blink example (LED_BUILTIN) may not point to the right pin, so it's safer to specify it explicitly, as in the code below.

#define LED_PIN 48

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}

Uploading

Blink upload in progress
▲ Upload in progress — progress is shown in the log at the bottom
Blink upload complete
▲ Upload complete — the Hard resetting via RTS pin... message means success
Example success message:
Wrote 301120 bytes ... in 1.4 seconds
Hash of data verified.
Hard resetting via RTS pin...

If the upload fails (common on the ESP32-S3)

The ESP32-S3 sometimes needs to be put into bootloader mode manually before it will accept an upload. Try these in order.

Method 1: click Upload → when Connecting... appears at the bottom, hold down the BOOT button → release once the upload starts

Method 2: hold BOOT → tap RST once → keep holding BOOT → click Upload

Checking the result

LED blink result
▲ The built-in LED (GPIO48) blinking every 0.5 seconds 🎉

If the LED blinks every 0.5 seconds, you're good. This confirms that the hardware, driver, board settings, and upload path are all working correctly, and you're ready to move on to implementing USB HID.

Chapter 6

Implementing a USB HID Keyboard

Now for the core of this project: implementing a USB HID Keyboard. The ESP32-S3 will be recognized by the PC as a USB keyboard, and code will be able to send keystrokes to it.

Step 1 — Check the USB settings

First, check the current USB-related settings in the Tools menu.

Checking USB settings
▲ Checking USB-related settings in the Tools menu

The key settings to check are:

ItemSetting
BoardESP32S3 Dev Module
USB CDC On BootEnabled (needs to be changed)
USB ModeHardware CDC and JTAG
Flash Size4MB

Step 2 — USB CDC On Boot → Enabled

Change Tools → USB CDC On Boot → Enabled. This setting must be on for the USB device to initialize automatically after boot.

USB CDC On Boot Enabled setting
▲ USB CDC On Boot switched to Enabled
USB HID on Arduino ESP32 3.x
Starting with ESP32 Arduino Core 3.x, you can implement USB HID easily with the built-in USB.h + USBHIDKeyboard.h libraries — no separate TinyUSB install needed.

Step 3 — Write and upload the code

Create a new sketch, paste in the code below, and upload it.

#include "USB.h"
#include "USBHIDKeyboard.h"

USBHIDKeyboard Keyboard;

void setup() {
  USB.begin();
  Keyboard.begin();

  // Wait for USB to be recognized
  delay(3000);

  Keyboard.println("Hello World!");
  Keyboard.println("ESP32-S3 USB HID Keyboard Test");
}

void loop() {
}
Uploading the USB keyboard sketch
▲ Writing and uploading the USB HID Keyboard sketch

Step 4 — Confirm the PC recognizes the USB keyboard

After uploading, confirm the PC recognizes the ESP32-S3 as a USB HID Keyboard device. You can check this in Windows Device Manager or via a notification.

Recognized as a USB keyboard
▲ The PC recognizing the ESP32-S3 as a USB HID Keyboard device

Step 5 — Notepad typing test

Open Notepad, click into it to place the cursor, then press the ESP32's RST button once. If text types itself in after about 3 seconds, it worked.

Notepad auto-typing complete
▲ "Hello World!" and "ESP32-S3 USB HID Keyboard Test" typed automatically into Notepad 🎉
How it works
USB.begin() → initializes the USB stack
Keyboard.begin() → registers the HID keyboard device
delay(3000) → waits for the PC to recognize the device
Keyboard.println() → sends the keystrokes (including Enter)

This confirms the ESP32-S3 really does behave like a USB keyboard. The next step is adding Wi-Fi so this keystroke can be triggered remotely.

Chapter 7

Connecting to Wi-Fi

With USB HID confirmed working, it's time to connect to Wi-Fi. The goal of this step is simply for the ESP32-S3 to join the router and get an IP address.

Watch the init order when using USB HID + Wi-Fi together
On Arduino ESP32 Core 3.x, the initialization order matters when using USB and Wi-Fi together. Verified order: Keyboard.begin()USB.begin()WiFi.begin()server.begin()

Wi-Fi connection code

#include <WiFi.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  // Connected — check the IP
  // Serial.println(WiFi.localIP());
}

void loop() { }

Checking the IP from the router

Once the ESP32 joins the router, it gets an IP via DHCP. Check the connected-devices list on the router's admin page, or print WiFi.localIP() to the Serial Monitor.

Checking the IP on the router
▲ Checking the ESP32's IP address on the router's admin page
Serial Monitor output
▲ Checking Wi-Fi connection status and IP address in the Serial Monitor
Port-recovery tip (a common ESP32-S3 quirk)
While running in USB HID mode, the COM port can disappear. Don't panic — recover it by holding BOOT → RST → keep holding BOOT → Upload.
Port recovery screen
▲ The COM port disappearing, and recovering it with the BOOT button
Chapter 8

Building the HTTP Web Server

With Wi-Fi confirmed working, it's time to bring up an HTTP web server. This lets a phone or remote PC's browser send an HTTP request to the ESP32.

WebServer code

#include <WiFi.h>
#include <WebServer.h>

WebServer server(80);

void handleRoot() {
  server.send(200, "text/html",
    "<h1>ESP32-S3 WakeKey32</h1>"
    "<p><a href='/wake'>Wake PC</a></p>"
  );
}

void setup() {
  // ... connect to WiFi ...

  server.on("/", handleRoot);
  server.begin();
}

void loop() {
  server.handleClient();
}

Confirming the web server works

Opening http://[ESP32's IP address]/ in a browser shows a page served by the ESP32.

ESP32 web server working
▲ Successfully connecting to the ESP32's web server in a browser
mDNS setup (optional)
Adding #include <ESPmDNS.h> and MDNS.begin("esp32") lets you connect via http://esp32.local/ instead of the IP address. This only works on the same Wi-Fi network.
Chapter 9

Final Code & Stabilization Work

The combined Wi-Fi + USB HID code wasn't stable right out of the gate. It worked, but USB recognition kept dropping and the keyboard behaved erratically. Here's the process of tracking down the causes, one by one, documented as it actually happened.

Bugs found and the root cause of the instability

The core bug: setTxPower was never actually being applied

Calling WiFi.setTxPower() before WiFi.begin() gets silently ignored, because the Wi-Fi driver hasn't started yet. So while I thought I was limiting output to 8.5dBm, it was actually transmitting at full power (~20dBm) the whole time. The current spike of 300mA+ during Wi-Fi transmission was colliding with USB enumeration timing — that was the root cause of the instability.

Six Stabilization Fixes

ItemChangeEffect
① setTxPower placement Moved after WiFi.begin() The 8.5dBm limit now actually takes effect — the single biggest fix
② USB init order USB first → wait for tud_mounted() → then Wi-Fi Separates things so the Wi-Fi current spike happens after USB enumeration finishes
③ CPU clock 240MHz → 160MHz Still plenty of performance, with more headroom for current spikes
④ Wi-Fi modem sleep WiFi.setSleep(true) Radio sleeps when idle → big drop in average current draw
⑤ loop() delay Added delay(2) Gives the CPU idle time so modem sleep can actually kick in
⑥ Declare Remote Wakeup USB.usbAttributes(...REMOTE_WAKEUP) Declares it in the USB descriptor → creates the Windows power-management tab

Setting the USB Remote Wakeup descriptor

For the Power Management tab to appear in Windows Device Manager, Remote Wakeup support must be declared in the USB descriptor. This one line has to be called before USB.begin().

// Must be called before USB.begin()
USB.usbAttributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP);
What waiting for tud_mounted() means
USB.begin() doesn't mean the PC recognizes it right away. You have to wait for the PC to enumerate the USB device and match a driver. Once tud_mounted() returns true, USB is fully recognized. Turn on Wi-Fi before that check passes, and the current spike lands right in the middle of enumeration.

Final code

#include <WiFi.h>
#include <WebServer.h>
#include <esp_system.h>
#include "USB.h"
#include "USBHIDKeyboard.h"
#include "tusb.h"

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

WebServer server(80);
USBHIDKeyboard Keyboard;

const char* resetReasonStr() {
  switch (esp_reset_reason()) {
    case ESP_RST_POWERON: return "Power-on";
    case ESP_RST_SW: return "Software reset";
    case ESP_RST_PANIC: return "Panic (crash)";
    case ESP_RST_BROWNOUT: return "BROWNOUT (power drop!)";
    case ESP_RST_WDT:
    case ESP_RST_INT_WDT:
    case ESP_RST_TASK_WDT: return "Watchdog";
    default: return "Other";
  }
}

void handleRoot() {
  server.send(200, "text/html",
    "<h2>ESP32 WakeKey32</h2>"
    "<p><a href='/wake'>Wake (Shift)</a></p>"
    "<p><a href='/type?text=Hello'>Type Hello</a></p>"
    "<p><a href='/status'>Status</a></p>"
  );
}

void handleWake() {
  if (tud_suspended()) {
    tud_remote_wakeup(); // Send the USB Remote Wakeup signal
    delay(1000); // Wait for the host to resume the bus
  }
  Keyboard.press(KEY_LEFT_SHIFT);
  delay(100);
  Keyboard.release(KEY_LEFT_SHIFT);
  server.send(200, "text/plain", "Wake signal sent!");
}

void handleType() {
  if (server.hasArg("text")) {
    Keyboard.print(server.arg("text"));
    server.send(200, "text/plain", "Typed: " + server.arg("text"));
  } else {
    server.send(400, "text/plain", "Missing ?text=");
  }
}

void handleStatus() {
  String msg = "WiFi : " + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\n";
  msg += "IP : " + WiFi.localIP().toString() + "\n";
  msg += "RSSI : " + String(WiFi.RSSI()) + " dBm\n";
  msg += "USB : " + String(tud_mounted() ? "Mounted" : "Not mounted") + "\n";
  msg += "Reset : " + String(resetReasonStr()) + "\n";
  msg += "Uptime: " + String(millis() / 1000) + " s";
  server.send(200, "text/plain", msg);
}

void setup() {
  setCpuFrequencyMhz(160); // 240→160MHz: more headroom for current spikes

  // Declare Remote Wakeup in the USB descriptor (must be before USB.begin())
  USB.usbAttributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP);
  Keyboard.begin();
  USB.begin();

  // Wait for USB enumeration to finish (up to 3s)
  uint32_t t0 = millis();
  while (!tud_mounted() && millis() - t0 < 3000) delay(50);
  delay(500); // Extra settling time right after enumeration

  WiFi.persistent(false);
  WiFi.setAutoReconnect(true);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  WiFi.setTxPower(WIFI_POWER_8_5dBm); // Must be called after begin() to actually apply
  WiFi.setSleep(true); // Modem sleep: lowers average current draw

  t0 = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) delay(250);

  server.on("/", handleRoot);
  server.on("/wake", handleWake);
  server.on("/type", handleType);
  server.on("/status", handleStatus);
  server.begin();
}

void loop() {
  server.handleClient();
  delay(2); // Gives modem sleep time to actually engage
}
Final code upload success screen
▲ Final code uploaded successfully — Wrote 983040 bytes, Hard resetting via RTS pin...
Final index page
▲ The finished index page — Wake (Shift) / Type 'Hello' / Status, three endpoints reachable from here
Testing the type endpoint with Hello
▲ Result of calling /type?text=Hello — "Hello" typed automatically into Notepad

The /status diagnostic page

A diagnostic endpoint for checking status without a Serial connection. If USB recognition gets flaky, open http://[IP]/status.

WiFi : Connected
IP : 192.168.0.xxx
RSSI : -52 dBm
USB : Mounted
Reset : Power-on
Uptime: 42 s
Reset: BROWNOUT (power drop!) means it's a power problem, not a code problem.
Switch to a rear USB port on the PC (motherboard-connected) or use a USB 3.0 port (900mA). If RSSI is worse than -75dBm, consider bumping up to WIFI_POWER_11dBm.
Troubleshooting

Troubleshooting — Real Issues I Ran Into

Here's a rundown of the issues I actually hit while building this, and how I fixed them. If you're new to the ESP32-S3, you'll likely run into every one of these at least once.

① The COM port disappears after uploading

Once it switches into USB HID mode, Windows recognizes the ESP32 as an HID keyboard rather than a serial port, so the COM port disappears.

Fix: enter bootloader mode in this order, then upload.

1. Hold down the BOOT button
2. Tap RST briefly and release
3. Release BOOT
4. Click Upload in Arduino IDE

If Serial Monitor shows waiting for download, you've successfully entered bootloader mode. From there, Upload works even without a COM port.
Upload after port recovery
▲ Successfully uploading after entering bootloader mode

② It stops after "Hard resetting via RTS pin..."

If this message appears at the end of an upload, the upload succeeded. The ESP32 resets itself automatically and runs the new code. No action needed.

If it instead drops into a bootloader-wait state (waiting for download) after this message, just press RST once to boot normally.

③ Wi-Fi keeps connecting and dropping

The ESP32's Wi-Fi radio draws a momentary current spike (up to 500mA) when it powers on. If the PC's USB port can't supply enough power, the resulting voltage drop makes the connection unstable.

Fixes (in priority order):
1. Switch to a phone charger (5V 1A or higher) for power
2. Plug directly into the PC instead of through a USB hub
3. Add WiFi.setTxPower(WIFI_POWER_8_5dBm) in code to lower transmit power
Direct USB connection to the PC with a short cable
▲ Plugged directly into a PC USB port with a short cable, to minimize power loss

④ Nothing shows up in Serial Monitor

This happens when the output already scrolled by before you opened Serial Monitor. Open Serial Monitor first, then press RST to reboot — the output will start from the beginning. Also double-check the baud rate matches the code (115200).

⑤ USB HID conflicting with Serial (CDC)

With USB CDC On Boot: Enabled, calling both Serial.begin() and USB.begin() can make the port disappear or conflict.

Fix: when USB CDC On Boot: Enabled is set, Serial is already wired to the USB CDC port, so there's no need to call Serial.begin() separately. Calling both Serial.begin() and USB.begin() makes two initializations fight over the same USB port, which is what causes the COM port to disappear or become unstable. Serial.print() and friends work fine over USB CDC without any separate init.

⑥ USB HID + Wi-Fi initialization order problem

Calling USB.begin() before Wi-Fi can cause the USB FreeRTOS task to interfere with Wi-Fi stack initialization, preventing Wi-Fi from connecting.

Verified order:
WiFi.begin() → wait for connection → server.begin()Keyboard.begin()USB.begin()
Chapter 10

Live Test: Waking Windows From Sleep

A USB HID keystroke alone can't wake a sleeping PC. For a USB device to wake a PC from sleep, it has to separately send a Remote Wakeup signal over the USB bus — this is exactly why an ordinary wireless keyboard dongle is able to wake a PC from sleep.

Step 1 — Code change: add tud_remote_wakeup()

On Arduino ESP32 Core 3.x, USB.wakeupHost() doesn't exist. You have to use TinyUSB directly. Add #include "tusb.h" and send the signal with tud_remote_wakeup().

#include <WiFi.h>
#include <WebServer.h>
#include "USB.h"
#include "USBHIDKeyboard.h"
#include "tusb.h" // added for tud_remote_wakeup()

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

WebServer server(80);
USBHIDKeyboard Keyboard;

void handleWake() {
  if (tud_suspended()) {
    tud_remote_wakeup(); // Send the USB Remote Wakeup signal (the key part)
  }
  delay(500); // Wait for the PC to wake up
  Keyboard.press(KEY_LEFT_SHIFT);
  delay(100);
  Keyboard.release(KEY_LEFT_SHIFT);
  server.send(200, "text/plain", "Wake signal sent!");
}

void handleStatus() {
  String msg = "WiFi : Connected
";
  msg += "IP : " + WiFi.localIP().toString() + "
";
  msg += "USB : OK
";
  msg += "Suspended: ";
  msg += tud_suspended() ? "Yes" : "No";
  server.send(200, "text/plain", msg);
}

void setup() {
  WiFi.persistent(false);
  WiFi.setAutoReconnect(true);
  WiFi.setTxPower(WIFI_POWER_8_5dBm);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  server.on("/wake", handleWake);
  server.on("/status", handleStatus);
  server.begin();

  Keyboard.begin();
  USB.begin();
}

void loop() {
  server.handleClient();
}
How to confirm it's working: after the PC sleeps, if http://[IP]/status shows Suspended: Yes, USB is correctly in the suspended state. Calling /wake from there sends the Remote Wakeup signal.

Step 2 — Windows Device Manager setting

By default, Windows doesn't allow any USB device to wake the computer from sleep. You need to enable this for the ESP32 HID keyboard device ahead of time, while the PC is on.

You must configure this while the PC is powered on. It can't be set after the PC is already asleep.
1. Open Device Manager (Win+X → Device Manager)
2. Expand Human Interface Devices
3. Right-click the ESP32 HID Keyboard device → Properties
4. Power Management tab → check "Allow this device to wake the computer"
5. Click OK
Device Manager power management setting
▲ HID Keyboard properties → Power Management tab → enabling wake-from-sleep

Step 3 — Live test ✅

I put the Windows PC to sleep, waited a while, then called it from a different PC using one of the methods below.

Three calling methods — all confirmed working

① Browser address bar:
http://192.168.0.12/wake

② curl (terminal/command prompt):
curl http://192.168.0.12/wake

③ Clicking from the index page:
http://192.168.0.12/ → click the Wake (Shift) link
Wake signal sent response screen
▲ Response to calling /wake — "Wake signal sent!" means the Remote Wakeup signal and Shift keystroke went through correctly

All three methods successfully woke the sleeping Windows PC. With that, this project's final goal was achieved.

Final confirmed flow
Another PC / phone browser
→ HTTP request to http://[ESP32 IP]/wake
→ ESP32 sends a USB Remote Wakeup signal via tud_remote_wakeup()
→ Windows wakes from sleep
→ Then connect remotely via RDP, etc. ✅

Download the Final Code

You can download this project's finished code (.ino) and use it as-is.

Before you download, you must edit this: the ssid and password values in the code are placeholders, YOUR_WIFI_SSID / YOUR_WIFI_PASSWORD. Replace them with your own router's SSID and password before uploading.

ESP32-S3 Geekble Nano · Wi-Fi USB HID WOL Project

A build log documenting the real process, trial and error included.

댓글

이 블로그의 인기 게시물

스노우쿨링 장소로 유명한 마우이 카팔루아 비치 (Kapalua Beach)

샌프란시스코 길로이 아울렛 Gilroy Outlet

하와이 로컬 슈퍼마켓 푸드랜드 팜스 (Foodland Farms) 연구