--- name: wol-wake-sleeping-fleet-host description: "Wake a sleeping fleet host (e.g. the FrankBook-Pro Mac mini) over the network with a Wake-on-LAN magic packet, and diagnose why it silently fails." --- Wake a sleeping fleet host over the network with a Wake-on-LAN (WoL) magic packet. ## When A fleet host is asleep (100% ping loss; `ip neigh show ` shows STALE or FAILED) and you need it up — e.g. the Playwright e2e `11-admin` spec needs the Mac mini, or a service on it is down. Recurring on the FrankBook-Pro Mac mini, which sleeps and breaks the e2e suite. ## 1. Find the MAC (the host is asleep, so you can't ask it) - `ip neigh show ` — even a **STALE** entry carries the MAC. Fastest source. - Fallback: Pi-hole / dnsmasq leases, the DHCP server, or fleet docs. - Known: **FrankBook-Pro Mac mini = 192.168.0.112, MAC `de:6b:6d:c1:52:23`.** ## 2. Send the magic packet - Format: `6×0xFF + 16×MAC` = 102 bytes, UDP to port **9** (and 7), broadcast. - **The workstation has TWO interfaces on 192.168.0.0/24:** a Wi-Fi link and a wired USB-Ethernet link (the default route, metric 100). A plain `sendto("255.255.255.255", 9)` leaves only the default-route interface. **Bind explicitly to each interface's local IP** and target the **subnet broadcast `192.168.0.255`** as well as `255.255.255.255`. - `wakeonlan` is not installed; use a raw UDP socket with `SO_BROADCAST=1`. - Send a burst (~15 packets per interface, ~0.2s apart). ## 3. Poll for the wake A Mac mini takes **30–90 s** to boot after a WoL wake. Poll `ping -c 1 -W 1 ` every 5 s for ~2–3 min before concluding failure. ## 4. If it does NOT wake (the common case) — diagnose the setting macOS honors a WoL packet **only when BOTH are enabled on the mini**: - **System Settings → Battery → Options → "Wake for network access"** = ON, and - the active network port's **"Enable Wake for LAN"** (Network → [interface] → Details). If either is off, **no packet from any source wakes it**, and you cannot change it while the host is asleep. A full power-off (smart plug cycled) also ignores WoL entirely. In that case: ask the user to toggle the setting (the durable fix so future wakes work), then re-fire the packet. ## Reference sender (raw socket, per-interface) ```python import socket, time MAC = "de:6b:6d:c1:52:23" mac = bytes(int(x,16) for x in MAC.split(":")) pkt = b"\xff"*6 + mac*16 # 102 bytes for local, dest in [("192.168.0.83","192.168.0.255"),("192.168.0.104","192.168.0.255"), ("192.168.0.83","255.255.255.255"),("192.168.0.104","255.255.255.255")]: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.bind((local, 0)) for _ in range(15): s.sendto(pkt,(dest,9)); s.sendto(pkt,(dest,7)); time.sleep(0.2) s.close() ```