mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Improve code quality command_line (#65333)
This commit is contained in:
parent
db6969739f
commit
3771c154fa
@ -1,4 +1,5 @@
|
|||||||
"""The command_line component."""
|
"""The command_line component."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -6,7 +7,9 @@ import subprocess
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def call_shell_with_timeout(command, timeout, *, log_return_code=True):
|
def call_shell_with_timeout(
|
||||||
|
command: str, timeout: int, *, log_return_code: bool = True
|
||||||
|
) -> int:
|
||||||
"""Run a shell command with a timeout.
|
"""Run a shell command with a timeout.
|
||||||
|
|
||||||
If log_return_code is set to False, it will not print an error if a non-zero
|
If log_return_code is set to False, it will not print an error if a non-zero
|
||||||
@ -30,7 +33,7 @@ def call_shell_with_timeout(command, timeout, *, log_return_code=True):
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
def check_output_or_log(command, timeout):
|
def check_output_or_log(command: str, timeout: int) -> str | None:
|
||||||
"""Run a shell command with a timeout and return the output."""
|
"""Run a shell command with a timeout and return the output."""
|
||||||
try:
|
try:
|
||||||
return_value = subprocess.check_output(
|
return_value = subprocess.check_output(
|
||||||
|
@ -23,6 +23,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.reload import setup_reload_service
|
from homeassistant.helpers.reload import setup_reload_service
|
||||||
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT, DOMAIN, PLATFORMS
|
from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT, DOMAIN, PLATFORMS
|
||||||
@ -59,14 +60,14 @@ def setup_platform(
|
|||||||
|
|
||||||
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
||||||
|
|
||||||
name = config.get(CONF_NAME)
|
name: str = config[CONF_NAME]
|
||||||
command = config.get(CONF_COMMAND)
|
command: str = config[CONF_COMMAND]
|
||||||
payload_off = config.get(CONF_PAYLOAD_OFF)
|
payload_off: str = config[CONF_PAYLOAD_OFF]
|
||||||
payload_on = config.get(CONF_PAYLOAD_ON)
|
payload_on: str = config[CONF_PAYLOAD_ON]
|
||||||
device_class = config.get(CONF_DEVICE_CLASS)
|
device_class: str | None = config.get(CONF_DEVICE_CLASS)
|
||||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
value_template: Template | None = config.get(CONF_VALUE_TEMPLATE)
|
||||||
command_timeout = config.get(CONF_COMMAND_TIMEOUT)
|
command_timeout: int = config[CONF_COMMAND_TIMEOUT]
|
||||||
unique_id = config.get(CONF_UNIQUE_ID)
|
unique_id: str | None = config.get(CONF_UNIQUE_ID)
|
||||||
if value_template is not None:
|
if value_template is not None:
|
||||||
value_template.hass = hass
|
value_template.hass = hass
|
||||||
data = CommandSensorData(hass, command, command_timeout)
|
data = CommandSensorData(hass, command, command_timeout)
|
||||||
@ -74,7 +75,6 @@ def setup_platform(
|
|||||||
add_entities(
|
add_entities(
|
||||||
[
|
[
|
||||||
CommandBinarySensor(
|
CommandBinarySensor(
|
||||||
hass,
|
|
||||||
data,
|
data,
|
||||||
name,
|
name,
|
||||||
device_class,
|
device_class,
|
||||||
@ -93,42 +93,25 @@ class CommandBinarySensor(BinarySensorEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass,
|
data: CommandSensorData,
|
||||||
data,
|
name: str,
|
||||||
name,
|
device_class: str | None,
|
||||||
device_class,
|
payload_on: str,
|
||||||
payload_on,
|
payload_off: str,
|
||||||
payload_off,
|
value_template: Template | None,
|
||||||
value_template,
|
unique_id: str | None,
|
||||||
unique_id,
|
) -> None:
|
||||||
):
|
|
||||||
"""Initialize the Command line binary sensor."""
|
"""Initialize the Command line binary sensor."""
|
||||||
self._hass = hass
|
|
||||||
self.data = data
|
self.data = data
|
||||||
self._name = name
|
self._attr_name = name
|
||||||
self._device_class = device_class
|
self._attr_device_class = device_class
|
||||||
self._state = False
|
self._attr_is_on = None
|
||||||
self._payload_on = payload_on
|
self._payload_on = payload_on
|
||||||
self._payload_off = payload_off
|
self._payload_off = payload_off
|
||||||
self._value_template = value_template
|
self._value_template = value_template
|
||||||
self._attr_unique_id = unique_id
|
self._attr_unique_id = unique_id
|
||||||
|
|
||||||
@property
|
def update(self) -> None:
|
||||||
def name(self):
|
|
||||||
"""Return the name of the sensor."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self):
|
|
||||||
"""Return true if the binary sensor is on."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_class(self):
|
|
||||||
"""Return the class of the binary sensor."""
|
|
||||||
return self._device_class
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Get the latest data and updates the state."""
|
"""Get the latest data and updates the state."""
|
||||||
self.data.update()
|
self.data.update()
|
||||||
value = self.data.value
|
value = self.data.value
|
||||||
@ -136,6 +119,6 @@ class CommandBinarySensor(BinarySensorEntity):
|
|||||||
if self._value_template is not None:
|
if self._value_template is not None:
|
||||||
value = self._value_template.render_with_possible_json_value(value, False)
|
value = self._value_template.render_with_possible_json_value(value, False)
|
||||||
if value == self._payload_on:
|
if value == self._payload_on:
|
||||||
self._state = True
|
self._attr_is_on = True
|
||||||
elif value == self._payload_off:
|
elif value == self._payload_off:
|
||||||
self._state = False
|
self._attr_is_on = False
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.reload import setup_reload_service
|
from homeassistant.helpers.reload import setup_reload_service
|
||||||
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import call_shell_with_timeout, check_output_or_log
|
from . import call_shell_with_timeout, check_output_or_log
|
||||||
@ -55,17 +57,16 @@ def setup_platform(
|
|||||||
|
|
||||||
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
||||||
|
|
||||||
devices = config.get(CONF_COVERS, {})
|
devices: dict[str, Any] = config.get(CONF_COVERS, {})
|
||||||
covers = []
|
covers = []
|
||||||
|
|
||||||
for device_name, device_config in devices.items():
|
for device_name, device_config in devices.items():
|
||||||
value_template = device_config.get(CONF_VALUE_TEMPLATE)
|
value_template: Template | None = device_config.get(CONF_VALUE_TEMPLATE)
|
||||||
if value_template is not None:
|
if value_template is not None:
|
||||||
value_template.hass = hass
|
value_template.hass = hass
|
||||||
|
|
||||||
covers.append(
|
covers.append(
|
||||||
CommandCover(
|
CommandCover(
|
||||||
hass,
|
|
||||||
device_config.get(CONF_FRIENDLY_NAME, device_name),
|
device_config.get(CONF_FRIENDLY_NAME, device_name),
|
||||||
device_config[CONF_COMMAND_OPEN],
|
device_config[CONF_COMMAND_OPEN],
|
||||||
device_config[CONF_COMMAND_CLOSE],
|
device_config[CONF_COMMAND_CLOSE],
|
||||||
@ -89,20 +90,18 @@ class CommandCover(CoverEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass,
|
name: str,
|
||||||
name,
|
command_open: str,
|
||||||
command_open,
|
command_close: str,
|
||||||
command_close,
|
command_stop: str,
|
||||||
command_stop,
|
command_state: str | None,
|
||||||
command_state,
|
value_template: Template | None,
|
||||||
value_template,
|
timeout: int,
|
||||||
timeout,
|
unique_id: str | None,
|
||||||
unique_id,
|
) -> None:
|
||||||
):
|
|
||||||
"""Initialize the cover."""
|
"""Initialize the cover."""
|
||||||
self._hass = hass
|
self._attr_name = name
|
||||||
self._name = name
|
self._state: int | None = None
|
||||||
self._state = None
|
|
||||||
self._command_open = command_open
|
self._command_open = command_open
|
||||||
self._command_close = command_close
|
self._command_close = command_close
|
||||||
self._command_stop = command_stop
|
self._command_stop = command_stop
|
||||||
@ -110,8 +109,9 @@ class CommandCover(CoverEntity):
|
|||||||
self._value_template = value_template
|
self._value_template = value_template
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
self._attr_unique_id = unique_id
|
self._attr_unique_id = unique_id
|
||||||
|
self._attr_should_poll = bool(command_state)
|
||||||
|
|
||||||
def _move_cover(self, command):
|
def _move_cover(self, command: str) -> bool:
|
||||||
"""Execute the actual commands."""
|
"""Execute the actual commands."""
|
||||||
_LOGGER.info("Running command: %s", command)
|
_LOGGER.info("Running command: %s", command)
|
||||||
|
|
||||||
@ -123,35 +123,29 @@ class CommandCover(CoverEntity):
|
|||||||
return success
|
return success
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def is_closed(self) -> bool | None:
|
||||||
"""Only poll if we have state command."""
|
|
||||||
return self._command_state is not None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the cover."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_closed(self):
|
|
||||||
"""Return if the cover is closed."""
|
"""Return if the cover is closed."""
|
||||||
if self.current_cover_position is not None:
|
if self.current_cover_position is not None:
|
||||||
return self.current_cover_position == 0
|
return self.current_cover_position == 0
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_cover_position(self):
|
def current_cover_position(self) -> int | None:
|
||||||
"""Return current position of cover.
|
"""Return current position of cover.
|
||||||
|
|
||||||
None is unknown, 0 is closed, 100 is fully open.
|
None is unknown, 0 is closed, 100 is fully open.
|
||||||
"""
|
"""
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
def _query_state(self):
|
def _query_state(self) -> str | None:
|
||||||
"""Query for the state."""
|
"""Query for the state."""
|
||||||
_LOGGER.info("Running state value command: %s", self._command_state)
|
if self._command_state:
|
||||||
return check_output_or_log(self._command_state, self._timeout)
|
_LOGGER.info("Running state value command: %s", self._command_state)
|
||||||
|
return check_output_or_log(self._command_state, self._timeout)
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
return None
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Update device state."""
|
"""Update device state."""
|
||||||
if self._command_state:
|
if self._command_state:
|
||||||
payload = str(self._query_state())
|
payload = str(self._query_state())
|
||||||
@ -159,14 +153,14 @@ class CommandCover(CoverEntity):
|
|||||||
payload = self._value_template.render_with_possible_json_value(payload)
|
payload = self._value_template.render_with_possible_json_value(payload)
|
||||||
self._state = int(payload)
|
self._state = int(payload)
|
||||||
|
|
||||||
def open_cover(self, **kwargs):
|
def open_cover(self, **kwargs) -> None:
|
||||||
"""Open the cover."""
|
"""Open the cover."""
|
||||||
self._move_cover(self._command_open)
|
self._move_cover(self._command_open)
|
||||||
|
|
||||||
def close_cover(self, **kwargs):
|
def close_cover(self, **kwargs) -> None:
|
||||||
"""Close the cover."""
|
"""Close the cover."""
|
||||||
self._move_cover(self._command_close)
|
self._move_cover(self._command_close)
|
||||||
|
|
||||||
def stop_cover(self, **kwargs):
|
def stop_cover(self, **kwargs) -> None:
|
||||||
"""Stop the cover."""
|
"""Stop the cover."""
|
||||||
self._move_cover(self._command_stop)
|
self._move_cover(self._command_stop)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
"""Support for command line notification services."""
|
"""Support for command line notification services."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
@ -6,7 +8,9 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant.components.notify import PLATFORM_SCHEMA, BaseNotificationService
|
from homeassistant.components.notify import PLATFORM_SCHEMA, BaseNotificationService
|
||||||
from homeassistant.const import CONF_COMMAND, CONF_NAME
|
from homeassistant.const import CONF_COMMAND, CONF_NAME
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
from homeassistant.util.process import kill_subprocess
|
from homeassistant.util.process import kill_subprocess
|
||||||
|
|
||||||
from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT
|
from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT
|
||||||
@ -22,10 +26,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_service(hass, config, discovery_info=None):
|
def get_service(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType,
|
||||||
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
|
) -> CommandLineNotificationService:
|
||||||
"""Get the Command Line notification service."""
|
"""Get the Command Line notification service."""
|
||||||
command = config[CONF_COMMAND]
|
command: str = config[CONF_COMMAND]
|
||||||
timeout = config[CONF_COMMAND_TIMEOUT]
|
timeout: int = config[CONF_COMMAND_TIMEOUT]
|
||||||
|
|
||||||
return CommandLineNotificationService(command, timeout)
|
return CommandLineNotificationService(command, timeout)
|
||||||
|
|
||||||
@ -33,12 +41,12 @@ def get_service(hass, config, discovery_info=None):
|
|||||||
class CommandLineNotificationService(BaseNotificationService):
|
class CommandLineNotificationService(BaseNotificationService):
|
||||||
"""Implement the notification service for the Command Line service."""
|
"""Implement the notification service for the Command Line service."""
|
||||||
|
|
||||||
def __init__(self, command, timeout):
|
def __init__(self, command: str, timeout: int) -> None:
|
||||||
"""Initialize the service."""
|
"""Initialize the service."""
|
||||||
self.command = command
|
self.command = command
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
|
|
||||||
def send_message(self, message="", **kwargs):
|
def send_message(self, message="", **kwargs) -> None:
|
||||||
"""Send a message to a command line."""
|
"""Send a message to a command line."""
|
||||||
with subprocess.Popen(
|
with subprocess.Popen(
|
||||||
self.command,
|
self.command,
|
||||||
|
@ -19,10 +19,10 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
from homeassistant.helpers import template
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.reload import setup_reload_service
|
from homeassistant.helpers.reload import setup_reload_service
|
||||||
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import check_output_or_log
|
from . import check_output_or_log
|
||||||
@ -59,23 +59,19 @@ def setup_platform(
|
|||||||
|
|
||||||
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
||||||
|
|
||||||
name = config.get(CONF_NAME)
|
name: str = config[CONF_NAME]
|
||||||
command = config.get(CONF_COMMAND)
|
command: str = config[CONF_COMMAND]
|
||||||
unit = config.get(CONF_UNIT_OF_MEASUREMENT)
|
unit: str | None = config.get(CONF_UNIT_OF_MEASUREMENT)
|
||||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
value_template: Template | None = config.get(CONF_VALUE_TEMPLATE)
|
||||||
command_timeout = config.get(CONF_COMMAND_TIMEOUT)
|
command_timeout: int = config[CONF_COMMAND_TIMEOUT]
|
||||||
unique_id = config.get(CONF_UNIQUE_ID)
|
unique_id: str | None = config.get(CONF_UNIQUE_ID)
|
||||||
if value_template is not None:
|
if value_template is not None:
|
||||||
value_template.hass = hass
|
value_template.hass = hass
|
||||||
json_attributes = config.get(CONF_JSON_ATTRIBUTES)
|
json_attributes: list[str] | None = config.get(CONF_JSON_ATTRIBUTES)
|
||||||
data = CommandSensorData(hass, command, command_timeout)
|
data = CommandSensorData(hass, command, command_timeout)
|
||||||
|
|
||||||
add_entities(
|
add_entities(
|
||||||
[
|
[CommandSensor(data, name, unit, value_template, json_attributes, unique_id)],
|
||||||
CommandSensor(
|
|
||||||
hass, data, name, unit, value_template, json_attributes, unique_id
|
|
||||||
)
|
|
||||||
],
|
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -85,57 +81,35 @@ class CommandSensor(SensorEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass,
|
data: CommandSensorData,
|
||||||
data,
|
name: str,
|
||||||
name,
|
unit_of_measurement: str | None,
|
||||||
unit_of_measurement,
|
value_template: Template | None,
|
||||||
value_template,
|
json_attributes: list[str] | None,
|
||||||
json_attributes,
|
unique_id: str | None,
|
||||||
unique_id,
|
) -> None:
|
||||||
):
|
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
self._hass = hass
|
|
||||||
self.data = data
|
self.data = data
|
||||||
self._attributes = None
|
self._attr_extra_state_attributes = {}
|
||||||
self._json_attributes = json_attributes
|
self._json_attributes = json_attributes
|
||||||
self._name = name
|
self._attr_name = name
|
||||||
self._state = None
|
self._attr_native_value = None
|
||||||
self._unit_of_measurement = unit_of_measurement
|
self._attr_native_unit_of_measurement = unit_of_measurement
|
||||||
self._value_template = value_template
|
self._value_template = value_template
|
||||||
self._attr_unique_id = unique_id
|
self._attr_unique_id = unique_id
|
||||||
|
|
||||||
@property
|
def update(self) -> None:
|
||||||
def name(self):
|
|
||||||
"""Return the name of the sensor."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_unit_of_measurement(self):
|
|
||||||
"""Return the unit the value is expressed in."""
|
|
||||||
return self._unit_of_measurement
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self):
|
|
||||||
"""Return the state of the device."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self):
|
|
||||||
"""Return the state attributes."""
|
|
||||||
return self._attributes
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Get the latest data and updates the state."""
|
"""Get the latest data and updates the state."""
|
||||||
self.data.update()
|
self.data.update()
|
||||||
value = self.data.value
|
value = self.data.value
|
||||||
|
|
||||||
if self._json_attributes:
|
if self._json_attributes:
|
||||||
self._attributes = {}
|
self._attr_extra_state_attributes = {}
|
||||||
if value:
|
if value:
|
||||||
try:
|
try:
|
||||||
json_dict = json.loads(value)
|
json_dict = json.loads(value)
|
||||||
if isinstance(json_dict, Mapping):
|
if isinstance(json_dict, Mapping):
|
||||||
self._attributes = {
|
self._attr_extra_state_attributes = {
|
||||||
k: json_dict[k]
|
k: json_dict[k]
|
||||||
for k in self._json_attributes
|
for k in self._json_attributes
|
||||||
if k in json_dict
|
if k in json_dict
|
||||||
@ -150,24 +124,26 @@ class CommandSensor(SensorEntity):
|
|||||||
if value is None:
|
if value is None:
|
||||||
value = STATE_UNKNOWN
|
value = STATE_UNKNOWN
|
||||||
elif self._value_template is not None:
|
elif self._value_template is not None:
|
||||||
self._state = self._value_template.render_with_possible_json_value(
|
self._attr_native_value = (
|
||||||
value, STATE_UNKNOWN
|
self._value_template.render_with_possible_json_value(
|
||||||
|
value, STATE_UNKNOWN
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._state = value
|
self._attr_native_value = value
|
||||||
|
|
||||||
|
|
||||||
class CommandSensorData:
|
class CommandSensorData:
|
||||||
"""The class for handling the data retrieval."""
|
"""The class for handling the data retrieval."""
|
||||||
|
|
||||||
def __init__(self, hass, command, command_timeout):
|
def __init__(self, hass: HomeAssistant, command: str, command_timeout: int) -> None:
|
||||||
"""Initialize the data object."""
|
"""Initialize the data object."""
|
||||||
self.value = None
|
self.value: str | None = None
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.command = command
|
self.command = command
|
||||||
self.timeout = command_timeout
|
self.timeout = command_timeout
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Get the latest data with a shell command."""
|
"""Get the latest data with a shell command."""
|
||||||
command = self.command
|
command = self.command
|
||||||
|
|
||||||
@ -177,7 +153,7 @@ class CommandSensorData:
|
|||||||
args_compiled = None
|
args_compiled = None
|
||||||
else:
|
else:
|
||||||
prog, args = command.split(" ", 1)
|
prog, args = command.split(" ", 1)
|
||||||
args_compiled = template.Template(args, self.hass)
|
args_compiled = Template(args, self.hass)
|
||||||
|
|
||||||
if args_compiled:
|
if args_compiled:
|
||||||
try:
|
try:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.reload import setup_reload_service
|
from homeassistant.helpers.reload import setup_reload_service
|
||||||
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import call_shell_with_timeout, check_output_or_log
|
from . import call_shell_with_timeout, check_output_or_log
|
||||||
@ -59,22 +61,21 @@ def setup_platform(
|
|||||||
|
|
||||||
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
setup_reload_service(hass, DOMAIN, PLATFORMS)
|
||||||
|
|
||||||
devices = config.get(CONF_SWITCHES, {})
|
devices: dict[str, Any] = config.get(CONF_SWITCHES, {})
|
||||||
switches = []
|
switches = []
|
||||||
|
|
||||||
for object_id, device_config in devices.items():
|
for object_id, device_config in devices.items():
|
||||||
value_template = device_config.get(CONF_VALUE_TEMPLATE)
|
value_template: Template | None = device_config.get(CONF_VALUE_TEMPLATE)
|
||||||
|
|
||||||
if value_template is not None:
|
if value_template is not None:
|
||||||
value_template.hass = hass
|
value_template.hass = hass
|
||||||
|
|
||||||
icon_template = device_config.get(CONF_ICON_TEMPLATE)
|
icon_template: Template | None = device_config.get(CONF_ICON_TEMPLATE)
|
||||||
if icon_template is not None:
|
if icon_template is not None:
|
||||||
icon_template.hass = hass
|
icon_template.hass = hass
|
||||||
|
|
||||||
switches.append(
|
switches.append(
|
||||||
CommandSwitch(
|
CommandSwitch(
|
||||||
hass,
|
|
||||||
object_id,
|
object_id,
|
||||||
device_config.get(CONF_FRIENDLY_NAME, object_id),
|
device_config.get(CONF_FRIENDLY_NAME, object_id),
|
||||||
device_config[CONF_COMMAND_ON],
|
device_config[CONF_COMMAND_ON],
|
||||||
@ -99,22 +100,20 @@ class CommandSwitch(SwitchEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
hass,
|
object_id: str,
|
||||||
object_id,
|
friendly_name: str,
|
||||||
friendly_name,
|
command_on: str,
|
||||||
command_on,
|
command_off: str,
|
||||||
command_off,
|
command_state: str | None,
|
||||||
command_state,
|
icon_template: Template | None,
|
||||||
icon_template,
|
value_template: Template | None,
|
||||||
value_template,
|
timeout: int,
|
||||||
timeout,
|
unique_id: str | None,
|
||||||
unique_id,
|
) -> None:
|
||||||
):
|
|
||||||
"""Initialize the switch."""
|
"""Initialize the switch."""
|
||||||
self._hass = hass
|
|
||||||
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
self.entity_id = ENTITY_ID_FORMAT.format(object_id)
|
||||||
self._name = friendly_name
|
self._attr_name = friendly_name
|
||||||
self._state = False
|
self._attr_is_on = False
|
||||||
self._command_on = command_on
|
self._command_on = command_on
|
||||||
self._command_off = command_off
|
self._command_off = command_off
|
||||||
self._command_state = command_state
|
self._command_state = command_state
|
||||||
@ -122,8 +121,9 @@ class CommandSwitch(SwitchEntity):
|
|||||||
self._value_template = value_template
|
self._value_template = value_template
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
self._attr_unique_id = unique_id
|
self._attr_unique_id = unique_id
|
||||||
|
self._attr_should_poll = bool(command_state)
|
||||||
|
|
||||||
def _switch(self, command):
|
def _switch(self, command: str) -> bool:
|
||||||
"""Execute the actual commands."""
|
"""Execute the actual commands."""
|
||||||
_LOGGER.info("Running command: %s", command)
|
_LOGGER.info("Running command: %s", command)
|
||||||
|
|
||||||
@ -134,12 +134,12 @@ class CommandSwitch(SwitchEntity):
|
|||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def _query_state_value(self, command):
|
def _query_state_value(self, command: str) -> str | None:
|
||||||
"""Execute state command for return value."""
|
"""Execute state command for return value."""
|
||||||
_LOGGER.info("Running state value command: %s", command)
|
_LOGGER.info("Running state value command: %s", command)
|
||||||
return check_output_or_log(command, self._timeout)
|
return check_output_or_log(command, self._timeout)
|
||||||
|
|
||||||
def _query_state_code(self, command):
|
def _query_state_code(self, command: str) -> bool:
|
||||||
"""Execute state command for return code."""
|
"""Execute state command for return code."""
|
||||||
_LOGGER.info("Running state code command: %s", command)
|
_LOGGER.info("Running state code command: %s", command)
|
||||||
return (
|
return (
|
||||||
@ -147,32 +147,20 @@ class CommandSwitch(SwitchEntity):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def assumed_state(self) -> bool:
|
||||||
"""Only poll if we have state command."""
|
|
||||||
return self._command_state is not None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the switch."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self):
|
|
||||||
"""Return true if device is on."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def assumed_state(self):
|
|
||||||
"""Return true if we do optimistic updates."""
|
"""Return true if we do optimistic updates."""
|
||||||
return self._command_state is None
|
return self._command_state is None
|
||||||
|
|
||||||
def _query_state(self):
|
def _query_state(self) -> str | int | None:
|
||||||
"""Query for state."""
|
"""Query for state."""
|
||||||
if self._value_template:
|
if self._command_state:
|
||||||
return self._query_state_value(self._command_state)
|
if self._value_template:
|
||||||
return self._query_state_code(self._command_state)
|
return self._query_state_value(self._command_state)
|
||||||
|
return self._query_state_code(self._command_state)
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
return None
|
||||||
|
|
||||||
def update(self):
|
def update(self) -> None:
|
||||||
"""Update device state."""
|
"""Update device state."""
|
||||||
if self._command_state:
|
if self._command_state:
|
||||||
payload = str(self._query_state())
|
payload = str(self._query_state())
|
||||||
@ -182,16 +170,16 @@ class CommandSwitch(SwitchEntity):
|
|||||||
)
|
)
|
||||||
if self._value_template:
|
if self._value_template:
|
||||||
payload = self._value_template.render_with_possible_json_value(payload)
|
payload = self._value_template.render_with_possible_json_value(payload)
|
||||||
self._state = payload.lower() == "true"
|
self._attr_is_on = payload.lower() == "true"
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs) -> None:
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
if self._switch(self._command_on) and not self._command_state:
|
if self._switch(self._command_on) and not self._command_state:
|
||||||
self._state = True
|
self._attr_is_on = True
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs) -> None:
|
||||||
"""Turn the device off."""
|
"""Turn the device off."""
|
||||||
if self._switch(self._command_off) and not self._command_state:
|
if self._switch(self._command_off) and not self._command_state:
|
||||||
self._state = False
|
self._attr_is_on = False
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
@ -51,6 +51,7 @@ async def test_template(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
entity_state = hass.states.get("binary_sensor.test")
|
entity_state = hass.states.get("binary_sensor.test")
|
||||||
|
assert entity_state
|
||||||
assert entity_state.state == STATE_ON
|
assert entity_state.state == STATE_ON
|
||||||
|
|
||||||
|
|
||||||
@ -65,10 +66,11 @@ async def test_sensor_off(hass: HomeAssistant) -> None:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
entity_state = hass.states.get("binary_sensor.test")
|
entity_state = hass.states.get("binary_sensor.test")
|
||||||
|
assert entity_state
|
||||||
assert entity_state.state == STATE_OFF
|
assert entity_state.state == STATE_OFF
|
||||||
|
|
||||||
|
|
||||||
async def test_unique_id(hass):
|
async def test_unique_id(hass: HomeAssistant) -> None:
|
||||||
"""Test unique_id option and if it only creates one binary sensor per id."""
|
"""Test unique_id option and if it only creates one binary sensor per id."""
|
||||||
assert await setup.async_setup_component(
|
assert await setup.async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
|
@ -6,6 +6,8 @@ import tempfile
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from pytest import LogCaptureFixture
|
||||||
|
|
||||||
from homeassistant import config as hass_config, setup
|
from homeassistant import config as hass_config, setup
|
||||||
from homeassistant.components.cover import DOMAIN, SCAN_INTERVAL
|
from homeassistant.components.cover import DOMAIN, SCAN_INTERVAL
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -36,7 +38,7 @@ async def setup_test_entity(hass: HomeAssistant, config_dict: dict[str, Any]) ->
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
async def test_no_covers(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_no_covers(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
|
||||||
"""Test that the cover does not polls when there's no state command."""
|
"""Test that the cover does not polls when there's no state command."""
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
@ -150,7 +152,9 @@ async def test_reload(hass: HomeAssistant) -> None:
|
|||||||
assert hass.states.get("cover.from_yaml")
|
assert hass.states.get("cover.from_yaml")
|
||||||
|
|
||||||
|
|
||||||
async def test_move_cover_failure(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_move_cover_failure(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test with state value."""
|
"""Test with state value."""
|
||||||
|
|
||||||
await setup_test_entity(
|
await setup_test_entity(
|
||||||
@ -163,7 +167,7 @@ async def test_move_cover_failure(caplog: Any, hass: HomeAssistant) -> None:
|
|||||||
assert "Command failed" in caplog.text
|
assert "Command failed" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_unique_id(hass):
|
async def test_unique_id(hass: HomeAssistant) -> None:
|
||||||
"""Test unique_id option and if it only creates one cover per id."""
|
"""Test unique_id option and if it only creates one cover per id."""
|
||||||
await setup_test_entity(
|
await setup_test_entity(
|
||||||
hass,
|
hass,
|
||||||
|
@ -7,6 +7,8 @@ import tempfile
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from pytest import LogCaptureFixture
|
||||||
|
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
from homeassistant.components.notify import DOMAIN
|
from homeassistant.components.notify import DOMAIN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -60,7 +62,9 @@ async def test_command_line_output(hass: HomeAssistant) -> None:
|
|||||||
assert message == handle.read()
|
assert message == handle.read()
|
||||||
|
|
||||||
|
|
||||||
async def test_error_for_none_zero_exit_code(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_error_for_none_zero_exit_code(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test if an error is logged for non zero exit codes."""
|
"""Test if an error is logged for non zero exit codes."""
|
||||||
await setup_test_service(
|
await setup_test_service(
|
||||||
hass,
|
hass,
|
||||||
@ -75,7 +79,7 @@ async def test_error_for_none_zero_exit_code(caplog: Any, hass: HomeAssistant) -
|
|||||||
assert "Command failed" in caplog.text
|
assert "Command failed" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_timeout(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_timeout(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
|
||||||
"""Test blocking is not forever."""
|
"""Test blocking is not forever."""
|
||||||
await setup_test_service(
|
await setup_test_service(
|
||||||
hass,
|
hass,
|
||||||
@ -90,7 +94,9 @@ async def test_timeout(caplog: Any, hass: HomeAssistant) -> None:
|
|||||||
assert "Timeout" in caplog.text
|
assert "Timeout" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_subprocess_exceptions(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_subprocess_exceptions(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test that notify subprocess exceptions are handled correctly."""
|
"""Test that notify subprocess exceptions are handled correctly."""
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
|
@ -4,6 +4,8 @@ from __future__ import annotations
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from pytest import LogCaptureFixture
|
||||||
|
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
from homeassistant.components.sensor import DOMAIN
|
from homeassistant.components.sensor import DOMAIN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -98,7 +100,9 @@ async def test_template_render_with_quote(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_bad_template_render(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_bad_template_render(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test rendering a broken template."""
|
"""Test rendering a broken template."""
|
||||||
|
|
||||||
await setup_test_entities(
|
await setup_test_entities(
|
||||||
@ -141,7 +145,9 @@ async def test_update_with_json_attrs(hass: HomeAssistant) -> None:
|
|||||||
assert entity_state.attributes["key_three"] == "value_three"
|
assert entity_state.attributes["key_three"] == "value_three"
|
||||||
|
|
||||||
|
|
||||||
async def test_update_with_json_attrs_no_data(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def]
|
async def test_update_with_json_attrs_no_data(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test attributes when no JSON result fetched."""
|
"""Test attributes when no JSON result fetched."""
|
||||||
|
|
||||||
await setup_test_entities(
|
await setup_test_entities(
|
||||||
@ -157,7 +163,9 @@ async def test_update_with_json_attrs_no_data(caplog, hass: HomeAssistant) -> No
|
|||||||
assert "Empty reply found when expecting JSON data" in caplog.text
|
assert "Empty reply found when expecting JSON data" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_update_with_json_attrs_not_dict(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def]
|
async def test_update_with_json_attrs_not_dict(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test attributes when the return value not a dict."""
|
"""Test attributes when the return value not a dict."""
|
||||||
|
|
||||||
await setup_test_entities(
|
await setup_test_entities(
|
||||||
@ -173,7 +181,9 @@ async def test_update_with_json_attrs_not_dict(caplog, hass: HomeAssistant) -> N
|
|||||||
assert "JSON result was not a dictionary" in caplog.text
|
assert "JSON result was not a dictionary" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_update_with_json_attrs_bad_json(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def]
|
async def test_update_with_json_attrs_bad_json(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test attributes when the return value is invalid JSON."""
|
"""Test attributes when the return value is invalid JSON."""
|
||||||
|
|
||||||
await setup_test_entities(
|
await setup_test_entities(
|
||||||
@ -189,7 +199,9 @@ async def test_update_with_json_attrs_bad_json(caplog, hass: HomeAssistant) -> N
|
|||||||
assert "Unable to parse output as JSON" in caplog.text
|
assert "Unable to parse output as JSON" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_update_with_missing_json_attrs(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def]
|
async def test_update_with_missing_json_attrs(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test attributes when an expected key is missing."""
|
"""Test attributes when an expected key is missing."""
|
||||||
|
|
||||||
await setup_test_entities(
|
await setup_test_entities(
|
||||||
@ -208,7 +220,9 @@ async def test_update_with_missing_json_attrs(caplog, hass: HomeAssistant) -> No
|
|||||||
assert "missing_key" not in entity_state.attributes
|
assert "missing_key" not in entity_state.attributes
|
||||||
|
|
||||||
|
|
||||||
async def test_update_with_unnecessary_json_attrs(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def]
|
async def test_update_with_unnecessary_json_attrs(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test attributes when an expected key is missing."""
|
"""Test attributes when an expected key is missing."""
|
||||||
|
|
||||||
await setup_test_entities(
|
await setup_test_entities(
|
||||||
@ -226,7 +240,7 @@ async def test_update_with_unnecessary_json_attrs(caplog, hass: HomeAssistant) -
|
|||||||
assert "key_three" not in entity_state.attributes
|
assert "key_three" not in entity_state.attributes
|
||||||
|
|
||||||
|
|
||||||
async def test_unique_id(hass):
|
async def test_unique_id(hass: HomeAssistant) -> None:
|
||||||
"""Test unique_id option and if it only creates one sensor per id."""
|
"""Test unique_id option and if it only creates one sensor per id."""
|
||||||
assert await setup.async_setup_component(
|
assert await setup.async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
|
@ -8,6 +8,8 @@ import tempfile
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from pytest import LogCaptureFixture
|
||||||
|
|
||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
from homeassistant.components.switch import DOMAIN, SCAN_INTERVAL
|
from homeassistant.components.switch import DOMAIN, SCAN_INTERVAL
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -269,10 +271,13 @@ async def test_name_is_set_correctly(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
entity_state = hass.states.get("switch.test")
|
entity_state = hass.states.get("switch.test")
|
||||||
|
assert entity_state
|
||||||
assert entity_state.name == "Test friendly name!"
|
assert entity_state.name == "Test friendly name!"
|
||||||
|
|
||||||
|
|
||||||
async def test_switch_command_state_fail(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_switch_command_state_fail(
|
||||||
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
|
) -> None:
|
||||||
"""Test that switch failures are handled correctly."""
|
"""Test that switch failures are handled correctly."""
|
||||||
await setup_test_entity(
|
await setup_test_entity(
|
||||||
hass,
|
hass,
|
||||||
@ -289,6 +294,7 @@ async def test_switch_command_state_fail(caplog: Any, hass: HomeAssistant) -> No
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
entity_state = hass.states.get("switch.test")
|
entity_state = hass.states.get("switch.test")
|
||||||
|
assert entity_state
|
||||||
assert entity_state.state == "on"
|
assert entity_state.state == "on"
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -300,13 +306,14 @@ async def test_switch_command_state_fail(caplog: Any, hass: HomeAssistant) -> No
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
entity_state = hass.states.get("switch.test")
|
entity_state = hass.states.get("switch.test")
|
||||||
|
assert entity_state
|
||||||
assert entity_state.state == "on"
|
assert entity_state.state == "on"
|
||||||
|
|
||||||
assert "Command failed" in caplog.text
|
assert "Command failed" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_switch_command_state_code_exceptions(
|
async def test_switch_command_state_code_exceptions(
|
||||||
caplog: Any, hass: HomeAssistant
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that switch state code exceptions are handled correctly."""
|
"""Test that switch state code exceptions are handled correctly."""
|
||||||
|
|
||||||
@ -339,7 +346,7 @@ async def test_switch_command_state_code_exceptions(
|
|||||||
|
|
||||||
|
|
||||||
async def test_switch_command_state_value_exceptions(
|
async def test_switch_command_state_value_exceptions(
|
||||||
caplog: Any, hass: HomeAssistant
|
caplog: LogCaptureFixture, hass: HomeAssistant
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that switch state value exceptions are handled correctly."""
|
"""Test that switch state value exceptions are handled correctly."""
|
||||||
|
|
||||||
@ -372,14 +379,14 @@ async def test_switch_command_state_value_exceptions(
|
|||||||
assert "Error trying to exec command" in caplog.text
|
assert "Error trying to exec command" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_no_switches(caplog: Any, hass: HomeAssistant) -> None:
|
async def test_no_switches(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
|
||||||
"""Test with no switches."""
|
"""Test with no switches."""
|
||||||
|
|
||||||
await setup_test_entity(hass, {})
|
await setup_test_entity(hass, {})
|
||||||
assert "No switches" in caplog.text
|
assert "No switches" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_unique_id(hass):
|
async def test_unique_id(hass: HomeAssistant) -> None:
|
||||||
"""Test unique_id option and if it only creates one switch per id."""
|
"""Test unique_id option and if it only creates one switch per id."""
|
||||||
await setup_test_entity(
|
await setup_test_entity(
|
||||||
hass,
|
hass,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user