Wake on LAN yaml configuration move to integration key (#81249)

* Wake on Lan integration yaml

* clean code

* Add test

* Add test fixture

* Address loading
This commit is contained in:
G Johansson 2022-11-16 06:23:48 +01:00 committed by GitHub
parent aedbfdabee
commit 52298a251b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 164 additions and 18 deletions

View File

@ -1,16 +1,27 @@
"""Support for sending Wake-On-LAN magic packets."""
import asyncio
from collections.abc import Coroutine
from functools import partial
import logging
from typing import Any
import voluptuous as vol
import wakeonlan
from homeassistant.const import CONF_BROADCAST_ADDRESS, CONF_BROADCAST_PORT, CONF_MAC
from homeassistant.const import (
CONF_BROADCAST_ADDRESS,
CONF_BROADCAST_PORT,
CONF_HOST,
CONF_MAC,
CONF_NAME,
Platform,
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN
from .const import CONF_OFF_ACTION, DEFAULT_NAME, DOMAIN
_LOGGER = logging.getLogger(__name__)
@ -24,9 +35,41 @@ WAKE_ON_LAN_SEND_MAGIC_PACKET_SCHEMA = vol.Schema(
}
)
SWITCH_SCHEMA = vol.Schema(
{
vol.Required(CONF_MAC): cv.string,
vol.Optional(CONF_BROADCAST_ADDRESS): cv.string,
vol.Optional(CONF_BROADCAST_PORT): cv.port,
vol.Optional(CONF_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OFF_ACTION): cv.SCRIPT_SCHEMA,
}
)
CONFIG_SCHEMA = vol.Schema(
{vol.Optional(DOMAIN): vol.All(cv.ensure_list, [vol.Schema(SWITCH_SCHEMA)])},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the wake on LAN component."""
load_coroutines: list[Coroutine[Any, Any, None]] = []
if wol_config := config.get(DOMAIN):
for switch_config in wol_config:
load_coroutines.append(
discovery.async_load_platform(
hass,
Platform.SWITCH,
DOMAIN,
switch_config,
config,
)
)
if load_coroutines:
await asyncio.gather(*load_coroutines)
async def send_magic_packet(call: ServiceCall) -> None:
"""Send magic packet to wake up a device."""

View File

@ -1,2 +1,6 @@
"""Constants for the Wake-On-LAN component."""
DOMAIN = "wake_on_lan"
CONF_OFF_ACTION = "turn_off"
DEFAULT_NAME = "Wake on LAN"
DEFAULT_PING_TIMEOUT = 1

View File

@ -0,0 +1,8 @@
{
"issues": {
"moved_yaml": {
"title": "The Wake on Lan YAML configuration has been moved",
"description": "Configuring Wake on Lan using YAML has been moved to integration key.\n\nYour existing YAML configuration will be working for 2 more versions.\n\nMigrate your YAML configuration to the integration key according to the documentation."
}
}
}

View File

@ -23,18 +23,14 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.script import Script
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import DOMAIN
from .const import CONF_OFF_ACTION, DEFAULT_NAME, DEFAULT_PING_TIMEOUT, DOMAIN
_LOGGER = logging.getLogger(__name__)
CONF_OFF_ACTION = "turn_off"
DEFAULT_NAME = "Wake on LAN"
DEFAULT_PING_TIMEOUT = 1
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_MAC): cv.string,
@ -47,21 +43,33 @@ PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
)
def setup_platform(
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up a wake on lan switch."""
broadcast_address: str | None = config.get(CONF_BROADCAST_ADDRESS)
broadcast_port: int | None = config.get(CONF_BROADCAST_PORT)
host: str | None = config.get(CONF_HOST)
mac_address: str = config[CONF_MAC]
name: str = config[CONF_NAME]
off_action: list[Any] | None = config.get(CONF_OFF_ACTION)
if (switch_config := discovery_info) is None:
async_create_issue(
hass,
DOMAIN,
"moved_yaml",
breaks_in_ha_version="2022.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="moved_yaml",
)
switch_config = config
add_entities(
broadcast_address: str | None = switch_config.get(CONF_BROADCAST_ADDRESS)
broadcast_port: int | None = switch_config.get(CONF_BROADCAST_PORT)
host: str | None = switch_config.get(CONF_HOST)
mac_address: str = switch_config[CONF_MAC]
name: str = switch_config[CONF_NAME]
off_action: list[Any] | None = switch_config.get(CONF_OFF_ACTION)
async_add_entities(
[
WolSwitch(
hass,

View File

@ -0,0 +1,8 @@
{
"issues": {
"moved_yaml": {
"description": "Configuring Wake on Lan using YAML has been moved to integration key.\n\nYour existing YAML configuration will be working for 2 more versions.\n\nMigrate your YAML configuration to the integration key according to the documentation.",
"title": "The Wake on Lan YAML configuration has been moved"
}
}
}

View File

@ -0,0 +1,13 @@
"""Test fixtures for Wake on Lan."""
from __future__ import annotations
from unittest.mock import patch
import pytest
@pytest.fixture(autouse=True)
def mock_send_magic_packet():
"""Mock magic packet."""
with patch("wakeonlan.send_magic_packet") as mock_send:
yield mock_send

View File

@ -1,14 +1,26 @@
"""Tests for Wake On LAN component."""
from __future__ import annotations
import subprocess
from unittest.mock import patch
import pytest
import voluptuous as vol
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.wake_on_lan import DOMAIN, SERVICE_SEND_MAGIC_PACKET
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
async def test_send_magic_packet(hass):
async def test_send_magic_packet(hass: HomeAssistant) -> None:
"""Test of send magic packet service call."""
with patch("homeassistant.components.wake_on_lan.wakeonlan") as mocked_wakeonlan:
mac = "aa:bb:cc:dd:ee:ff"
@ -65,3 +77,53 @@ async def test_send_magic_packet(hass):
assert len(mocked_wakeonlan.mock_calls) == 4
assert mocked_wakeonlan.mock_calls[-1][1][0] == mac
assert not mocked_wakeonlan.mock_calls[-1][2]
async def test_setup_from_integration_yaml(hass: HomeAssistant) -> None:
"""Test setup from integration yaml."""
assert await async_setup_component(
hass,
DOMAIN,
{
DOMAIN: [
{
"mac": "00-01-02-03-04-05",
"host": "validhostname",
},
{
"mac": "06-07-08-09-0A-0B",
"host": "validhostname2",
"name": "Friendly Name",
},
],
},
)
await hass.async_block_till_done()
state = hass.states.get("switch.wake_on_lan")
state2 = hass.states.get("switch.friendly_name")
assert state.state == STATE_OFF
assert state2.state == STATE_OFF
with patch.object(subprocess, "call", return_value=0):
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.wake_on_lan"},
blocking=True,
)
state = hass.states.get("switch.wake_on_lan")
assert state.state == STATE_ON
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.wake_on_lan"},
blocking=True,
)
state = hass.states.get("switch.wake_on_lan")
assert state.state == STATE_ON