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.""" """Support for sending Wake-On-LAN magic packets."""
import asyncio
from collections.abc import Coroutine
from functools import partial from functools import partial
import logging import logging
from typing import Any
import voluptuous as vol import voluptuous as vol
import wakeonlan 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.core import HomeAssistant, ServiceCall
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN from .const import CONF_OFF_ACTION, DEFAULT_NAME, DOMAIN
_LOGGER = logging.getLogger(__name__) _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: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the wake on LAN component.""" """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: async def send_magic_packet(call: ServiceCall) -> None:
"""Send magic packet to wake up a device.""" """Send magic packet to wake up a device."""

View File

@ -1,2 +1,6 @@
"""Constants for the Wake-On-LAN component.""" """Constants for the Wake-On-LAN component."""
DOMAIN = "wake_on_lan" 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 from homeassistant.helpers import device_registry as dr
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback 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.script import Script
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType 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__) _LOGGER = logging.getLogger(__name__)
CONF_OFF_ACTION = "turn_off"
DEFAULT_NAME = "Wake on LAN"
DEFAULT_PING_TIMEOUT = 1
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend( PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
{ {
vol.Required(CONF_MAC): cv.string, 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, hass: HomeAssistant,
config: ConfigType, config: ConfigType,
add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up a wake on lan switch.""" """Set up a wake on lan switch."""
broadcast_address: str | None = config.get(CONF_BROADCAST_ADDRESS) if (switch_config := discovery_info) is None:
broadcast_port: int | None = config.get(CONF_BROADCAST_PORT) async_create_issue(
host: str | None = config.get(CONF_HOST) hass,
mac_address: str = config[CONF_MAC] DOMAIN,
name: str = config[CONF_NAME] "moved_yaml",
off_action: list[Any] | None = config.get(CONF_OFF_ACTION) 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( WolSwitch(
hass, 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.""" """Tests for Wake On LAN component."""
from __future__ import annotations
import subprocess
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
import voluptuous as vol 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.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 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.""" """Test of send magic packet service call."""
with patch("homeassistant.components.wake_on_lan.wakeonlan") as mocked_wakeonlan: with patch("homeassistant.components.wake_on_lan.wakeonlan") as mocked_wakeonlan:
mac = "aa:bb:cc:dd:ee:ff" 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 len(mocked_wakeonlan.mock_calls) == 4
assert mocked_wakeonlan.mock_calls[-1][1][0] == mac assert mocked_wakeonlan.mock_calls[-1][1][0] == mac
assert not mocked_wakeonlan.mock_calls[-1][2] 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