* Make async_get_device connections Optional, default None * Remove unnecessary async_get_device connections arg usages Some of these were using an incorrect collection type, which didn't cause issues mostly just due to luck.
1117 lines
38 KiB
Python
1117 lines
38 KiB
Python
"""The tests for MQTT device triggers."""
|
|
import json
|
|
|
|
import pytest
|
|
|
|
import homeassistant.components.automation as automation
|
|
from homeassistant.components.mqtt import DOMAIN, debug_info
|
|
from homeassistant.components.mqtt.device_trigger import async_attach_trigger
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from tests.common import (
|
|
assert_lists_same,
|
|
async_fire_mqtt_message,
|
|
async_get_device_automations,
|
|
async_mock_service,
|
|
mock_device_registry,
|
|
mock_registry,
|
|
)
|
|
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa
|
|
|
|
|
|
@pytest.fixture
|
|
def device_reg(hass):
|
|
"""Return an empty, loaded, registry."""
|
|
return mock_device_registry(hass)
|
|
|
|
|
|
@pytest.fixture
|
|
def entity_reg(hass):
|
|
"""Return an empty, loaded, registry."""
|
|
return mock_registry(hass)
|
|
|
|
|
|
@pytest.fixture
|
|
def calls(hass):
|
|
"""Track calls to a mock service."""
|
|
return async_mock_service(hass, "test", "automation")
|
|
|
|
|
|
async def test_get_triggers(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test we get the expected triggers from a discovered mqtt device."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
expected_triggers = [
|
|
{
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
]
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert_lists_same(triggers, expected_triggers)
|
|
|
|
|
|
async def test_get_unknown_triggers(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test we don't get unknown triggers."""
|
|
# Discover a sensor (without device triggers)
|
|
data1 = (
|
|
'{ "device":{"identifiers":["0AFFD2"]},'
|
|
' "state_topic": "foobar/sensor",'
|
|
' "unique_id": "unique" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert_lists_same(triggers, [])
|
|
|
|
|
|
async def test_get_non_existing_triggers(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test getting non existing triggers."""
|
|
# Discover a sensor (without device triggers)
|
|
data1 = (
|
|
'{ "device":{"identifiers":["0AFFD2"]},'
|
|
' "state_topic": "foobar/sensor",'
|
|
' "unique_id": "unique" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert_lists_same(triggers, [])
|
|
|
|
|
|
@pytest.mark.no_fail_on_log_exception
|
|
async def test_discover_bad_triggers(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test bad discovery message."""
|
|
# Test sending bad data
|
|
data0 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payloads": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data0)
|
|
await hass.async_block_till_done()
|
|
assert device_reg.async_get_device({("mqtt", "0AFFD2")}) is None
|
|
|
|
# Test sending correct data
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
expected_triggers = [
|
|
{
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
]
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert_lists_same(triggers, expected_triggers)
|
|
|
|
|
|
async def test_update_remove_triggers(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test triggers can be updated and removed."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
data2 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_2" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
expected_triggers1 = [
|
|
{
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
]
|
|
expected_triggers2 = [dict(expected_triggers1[0])]
|
|
expected_triggers2[0]["subtype"] = "button_2"
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert_lists_same(triggers, expected_triggers1)
|
|
|
|
# Update trigger
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert_lists_same(triggers, expected_triggers2)
|
|
|
|
# Remove trigger
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
assert device_entry is None
|
|
|
|
|
|
async def test_if_fires_on_mqtt_message(hass, device_reg, calls, mqtt_mock):
|
|
"""Test triggers firing."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
data2 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "long_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_long_press",'
|
|
' "subtype": "button_2" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla2/config", data2)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla2",
|
|
"type": "button_1",
|
|
"subtype": "button_long_press",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("long_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
assert calls[0].data["some"] == "short_press"
|
|
|
|
# Fake long press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "long_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 2
|
|
assert calls[1].data["some"] == "long_press"
|
|
|
|
|
|
async def test_if_fires_on_mqtt_message_late_discover(
|
|
hass, device_reg, calls, mqtt_mock
|
|
):
|
|
"""Test triggers firing of MQTT device triggers discovered after setup."""
|
|
data0 = (
|
|
'{ "device":{"identifiers":["0AFFD2"]},'
|
|
' "state_topic": "foobar/sensor",'
|
|
' "unique_id": "unique" }'
|
|
)
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
data2 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "long_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_long_press",'
|
|
' "subtype": "button_2" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla0/config", data0)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla2",
|
|
"type": "button_1",
|
|
"subtype": "button_long_press",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("long_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla2/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
assert calls[0].data["some"] == "short_press"
|
|
|
|
# Fake long press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "long_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 2
|
|
assert calls[1].data["some"] == "long_press"
|
|
|
|
|
|
async def test_if_fires_on_mqtt_message_after_update(
|
|
hass, device_reg, calls, mqtt_mock
|
|
):
|
|
"""Test triggers firing after update."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
data2 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "topic": "foobar/triggers/buttonOne",'
|
|
' "type": "button_long_press",'
|
|
' "subtype": "button_2" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
# Update the trigger with different topic
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/buttonOne", "")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 2
|
|
|
|
# Update the trigger with same topic
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 2
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/buttonOne", "")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 3
|
|
|
|
|
|
async def test_no_resubscribe_same_topic(hass, device_reg, mqtt_mock):
|
|
"""Test subscription to topics without change."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
call_count = mqtt_mock.async_subscribe.call_count
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
assert mqtt_mock.async_subscribe.call_count == call_count
|
|
|
|
|
|
async def test_not_fires_on_mqtt_message_after_remove_by_mqtt(
|
|
hass, device_reg, calls, mqtt_mock
|
|
):
|
|
"""Test triggers not firing after removal."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
# Remove the trigger
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
# Rediscover the trigger
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 2
|
|
|
|
|
|
async def test_not_fires_on_mqtt_message_after_remove_from_registry(
|
|
hass, device_reg, calls, mqtt_mock
|
|
):
|
|
"""Test triggers not firing after removal."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
assert await async_setup_component(
|
|
hass,
|
|
automation.DOMAIN,
|
|
{
|
|
automation.DOMAIN: [
|
|
{
|
|
"trigger": {
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
"action": {
|
|
"service": "test.automation",
|
|
"data_template": {"some": ("short_press")},
|
|
},
|
|
},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
# Remove the device
|
|
device_reg.async_remove_device(device_entry.id)
|
|
await hass.async_block_till_done()
|
|
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
|
|
async def test_attach_remove(hass, device_reg, mqtt_mock):
|
|
"""Test attach and removal of trigger."""
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
calls = []
|
|
|
|
def callback(trigger):
|
|
calls.append(trigger["trigger"]["payload"])
|
|
|
|
remove = await async_attach_trigger(
|
|
hass,
|
|
{
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
callback,
|
|
None,
|
|
)
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
assert calls[0] == "short_press"
|
|
|
|
# Remove the trigger
|
|
remove()
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify the triggers are no longer active
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
|
|
async def test_attach_remove_late(hass, device_reg, mqtt_mock):
|
|
"""Test attach and removal of trigger ."""
|
|
data0 = (
|
|
'{ "device":{"identifiers":["0AFFD2"]},'
|
|
' "state_topic": "foobar/sensor",'
|
|
' "unique_id": "unique" }'
|
|
)
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla0/config", data0)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
calls = []
|
|
|
|
def callback(trigger):
|
|
calls.append(trigger["trigger"]["payload"])
|
|
|
|
remove = await async_attach_trigger(
|
|
hass,
|
|
{
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
callback,
|
|
None,
|
|
)
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake short press.
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
assert calls[0] == "short_press"
|
|
|
|
# Remove the trigger
|
|
remove()
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify the triggers are no longer active
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 1
|
|
|
|
|
|
async def test_attach_remove_late2(hass, device_reg, mqtt_mock):
|
|
"""Test attach and removal of trigger ."""
|
|
data0 = (
|
|
'{ "device":{"identifiers":["0AFFD2"]},'
|
|
' "state_topic": "foobar/sensor",'
|
|
' "unique_id": "unique" }'
|
|
)
|
|
data1 = (
|
|
'{ "automation_type":"trigger",'
|
|
' "device":{"identifiers":["0AFFD2"]},'
|
|
' "payload": "short_press",'
|
|
' "topic": "foobar/triggers/button1",'
|
|
' "type": "button_short_press",'
|
|
' "subtype": "button_1" }'
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla0/config", data0)
|
|
await hass.async_block_till_done()
|
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
|
|
|
|
calls = []
|
|
|
|
def callback(trigger):
|
|
calls.append(trigger["trigger"]["payload"])
|
|
|
|
remove = await async_attach_trigger(
|
|
hass,
|
|
{
|
|
"platform": "device",
|
|
"domain": DOMAIN,
|
|
"device_id": device_entry.id,
|
|
"discovery_id": "bla1",
|
|
"type": "button_short_press",
|
|
"subtype": "button_1",
|
|
},
|
|
callback,
|
|
None,
|
|
)
|
|
|
|
# Remove the trigger
|
|
remove()
|
|
await hass.async_block_till_done()
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify the triggers are no longer active
|
|
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
|
|
await hass.async_block_till_done()
|
|
assert len(calls) == 0
|
|
|
|
|
|
async def test_entity_device_info_with_connection(hass, mqtt_mock):
|
|
"""Test MQTT device registry integration."""
|
|
registry = await hass.helpers.device_registry.async_get_registry()
|
|
|
|
data = json.dumps(
|
|
{
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {
|
|
"connections": [["mac", "02:5b:26:a8:dc:12"]],
|
|
"manufacturer": "Whatever",
|
|
"name": "Beer",
|
|
"model": "Glass",
|
|
"sw_version": "0.1-beta",
|
|
},
|
|
}
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
device = registry.async_get_device(set(), {("mac", "02:5b:26:a8:dc:12")})
|
|
assert device is not None
|
|
assert device.connections == {("mac", "02:5b:26:a8:dc:12")}
|
|
assert device.manufacturer == "Whatever"
|
|
assert device.name == "Beer"
|
|
assert device.model == "Glass"
|
|
assert device.sw_version == "0.1-beta"
|
|
|
|
|
|
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
|
|
"""Test MQTT device registry integration."""
|
|
registry = await hass.helpers.device_registry.async_get_registry()
|
|
|
|
data = json.dumps(
|
|
{
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {
|
|
"identifiers": ["helloworld"],
|
|
"manufacturer": "Whatever",
|
|
"name": "Beer",
|
|
"model": "Glass",
|
|
"sw_version": "0.1-beta",
|
|
},
|
|
}
|
|
)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
device = registry.async_get_device({("mqtt", "helloworld")})
|
|
assert device is not None
|
|
assert device.identifiers == {("mqtt", "helloworld")}
|
|
assert device.manufacturer == "Whatever"
|
|
assert device.name == "Beer"
|
|
assert device.model == "Glass"
|
|
assert device.sw_version == "0.1-beta"
|
|
|
|
|
|
async def test_entity_device_info_update(hass, mqtt_mock):
|
|
"""Test device registry update."""
|
|
registry = await hass.helpers.device_registry.async_get_registry()
|
|
|
|
config = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {
|
|
"identifiers": ["helloworld"],
|
|
"connections": [["mac", "02:5b:26:a8:dc:12"]],
|
|
"manufacturer": "Whatever",
|
|
"name": "Beer",
|
|
"model": "Glass",
|
|
"sw_version": "0.1-beta",
|
|
},
|
|
}
|
|
|
|
data = json.dumps(config)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
device = registry.async_get_device({("mqtt", "helloworld")})
|
|
assert device is not None
|
|
assert device.name == "Beer"
|
|
|
|
config["device"]["name"] = "Milk"
|
|
data = json.dumps(config)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
device = registry.async_get_device({("mqtt", "helloworld")})
|
|
assert device is not None
|
|
assert device.name == "Milk"
|
|
|
|
|
|
async def test_cleanup_trigger(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test trigger discovery topic is cleaned when device is removed from registry."""
|
|
config = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
}
|
|
|
|
data = json.dumps(config)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is created
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert triggers[0]["type"] == "foo"
|
|
|
|
device_reg.async_remove_device(device_entry.id)
|
|
await hass.async_block_till_done()
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is None
|
|
|
|
# Verify retained discovery topic has been cleared
|
|
mqtt_mock.async_publish.assert_called_once_with(
|
|
"homeassistant/device_automation/bla/config", "", 0, True
|
|
)
|
|
|
|
|
|
async def test_cleanup_device(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test removal from device registry when trigger is removed."""
|
|
config = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
}
|
|
|
|
data = json.dumps(config)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is created
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert triggers[0]["type"] == "foo"
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is None
|
|
|
|
|
|
async def test_cleanup_device_several_triggers(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test removal from device registry when the last trigger is removed."""
|
|
config1 = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
}
|
|
|
|
config2 = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo2",
|
|
"subtype": "bar",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
}
|
|
|
|
data1 = json.dumps(config1)
|
|
data2 = json.dumps(config2)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla2/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is created
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert len(triggers) == 2
|
|
assert triggers[0]["type"] == "foo"
|
|
assert triggers[1]["type"] == "foo2"
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is not cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert len(triggers) == 1
|
|
assert triggers[0]["type"] == "foo2"
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla2/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is None
|
|
|
|
|
|
async def test_cleanup_device_with_entity1(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test removal from device registry for device with entity.
|
|
|
|
Trigger removed first, then entity.
|
|
"""
|
|
config1 = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
}
|
|
|
|
config2 = {
|
|
"name": "test_binary_sensor",
|
|
"state_topic": "test-topic",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
"unique_id": "veryunique",
|
|
}
|
|
|
|
data1 = json.dumps(config1)
|
|
data2 = json.dumps(config2)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla2/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is created
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert len(triggers) == 3 # 2 binary_sensor triggers + device trigger
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is not cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert len(triggers) == 2 # 2 binary_sensor triggers
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla2/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is None
|
|
|
|
|
|
async def test_cleanup_device_with_entity2(hass, device_reg, entity_reg, mqtt_mock):
|
|
"""Test removal from device registry for device with entity.
|
|
|
|
Entity removed first, then trigger.
|
|
"""
|
|
config1 = {
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
}
|
|
|
|
config2 = {
|
|
"name": "test_binary_sensor",
|
|
"state_topic": "test-topic",
|
|
"device": {"identifiers": ["helloworld"]},
|
|
"unique_id": "veryunique",
|
|
}
|
|
|
|
data1 = json.dumps(config1)
|
|
data2 = json.dumps(config2)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", data1)
|
|
await hass.async_block_till_done()
|
|
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla2/config", data2)
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is created
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert len(triggers) == 3 # 2 binary_sensor triggers + device trigger
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla2/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is not cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is not None
|
|
|
|
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
|
assert len(triggers) == 1 # device trigger
|
|
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla1/config", "")
|
|
await hass.async_block_till_done()
|
|
|
|
# Verify device registry entry is cleared
|
|
device_entry = device_reg.async_get_device({("mqtt", "helloworld")})
|
|
assert device_entry is None
|
|
|
|
|
|
async def test_trigger_debug_info(hass, mqtt_mock):
|
|
"""Test debug_info.
|
|
|
|
This is a test helper for MQTT debug_info.
|
|
"""
|
|
registry = await hass.helpers.device_registry.async_get_registry()
|
|
|
|
config = {
|
|
"platform": "mqtt",
|
|
"automation_type": "trigger",
|
|
"topic": "test-topic",
|
|
"type": "foo",
|
|
"subtype": "bar",
|
|
"device": {
|
|
"connections": [["mac", "02:5b:26:a8:dc:12"]],
|
|
"manufacturer": "Whatever",
|
|
"name": "Beer",
|
|
"model": "Glass",
|
|
"sw_version": "0.1-beta",
|
|
},
|
|
}
|
|
data = json.dumps(config)
|
|
async_fire_mqtt_message(hass, "homeassistant/device_automation/bla/config", data)
|
|
await hass.async_block_till_done()
|
|
|
|
device = registry.async_get_device(set(), {("mac", "02:5b:26:a8:dc:12")})
|
|
assert device is not None
|
|
|
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
|
assert len(debug_info_data["entities"]) == 0
|
|
assert len(debug_info_data["triggers"]) == 1
|
|
assert (
|
|
debug_info_data["triggers"][0]["discovery_data"]["topic"]
|
|
== "homeassistant/device_automation/bla/config"
|
|
)
|
|
assert debug_info_data["triggers"][0]["discovery_data"]["payload"] == config
|