mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
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:
parent
aedbfdabee
commit
52298a251b
@ -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."""
|
||||||
|
@ -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
|
||||||
|
8
homeassistant/components/wake_on_lan/strings.json
Normal file
8
homeassistant/components/wake_on_lan/strings.json
Normal 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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
tests/components/wake_on_lan/conftest.py
Normal file
13
tests/components/wake_on_lan/conftest.py
Normal 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
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user