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

Exclude attributes for automation and script domains #70168

Merged
merged 18 commits into from
Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions homeassistant/components/automation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.integration_platform import (
async_process_integration_platform_for_component,
)
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.script import (
ATTR_CUR,
Expand Down Expand Up @@ -227,6 +230,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up all automations."""
hass.data[DOMAIN] = component = EntityComponent(LOGGER, DOMAIN, hass)

# Process integration platforms right away since
# we will create entities before firing EVENT_COMPONENT_LOADED
await async_process_integration_platform_for_component(hass, DOMAIN)

# To register the automation blueprints
async_get_blueprints(hass)

Expand Down
12 changes: 12 additions & 0 deletions homeassistant/components/automation/recorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Integration platform for recorder."""
from __future__ import annotations

from homeassistant.core import HomeAssistant, callback

from . import ATTR_CUR, ATTR_LAST_TRIGGERED, ATTR_MAX, ATTR_MODE, CONF_ID


@callback
def exclude_attributes(hass: HomeAssistant) -> set[str]:
"""Exclude extra attributes from being recorded in the database."""
return {ATTR_LAST_TRIGGERED, ATTR_MODE, ATTR_CUR, ATTR_MAX, CONF_ID}
7 changes: 7 additions & 0 deletions homeassistant/components/script/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
from homeassistant.helpers.config_validation import make_entity_service_schema
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.integration_platform import (
async_process_integration_platform_for_component,
)
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.script import (
ATTR_CUR,
Expand Down Expand Up @@ -165,6 +168,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Load the scripts from the configuration."""
hass.data[DOMAIN] = component = EntityComponent(LOGGER, DOMAIN, hass)

# Process integration platforms right away since
# we will create entities before firing EVENT_COMPONENT_LOADED
await async_process_integration_platform_for_component(hass, DOMAIN)

# To register scripts as valid domain for Blueprint
async_get_blueprints(hass)

Expand Down
12 changes: 12 additions & 0 deletions homeassistant/components/script/recorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Integration platform for recorder."""
from __future__ import annotations

from homeassistant.core import HomeAssistant, callback

from . import ATTR_CUR, ATTR_LAST_ACTION, ATTR_LAST_TRIGGERED, ATTR_MAX, ATTR_MODE


@callback
def exclude_attributes(hass: HomeAssistant) -> set[str]:
"""Exclude extra attributes from being recorded in the database."""
return {ATTR_LAST_TRIGGERED, ATTR_MODE, ATTR_CUR, ATTR_MAX, ATTR_LAST_ACTION}
68 changes: 68 additions & 0 deletions tests/components/automation/test_recorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""The tests for automation recorder."""
from __future__ import annotations

import pytest

from homeassistant.components import automation
from homeassistant.components.automation import (
ATTR_CUR,
ATTR_LAST_TRIGGERED,
ATTR_MAX,
ATTR_MODE,
CONF_ID,
)
from homeassistant.components.recorder.models import StateAttributes, States
from homeassistant.components.recorder.util import session_scope
from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME
from homeassistant.core import State
from homeassistant.setup import async_setup_component

from tests.common import async_init_recorder_component, async_mock_service
from tests.components.recorder.common import async_wait_recording_done_without_instance


@pytest.fixture
def calls(hass):
"""Track calls to a mock service."""
return async_mock_service(hass, "test", "automation")


async def test_exclude_attributes(hass, calls):
"""Test automation registered attributes to be excluded."""
await async_init_recorder_component(hass)
await hass.async_block_till_done()
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: {
"trigger": {"platform": "event", "event_type": "test_event"},
"action": {"service": "test.automation", "entity_id": "hello.world"},
}
},
)
await hass.async_block_till_done()
hass.bus.async_fire("test_event")
await hass.async_block_till_done()
assert len(calls) == 1
assert ["hello.world"] == calls[0].data.get(ATTR_ENTITY_ID)
await async_wait_recording_done_without_instance(hass)

def _fetch_states() -> list[State]:
with session_scope(hass=hass) as session:
native_states = []
for db_state, db_state_attributes in session.query(States, StateAttributes):
state = db_state.to_native()
state.attributes = db_state_attributes.to_native()
native_states.append(state)
return native_states

states: list[State] = await hass.async_add_executor_job(_fetch_states)
assert len(states) > 1
for state in states:
assert ATTR_LAST_TRIGGERED not in state.attributes
assert ATTR_MODE not in state.attributes
assert ATTR_CUR not in state.attributes
assert CONF_ID not in state.attributes
assert ATTR_MAX not in state.attributes
assert ATTR_FRIENDLY_NAME in state.attributes
83 changes: 83 additions & 0 deletions tests/components/script/test_recorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""The tests for script recorder."""
from __future__ import annotations

import pytest

from homeassistant.components import script
from homeassistant.components.recorder.models import StateAttributes, States
from homeassistant.components.recorder.util import session_scope
from homeassistant.components.script import (
ATTR_CUR,
ATTR_LAST_ACTION,
ATTR_LAST_TRIGGERED,
ATTR_MAX,
ATTR_MODE,
)
from homeassistant.const import ATTR_FRIENDLY_NAME
from homeassistant.core import Context, State, callback
from homeassistant.setup import async_setup_component

from tests.common import async_init_recorder_component, async_mock_service
from tests.components.recorder.common import async_wait_recording_done_without_instance


@pytest.fixture
def calls(hass):
"""Track calls to a mock service."""
return async_mock_service(hass, "test", "automation")


async def test_exclude_attributes(hass, calls):
"""Test automation registered attributes to be excluded."""
await async_init_recorder_component(hass)
await hass.async_block_till_done()
calls = []
context = Context()

@callback
def record_call(service):
"""Add recorded event to set."""
calls.append(service)

hass.services.async_register("test", "script", record_call)

assert await async_setup_component(
hass,
"script",
{
"script": {
"test": {
"sequence": {
"service": "test.script",
"data_template": {"hello": "{{ greeting }}"},
}
}
}
},
)

await hass.services.async_call(
script.DOMAIN, "test", {"greeting": "world"}, context=context
)
await hass.async_block_till_done()
await async_wait_recording_done_without_instance(hass)
assert len(calls) == 1

def _fetch_states() -> list[State]:
with session_scope(hass=hass) as session:
native_states = []
for db_state, db_state_attributes in session.query(States, StateAttributes):
state = db_state.to_native()
state.attributes = db_state_attributes.to_native()
native_states.append(state)
return native_states

states: list[State] = await hass.async_add_executor_job(_fetch_states)
assert len(states) > 1
for state in states:
assert ATTR_LAST_TRIGGERED not in state.attributes
assert ATTR_MODE not in state.attributes
assert ATTR_CUR not in state.attributes
assert ATTR_LAST_ACTION not in state.attributes
assert ATTR_MAX not in state.attributes
assert ATTR_FRIENDLY_NAME in state.attributes