mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 17:27:52 +00:00
Add service homeworks.send_command (#114059)
* Add service homeworks.send_command * Translate exception
This commit is contained in:
parent
adbaed2c6d
commit
d058615961
@ -2,8 +2,10 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from time import sleep
|
||||
from typing import Any
|
||||
|
||||
from pyhomeworks.pyhomeworks import HW_BUTTON_PRESSED, HW_BUTTON_RELEASED, Homeworks
|
||||
@ -18,8 +20,8 @@ from homeassistant.const import (
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.core import Event, HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady, ServiceValidationError
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
||||
@ -40,6 +42,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.LIGHT]
|
||||
|
||||
CONF_COMMAND = "command"
|
||||
|
||||
EVENT_BUTTON_PRESS = "homeworks_button_press"
|
||||
EVENT_BUTTON_RELEASE = "homeworks_button_release"
|
||||
|
||||
@ -77,6 +81,13 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
SERVICE_SEND_COMMAND_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_CONTROLLER_ID): str,
|
||||
vol.Required(CONF_COMMAND): vol.All(cv.ensure_list, [str]),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HomeworksData:
|
||||
@ -87,6 +98,66 @@ class HomeworksData:
|
||||
keypads: dict[str, HomeworksKeypad]
|
||||
|
||||
|
||||
@callback
|
||||
def async_setup_services(hass: HomeAssistant) -> None:
|
||||
"""Set up services for Lutron Homeworks Series 4 and 8 integration."""
|
||||
|
||||
async def async_call_service(service_call: ServiceCall) -> None:
|
||||
"""Call the service."""
|
||||
await async_send_command(hass, service_call.data)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
"send_command",
|
||||
async_call_service,
|
||||
schema=SERVICE_SEND_COMMAND_SCHEMA,
|
||||
)
|
||||
|
||||
|
||||
async def async_send_command(hass: HomeAssistant, data: Mapping[str, Any]) -> None:
|
||||
"""Send command to a controller."""
|
||||
|
||||
def get_controller_ids() -> list[str]:
|
||||
"""Get homeworks data for the specified controller ID."""
|
||||
return [data.controller_id for data in hass.data[DOMAIN].values()]
|
||||
|
||||
def get_homeworks_data(controller_id: str) -> HomeworksData | None:
|
||||
"""Get homeworks data for the specified controller ID."""
|
||||
data: HomeworksData
|
||||
for data in hass.data[DOMAIN].values():
|
||||
if data.controller_id == controller_id:
|
||||
return data
|
||||
return None
|
||||
|
||||
def send_commands(controller: Homeworks, commands: list[str]) -> None:
|
||||
"""Send commands to controller."""
|
||||
_LOGGER.debug("Send commands: %s", commands)
|
||||
for command in commands:
|
||||
if command.lower().startswith("delay"):
|
||||
delay = int(command.partition(" ")[2])
|
||||
_LOGGER.debug("Sleeping for %s ms", delay)
|
||||
sleep(delay / 1000)
|
||||
else:
|
||||
_LOGGER.debug("Sending command '%s'", command)
|
||||
# pylint: disable-next=protected-access
|
||||
controller._send(command)
|
||||
|
||||
homeworks_data = get_homeworks_data(data[CONF_CONTROLLER_ID])
|
||||
if not homeworks_data:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="invalid_controller_id",
|
||||
translation_placeholders={
|
||||
"controller_id": data[CONF_CONTROLLER_ID],
|
||||
"controller_ids": ",".join(get_controller_ids()),
|
||||
},
|
||||
)
|
||||
|
||||
await hass.async_add_executor_job(
|
||||
send_commands, homeworks_data.controller, data[CONF_COMMAND]
|
||||
)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Start Homeworks controller."""
|
||||
|
||||
@ -97,6 +168,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
)
|
||||
)
|
||||
|
||||
async_setup_services(hass)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
5
homeassistant/components/homeworks/icons.json
Normal file
5
homeassistant/components/homeworks/icons.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"services": {
|
||||
"send_command": "mdi:console"
|
||||
}
|
||||
}
|
13
homeassistant/components/homeworks/services.yaml
Normal file
13
homeassistant/components/homeworks/services.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
send_command:
|
||||
fields:
|
||||
controller_id:
|
||||
required: true
|
||||
example: "lutron_homeworks"
|
||||
selector:
|
||||
text:
|
||||
command:
|
||||
required: true
|
||||
example: "KBP, [02:08:02:01], 1"
|
||||
selector:
|
||||
text:
|
||||
multiple: true
|
@ -39,6 +39,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"invalid_controller_id": {
|
||||
"message": "Invalid controller_id '{controller_id}', expected one of '{controller_ids}'"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"error": {
|
||||
"duplicated_addr": "The specified address is already in use",
|
||||
@ -142,5 +147,21 @@
|
||||
"title": "[%key:component::homeworks::options::step::init::menu_options::select_edit_light%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"send_command": {
|
||||
"name": "Send command",
|
||||
"description": "Send custom command to a controller",
|
||||
"fields": {
|
||||
"command": {
|
||||
"name": "Command",
|
||||
"description": "Command to send to the controller. This can either be a single command or a list of commands."
|
||||
},
|
||||
"controller_id": {
|
||||
"name": "Controller ID",
|
||||
"description": "The controller to which to send command."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,14 @@
|
||||
from unittest.mock import ANY, MagicMock
|
||||
|
||||
from pyhomeworks.pyhomeworks import HW_BUTTON_PRESSED, HW_BUTTON_RELEASED
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.homeworks import EVENT_BUTTON_PRESS, EVENT_BUTTON_RELEASE
|
||||
from homeassistant.components.homeworks.const import CONF_DIMMERS, CONF_KEYPADS, DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry, async_capture_events
|
||||
@ -114,3 +116,77 @@ async def test_keypad_events(
|
||||
await hass.async_block_till_done()
|
||||
assert len(press_events) == 1
|
||||
assert len(release_events) == 1
|
||||
|
||||
|
||||
async def test_send_command(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_homeworks: MagicMock,
|
||||
) -> None:
|
||||
"""Test the send command service."""
|
||||
mock_controller = MagicMock()
|
||||
mock_homeworks.return_value = mock_controller
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_controller._send.reset_mock()
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"send_command",
|
||||
{"controller_id": "main_controller", "command": "KBP, [02:08:02:01], 1"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_controller._send.mock_calls) == 1
|
||||
assert mock_controller._send.mock_calls[0][1] == ("KBP, [02:08:02:01], 1",)
|
||||
|
||||
mock_controller._send.reset_mock()
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"send_command",
|
||||
{
|
||||
"controller_id": "main_controller",
|
||||
"command": [
|
||||
"KBP, [02:08:02:01], 1",
|
||||
"KBH, [02:08:02:01], 1",
|
||||
"KBR, [02:08:02:01], 1",
|
||||
],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_controller._send.mock_calls) == 3
|
||||
assert mock_controller._send.mock_calls[0][1] == ("KBP, [02:08:02:01], 1",)
|
||||
assert mock_controller._send.mock_calls[1][1] == ("KBH, [02:08:02:01], 1",)
|
||||
assert mock_controller._send.mock_calls[2][1] == ("KBR, [02:08:02:01], 1",)
|
||||
|
||||
mock_controller._send.reset_mock()
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"send_command",
|
||||
{
|
||||
"controller_id": "main_controller",
|
||||
"command": [
|
||||
"KBP, [02:08:02:01], 1",
|
||||
"delay 50",
|
||||
"KBH, [02:08:02:01], 1",
|
||||
"dElAy 100",
|
||||
"KBR, [02:08:02:01], 1",
|
||||
],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_controller._send.mock_calls) == 3
|
||||
assert mock_controller._send.mock_calls[0][1] == ("KBP, [02:08:02:01], 1",)
|
||||
assert mock_controller._send.mock_calls[1][1] == ("KBH, [02:08:02:01], 1",)
|
||||
assert mock_controller._send.mock_calls[2][1] == ("KBR, [02:08:02:01], 1",)
|
||||
|
||||
mock_controller._send.reset_mock()
|
||||
with pytest.raises(ServiceValidationError):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"send_command",
|
||||
{"controller_id": "unknown_controller", "command": "KBP, [02:08:02:01], 1"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mock_controller._send.mock_calls) == 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user