Compare commits

..

1 Commits

Author SHA1 Message Date
Stefan Agner
20740326cb Machine container: Remove codenotary configuration
The builder no longer creates Codenotary signatures and Supervisor no
longer checks Codenotary signatures. This information has become obsolete,
so remove it from the build.yaml builder configuration.
2025-10-06 19:17:30 +02:00
7 changed files with 115 additions and 246 deletions

View File

@@ -20,9 +20,8 @@ set_temperature:
selector:
number:
min: 0
max: 250
max: 100
step: 0.5
mode: box
unit_of_measurement: "°"
operation_mode:
example: eco

View File

@@ -2,7 +2,6 @@
from __future__ import annotations
import asyncio
from typing import Any
import voluptuous as vol
@@ -21,7 +20,7 @@ from homeassistant.const import (
CONF_PLATFORM,
CONF_TYPE,
)
from homeassistant.core import CALLBACK_TYPE, Context, HomeAssistant, callback
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import (
config_validation as cv,
@@ -455,28 +454,8 @@ async def async_attach_trigger(
zwave_js_config = await validate_value_updated_trigger_config(
hass, zwave_js_config
)
@callback
def run_action(
extra_trigger_payload: dict[str, Any],
description: str,
context: Context | None = None,
) -> asyncio.Task[Any]:
"""Run action with trigger variables."""
payload = {
"trigger": {
**trigger_info["trigger_data"],
CONF_PLATFORM: VALUE_UPDATED_PLATFORM_TYPE,
"description": description,
**extra_trigger_payload,
}
}
return hass.async_create_task(action(payload, context))
return await attach_value_updated_trigger(
hass, zwave_js_config[CONF_OPTIONS], run_action
hass, zwave_js_config[CONF_OPTIONS], action, trigger_info
)
raise HomeAssistantError(f"Unhandled trigger type {trigger_type}")

View File

@@ -17,12 +17,19 @@ from homeassistant.const import (
ATTR_DEVICE_ID,
ATTR_ENTITY_ID,
CONF_OPTIONS,
CONF_PLATFORM,
)
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.automation import move_top_level_schema_fields_to_options
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.trigger import Trigger, TriggerActionRunner, TriggerConfig
from homeassistant.helpers.trigger import (
Trigger,
TriggerActionType,
TriggerConfig,
TriggerData,
TriggerInfo,
)
from homeassistant.helpers.typing import ConfigType
from ..const import (
@@ -120,13 +127,17 @@ _CONFIG_SCHEMA = vol.Schema(
class EventTrigger(Trigger):
"""Z-Wave JS event trigger."""
_hass: HomeAssistant
_options: dict[str, Any]
_event_source: str
_event_name: str
_event_data_filter: dict
_job: HassJob
_trigger_data: TriggerData
_unsubs: list[Callable]
_action_runner: TriggerActionRunner
_platform_type = PLATFORM_TYPE
@classmethod
async def async_validate_complete_config(
@@ -165,12 +176,14 @@ class EventTrigger(Trigger):
def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None:
"""Initialize trigger."""
super().__init__(hass, config)
self._hass = hass
assert config.options is not None
self._options = config.options
async def async_attach_runner(
self, run_action: TriggerActionRunner
async def async_attach(
self,
action: TriggerActionType,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
dev_reg = dr.async_get(self._hass)
@@ -185,7 +198,8 @@ class EventTrigger(Trigger):
self._event_source = options[ATTR_EVENT_SOURCE]
self._event_name = options[ATTR_EVENT]
self._event_data_filter = options.get(ATTR_EVENT_DATA, {})
self._action_runner = run_action
self._job = HassJob(action)
self._trigger_data = trigger_info["trigger_data"]
self._unsubs: list[Callable] = []
self._create_zwave_listeners()
@@ -211,7 +225,9 @@ class EventTrigger(Trigger):
if event_data[key] != val:
return
payload: dict[str, Any] = {
payload = {
**self._trigger_data,
CONF_PLATFORM: self._platform_type,
ATTR_EVENT_SOURCE: self._event_source,
ATTR_EVENT: self._event_name,
ATTR_EVENT_DATA: event_data,
@@ -221,17 +237,21 @@ class EventTrigger(Trigger):
f"Z-Wave JS '{self._event_source}' event '{self._event_name}' was emitted"
)
description = primary_desc
if device:
device_name = device.name_by_user or device.name
payload[ATTR_DEVICE_ID] = device.id
home_and_node_id = get_home_and_node_id_from_device_entry(device)
assert home_and_node_id
payload[ATTR_NODE_ID] = home_and_node_id[1]
description = f"{primary_desc} on {device_name}"
payload["description"] = f"{primary_desc} on {device_name}"
else:
payload["description"] = primary_desc
description = f"{description} with event data: {event_data}"
self._action_runner(payload, description)
payload["description"] = (
f"{payload['description']} with event data: {event_data}"
)
self._hass.async_run_hass_job(self._job, {"trigger": payload})
@callback
def _async_remove(self) -> None:

View File

@@ -11,12 +11,23 @@ from zwave_js_server.const import CommandClass
from zwave_js_server.model.driver import Driver
from zwave_js_server.model.value import Value, get_value_id_str
from homeassistant.const import ATTR_DEVICE_ID, ATTR_ENTITY_ID, CONF_OPTIONS, MATCH_ALL
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.const import (
ATTR_DEVICE_ID,
ATTR_ENTITY_ID,
CONF_OPTIONS,
CONF_PLATFORM,
MATCH_ALL,
)
from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.automation import move_top_level_schema_fields_to_options
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.trigger import Trigger, TriggerActionRunner, TriggerConfig
from homeassistant.helpers.trigger import (
Trigger,
TriggerActionType,
TriggerConfig,
TriggerInfo,
)
from homeassistant.helpers.typing import ConfigType
from ..config_validation import VALUE_SCHEMA
@@ -89,7 +100,12 @@ async def async_validate_trigger_config(
async def async_attach_trigger(
hass: HomeAssistant, options: ConfigType, run_action: TriggerActionRunner
hass: HomeAssistant,
options: ConfigType,
action: TriggerActionType,
trigger_info: TriggerInfo,
*,
platform_type: str = PLATFORM_TYPE,
) -> CALLBACK_TYPE:
"""Listen for state changes based on configuration."""
dev_reg = dr.async_get(hass)
@@ -105,6 +121,9 @@ async def async_attach_trigger(
endpoint = options.get(ATTR_ENDPOINT)
property_key = options.get(ATTR_PROPERTY_KEY)
unsubs: list[Callable] = []
job = HassJob(action)
trigger_data = trigger_info["trigger_data"]
@callback
def async_on_value_updated(
@@ -133,8 +152,10 @@ async def async_attach_trigger(
return
device_name = device.name_by_user or device.name
description = f"Z-Wave value {value.value_id} updated on {device_name}"
payload = {
**trigger_data,
CONF_PLATFORM: platform_type,
ATTR_DEVICE_ID: device.id,
ATTR_NODE_ID: value.node.node_id,
ATTR_COMMAND_CLASS: value.command_class,
@@ -148,9 +169,10 @@ async def async_attach_trigger(
ATTR_PREVIOUS_VALUE_RAW: prev_value_raw,
ATTR_CURRENT_VALUE: curr_value,
ATTR_CURRENT_VALUE_RAW: curr_value_raw,
"description": f"Z-Wave value {value.value_id} updated on {device_name}",
}
run_action(payload, description)
hass.async_run_hass_job(job, {"trigger": payload})
@callback
def async_remove() -> None:
@@ -201,6 +223,7 @@ async def async_attach_trigger(
class ValueUpdatedTrigger(Trigger):
"""Z-Wave JS value updated trigger."""
_hass: HomeAssistant
_options: dict[str, Any]
@classmethod
@@ -222,12 +245,16 @@ class ValueUpdatedTrigger(Trigger):
def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None:
"""Initialize trigger."""
super().__init__(hass, config)
self._hass = hass
assert config.options is not None
self._options = config.options
async def async_attach_runner(
self, run_action: TriggerActionRunner
async def async_attach(
self,
action: TriggerActionType,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
return await async_attach_trigger(self._hass, self._options, run_action)
return await async_attach_trigger(
self._hass, self._options, action, trigger_info
)

View File

@@ -28,10 +28,8 @@ from homeassistant.core import (
CALLBACK_TYPE,
Context,
HassJob,
HassJobType,
HomeAssistant,
callback,
get_hassjob_callable_job_type,
is_callback,
)
from homeassistant.exceptions import HomeAssistantError, TemplateError
@@ -180,8 +178,6 @@ _TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
class Trigger(abc.ABC):
"""Trigger class."""
_hass: HomeAssistant
@classmethod
async def async_validate_complete_config(
cls, hass: HomeAssistant, complete_config: ConfigType
@@ -216,33 +212,14 @@ class Trigger(abc.ABC):
def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None:
"""Initialize trigger."""
self._hass = hass
async def async_attach_action(
self,
action: TriggerAction,
action_payload_builder: TriggerActionPayloadBuilder,
) -> CALLBACK_TYPE:
"""Attach the trigger to an action."""
@callback
def run_action(
extra_trigger_payload: dict[str, Any],
description: str,
context: Context | None = None,
) -> asyncio.Task[Any]:
"""Run action with trigger variables."""
payload = action_payload_builder(extra_trigger_payload, description)
return self._hass.async_create_task(action(payload, context))
return await self.async_attach_runner(run_action)
@abc.abstractmethod
async def async_attach_runner(
self, run_action: TriggerActionRunner
async def async_attach(
self,
action: TriggerActionType,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach the trigger to an action runner."""
"""Attach the trigger."""
class TriggerProtocol(Protocol):
@@ -280,43 +257,6 @@ class TriggerConfig:
options: dict[str, Any] | None = None
class TriggerActionRunner(Protocol):
"""Protocol type for the trigger action runner helper callback."""
@callback
def __call__(
self,
extra_trigger_payload: dict[str, Any],
description: str,
context: Context | None = None,
) -> asyncio.Task[Any]:
"""Define trigger action runner type.
Returns:
A Task that allows awaiting for the action to finish.
"""
class TriggerActionPayloadBuilder(Protocol):
"""Protocol type for the trigger action payload builder."""
def __call__(
self, extra_trigger_payload: dict[str, Any], description: str
) -> dict[str, Any]:
"""Define trigger action payload builder type."""
class TriggerAction(Protocol):
"""Protocol type for trigger action callback."""
async def __call__(
self,
run_variables: dict[str, Any],
context: Context | None = None,
) -> Any:
"""Define action callback type."""
class TriggerActionType(Protocol):
"""Protocol type for trigger action callback."""
@@ -553,71 +493,6 @@ def _trigger_action_wrapper(
return wrapper_func
async def _async_attach_trigger_cls(
hass: HomeAssistant,
trigger_cls: type[Trigger],
trigger_key: str,
conf: ConfigType,
action: Callable,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Initialize a new Trigger class and attach it."""
def action_payload_builder(
extra_trigger_payload: dict[str, Any], description: str
) -> dict[str, Any]:
"""Build action variables."""
payload = {
"trigger": {
**trigger_info["trigger_data"],
CONF_PLATFORM: trigger_key,
"description": description,
**extra_trigger_payload,
}
}
if CONF_VARIABLES in conf:
trigger_variables = conf[CONF_VARIABLES]
payload.update(trigger_variables.async_render(hass, payload))
return payload
# Wrap sync action so that it is always async.
# This should be removed when sync actions are no longer supported.
match get_hassjob_callable_job_type(action):
case HassJobType.Executor:
original_action = action
async def wrapped_executor_action(
run_variables: dict[str, Any], context: Context | None = None
) -> Any:
"""Wrap sync action to be called in executor."""
return await hass.async_add_executor_job(
original_action, run_variables, context
)
action = wrapped_executor_action
case HassJobType.Callback:
original_action = action
async def wrapped_callback_action(
run_variables: dict[str, Any], context: Context | None = None
) -> Any:
"""Wrap callback action to be awaitable."""
return original_action(run_variables, context)
action = wrapped_callback_action
trigger = trigger_cls(
hass,
TriggerConfig(
key=trigger_key,
target=conf.get(CONF_TARGET),
options=conf.get(CONF_OPTIONS),
),
)
return await trigger.async_attach_action(action, action_payload_builder)
async def async_initialize_triggers(
hass: HomeAssistant,
trigger_config: list[ConfigType],
@@ -657,17 +532,23 @@ async def async_initialize_triggers(
trigger_data=trigger_data,
)
action_wrapper = _trigger_action_wrapper(hass, action, conf)
if hasattr(platform, "async_get_triggers"):
trigger_descriptors = await platform.async_get_triggers(hass)
relative_trigger_key = get_relative_description_key(
platform_domain, trigger_key
)
trigger_cls = trigger_descriptors[relative_trigger_key]
coro = _async_attach_trigger_cls(
hass, trigger_cls, trigger_key, conf, action, info
trigger = trigger_cls(
hass,
TriggerConfig(
key=trigger_key,
target=conf.get(CONF_TARGET),
options=conf.get(CONF_OPTIONS),
),
)
coro = trigger.async_attach(action_wrapper, info)
else:
action_wrapper = _trigger_action_wrapper(hass, action, conf)
coro = platform.async_attach_trigger(hass, conf, action_wrapper, info)
triggers.append(create_eager_task(coro))

View File

@@ -5,9 +5,6 @@ build_from:
armhf: "ghcr.io/home-assistant/armhf-homeassistant:"
amd64: "ghcr.io/home-assistant/amd64-homeassistant:"
i386: "ghcr.io/home-assistant/i386-homeassistant:"
codenotary:
signer: notary@home-assistant.io
base_image: notary@home-assistant.io
cosign:
base_identity: https://github.com/home-assistant/core/.*
identity: https://github.com/home-assistant/core/.*

View File

@@ -24,7 +24,9 @@ from homeassistant.helpers.trigger import (
DATA_PLUGGABLE_ACTIONS,
PluggableAction,
Trigger,
TriggerActionRunner,
TriggerActionType,
TriggerConfig,
TriggerInfo,
_async_get_trigger_platform,
async_initialize_triggers,
async_validate_trigger_config,
@@ -447,31 +449,7 @@ async def test_pluggable_action(
assert not plug_2
class TriggerActionFunctionTypeHelper:
"""Helper for testing different trigger action function types."""
def __init__(self) -> None:
"""Init helper."""
self.action_calls = []
@callback
def cb_action(self, *args):
"""Callback action."""
self.action_calls.append([*args])
def sync_action(self, *args):
"""Sync action."""
self.action_calls.append([*args])
async def async_action(self, *args):
"""Async action."""
self.action_calls.append([*args])
@pytest.mark.parametrize("action_method", ["cb_action", "sync_action", "async_action"])
async def test_platform_multiple_triggers(
hass: HomeAssistant, action_method: str
) -> None:
async def test_platform_multiple_triggers(hass: HomeAssistant) -> None:
"""Test a trigger platform with multiple trigger."""
class MockTrigger(Trigger):
@@ -484,23 +462,30 @@ async def test_platform_multiple_triggers(
"""Validate config."""
return config
def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None:
"""Initialize trigger."""
class MockTrigger1(MockTrigger):
"""Mock trigger 1."""
async def async_attach_runner(
self, run_action: TriggerActionRunner
async def async_attach(
self,
action: TriggerActionType,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
run_action({"extra": "test_trigger_1"}, "trigger 1 desc")
action({"trigger": "test_trigger_1"})
class MockTrigger2(MockTrigger):
"""Mock trigger 2."""
async def async_attach_runner(
self, run_action: TriggerActionRunner
async def async_attach(
self,
action: TriggerActionType,
trigger_info: TriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
run_action({"extra": "test_trigger_2"}, "trigger 2 desc")
action({"trigger": "test_trigger_2"})
async def async_get_triggers(hass: HomeAssistant) -> dict[str, type[Trigger]]:
return {
@@ -523,41 +508,22 @@ async def test_platform_multiple_triggers(
log_cb = MagicMock()
action_helper = TriggerActionFunctionTypeHelper()
action_method = getattr(action_helper, action_method)
action_calls = []
await async_initialize_triggers(hass, config_1, action_method, "test", "", log_cb)
assert len(action_helper.action_calls) == 1
assert action_helper.action_calls[0][0] == {
"trigger": {
"alias": None,
"description": "trigger 1 desc",
"extra": "test_trigger_1",
"id": "0",
"idx": "0",
"platform": "test",
}
}
action_helper.action_calls.clear()
@callback
def cb_action(*args):
action_calls.append([*args])
await async_initialize_triggers(hass, config_2, action_method, "test", "", log_cb)
assert len(action_helper.action_calls) == 1
assert action_helper.action_calls[0][0] == {
"trigger": {
"alias": None,
"description": "trigger 2 desc",
"extra": "test_trigger_2",
"id": "0",
"idx": "0",
"platform": "test.trig_2",
}
}
action_helper.action_calls.clear()
await async_initialize_triggers(hass, config_1, cb_action, "test", "", log_cb)
assert action_calls == [[{"trigger": "test_trigger_1"}]]
action_calls.clear()
await async_initialize_triggers(hass, config_2, cb_action, "test", "", log_cb)
assert action_calls == [[{"trigger": "test_trigger_2"}]]
action_calls.clear()
with pytest.raises(KeyError):
await async_initialize_triggers(
hass, config_3, action_method, "test", "", log_cb
)
await async_initialize_triggers(hass, config_3, cb_action, "test", "", log_cb)
async def test_platform_migrate_trigger(hass: HomeAssistant) -> None: