Add unique_id configuration variable to command_line integration (#58596)

This commit is contained in:
Gabriel Rauter 2022-01-03 11:44:47 +01:00 committed by GitHub
parent 545b10a711
commit d26275011a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 209 additions and 4 deletions

View file

@ -16,6 +16,7 @@ from homeassistant.const import (
CONF_NAME,
CONF_PAYLOAD_OFF,
CONF_PAYLOAD_ON,
CONF_UNIQUE_ID,
CONF_VALUE_TEMPLATE,
)
from homeassistant.core import HomeAssistant
@ -43,6 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_COMMAND_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
vol.Optional(CONF_UNIQUE_ID): cv.string,
}
)
@ -64,6 +66,7 @@ def setup_platform(
device_class = config.get(CONF_DEVICE_CLASS)
value_template = config.get(CONF_VALUE_TEMPLATE)
command_timeout = config.get(CONF_COMMAND_TIMEOUT)
unique_id = config.get(CONF_UNIQUE_ID)
if value_template is not None:
value_template.hass = hass
data = CommandSensorData(hass, command, command_timeout)
@ -71,7 +74,14 @@ def setup_platform(
add_entities(
[
CommandBinarySensor(
hass, data, name, device_class, payload_on, payload_off, value_template
hass,
data,
name,
device_class,
payload_on,
payload_off,
value_template,
unique_id,
)
],
True,
@ -82,7 +92,15 @@ class CommandBinarySensor(BinarySensorEntity):
"""Representation of a command line binary sensor."""
def __init__(
self, hass, data, name, device_class, payload_on, payload_off, value_template
self,
hass,
data,
name,
device_class,
payload_on,
payload_off,
value_template,
unique_id,
):
"""Initialize the Command line binary sensor."""
self._hass = hass
@ -93,6 +111,7 @@ class CommandBinarySensor(BinarySensorEntity):
self._payload_on = payload_on
self._payload_off = payload_off
self._value_template = value_template
self._attr_unique_id = unique_id
@property
def name(self):

View file

@ -13,6 +13,7 @@ from homeassistant.const import (
CONF_COMMAND_STOP,
CONF_COVERS,
CONF_FRIENDLY_NAME,
CONF_UNIQUE_ID,
CONF_VALUE_TEMPLATE,
)
from homeassistant.core import HomeAssistant
@ -35,6 +36,7 @@ COVER_SCHEMA = vol.Schema(
vol.Optional(CONF_FRIENDLY_NAME): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_COMMAND_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
vol.Optional(CONF_UNIQUE_ID): cv.string,
}
)
@ -71,6 +73,7 @@ def setup_platform(
device_config.get(CONF_COMMAND_STATE),
value_template,
device_config[CONF_COMMAND_TIMEOUT],
device_config.get(CONF_UNIQUE_ID),
)
)
@ -94,6 +97,7 @@ class CommandCover(CoverEntity):
command_state,
value_template,
timeout,
unique_id,
):
"""Initialize the cover."""
self._hass = hass
@ -105,6 +109,7 @@ class CommandCover(CoverEntity):
self._command_state = command_state
self._value_template = value_template
self._timeout = timeout
self._attr_unique_id = unique_id
def _move_cover(self, command):
"""Execute the actual commands."""

View file

@ -12,6 +12,7 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.const import (
CONF_COMMAND,
CONF_NAME,
CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
CONF_VALUE_TEMPLATE,
STATE_UNKNOWN,
@ -43,6 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_UNIQUE_ID): cv.string,
}
)
@ -62,13 +64,19 @@ def setup_platform(
unit = config.get(CONF_UNIT_OF_MEASUREMENT)
value_template = config.get(CONF_VALUE_TEMPLATE)
command_timeout = config.get(CONF_COMMAND_TIMEOUT)
unique_id = config.get(CONF_UNIQUE_ID)
if value_template is not None:
value_template.hass = hass
json_attributes = config.get(CONF_JSON_ATTRIBUTES)
data = CommandSensorData(hass, command, command_timeout)
add_entities(
[CommandSensor(hass, data, name, unit, value_template, json_attributes)], True
[
CommandSensor(
hass, data, name, unit, value_template, json_attributes, unique_id
)
],
True,
)
@ -76,7 +84,14 @@ class CommandSensor(SensorEntity):
"""Representation of a sensor that is using shell commands."""
def __init__(
self, hass, data, name, unit_of_measurement, value_template, json_attributes
self,
hass,
data,
name,
unit_of_measurement,
value_template,
json_attributes,
unique_id,
):
"""Initialize the sensor."""
self._hass = hass
@ -87,6 +102,7 @@ class CommandSensor(SensorEntity):
self._state = None
self._unit_of_measurement = unit_of_measurement
self._value_template = value_template
self._attr_unique_id = unique_id
@property
def name(self):

View file

@ -17,6 +17,7 @@ from homeassistant.const import (
CONF_FRIENDLY_NAME,
CONF_ICON_TEMPLATE,
CONF_SWITCHES,
CONF_UNIQUE_ID,
CONF_VALUE_TEMPLATE,
)
from homeassistant.core import HomeAssistant
@ -39,6 +40,7 @@ SWITCH_SCHEMA = vol.Schema(
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_ICON_TEMPLATE): cv.template,
vol.Optional(CONF_COMMAND_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
vol.Optional(CONF_UNIQUE_ID): cv.string,
}
)
@ -81,6 +83,7 @@ def setup_platform(
icon_template,
value_template,
device_config[CONF_COMMAND_TIMEOUT],
device_config.get(CONF_UNIQUE_ID),
)
)
@ -105,6 +108,7 @@ class CommandSwitch(SwitchEntity):
icon_template,
value_template,
timeout,
unique_id,
):
"""Initialize the switch."""
self._hass = hass
@ -117,6 +121,7 @@ class CommandSwitch(SwitchEntity):
self._icon_template = icon_template
self._value_template = value_template
self._timeout = timeout
self._attr_unique_id = unique_id
def _switch(self, command):
"""Execute the actual commands."""

