mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 15:47:12 +00:00
Merge pull request #47490 from home-assistant/rc
This commit is contained in:
commit
1145c30c4b
@ -2,7 +2,7 @@
|
||||
"domain": "amcrest",
|
||||
"name": "Amcrest",
|
||||
"documentation": "https://www.home-assistant.io/integrations/amcrest",
|
||||
"requirements": ["amcrest==1.7.0"],
|
||||
"requirements": ["amcrest==1.7.1"],
|
||||
"dependencies": ["ffmpeg"],
|
||||
"codeowners": ["@pnbruckner"]
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Home Assistant Frontend",
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"requirements": [
|
||||
"home-assistant-frontend==20210302.4"
|
||||
"home-assistant-frontend==20210302.5"
|
||||
],
|
||||
"dependencies": [
|
||||
"api",
|
||||
|
@ -19,7 +19,6 @@ from .const import (
|
||||
CONF_ALLOW_UNREACHABLE,
|
||||
DEFAULT_ALLOW_HUE_GROUPS,
|
||||
DEFAULT_ALLOW_UNREACHABLE,
|
||||
DEFAULT_SCENE_TRANSITION,
|
||||
LOGGER,
|
||||
)
|
||||
from .errors import AuthenticationRequired, CannotConnect
|
||||
@ -34,9 +33,7 @@ SCENE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_GROUP_NAME): cv.string,
|
||||
vol.Required(ATTR_SCENE_NAME): cv.string,
|
||||
vol.Optional(
|
||||
ATTR_TRANSITION, default=DEFAULT_SCENE_TRANSITION
|
||||
): cv.positive_int,
|
||||
vol.Optional(ATTR_TRANSITION): cv.positive_int,
|
||||
}
|
||||
)
|
||||
# How long should we sleep if the hub is busy
|
||||
@ -209,7 +206,7 @@ class HueBridge:
|
||||
"""Service to call directly into bridge to set scenes."""
|
||||
group_name = call.data[ATTR_GROUP_NAME]
|
||||
scene_name = call.data[ATTR_SCENE_NAME]
|
||||
transition = call.data.get(ATTR_TRANSITION, DEFAULT_SCENE_TRANSITION)
|
||||
transition = call.data.get(ATTR_TRANSITION)
|
||||
|
||||
group = next(
|
||||
(group for group in self.api.groups.values() if group.name == group_name),
|
||||
|
@ -14,8 +14,6 @@ DEFAULT_ALLOW_UNREACHABLE = False
|
||||
CONF_ALLOW_HUE_GROUPS = "allow_hue_groups"
|
||||
DEFAULT_ALLOW_HUE_GROUPS = False
|
||||
|
||||
DEFAULT_SCENE_TRANSITION = 4
|
||||
|
||||
GROUP_TYPE_LIGHT_GROUP = "LightGroup"
|
||||
GROUP_TYPE_ROOM = "Room"
|
||||
GROUP_TYPE_LUMINAIRE = "Luminaire"
|
||||
|
@ -29,7 +29,6 @@ CONF_GATEWAY_TYPE_ALL: List[str] = [
|
||||
|
||||
|
||||
DOMAIN: str = "mysensors"
|
||||
MYSENSORS_GATEWAY_READY: str = "mysensors_gateway_ready_{}"
|
||||
MYSENSORS_GATEWAY_START_TASK: str = "mysensors_gateway_start_task_{}"
|
||||
MYSENSORS_GATEWAYS: str = "mysensors_gateways"
|
||||
PLATFORM: str = "platform"
|
||||
|
@ -26,7 +26,6 @@ from .const import (
|
||||
CONF_TOPIC_OUT_PREFIX,
|
||||
CONF_VERSION,
|
||||
DOMAIN,
|
||||
MYSENSORS_GATEWAY_READY,
|
||||
MYSENSORS_GATEWAY_START_TASK,
|
||||
MYSENSORS_GATEWAYS,
|
||||
GatewayId,
|
||||
@ -36,7 +35,7 @@ from .helpers import discover_mysensors_platform, validate_child, validate_node
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
GATEWAY_READY_TIMEOUT = 15.0
|
||||
GATEWAY_READY_TIMEOUT = 20.0
|
||||
MQTT_COMPONENT = "mqtt"
|
||||
|
||||
|
||||
@ -64,24 +63,16 @@ async def try_connect(hass: HomeAssistantType, user_input: Dict[str, str]) -> bo
|
||||
if user_input[CONF_DEVICE] == MQTT_COMPONENT:
|
||||
return True # dont validate mqtt. mqtt gateways dont send ready messages :(
|
||||
try:
|
||||
gateway_ready = asyncio.Future()
|
||||
gateway_ready = asyncio.Event()
|
||||
|
||||
def gateway_ready_callback(msg):
|
||||
msg_type = msg.gateway.const.MessageType(msg.type)
|
||||
_LOGGER.debug("Received MySensors msg type %s: %s", msg_type.name, msg)
|
||||
if msg_type.name != "internal":
|
||||
return
|
||||
internal = msg.gateway.const.Internal(msg.sub_type)
|
||||
if internal.name != "I_GATEWAY_READY":
|
||||
return
|
||||
_LOGGER.debug("Received gateway ready")
|
||||
gateway_ready.set_result(True)
|
||||
def on_conn_made(_: BaseAsyncGateway) -> None:
|
||||
gateway_ready.set()
|
||||
|
||||
gateway: Optional[BaseAsyncGateway] = await _get_gateway(
|
||||
hass,
|
||||
device=user_input[CONF_DEVICE],
|
||||
version=user_input[CONF_VERSION],
|
||||
event_callback=gateway_ready_callback,
|
||||
event_callback=lambda _: None,
|
||||
persistence_file=None,
|
||||
baud_rate=user_input.get(CONF_BAUD_RATE),
|
||||
tcp_port=user_input.get(CONF_TCP_PORT),
|
||||
@ -92,12 +83,13 @@ async def try_connect(hass: HomeAssistantType, user_input: Dict[str, str]) -> bo
|
||||
)
|
||||
if gateway is None:
|
||||
return False
|
||||
gateway.on_conn_made = on_conn_made
|
||||
|
||||
connect_task = None
|
||||
try:
|
||||
connect_task = asyncio.create_task(gateway.start())
|
||||
with async_timeout.timeout(20):
|
||||
await gateway_ready
|
||||
with async_timeout.timeout(GATEWAY_READY_TIMEOUT):
|
||||
await gateway_ready.wait()
|
||||
return True
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.info("Try gateway connect failed with timeout")
|
||||
@ -280,6 +272,12 @@ async def _gw_start(
|
||||
hass: HomeAssistantType, entry: ConfigEntry, gateway: BaseAsyncGateway
|
||||
):
|
||||
"""Start the gateway."""
|
||||
gateway_ready = asyncio.Event()
|
||||
|
||||
def gateway_connected(_: BaseAsyncGateway):
|
||||
gateway_ready.set()
|
||||
|
||||
gateway.on_conn_made = gateway_connected
|
||||
# Don't use hass.async_create_task to avoid holding up setup indefinitely.
|
||||
hass.data[DOMAIN][
|
||||
MYSENSORS_GATEWAY_START_TASK.format(entry.entry_id)
|
||||
@ -294,21 +292,15 @@ async def _gw_start(
|
||||
if entry.data[CONF_DEVICE] == MQTT_COMPONENT:
|
||||
# Gatways connected via mqtt doesn't send gateway ready message.
|
||||
return
|
||||
gateway_ready = asyncio.Future()
|
||||
gateway_ready_key = MYSENSORS_GATEWAY_READY.format(entry.entry_id)
|
||||
hass.data[DOMAIN][gateway_ready_key] = gateway_ready
|
||||
|
||||
try:
|
||||
with async_timeout.timeout(GATEWAY_READY_TIMEOUT):
|
||||
await gateway_ready
|
||||
await gateway_ready.wait()
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.warning(
|
||||
"Gateway %s not ready after %s secs so continuing with setup",
|
||||
"Gateway %s not connected after %s secs so continuing with setup",
|
||||
entry.data[CONF_DEVICE],
|
||||
GATEWAY_READY_TIMEOUT,
|
||||
)
|
||||
finally:
|
||||
hass.data[DOMAIN].pop(gateway_ready_key, None)
|
||||
|
||||
|
||||
def _gw_callback_factory(
|
||||
|
@ -8,14 +8,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
from homeassistant.util import decorator
|
||||
|
||||
from .const import (
|
||||
CHILD_CALLBACK,
|
||||
DOMAIN,
|
||||
MYSENSORS_GATEWAY_READY,
|
||||
NODE_CALLBACK,
|
||||
DevId,
|
||||
GatewayId,
|
||||
)
|
||||
from .const import CHILD_CALLBACK, NODE_CALLBACK, DevId, GatewayId
|
||||
from .device import get_mysensors_devices
|
||||
from .helpers import discover_mysensors_platform, validate_set_msg
|
||||
|
||||
@ -75,20 +68,6 @@ async def handle_sketch_version(
|
||||
_handle_node_update(hass, gateway_id, msg)
|
||||
|
||||
|
||||
@HANDLERS.register("I_GATEWAY_READY")
|
||||
async def handle_gateway_ready(
|
||||
hass: HomeAssistantType, gateway_id: GatewayId, msg: Message
|
||||
) -> None:
|
||||
"""Handle an internal gateway ready message.
|
||||
|
||||
Set asyncio future result if gateway is ready.
|
||||
"""
|
||||
gateway_ready = hass.data[DOMAIN].get(MYSENSORS_GATEWAY_READY.format(gateway_id))
|
||||
if gateway_ready is None or gateway_ready.cancelled():
|
||||
return
|
||||
gateway_ready.set_result(True)
|
||||
|
||||
|
||||
@callback
|
||||
def _handle_child_update(
|
||||
hass: HomeAssistantType, gateway_id: GatewayId, validated: Dict[str, List[DevId]]
|
||||
|
@ -7,6 +7,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components.camera import SUPPORT_STREAM, Camera
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
@ -49,15 +50,17 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
|
||||
data_handler = hass.data[DOMAIN][entry.entry_id][DATA_HANDLER]
|
||||
|
||||
await data_handler.register_data_class(
|
||||
CAMERA_DATA_CLASS_NAME, CAMERA_DATA_CLASS_NAME, None
|
||||
)
|
||||
|
||||
if CAMERA_DATA_CLASS_NAME not in data_handler.data:
|
||||
raise PlatformNotReady
|
||||
|
||||
async def get_entities():
|
||||
"""Retrieve Netatmo entities."""
|
||||
await data_handler.register_data_class(
|
||||
CAMERA_DATA_CLASS_NAME, CAMERA_DATA_CLASS_NAME, None
|
||||
)
|
||||
|
||||
data = data_handler.data
|
||||
|
||||
if not data.get(CAMERA_DATA_CLASS_NAME):
|
||||
if not data_handler.data.get(CAMERA_DATA_CLASS_NAME):
|
||||
return []
|
||||
|
||||
data_class = data_handler.data[CAMERA_DATA_CLASS_NAME]
|
||||
@ -94,24 +97,25 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
|
||||
async_add_entities(await get_entities(), True)
|
||||
|
||||
await data_handler.unregister_data_class(CAMERA_DATA_CLASS_NAME, None)
|
||||
|
||||
platform = entity_platform.current_platform.get()
|
||||
|
||||
if data_handler.data[CAMERA_DATA_CLASS_NAME] is not None:
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_PERSONS_HOME,
|
||||
{vol.Required(ATTR_PERSONS): vol.All(cv.ensure_list, [cv.string])},
|
||||
"_service_set_persons_home",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_PERSON_AWAY,
|
||||
{vol.Optional(ATTR_PERSON): cv.string},
|
||||
"_service_set_person_away",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_CAMERA_LIGHT,
|
||||
{vol.Required(ATTR_CAMERA_LIGHT_MODE): vol.In(CAMERA_LIGHT_MODES)},
|
||||
"_service_set_camera_light",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_PERSONS_HOME,
|
||||
{vol.Required(ATTR_PERSONS): vol.All(cv.ensure_list, [cv.string])},
|
||||
"_service_set_persons_home",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_PERSON_AWAY,
|
||||
{vol.Optional(ATTR_PERSON): cv.string},
|
||||
"_service_set_person_away",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_CAMERA_LIGHT,
|
||||
{vol.Required(ATTR_CAMERA_LIGHT_MODE): vol.In(CAMERA_LIGHT_MODES)},
|
||||
"_service_set_camera_light",
|
||||
)
|
||||
|
||||
|
||||
class NetatmoCamera(NetatmoBase, Camera):
|
||||
|
@ -25,6 +25,7 @@ from homeassistant.const import (
|
||||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.device_registry import async_get_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@ -81,6 +82,7 @@ NETATMO_MAP_PRESET = {
|
||||
STATE_NETATMO_AWAY: PRESET_AWAY,
|
||||
STATE_NETATMO_OFF: STATE_NETATMO_OFF,
|
||||
STATE_NETATMO_MANUAL: STATE_NETATMO_MANUAL,
|
||||
STATE_NETATMO_HOME: PRESET_SCHEDULE,
|
||||
}
|
||||
|
||||
HVAC_MAP_NETATMO = {
|
||||
@ -111,8 +113,8 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
)
|
||||
home_data = data_handler.data.get(HOMEDATA_DATA_CLASS_NAME)
|
||||
|
||||
if not home_data:
|
||||
return
|
||||
if HOMEDATA_DATA_CLASS_NAME not in data_handler.data:
|
||||
raise PlatformNotReady
|
||||
|
||||
async def get_entities():
|
||||
"""Retrieve Netatmo entities."""
|
||||
@ -151,6 +153,8 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
|
||||
async_add_entities(await get_entities(), True)
|
||||
|
||||
await data_handler.unregister_data_class(HOMEDATA_DATA_CLASS_NAME, None)
|
||||
|
||||
platform = entity_platform.current_platform.get()
|
||||
|
||||
if home_data is not None:
|
||||
|
@ -129,7 +129,11 @@ class NetatmoDataHandler:
|
||||
if update_callback:
|
||||
update_callback()
|
||||
|
||||
except (pyatmo.NoDevice, pyatmo.ApiError) as err:
|
||||
except pyatmo.NoDevice as err:
|
||||
_LOGGER.debug(err)
|
||||
self.data[data_class_entry] = None
|
||||
|
||||
except pyatmo.ApiError as err:
|
||||
_LOGGER.debug(err)
|
||||
|
||||
async def register_data_class(
|
||||
|
@ -31,18 +31,15 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
|
||||
data_handler = hass.data[DOMAIN][entry.entry_id][DATA_HANDLER]
|
||||
|
||||
if CAMERA_DATA_CLASS_NAME not in data_handler.data:
|
||||
raise PlatformNotReady
|
||||
|
||||
async def get_entities():
|
||||
"""Retrieve Netatmo entities."""
|
||||
await data_handler.register_data_class(
|
||||
CAMERA_DATA_CLASS_NAME, CAMERA_DATA_CLASS_NAME, None
|
||||
)
|
||||
|
||||
entities = []
|
||||
all_cameras = []
|
||||
|
||||
if CAMERA_DATA_CLASS_NAME not in data_handler.data:
|
||||
raise PlatformNotReady
|
||||
|
||||
try:
|
||||
for home in data_handler.data[CAMERA_DATA_CLASS_NAME].cameras.values():
|
||||
for camera in home.values():
|
||||
|
@ -20,6 +20,7 @@ from homeassistant.const import (
|
||||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.device_registry import async_entries_for_config_entry
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
@ -129,14 +130,25 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Set up the Netatmo weather and homecoach platform."""
|
||||
data_handler = hass.data[DOMAIN][entry.entry_id][DATA_HANDLER]
|
||||
|
||||
await data_handler.register_data_class(
|
||||
WEATHERSTATION_DATA_CLASS_NAME, WEATHERSTATION_DATA_CLASS_NAME, None
|
||||
)
|
||||
await data_handler.register_data_class(
|
||||
HOMECOACH_DATA_CLASS_NAME, HOMECOACH_DATA_CLASS_NAME, None
|
||||
)
|
||||
|
||||
async def find_entities(data_class_name):
|
||||
"""Find all entities."""
|
||||
await data_handler.register_data_class(data_class_name, data_class_name, None)
|
||||
if data_class_name not in data_handler.data:
|
||||
raise PlatformNotReady
|
||||
|
||||
all_module_infos = {}
|
||||
data = data_handler.data
|
||||
|
||||
if not data.get(data_class_name):
|
||||
if data_class_name not in data:
|
||||
return []
|
||||
|
||||
if data[data_class_name] is None:
|
||||
return []
|
||||
|
||||
data_class = data[data_class_name]
|
||||
@ -174,6 +186,8 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
NetatmoSensor(data_handler, data_class_name, module, condition)
|
||||
)
|
||||
|
||||
await data_handler.unregister_data_class(data_class_name, None)
|
||||
|
||||
return entities
|
||||
|
||||
for data_class_name in [
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "opentherm_gw",
|
||||
"name": "OpenTherm Gateway",
|
||||
"documentation": "https://www.home-assistant.io/integrations/opentherm_gw",
|
||||
"requirements": ["pyotgw==1.0b1"],
|
||||
"requirements": ["pyotgw==1.1b1"],
|
||||
"codeowners": ["@mvn23"],
|
||||
"config_flow": true
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Philips TV",
|
||||
"documentation": "https://www.home-assistant.io/integrations/philips_js",
|
||||
"requirements": [
|
||||
"ha-philipsjs==2.3.0"
|
||||
"ha-philipsjs==2.3.1"
|
||||
],
|
||||
"codeowners": [
|
||||
"@elupus"
|
||||
|
@ -13,10 +13,9 @@ from homeassistant.exceptions import (
|
||||
TemplateError,
|
||||
Unauthorized,
|
||||
)
|
||||
from homeassistant.helpers import config_validation as cv, entity
|
||||
from homeassistant.helpers import config_validation as cv, entity, template
|
||||
from homeassistant.helpers.event import TrackTemplate, async_track_template_result
|
||||
from homeassistant.helpers.service import async_get_all_descriptions
|
||||
from homeassistant.helpers.template import Template
|
||||
from homeassistant.loader import IntegrationNotFound, async_get_integration
|
||||
|
||||
from . import const, decorators, messages
|
||||
@ -132,6 +131,11 @@ async def handle_call_service(hass, connection, msg):
|
||||
if msg["domain"] == HASS_DOMAIN and msg["service"] in ["restart", "stop"]:
|
||||
blocking = False
|
||||
|
||||
# We do not support templates.
|
||||
target = msg.get("target")
|
||||
if template.is_complex(target):
|
||||
raise vol.Invalid("Templates are not supported here")
|
||||
|
||||
try:
|
||||
context = connection.context(msg)
|
||||
await hass.services.async_call(
|
||||
@ -140,7 +144,7 @@ async def handle_call_service(hass, connection, msg):
|
||||
msg.get("service_data"),
|
||||
blocking,
|
||||
context,
|
||||
target=msg.get("target"),
|
||||
target=target,
|
||||
)
|
||||
connection.send_message(
|
||||
messages.result_message(msg["id"], {"context": context})
|
||||
@ -256,14 +260,14 @@ def handle_ping(hass, connection, msg):
|
||||
async def handle_render_template(hass, connection, msg):
|
||||
"""Handle render_template command."""
|
||||
template_str = msg["template"]
|
||||
template = Template(template_str, hass)
|
||||
template_obj = template.Template(template_str, hass)
|
||||
variables = msg.get("variables")
|
||||
timeout = msg.get("timeout")
|
||||
info = None
|
||||
|
||||
if timeout:
|
||||
try:
|
||||
timed_out = await template.async_render_will_timeout(timeout)
|
||||
timed_out = await template_obj.async_render_will_timeout(timeout)
|
||||
except TemplateError as ex:
|
||||
connection.send_error(msg["id"], const.ERR_TEMPLATE_ERROR, str(ex))
|
||||
return
|
||||
@ -294,7 +298,7 @@ async def handle_render_template(hass, connection, msg):
|
||||
try:
|
||||
info = async_track_template_result(
|
||||
hass,
|
||||
[TrackTemplate(template, variables)],
|
||||
[TrackTemplate(template_obj, variables)],
|
||||
_template_listener,
|
||||
raise_on_template_error=True,
|
||||
)
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Z-Wave JS",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/zwave_js",
|
||||
"requirements": ["zwave-js-server-python==0.21.0"],
|
||||
"requirements": ["zwave-js-server-python==0.21.1"],
|
||||
"codeowners": ["@home-assistant/z-wave"],
|
||||
"dependencies": ["http", "websocket_api"]
|
||||
}
|
||||
|
@ -70,10 +70,15 @@ set_config_parameter:
|
||||
refresh_value:
|
||||
name: Refresh value(s) of a Z-Wave entity
|
||||
description: Force update value(s) for a Z-Wave entity
|
||||
target:
|
||||
entity:
|
||||
integration: zwave_js
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Entity whose value(s) should be refreshed
|
||||
required: true
|
||||
example: sensor.family_room_motion
|
||||
selector:
|
||||
entity:
|
||||
integration: zwave_js
|
||||
refresh_all_values:
|
||||
name: Refresh all values?
|
||||
description: Whether to refresh all values (true) or just the primary value (false)
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 2021
|
||||
MINOR_VERSION = 3
|
||||
PATCH_VERSION = "1"
|
||||
PATCH_VERSION = "2"
|
||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER = (3, 8, 0)
|
||||
|
@ -15,7 +15,7 @@ defusedxml==0.6.0
|
||||
distro==1.5.0
|
||||
emoji==1.2.0
|
||||
hass-nabucasa==0.41.0
|
||||
home-assistant-frontend==20210302.4
|
||||
home-assistant-frontend==20210302.5
|
||||
httpx==0.16.1
|
||||
jinja2>=2.11.3
|
||||
netdisco==2.8.2
|
||||
|
@ -245,7 +245,7 @@ alpha_vantage==2.3.1
|
||||
ambiclimate==0.2.1
|
||||
|
||||
# homeassistant.components.amcrest
|
||||
amcrest==1.7.0
|
||||
amcrest==1.7.1
|
||||
|
||||
# homeassistant.components.androidtv
|
||||
androidtv[async]==0.0.57
|
||||
@ -721,7 +721,7 @@ guppy3==3.1.0
|
||||
ha-ffmpeg==3.0.2
|
||||
|
||||
# homeassistant.components.philips_js
|
||||
ha-philipsjs==2.3.0
|
||||
ha-philipsjs==2.3.1
|
||||
|
||||
# homeassistant.components.habitica
|
||||
habitipy==0.2.0
|
||||
@ -763,7 +763,7 @@ hole==0.5.1
|
||||
holidays==0.10.5.2
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20210302.4
|
||||
home-assistant-frontend==20210302.5
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.10
|
||||
@ -1603,7 +1603,7 @@ pyoppleio==1.0.5
|
||||
pyota==2.0.5
|
||||
|
||||
# homeassistant.components.opentherm_gw
|
||||
pyotgw==1.0b1
|
||||
pyotgw==1.1b1
|
||||
|
||||
# homeassistant.auth.mfa_modules.notify
|
||||
# homeassistant.auth.mfa_modules.totp
|
||||
@ -2397,4 +2397,4 @@ zigpy==0.32.0
|
||||
zm-py==0.5.2
|
||||
|
||||
# homeassistant.components.zwave_js
|
||||
zwave-js-server-python==0.21.0
|
||||
zwave-js-server-python==0.21.1
|
||||
|
@ -382,7 +382,7 @@ guppy3==3.1.0
|
||||
ha-ffmpeg==3.0.2
|
||||
|
||||
# homeassistant.components.philips_js
|
||||
ha-philipsjs==2.3.0
|
||||
ha-philipsjs==2.3.1
|
||||
|
||||
# homeassistant.components.habitica
|
||||
habitipy==0.2.0
|
||||
@ -412,7 +412,7 @@ hole==0.5.1
|
||||
holidays==0.10.5.2
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20210302.4
|
||||
home-assistant-frontend==20210302.5
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.10
|
||||
@ -851,7 +851,7 @@ pyopenuv==1.0.9
|
||||
pyopnsense==0.2.0
|
||||
|
||||
# homeassistant.components.opentherm_gw
|
||||
pyotgw==1.0b1
|
||||
pyotgw==1.1b1
|
||||
|
||||
# homeassistant.auth.mfa_modules.notify
|
||||
# homeassistant.auth.mfa_modules.totp
|
||||
@ -1234,4 +1234,4 @@ zigpy-znp==0.4.0
|
||||
zigpy==0.32.0
|
||||
|
||||
# homeassistant.components.zwave_js
|
||||
zwave-js-server-python==0.21.0
|
||||
zwave-js-server-python==0.21.1
|
||||
|
@ -189,6 +189,7 @@ async def test_hue_activate_scene(hass, mock_api):
|
||||
|
||||
assert len(mock_api.mock_requests) == 3
|
||||
assert mock_api.mock_requests[2]["json"]["scene"] == "scene_1"
|
||||
assert "transitiontime" not in mock_api.mock_requests[2]["json"]
|
||||
assert mock_api.mock_requests[2]["path"] == "groups/group_1/action"
|
||||
|
||||
|
||||
|
@ -21,13 +21,7 @@ from tests.common import MockEntity, MockEntityPlatform, async_mock_service
|
||||
|
||||
async def test_call_service(hass, websocket_client):
|
||||
"""Test call service command."""
|
||||
calls = []
|
||||
|
||||
@callback
|
||||
def service_call(call):
|
||||
calls.append(call)
|
||||
|
||||
hass.services.async_register("domain_test", "test_service", service_call)
|
||||
calls = async_mock_service(hass, "domain_test", "test_service")
|
||||
|
||||
await websocket_client.send_json(
|
||||
{
|
||||
@ -54,13 +48,7 @@ async def test_call_service(hass, websocket_client):
|
||||
|
||||
async def test_call_service_target(hass, websocket_client):
|
||||
"""Test call service command with target."""
|
||||
calls = []
|
||||
|
||||
@callback
|
||||
def service_call(call):
|
||||
calls.append(call)
|
||||
|
||||
hass.services.async_register("domain_test", "test_service", service_call)
|
||||
calls = async_mock_service(hass, "domain_test", "test_service")
|
||||
|
||||
await websocket_client.send_json(
|
||||
{
|
||||
@ -93,6 +81,28 @@ async def test_call_service_target(hass, websocket_client):
|
||||
}
|
||||
|
||||
|
||||
async def test_call_service_target_template(hass, websocket_client):
|
||||
"""Test call service command with target does not allow template."""
|
||||
await websocket_client.send_json(
|
||||
{
|
||||
"id": 5,
|
||||
"type": "call_service",
|
||||
"domain": "domain_test",
|
||||
"service": "test_service",
|
||||
"service_data": {"hello": "world"},
|
||||
"target": {
|
||||
"entity_id": "{{ 1 }}",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg["id"] == 5
|
||||
assert msg["type"] == const.TYPE_RESULT
|
||||
assert not msg["success"]
|
||||
assert msg["error"]["code"] == const.ERR_INVALID_FORMAT
|
||||
|
||||
|
||||
async def test_call_service_not_found(hass, websocket_client):
|
||||
"""Test call service command."""
|
||||
await websocket_client.send_json(
|
||||
@ -232,7 +242,6 @@ async def test_call_service_error(hass, websocket_client):
|
||||
)
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
print(msg)
|
||||
assert msg["id"] == 5
|
||||
assert msg["type"] == const.TYPE_RESULT
|
||||
assert msg["success"] is False
|
||||
@ -249,7 +258,6 @@ async def test_call_service_error(hass, websocket_client):
|
||||
)
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
print(msg)
|
||||
assert msg["id"] == 6
|
||||
assert msg["type"] == const.TYPE_RESULT
|
||||
assert msg["success"] is False
|
||||
|
Loading…
x
Reference in New Issue
Block a user