Skip to content

Commit

Permalink
Fix reload service in Command Line (#94436)
Browse files Browse the repository at this point in the history
* Fix reload in Command Line

* Add read new yaml
  • Loading branch information
gjohansson-ST committed Jun 12, 2023
1 parent f931cc3 commit bd74f03
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 58 deletions.
41 changes: 33 additions & 8 deletions homeassistant/components/command_line/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,15 @@
CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
CONF_VALUE_TEMPLATE,
SERVICE_RELOAD,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import Event, HomeAssistant, ServiceCall
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.entity_platform import async_get_platforms
from homeassistant.helpers.reload import async_integration_yaml_config
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.typing import ConfigType

from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT, DOMAIN
Expand Down Expand Up @@ -163,14 +166,39 @@

async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Command Line from yaml config."""
command_line_config: list[dict[str, dict[str, Any]]] = config.get(DOMAIN, [])

async def _reload_config(call: Event | ServiceCall) -> None:
"""Reload Command Line."""
reload_config = await async_integration_yaml_config(hass, "command_line")
reset_platforms = async_get_platforms(hass, "command_line")
for reset_platform in reset_platforms:
_LOGGER.debug("Reload resetting platform: %s", reset_platform.domain)
await reset_platform.async_reset()
if not reload_config:
return
await async_load_platforms(hass, reload_config.get(DOMAIN, []), reload_config)

async_register_admin_service(hass, DOMAIN, SERVICE_RELOAD, _reload_config)

await async_load_platforms(hass, config.get(DOMAIN, []), config)

return True


async def async_load_platforms(
hass: HomeAssistant,
command_line_config: list[dict[str, dict[str, Any]]],
config: ConfigType,
) -> None:
"""Load platforms from yaml."""
if not command_line_config:
return True
return

_LOGGER.debug("Full config loaded: %s", command_line_config)

load_coroutines: list[Coroutine[Any, Any, None]] = []
platforms: list[Platform] = []
reload_configs: list[tuple] = []
for platform_config in command_line_config:
for platform, _config in platform_config.items():
if (mapped_platform := PLATFORM_MAPPING[platform]) not in platforms:
Expand All @@ -180,6 +208,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
platform_config,
PLATFORM_MAPPING[platform],
)
reload_configs.append((PLATFORM_MAPPING[platform], _config))
load_coroutines.append(
discovery.async_load_platform(
hass,
Expand All @@ -190,10 +219,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
)
)

await async_setup_reload_service(hass, DOMAIN, platforms)

if load_coroutines:
_LOGGER.debug("Loading platforms: %s", platforms)
await asyncio.gather(*load_coroutines)

return True
13 changes: 7 additions & 6 deletions tests/components/command_line/fixtures/configuration.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cover:
- platform: command_line
covers:
from_yaml:
command_state: "echo closed"
value_template: "{{ value }}"
command_line:
- "binary_sensor":
"name": "Test"
"command": "echo 1"
"payload_on": "1"
"payload_off": "0"
"command_timeout": 15
Empty file.
44 changes: 2 additions & 42 deletions tests/components/command_line/test_cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import pytest

from homeassistant import config as hass_config, setup
from homeassistant import setup
from homeassistant.components.command_line import DOMAIN
from homeassistant.components.command_line.cover import CommandCover
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN, SCAN_INTERVAL
Expand All @@ -21,15 +21,14 @@
ATTR_ENTITY_ID,
SERVICE_CLOSE_COVER,
SERVICE_OPEN_COVER,
SERVICE_RELOAD,
SERVICE_STOP_COVER,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.issue_registry as ir
import homeassistant.util.dt as dt_util

from tests.common import async_fire_time_changed, get_fixture_path
from tests.common import async_fire_time_changed


async def test_no_covers_platform_yaml(
Expand Down Expand Up @@ -214,45 +213,6 @@ async def test_state_value(hass: HomeAssistant) -> None:
assert entity_state.state == "closed"


@pytest.mark.parametrize(
"get_config",
[
{
"command_line": [
{
"cover": {
"command_state": "echo open",
"value_template": "{{ value }}",
"name": "Test",
}
}
]
}
],
)
async def test_reload(hass: HomeAssistant, load_yaml_integration: None) -> None:
"""Verify we can reload command_line covers."""

entity_state = hass.states.get("cover.test")
assert entity_state
assert entity_state.state == "unknown"

yaml_path = get_fixture_path("configuration.yaml", "command_line")
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
await hass.services.async_call(
"command_line",
SERVICE_RELOAD,
{},
blocking=True,
)
await hass.async_block_till_done()

assert len(hass.states.async_all()) == 1

assert not hass.states.get("cover.test")
assert hass.states.get("cover.from_yaml")


@pytest.mark.parametrize(
"get_config",
[
Expand Down
61 changes: 59 additions & 2 deletions tests/components/command_line/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
from __future__ import annotations

from datetime import timedelta
from unittest.mock import patch

from homeassistant.const import STATE_ON, STATE_OPEN
import pytest

from homeassistant import config as hass_config
from homeassistant.components.command_line.const import DOMAIN
from homeassistant.const import SERVICE_RELOAD, STATE_ON, STATE_OPEN
from homeassistant.core import HomeAssistant
import homeassistant.util.dt as dt_util

from tests.common import async_fire_time_changed
from tests.common import async_fire_time_changed, get_fixture_path


async def test_setup_config(hass: HomeAssistant, load_yaml_integration: None) -> None:
Expand All @@ -25,3 +30,55 @@ async def test_setup_config(hass: HomeAssistant, load_yaml_integration: None) ->
assert state_sensor.state == "5"
assert state_cover.state == STATE_OPEN
assert state_switch.state == STATE_ON


async def test_reload_service(
hass: HomeAssistant, load_yaml_integration: None, caplog: pytest.LogCaptureFixture
) -> None:
"""Test reload serviice."""

async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10))
await hass.async_block_till_done()

state_binary_sensor = hass.states.get("binary_sensor.test")
state_sensor = hass.states.get("sensor.test")
assert state_binary_sensor.state == STATE_ON
assert state_sensor.state == "5"

caplog.clear()

yaml_path = get_fixture_path("configuration.yaml", "command_line")
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
await hass.services.async_call(
DOMAIN,
SERVICE_RELOAD,
{},
blocking=True,
)
await hass.async_block_till_done()

assert "Loading config" in caplog.text

state_binary_sensor = hass.states.get("binary_sensor.test")
state_sensor = hass.states.get("sensor.test")
assert state_binary_sensor.state == STATE_ON
assert not state_sensor

caplog.clear()

yaml_path = get_fixture_path("configuration_empty.yaml", "command_line")
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
await hass.services.async_call(
DOMAIN,
SERVICE_RELOAD,
{},
blocking=True,
)
await hass.async_block_till_done()

state_binary_sensor = hass.states.get("binary_sensor.test")
state_sensor = hass.states.get("sensor.test")
assert not state_binary_sensor
assert not state_sensor

assert "Loading config" not in caplog.text

0 comments on commit bd74f03

Please sign in to comment.