mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 10:13:52 -05:00
Add vibration triggers (#176408)
This commit is contained in:
Generated
+2
@@ -1967,6 +1967,8 @@ CLAUDE.md @home-assistant/core
|
||||
/tests/components/version/ @ludeeus
|
||||
/homeassistant/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja @iprak @sapuseven
|
||||
/tests/components/vesync/ @markperdue @webdjoe @thegardenmonkey @cdnninja @iprak @sapuseven
|
||||
/homeassistant/components/vibration/ @home-assistant/core
|
||||
/tests/components/vibration/ @home-assistant/core
|
||||
/homeassistant/components/vicare/ @CFenner @lackas
|
||||
/tests/components/vicare/ @CFenner @lackas
|
||||
/homeassistant/components/victron_ble/ @rajlaud
|
||||
|
||||
@@ -264,6 +264,7 @@ DEFAULT_INTEGRATIONS = {
|
||||
"occupancy",
|
||||
"power",
|
||||
"temperature",
|
||||
"vibration",
|
||||
"window",
|
||||
}
|
||||
DEFAULT_INTEGRATIONS_RECOVERY_MODE = {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
"""Integration for vibration triggers."""
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
DOMAIN = "vibration"
|
||||
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
|
||||
|
||||
__all__ = []
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the component."""
|
||||
return True
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"triggers": {
|
||||
"cleared": {
|
||||
"trigger": "mdi:vibrate-off"
|
||||
},
|
||||
"detected": {
|
||||
"trigger": "mdi:vibrate"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"domain": "vibration",
|
||||
"name": "Vibration",
|
||||
"codeowners": ["@home-assistant/core"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/vibration",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"common": {
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_for_name": "For at least"
|
||||
},
|
||||
"title": "Vibration",
|
||||
"triggers": {
|
||||
"cleared": {
|
||||
"description": "Triggers when one or more vibration sensors stop detecting vibration.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"name": "[%key:component::vibration::common::trigger_behavior_name%]"
|
||||
},
|
||||
"for": {
|
||||
"name": "[%key:component::vibration::common::trigger_for_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Vibration cleared"
|
||||
},
|
||||
"detected": {
|
||||
"description": "Triggers when one or more vibration sensors start detecting vibration.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"name": "[%key:component::vibration::common::trigger_behavior_name%]"
|
||||
},
|
||||
"for": {
|
||||
"name": "[%key:component::vibration::common::trigger_for_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Vibration detected"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
"""Provides triggers for vibration."""
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DOMAIN as BINARY_SENSOR_DOMAIN,
|
||||
BinarySensorDeviceClass,
|
||||
)
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.automation import DomainSpec
|
||||
from homeassistant.helpers.trigger import Trigger, make_entity_target_state_trigger
|
||||
|
||||
VIBRATION_DOMAIN_SPECS: dict[str, DomainSpec] = {
|
||||
BINARY_SENSOR_DOMAIN: DomainSpec(device_class=BinarySensorDeviceClass.VIBRATION),
|
||||
}
|
||||
|
||||
TRIGGERS: dict[str, type[Trigger]] = {
|
||||
"detected": make_entity_target_state_trigger(VIBRATION_DOMAIN_SPECS, STATE_ON),
|
||||
"cleared": make_entity_target_state_trigger(VIBRATION_DOMAIN_SPECS, STATE_OFF),
|
||||
}
|
||||
|
||||
|
||||
async def async_get_triggers(hass: HomeAssistant) -> dict[str, type[Trigger]]:
|
||||
"""Return the triggers for vibration."""
|
||||
return TRIGGERS
|
||||
@@ -0,0 +1,26 @@
|
||||
.trigger_common_fields: &trigger_common_fields
|
||||
behavior:
|
||||
required: true
|
||||
default: each
|
||||
selector:
|
||||
automation_behavior:
|
||||
mode: trigger
|
||||
for:
|
||||
required: true
|
||||
default: 00:00:00
|
||||
selector:
|
||||
duration:
|
||||
|
||||
detected:
|
||||
fields: *trigger_common_fields
|
||||
target:
|
||||
entity:
|
||||
- domain: binary_sensor
|
||||
device_class: vibration
|
||||
|
||||
cleared:
|
||||
fields: *trigger_common_fields
|
||||
target:
|
||||
entity:
|
||||
- domain: binary_sensor
|
||||
device_class: vibration
|
||||
@@ -126,6 +126,7 @@ NO_IOT_CLASS = [
|
||||
"temperature",
|
||||
"timer",
|
||||
"trace",
|
||||
"vibration",
|
||||
"web_rtc",
|
||||
"webhook",
|
||||
"websocket_api",
|
||||
|
||||
@@ -2076,6 +2076,7 @@ NO_QUALITY_SCALE = [
|
||||
"timer",
|
||||
"trace",
|
||||
"usage_prediction",
|
||||
"vibration",
|
||||
"web_rtc",
|
||||
"webhook",
|
||||
"websocket_api",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"""Tests for the vibration integration."""
|
||||
@@ -0,0 +1,200 @@
|
||||
"""Test vibration trigger."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
from homeassistant.const import ATTR_DEVICE_CLASS, STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.components.common import (
|
||||
TriggerStateDescription,
|
||||
assert_trigger_behavior_all,
|
||||
assert_trigger_behavior_each,
|
||||
assert_trigger_behavior_first,
|
||||
assert_trigger_options_supported,
|
||||
parametrize_target_entities,
|
||||
parametrize_trigger_states,
|
||||
target_entities,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def target_binary_sensors(hass: HomeAssistant) -> dict[str, list[str]]:
|
||||
"""Create multiple binary sensor entities associated with different targets."""
|
||||
return await target_entities(hass, "binary_sensor")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trigger_key", "base_options", "supports_behavior", "supports_duration"),
|
||||
[
|
||||
("vibration.detected", {}, True, True),
|
||||
("vibration.cleared", {}, True, True),
|
||||
],
|
||||
)
|
||||
async def test_vibration_trigger_options_validation(
|
||||
hass: HomeAssistant,
|
||||
trigger_key: str,
|
||||
base_options: dict[str, Any] | None,
|
||||
supports_behavior: bool,
|
||||
supports_duration: bool,
|
||||
) -> None:
|
||||
"""Test that vibration triggers support the expected options."""
|
||||
await assert_trigger_options_supported(
|
||||
hass,
|
||||
trigger_key,
|
||||
base_options,
|
||||
supports_behavior=supports_behavior,
|
||||
supports_duration=supports_duration,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trigger_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("binary_sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("trigger", "trigger_options", "states"),
|
||||
[
|
||||
*parametrize_trigger_states(
|
||||
trigger="vibration.detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.VIBRATION
|
||||
},
|
||||
trigger_from_none=False,
|
||||
),
|
||||
*parametrize_trigger_states(
|
||||
trigger="vibration.cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.VIBRATION
|
||||
},
|
||||
trigger_from_none=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_vibration_trigger_binary_sensor_behavior_each(
|
||||
hass: HomeAssistant,
|
||||
target_binary_sensors: dict[str, list[str]],
|
||||
trigger_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
trigger: str,
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test vibration trigger fires for binary_sensor entities with device_class vibration."""
|
||||
await assert_trigger_behavior_each(
|
||||
hass,
|
||||
target_entities=target_binary_sensors,
|
||||
trigger_target_config=trigger_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
trigger=trigger,
|
||||
trigger_options=trigger_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trigger_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("binary_sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("trigger", "trigger_options", "states"),
|
||||
[
|
||||
*parametrize_trigger_states(
|
||||
trigger="vibration.detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.VIBRATION
|
||||
},
|
||||
trigger_from_none=False,
|
||||
),
|
||||
*parametrize_trigger_states(
|
||||
trigger="vibration.cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.VIBRATION
|
||||
},
|
||||
trigger_from_none=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_vibration_trigger_binary_sensor_behavior_first(
|
||||
hass: HomeAssistant,
|
||||
target_binary_sensors: dict[str, list[str]],
|
||||
trigger_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
trigger: str,
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test vibration trigger fires on the first binary_sensor state change."""
|
||||
await assert_trigger_behavior_first(
|
||||
hass,
|
||||
target_entities=target_binary_sensors,
|
||||
trigger_target_config=trigger_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
trigger=trigger,
|
||||
trigger_options=trigger_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trigger_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("binary_sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("trigger", "trigger_options", "states"),
|
||||
[
|
||||
*parametrize_trigger_states(
|
||||
trigger="vibration.detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.VIBRATION
|
||||
},
|
||||
trigger_from_none=False,
|
||||
),
|
||||
*parametrize_trigger_states(
|
||||
trigger="vibration.cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.VIBRATION
|
||||
},
|
||||
trigger_from_none=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_vibration_trigger_binary_sensor_behavior_all(
|
||||
hass: HomeAssistant,
|
||||
target_binary_sensors: dict[str, list[str]],
|
||||
trigger_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
trigger: str,
|
||||
trigger_options: dict[str, Any],
|
||||
states: list[TriggerStateDescription],
|
||||
) -> None:
|
||||
"""Test vibration trigger fires when all binary_sensors have changed state."""
|
||||
await assert_trigger_behavior_all(
|
||||
hass,
|
||||
target_entities=target_binary_sensors,
|
||||
trigger_target_config=trigger_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
trigger=trigger,
|
||||
trigger_options=trigger_options,
|
||||
states=states,
|
||||
)
|
||||
@@ -100,6 +100,7 @@
|
||||
'update',
|
||||
'vacuum',
|
||||
'valve',
|
||||
'vibration',
|
||||
'wake_word',
|
||||
'water_heater',
|
||||
'weather',
|
||||
@@ -209,6 +210,7 @@
|
||||
'update',
|
||||
'vacuum',
|
||||
'valve',
|
||||
'vibration',
|
||||
'wake_word',
|
||||
'water_heater',
|
||||
'weather',
|
||||
|
||||
Reference in New Issue
Block a user