Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add samsungtv.turn_off trigger #91903

Closed
wants to merge 9 commits into from
11 changes: 8 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
"appPort": ["8123:8123"],
"runArgs": ["-e", "GIT_EDITOR=code --wait"],
"extensions": [
"ms-python.vscode-pylance",
"ms-python.python",
"visualstudioexptteam.vscodeintellicode",
"redhat.vscode-yaml",
"esbenp.prettier-vscode",
"GitHub.vscode-pull-request-github"
"GitHub.vscode-pull-request-github",
"ms-python.pylint",
"ms-python.black-formatter"
],
// Please keep this file in sync with settings in home-assistant/.vscode/settings.default.json
"settings": {
Expand All @@ -24,7 +26,10 @@
"python.linting.pydocstylePath": "/usr/local/bin/pydocstyle",
"python.linting.mypyPath": "/usr/local/bin/mypy",
"python.linting.pylintPath": "/usr/local/bin/pylint",
"python.formatting.provider": "black",
"python.formatting.provider": "none",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.testing.pytestArgs": ["--no-cov"],
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
Expand Down
5 changes: 4 additions & 1 deletion .vscode/settings.default.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
// Please keep this file in sync with settings in home-assistant/.devcontainer/devcontainer.json
"python.formatting.provider": "black",
"python.formatting.provider": "none",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
}
// Added --no-cov to work around TypeError: message must be set
// https://github.com/microsoft/vscode-python/issues/14067
"python.testing.pytestArgs": ["--no-cov"],
Expand Down
16 changes: 9 additions & 7 deletions homeassistant/components/samsungtv/device_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
async_get_client_by_device_entry,
async_get_device_entry_by_device_id,
)
from .triggers.turn_on import (
PLATFORM_TYPE as TURN_ON_PLATFORM_TYPE,
async_get_turn_on_trigger,
from .triggers.turn_on_off import (
PLATFORM_TYPE_TURN_OFF,
PLATFORM_TYPE_TURN_ON,
async_get_turn_on_off_triggers,
)

TRIGGER_TYPES = {TURN_ON_PLATFORM_TYPE}
TRIGGER_TYPES = {PLATFORM_TYPE_TURN_ON, PLATFORM_TYPE_TURN_OFF}
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
{
vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
Expand All @@ -38,7 +39,7 @@ async def async_validate_trigger_config(
"""Validate config."""
config = TRIGGER_SCHEMA(config)

if config[CONF_TYPE] == TURN_ON_PLATFORM_TYPE:
if config[CONF_TYPE] in [PLATFORM_TYPE_TURN_ON, PLATFORM_TYPE_TURN_OFF]:
device_id = config[CONF_DEVICE_ID]
try:
device = async_get_device_entry_by_device_id(hass, device_id)
Expand All @@ -54,7 +55,7 @@ async def async_get_triggers(
_hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
"""List device triggers for device."""
triggers = [async_get_turn_on_trigger(device_id)]
triggers = async_get_turn_on_off_triggers(device_id)
return triggers


Expand All @@ -65,7 +66,8 @@ async def async_attach_trigger(
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
if (trigger_type := config[CONF_TYPE]) == TURN_ON_PLATFORM_TYPE:
trigger_type = config[CONF_TYPE]
if config[CONF_TYPE] in [PLATFORM_TYPE_TURN_ON, PLATFORM_TYPE_TURN_OFF]:
trigger_config = {
CONF_PLATFORM: trigger_type,
CONF_DEVICE_ID: config[CONF_DEVICE_ID],
Expand Down
27 changes: 23 additions & 4 deletions homeassistant/components/samsungtv/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@
from .bridge import SamsungTVBridge, SamsungTVWSBridge
from .const import CONF_SSDP_RENDERING_CONTROL_LOCATION, DOMAIN, LOGGER
from .entity import SamsungTVEntity
from .triggers.turn_on import async_get_turn_on_trigger
from .triggers.turn_on_off import (
PLATFORM_TYPE_TURN_OFF,
PLATFORM_TYPE_TURN_ON,
async_get_turn_on_off_triggers,
)

SOURCES = {"TV": "KEY_TV", "HDMI": "KEY_HDMI"}

Expand Down Expand Up @@ -87,6 +91,7 @@ def __init__(
CONF_SSDP_RENDERING_CONTROL_LOCATION
)
self._turn_on = PluggableAction(self.async_write_ha_state)
self._turn_off = PluggableAction(self.async_write_ha_state)
# Assume that the TV is in Play mode
self._playing: bool = True

Expand Down Expand Up @@ -331,13 +336,27 @@ async def async_added_to_hass(self) -> None:
if (entry := self.registry_entry) and entry.device_id:
self.async_on_remove(
self._turn_on.async_register(
self.hass, async_get_turn_on_trigger(entry.device_id)
)
self.hass,
async_get_turn_on_off_triggers(
entry.device_id, PLATFORM_TYPE_TURN_ON
)[0],
),
)
self.async_on_remove(
self._turn_off.async_register(
self.hass,
async_get_turn_on_off_triggers(
entry.device_id, PLATFORM_TYPE_TURN_OFF
)[0],
),
)

async def async_turn_off(self) -> None:
"""Turn off media player."""
await self._bridge.async_power_off()
if self._turn_off:
await self._turn_off.async_run(self.hass, self._context)
else:
await self._bridge.async_power_off()

async def async_set_volume_level(self, volume: float) -> None:
"""Set volume level on the media player."""
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/samsungtv/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
},
"device_automation": {
"trigger_type": {
"samsungtv.turn_on": "Device is requested to turn on"
"samsungtv.turn_on": "Device is requested to turn on",
"samsungtv.turn_off": "Device is requested to turn off"
}
}
}
7 changes: 5 additions & 2 deletions homeassistant/components/samsungtv/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
)
from homeassistant.helpers.typing import ConfigType

from .triggers import turn_on
from .triggers import turn_on_off

TRIGGERS = {
"turn_on": turn_on,
# Not sure what to do here
"turn_on": turn_on_off,
"turn_off": turn_on_off,
}


Expand All @@ -24,6 +26,7 @@ def _get_trigger_platform(config: ConfigType) -> TriggerProtocol:
platform_split = config[CONF_PLATFORM].split(".", maxsplit=1)
if len(platform_split) < 2 or platform_split[1] not in TRIGGERS:
raise ValueError(f"Unknown Samsung TV trigger platform {config[CONF_PLATFORM]}")
# Not sure what to do here too
return cast(TriggerProtocol, TRIGGERS[platform_split[1]])


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Samsung TV device turn on trigger."""
"""Samsung TV device turn on and turn off triggers."""
from __future__ import annotations

import voluptuous as vol
Expand Down Expand Up @@ -26,15 +26,18 @@
async_get_device_id_from_entity_id,
)

# Platform type should be <DOMAIN>.<SUBMODULE_NAME>
PLATFORM_TYPE = f"{DOMAIN}.{__name__.rsplit('.', maxsplit=1)[-1]}"

TRIGGER_TYPE_TURN_ON = "turn_on"
TRIGGER_TYPE_TURN_OFF = "turn_off"

PLATFORM_TYPE_TURN_ON = f"{DOMAIN}.{TRIGGER_TYPE_TURN_ON}"
PLATFORM_TYPE_TURN_OFF = f"{DOMAIN}.{TRIGGER_TYPE_TURN_OFF}"

TRIGGER_SCHEMA = vol.All(
cv.TRIGGER_BASE_SCHEMA.extend(
{
vol.Required(CONF_PLATFORM): PLATFORM_TYPE,
vol.Required(CONF_PLATFORM): vol.In(
PLATFORM_TYPE_TURN_ON, PLATFORM_TYPE_TURN_OFF
),
vol.Optional(ATTR_DEVICE_ID): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
},
Expand All @@ -43,24 +46,34 @@
)


def async_get_turn_on_trigger(device_id: str) -> dict[str, str]:
"""Return data for a turn on trigger."""
def async_get_turn_on_off_triggers(
device_id: str, platform_type: str | None = None
) -> list[dict[str, str]]:
"""Return data for turn on and turn off triggers."""

if platform_type is None:
platforms = [PLATFORM_TYPE_TURN_ON, PLATFORM_TYPE_TURN_OFF]
else:
platforms = [platform_type]

return {
CONF_PLATFORM: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_TYPE: PLATFORM_TYPE,
}
triggers = []
for platform in platforms:
triggers.append(
{
CONF_PLATFORM: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_TYPE: platform,
}
)
return triggers


async def async_attach_trigger(
hass: HomeAssistant,
config: ConfigType,
action: TriggerActionType,
trigger_info: TriggerInfo,
*,
platform_type: str = PLATFORM_TYPE,
) -> CALLBACK_TYPE | None:
"""Attach a trigger."""
device_ids = set()
Expand All @@ -82,19 +95,22 @@ async def async_attach_trigger(
for device_id in device_ids:
device = async_get_device_entry_by_device_id(hass, device_id)
device_name = device.name_by_user or device.name
# Example: extracts "turn off" from "samsungtv.turn_off"
platform_type = config[CONF_PLATFORM]
trigger_name = platform_type.split(".")[1].replace("_", " ")

variables = {
**trigger_data,
CONF_PLATFORM: platform_type,
ATTR_DEVICE_ID: device_id,
"description": f"Samsung turn on trigger for {device_name}",
"description": f"Samsung {trigger_name} trigger for {device_name}",
}

turn_on_trigger = async_get_turn_on_trigger(device_id)
trigger = async_get_turn_on_off_triggers(device_id, platform_type)[0]

unsubs.append(
PluggableAction.async_attach_trigger(
hass, turn_on_trigger, action, {"trigger": variables}
hass, trigger, action, {"trigger": variables}
)
)

Expand Down
Loading