View file

@ -7,6 +7,7 @@ from homeassistant import setup
from homeassistant.components.binary_sensor import DOMAIN
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
async def setup_test_entity(hass: HomeAssistant, config_dict: dict[str, Any]) -> None:
@ -65,3 +66,47 @@ async def test_sensor_off(hass: HomeAssistant) -> None:
)
entity_state = hass.states.get("binary_sensor.test")
assert entity_state.state == STATE_OFF
async def test_unique_id(hass):
"""Test unique_id option and if it only creates one binary sensor per id."""
assert await setup.async_setup_component(
hass,
DOMAIN,
{
DOMAIN: [
{
"platform": "command_line",
"unique_id": "unique",
"command": "echo 0",
},
{
"platform": "command_line",
"unique_id": "not-so-unique-anymore",
"command": "echo 1",
},
{
"platform": "command_line",
"unique_id": "not-so-unique-anymore",
"command": "echo 2",
},
]
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 2
ent_reg = entity_registry.async_get(hass)
assert len(ent_reg.entities) == 2
assert (
ent_reg.async_get_entity_id("binary_sensor", "command_line", "unique")
is not None
)
assert (
ent_reg.async_get_entity_id(
"binary_sensor", "command_line", "not-so-unique-anymore"
)
is not None
)

View file

@ -16,6 +16,7 @@ from homeassistant.const import (
SERVICE_STOP_COVER,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
import homeassistant.util.dt as dt_util
from tests.common import async_fire_time_changed, get_fixture_path
@ -160,3 +161,41 @@ async def test_move_cover_failure(caplog: Any, hass: HomeAssistant) -> None:
DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
)
assert "Command failed" in caplog.text
async def test_unique_id(hass):
"""Test unique_id option and if it only creates one cover per id."""
await setup_test_entity(
hass,
{
"unique": {
"command_open": "echo open",
"command_close": "echo close",
"command_stop": "echo stop",
"unique_id": "unique",
},
"not_unique_1": {
"command_open": "echo open",
"command_close": "echo close",
"command_stop": "echo stop",
"unique_id": "not-so-unique-anymore",
},
"not_unique_2": {
"command_open": "echo open",
"command_close": "echo close",
"command_stop": "echo stop",
"unique_id": "not-so-unique-anymore",
},
},
)
assert len(hass.states.async_all()) == 2
ent_reg = entity_registry.async_get(hass)
assert len(ent_reg.entities) == 2
assert ent_reg.async_get_entity_id("cover", "command_line", "unique") is not None
assert (
ent_reg.async_get_entity_id("cover", "command_line", "not-so-unique-anymore")
is not None
)

View file

@ -7,6 +7,7 @@ from unittest.mock import patch
from homeassistant import setup
from homeassistant.components.sensor import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
async def setup_test_entities(hass: HomeAssistant, config_dict: dict[str, Any]) -> None:
@ -223,3 +224,42 @@ async def test_update_with_unnecessary_json_attrs(caplog, hass: HomeAssistant) -
assert entity_state.attributes["key"] == "some_json_value"
assert entity_state.attributes["another_key"] == "another_json_value"
assert "key_three" not in entity_state.attributes
async def test_unique_id(hass):
"""Test unique_id option and if it only creates one sensor per id."""
assert await setup.async_setup_component(
hass,
DOMAIN,
{
DOMAIN: [
{
"platform": "command_line",
"unique_id": "unique",
"command": "echo 0",
},
{
"platform": "command_line",
"unique_id": "not-so-unique-anymore",
"command": "echo 1",
},
{
"platform": "command_line",
"unique_id": "not-so-unique-anymore",
"command": "echo 2",
},
]
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 2
ent_reg = entity_registry.async_get(hass)
assert len(ent_reg.entities) == 2
assert ent_reg.async_get_entity_id("sensor", "command_line", "unique") is not None
assert (
ent_reg.async_get_entity_id("sensor", "command_line", "not-so-unique-anymore")
is not None
)

View file

@ -18,6 +18,7 @@ from homeassistant.const import (
STATE_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
import homeassistant.util.dt as dt_util
from tests.common import async_fire_time_changed
@ -376,3 +377,38 @@ async def test_no_switches(caplog: Any, hass: HomeAssistant) -> None:
await setup_test_entity(hass, {})
assert "No switches" in caplog.text
async def test_unique_id(hass):
"""Test unique_id option and if it only creates one switch per id."""
await setup_test_entity(
hass,
{
"unique": {
"command_on": "echo on",
"command_off": "echo off",
"unique_id": "unique",
},
"not_unique_1": {
"command_on": "echo on",
"command_off": "echo off",
"unique_id": "not-so-unique-anymore",
},
"not_unique_2": {
"command_on": "echo on",
"command_off": "echo off",
"unique_id": "not-so-unique-anymore",
},
},
)
assert len(hass.states.async_all()) == 2
ent_reg = entity_registry.async_get(hass)
assert len(ent_reg.entities) == 2
assert ent_reg.async_get_entity_id("switch", "command_line", "unique") is not None
assert (
ent_reg.async_get_entity_id("switch", "command_line", "not-so-unique-anymore")
is not None
)