[BUG] Wake on LAN stopped working

Hi guys,

I have HA in docker on RPi3 with configured WOL. I have also pivpn running on this machine and everything worked fine until few days ago. Here are logs whats going on.

2024-01-09 10:25:35.838 INFO (MainThread) [homeassistant.components.wake_on_lan] Send magic packet to mac a1:b2:c3:d4:e5:f6 (broadcast: 255.255.255.255, port: 9)
2024-01-09 10:25:35.850 INFO (SyncWorker_15) [wakeonlan] macs: ('a1:b2:c3:d4:e5:f6',)
ip_address: 255.255.255.255
port: 9
int: None
2024-01-09 10:25:35.859 INFO (SyncWorker_15) [wakeonlan] packet: b'\xff\xff\xff\xff\xff\xff\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6\xa1\xb2\xc3\xd4\xe5\xf6'
2024-01-09 10:25:35.907 ERROR (MainThread) [homeassistant.components.script.wake_up_pc] wake up PC: Error executing script. Unexpected error for call_service at pos 1: [Errno 126] Required key not available
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 451, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 684, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1744, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1781, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/components/wake_on_lan/__init__.py", line 50, in send_magic_packet
    await hass.async_add_executor_job(
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.10/site-packages/wakeonlan.py", line 68, in send_magic_packet
    sock.send(packet)
OSError: [Errno 126] Required key not available
2024-01-09 10:25:36.100 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/script/__init__.py", line 484, in _async_run
    return await self.script.async_run(script_vars, context)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1524, in async_run
    await asyncio.shield(run.async_run())
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 409, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 453, in _async_step
    self._handle_exception(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 476, in _handle_exception
    raise exception
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 451, in _async_step
    await getattr(self, handler)()
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 684, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1744, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1781, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/components/wake_on_lan/__init__.py", line 50, in send_magic_packet
    await hass.async_add_executor_job(
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/local/lib/python3.10/site-packages/wakeonlan.py", line 68, in send_magic_packet
    sock.send(packet)
OSError: [Errno 126] Required key not available

I added there some logs, mac changed. When I run this code locally it works fine. However when I run this script inside the docker container it returns same error. So I quite dont understand. Does it have something with docker image? Last things I updated on Rpi was only changing VPN settings - changed host ip address to domain address.

Home Assistant 2022.11.5
Docker version 24.0.6, build ed223bc

docker-compose

version: '3'
services:
  homeassistant:
    container_name: homeassistant
    image: "homeassistant/home-assistant:latest"
    volumes:
      - /home/path/to/homeassistant/config:/config
      - /home/path/to/homeassistant/tmp:/tmp
      - /etc/localtime:/etc/localtime:ro
    network_mode: "host"
    restart: always
    privileged: true

What code? :wink:

/usr/local/lib/python3.10/site-packages/wakeonlan.py

But what do you mean by run?

That file is supposed to come from a package, pywakeonlan v2.1.0

Line 68 in that file is not in send_magic_packet

Anyway,

and

Seems pretty much incompatible, unless you never recreated the container since november 2022…

I though I made quite clear post.
by run the code I mean I copied the code from wakeonlan.py to my local machine and run it with same parameters as its run from HA.

The lines are incompatible because I added logs which I included in first post

I added there some logs, mac changed.

Seems pretty much incompatible, unless you never recreated the container since november 2022…

I am more for dont touch what works fine because it happend to me lot of times that when I updated HA things stopped working.

I have already fixed it by I want to know the reason why it suddently stopped working. Putting my version of wakeonlan.py

#!/usr/bin/env python3
"""
Small module for use with the wake on lan protocol.

"""
import argparse
import socket
from typing import List
import logging

_LOGGER = logging.getLogger(__name__)

BROADCAST_IP = "255.255.255.255"
DEFAULT_PORT = 9


def create_magic_packet(macaddress: str) -> bytes:
    """
    Create a magic packet.

    A magic packet is a packet that can be used with the for wake on lan
    protocol to wake up a computer. The packet is constructed from the
    mac address given as a parameter.

    Args:
        macaddress: the mac address that should be parsed into a magic packet.

    """
    if len(macaddress) == 17:
        sep = macaddress[2]
        macaddress = macaddress.replace(sep, "")
    elif len(macaddress) != 12:
        raise ValueError("Incorrect MAC address format")

    return bytes.fromhex("F" * 12 + macaddress * 16)


def send_magic_packet(
    *macs: str,
    ip_address: str = BROADCAST_IP,
    port: int = DEFAULT_PORT,
    interface: str = None
) -> None:
    """
    Wake up computers having any of the given mac addresses.

    Wake on lan must be enabled on the host device.

    Args:
        macs: One or more macaddresses of machines to wake.

    Keyword Args:
        ip_address: the ip address of the host to send the magic packet to.
        port: the port of the host to send the magic packet to.
        interface: the ip address of the network adapter to route the magic packet through.

    """
    _LOGGER.info(f'macs: {macs}\nip_address: {ip_address}\nport: {port}\nint: {interface}')
    packets = [create_magic_packet(mac) for mac in macs]

#    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
#        if interface is not None:
#            sock.bind((interface, 0))
#        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
#        sock.connect((ip_address, port))
#        for packet in packets:
#            _LOGGER.info(f'packet: {packet}')
#            sock.send(packet)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    for packet in packets:
        sock.sendto(packet, (ip_address,port))
    sock.close()

def main(argv: List[str] = None) -> None:
    """
    Run wake on lan as a CLI application.

    """
    parser = argparse.ArgumentParser(
        description="Wake one or more computers using the wake on lan protocol.",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        "macs",
        metavar="mac address",
        nargs="+",
        help="The mac addresses of the computers you are trying to wake.",
    )
    parser.add_argument(
        "-i",
        metavar="ip",
        default=BROADCAST_IP,
        help="The ip address of the host to send the magic packet to.",
    )
    parser.add_argument(
        "-p",
        metavar="port",
        type=int,
        default=DEFAULT_PORT,
        help="The port of the host to send the magic packet to.",
    )
    parser.add_argument(
        "-n",
        metavar="interface",
        default=None,
        help="The ip address of the network adapter to route the magic packet through.",
    )
    _LOGGER.info(f'ARGV, {argv}')
    args = parser.parse_args(argv)
    _LOGGER.info(f'args: {args}')
    send_magic_packet(*args.macs, ip_address=args.i, port=args.p, interface=args.n)


if __name__ == "__main__":  # pragma: nocover
    main()

Absolutely not, but now you did better :wink:

Fair enough, but then you should pin the docker image tag (:2022.11.5 rather than :latest) or the next time you recreate the container, you’ll fetch the, well, latest version and bring havoc to your setup.

Also note that the longer you delay updates, the more difficult it will be.
Be prepare for some headaches if you update at some point.

Also, keep in mind that if/when you’ll recreate the container, your modifications will be lost unless you “mount” the modified file.