But why?
I love playing video games. Lately my friends and I have started a playthrough of Baldur’s Gate 3 (it’s been a blast, such a fun game!).
Unfortunately I have to travel fairly often. Now I could just run BG3 on my laptop, BG3 does have a really nice macOS build. But I’m a software engineer with a PhD in overengineering things (I run a k3s
cluster just for Plex).
The plan is to use WoL to wake up my windows machine, and then use Sunshine + Moonlight to stream the game to my laptop.
The how
I thought the problem was simple enough, I could just use Tailscale to access my windows machine. Unfortunately WoL operates at OSI-2 layer and Tailscale on OSI-3 layer. Once a device is in a deep sleep mode, the NIC may not be fully functional in the context of a Tailscale connection, especially if the VPN connection is terminated.
I could just use a Raspberry Pi but I didn’t feel like spending ~$50 on such a small scale project. So after 2 minutes of research and ₹539 later, I ordered a Pi Pico W.
Le Problems
The Pico does not work.
TIL there are two types of USB micro cables. One for charging and one for data transfer. The one I had was for charging i.e. the Pico wasn’t being recognised by my machines.
Once I got that sorted out, I faced another challenge:
The Pico cannot run Tailscale.
I realized this after the Pico was at my door. I had 2 options:
- Give up
- Try to remotely “notify” the Pico to send the ✨magic packets✨
Would something like… MQTT work?
The Plan
- Setup a
mosquitto
broker on my VPS (thank you Oracle for the free tier ♥) - Write a small
micropython
script to listen for MQTT messages - Send the WoL ✨magic packets✨
Mosquitto
Incredibly easy to set up, on my VPS I installed mosquitto
:
sudo apt install mosquitto
And a simple mosquitto.conf
:
listener 4242 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/passwd
Finally, generate a password file:
mosquitto_passwd -c /etc/mosquitto/passwd <username>
And then play around with mosquitto_pub
and mosquitto_sub
to make sure everything is working.
Micropython
I used Thonny to install umqtt.simple
and used the following script:
import network
import time
from umqtt.simple import MQTTClient
import machine
import socket
# Configuration
WIFI_SSID = "WiFi"
WIFI_PASSWORD = "password"
MQTT_BROKER = "mosquitto.vps.com"
MQTT_PORT = 4242
MQTT_USER = "mosquitto"
MQTT_PASSWORD = "mosquitto"
MQTT_TOPIC = b"wol/command"
TARGET_MAC = "AA:BB:CC:DD:EE:FF"
BROADCAST_IP = "255.255.255.255"
WOL_PORT = 9
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while not wlan.isconnected():
time.sleep(1)
print('WiFi connected')
def send_wol_packet(mac_address):
mac_bytes = bytes.fromhex(mac_address.replace(':', ''))
magic_packet = b'\xff' * 6 + mac_bytes * 16
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.sendto(magic_packet, (BROADCAST_IP, WOL_PORT))
sock.close()
print(f"Sent WoL packet to {mac_address}")
def on_message(topic, msg):
if msg == b"wake":
print("Wake-on-LAN command received")
# Callback to send WoL packet
send_wol_packet(TARGET_MAC)
def main():
connect_wifi()
client = MQTTClient("pico", MQTT_BROKER, MQTT_PORT, MQTT_USER, MQTT_PASSWORD)
client.set_callback(on_message)
client.connect()
client.subscribe(MQTT_TOPIC)
print(f"Connected to MQTT broker, subscribed to {MQTT_TOPIC}")
while True:
client.check_msg()
time.sleep(1)
if __name__ == "__main__":
main()
And voila! Here’s a demo video of the Pico W successfully waking my Windows machine remotely:
Why didn’t you…
- Use the router with OpenWRT to send WoL packets
- Run the game on your perfectly capable Steam Deck / Laptop
Could I have? Sure. Would it have been more efficient? Absolutely. But where’s the fun in that?
I believe side projects are the perfect playground for overengineering. I’m a big fan of doing things the “boring” way in production so this is a welcome escape.
Building a Rube Goldberg machine of a solution puts a smile on my face every time.