forked from home-assistant/core
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77f14b63f5 | ||
|
|
a08df4e18f | ||
|
|
58b743eec1 | ||
|
|
41736c93a1 | ||
|
|
733a394c55 | ||
|
|
ba0d3aad1c | ||
|
|
5c3cb044d0 | ||
|
|
a3ca48c1bd | ||
|
|
5356ce2b6d | ||
|
|
02def46991 | ||
|
|
3ae82c3cac | ||
|
|
b5548c57fb | ||
|
|
e5281051a3 | ||
|
|
346ae78a8e | ||
|
|
b5650bdd52 | ||
|
|
bf28268732 | ||
|
|
4eb794ae84 | ||
|
|
21b5551506 | ||
|
|
e0131f726f | ||
|
|
e685b1a1e3 | ||
|
|
0d00e49dfc | ||
|
|
36e08e770b | ||
|
|
e3b3d136d8 | ||
|
|
0a5a5ff053 | ||
|
|
0bb7592fab | ||
|
|
d081ac8d4a | ||
|
|
b96e0e69f2 | ||
|
|
82cca8fb1c | ||
|
|
a9602e7a08 | ||
|
|
c08ae64085 | ||
|
|
01e558430a | ||
|
|
31b061e8f1 | ||
|
|
4ca40367d1 | ||
|
|
12da88cae9 | ||
|
|
0520ce5ed3 | ||
|
|
995e22d3bb | ||
|
|
6296d78e58 | ||
|
|
2c7fd30029 |
@@ -133,7 +133,7 @@ class CastOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
)
|
||||
|
||||
if not bad_cec and not bad_hosts and not bad_uuid:
|
||||
updated_config = {}
|
||||
updated_config = dict(current_config)
|
||||
updated_config[CONF_IGNORE_CEC] = ignore_cec
|
||||
updated_config[CONF_KNOWN_HOSTS] = known_hosts
|
||||
updated_config[CONF_UUID] = wanted_uuid
|
||||
|
||||
@@ -7,6 +7,7 @@ from datetime import timedelta
|
||||
import functools as ft
|
||||
import json
|
||||
import logging
|
||||
from urllib.parse import quote
|
||||
|
||||
import pychromecast
|
||||
from pychromecast.controllers.homeassistant import HomeAssistantController
|
||||
@@ -472,7 +473,7 @@ class CastDevice(MediaPlayerEntity):
|
||||
media_id = async_sign_path(
|
||||
self.hass,
|
||||
refresh_token.id,
|
||||
media_id,
|
||||
quote(media_id),
|
||||
timedelta(seconds=media_source.DEFAULT_EXPIRY_TIME),
|
||||
)
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ from .const import DOMAIN
|
||||
PLATFORMS = ["sensor"]
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: dict):
|
||||
async def async_setup(hass: HomeAssistant, config: dict) -> bool:
|
||||
"""Set up the Coronavirus component."""
|
||||
# Make sure coordinator is initialized.
|
||||
await get_coordinator(hass)
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Coronavirus from a config entry."""
|
||||
if isinstance(entry.data["country"], int):
|
||||
hass.config_entries.async_update_entry(
|
||||
@@ -44,6 +44,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
if not entry.unique_id:
|
||||
hass.config_entries.async_update_entry(entry, unique_id=entry.data["country"])
|
||||
|
||||
coordinator = await get_coordinator(hass)
|
||||
if not coordinator.last_update_success:
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
for platform in PLATFORMS:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, platform)
|
||||
@@ -52,9 +56,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unload_ok = all(
|
||||
return all(
|
||||
await asyncio.gather(
|
||||
*[
|
||||
hass.config_entries.async_forward_entry_unload(entry, platform)
|
||||
@@ -63,10 +67,10 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
)
|
||||
)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
async def get_coordinator(hass):
|
||||
async def get_coordinator(
|
||||
hass: HomeAssistant,
|
||||
) -> update_coordinator.DataUpdateCoordinator:
|
||||
"""Get the data update coordinator."""
|
||||
if DOMAIN in hass.data:
|
||||
return hass.data[DOMAIN]
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
"""Config flow for Coronavirus integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
@@ -15,13 +19,18 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
_options = None
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
|
||||
if self._options is None:
|
||||
self._options = {OPTION_WORLDWIDE: "Worldwide"}
|
||||
coordinator = await get_coordinator(self.hass)
|
||||
if not coordinator.last_update_success:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
|
||||
self._options = {OPTION_WORLDWIDE: "Worldwide"}
|
||||
for case in sorted(
|
||||
coordinator.data.values(), key=lambda case: case.country
|
||||
):
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Service is already configured"
|
||||
"already_configured": "Service is already configured",
|
||||
"cannot_connect": "Failed to connect"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"domain": "devolo_home_control",
|
||||
"name": "devolo Home Control",
|
||||
"documentation": "https://www.home-assistant.io/integrations/devolo_home_control",
|
||||
"requirements": ["devolo-home-control-api==0.17.1"],
|
||||
"requirements": ["devolo-home-control-api==0.17.3"],
|
||||
"after_dependencies": ["zeroconf"],
|
||||
"config_flow": true,
|
||||
"codeowners": ["@2Fake", "@Shutgun"],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "DHCP Discovery",
|
||||
"documentation": "https://www.home-assistant.io/integrations/dhcp",
|
||||
"requirements": [
|
||||
"scapy==2.4.4", "aiodiscover==1.3.3"
|
||||
"scapy==2.4.4", "aiodiscover==1.3.4"
|
||||
],
|
||||
"codeowners": [
|
||||
"@bdraco"
|
||||
|
||||
@@ -507,5 +507,5 @@ def state_needs_accessory_mode(state):
|
||||
or state.domain == MEDIA_PLAYER_DOMAIN
|
||||
and state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_TV
|
||||
or state.domain == REMOTE_DOMAIN
|
||||
and state.attributes.get(ATTR_SUPPORTED_FEATURES) & SUPPORT_ACTIVITY
|
||||
and state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) & SUPPORT_ACTIVITY
|
||||
)
|
||||
|
||||
@@ -209,8 +209,11 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow):
|
||||
}
|
||||
|
||||
if "id" not in properties:
|
||||
_LOGGER.warning(
|
||||
"HomeKit device %s: id not exposed, in violation of spec", properties
|
||||
# This can happen if the TXT record is received after the PTR record
|
||||
# we will wait for the next update in this case
|
||||
_LOGGER.debug(
|
||||
"HomeKit device %s: id not exposed; TXT record may have not yet been received",
|
||||
properties,
|
||||
)
|
||||
return self.async_abort(reason="invalid_properties")
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
|
||||
"requirements": [
|
||||
"aiohomekit==0.2.60"
|
||||
"aiohomekit==0.2.61"
|
||||
],
|
||||
"zeroconf": [
|
||||
"_hap._tcp.local."
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Authentication for HTTP component."""
|
||||
import logging
|
||||
import secrets
|
||||
from urllib.parse import unquote
|
||||
|
||||
from aiohttp import hdrs
|
||||
from aiohttp.web import middleware
|
||||
@@ -30,11 +31,16 @@ def async_sign_path(hass, refresh_token_id, path, expiration):
|
||||
|
||||
now = dt_util.utcnow()
|
||||
encoded = jwt.encode(
|
||||
{"iss": refresh_token_id, "path": path, "iat": now, "exp": now + expiration},
|
||||
{
|
||||
"iss": refresh_token_id,
|
||||
"path": unquote(path),
|
||||
"iat": now,
|
||||
"exp": now + expiration,
|
||||
},
|
||||
secret,
|
||||
algorithm="HS256",
|
||||
)
|
||||
return f"{path}?{SIGN_QUERY_PARAM}=" f"{encoded.decode()}"
|
||||
return f"{path}?{SIGN_QUERY_PARAM}={encoded.decode()}"
|
||||
|
||||
|
||||
@callback
|
||||
|
||||
@@ -751,3 +751,20 @@ class Light(LightEntity):
|
||||
"Light is deprecated, modify %s to extend LightEntity",
|
||||
cls.__name__,
|
||||
)
|
||||
|
||||
|
||||
def legacy_supported_features(
|
||||
supported_features: int, supported_color_modes: list[str] | None
|
||||
) -> int:
|
||||
"""Calculate supported features with backwards compatibility."""
|
||||
# Backwards compatibility for supported_color_modes added in 2021.4
|
||||
if supported_color_modes is None:
|
||||
return supported_features
|
||||
if any(mode in supported_color_modes for mode in COLOR_MODES_COLOR):
|
||||
supported_features |= SUPPORT_COLOR
|
||||
if any(mode in supported_color_modes for mode in COLOR_MODES_BRIGHTNESS):
|
||||
supported_features |= SUPPORT_BRIGHTNESS
|
||||
if COLOR_MODE_COLOR_TEMP in supported_color_modes:
|
||||
supported_features |= SUPPORT_COLOR_TEMP
|
||||
|
||||
return supported_features
|
||||
|
||||
@@ -114,7 +114,7 @@ def _add_log_filter(logger, patterns):
|
||||
"""Add a Filter to the logger based on a regexp of the filter_str."""
|
||||
|
||||
def filter_func(logrecord):
|
||||
return not any(p.match(logrecord.getMessage()) for p in patterns)
|
||||
return not any(p.search(logrecord.getMessage()) for p in patterns)
|
||||
|
||||
logger.addFilter(filter_func)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from time import gmtime, strftime, time
|
||||
from time import localtime, strftime, time
|
||||
|
||||
from aiolyric.objects.device import LyricDevice
|
||||
from aiolyric.objects.location import LyricLocation
|
||||
@@ -82,7 +82,7 @@ SCHEMA_HOLD_TIME = {
|
||||
vol.Required(ATTR_TIME_PERIOD, default="01:00:00"): vol.All(
|
||||
cv.time_period,
|
||||
cv.positive_timedelta,
|
||||
lambda td: strftime("%H:%M:%S", gmtime(time() + td.total_seconds())),
|
||||
lambda td: strftime("%H:%M:%S", localtime(time() + td.total_seconds())),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import voluptuous as vol
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SCAN_INTERVAL
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.discovery import load_platform
|
||||
from homeassistant.util.dt import now
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -59,7 +60,7 @@ def setup(hass, config):
|
||||
scan_interval = gateway[CONF_SCAN_INTERVAL].total_seconds()
|
||||
|
||||
try:
|
||||
cube = MaxCube(host, port)
|
||||
cube = MaxCube(host, port, now=now)
|
||||
hass.data[DATA_KEY][host] = MaxCubeHandle(cube, scan_interval)
|
||||
except timeout as ex:
|
||||
_LOGGER.error("Unable to connect to Max!Cube gateway: %s", str(ex))
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"domain": "maxcube",
|
||||
"name": "eQ-3 MAX!",
|
||||
"documentation": "https://www.home-assistant.io/integrations/maxcube",
|
||||
"requirements": ["maxcube-api==0.4.1"],
|
||||
"requirements": ["maxcube-api==0.4.2"],
|
||||
"codeowners": []
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from urllib.parse import quote
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -123,7 +124,7 @@ async def websocket_resolve_media(hass, connection, msg):
|
||||
url = async_sign_path(
|
||||
hass,
|
||||
connection.refresh_token_id,
|
||||
url,
|
||||
quote(url),
|
||||
timedelta(seconds=msg["expires"]),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Support for MQTT fans."""
|
||||
import functools
|
||||
import logging
|
||||
import math
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -32,6 +33,7 @@ import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.reload import async_setup_reload_service
|
||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||
from homeassistant.util.percentage import (
|
||||
int_states_in_range,
|
||||
ordered_list_item_to_percentage,
|
||||
percentage_to_ordered_list_item,
|
||||
percentage_to_ranged_value,
|
||||
@@ -224,6 +226,9 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
self._optimistic_preset_mode = None
|
||||
self._optimistic_speed = None
|
||||
|
||||
self._legacy_speeds_list = []
|
||||
self._legacy_speeds_list_no_off = []
|
||||
|
||||
MqttEntity.__init__(self, hass, config, config_entry, discovery_data)
|
||||
|
||||
@staticmethod
|
||||
@@ -284,28 +289,18 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
self._legacy_speeds_list_no_off = speed_list_without_preset_modes(
|
||||
self._legacy_speeds_list
|
||||
)
|
||||
else:
|
||||
self._legacy_speeds_list = []
|
||||
|
||||
self._feature_percentage = CONF_PERCENTAGE_COMMAND_TOPIC in config
|
||||
self._feature_preset_mode = CONF_PRESET_MODE_COMMAND_TOPIC in config
|
||||
if self._feature_preset_mode:
|
||||
self._speeds_list = speed_list_without_preset_modes(
|
||||
self._legacy_speeds_list + config[CONF_PRESET_MODES_LIST]
|
||||
)
|
||||
self._preset_modes = (
|
||||
self._legacy_speeds_list + config[CONF_PRESET_MODES_LIST]
|
||||
)
|
||||
self._preset_modes = config[CONF_PRESET_MODES_LIST]
|
||||
else:
|
||||
self._speeds_list = speed_list_without_preset_modes(
|
||||
self._legacy_speeds_list
|
||||
)
|
||||
self._preset_modes = []
|
||||
|
||||
if not self._speeds_list or self._feature_percentage:
|
||||
self._speed_count = 100
|
||||
if self._feature_percentage:
|
||||
self._speed_count = min(int_states_in_range(self._speed_range), 100)
|
||||
else:
|
||||
self._speed_count = len(self._speeds_list)
|
||||
self._speed_count = len(self._legacy_speeds_list_no_off) or 100
|
||||
|
||||
optimistic = config[CONF_OPTIMISTIC]
|
||||
self._optimistic = optimistic or self._topic[CONF_STATE_TOPIC] is None
|
||||
@@ -327,11 +322,7 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
self._topic[CONF_OSCILLATION_COMMAND_TOPIC] is not None
|
||||
and SUPPORT_OSCILLATE
|
||||
)
|
||||
if self._feature_preset_mode and self._speeds_list:
|
||||
self._supported_features |= SUPPORT_SET_SPEED
|
||||
if self._feature_percentage:
|
||||
self._supported_features |= SUPPORT_SET_SPEED
|
||||
if self._feature_legacy_speeds:
|
||||
if self._feature_percentage or self._feature_legacy_speeds:
|
||||
self._supported_features |= SUPPORT_SET_SPEED
|
||||
if self._feature_preset_mode:
|
||||
self._supported_features |= SUPPORT_PRESET_MODE
|
||||
@@ -414,10 +405,6 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
return
|
||||
|
||||
self._preset_mode = preset_mode
|
||||
if not self._implemented_percentage and (preset_mode in self.speed_list):
|
||||
self._percentage = ordered_list_item_to_percentage(
|
||||
self.speed_list, preset_mode
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
if self._topic[CONF_PRESET_MODE_STATE_TOPIC] is not None:
|
||||
@@ -455,13 +442,12 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
)
|
||||
return
|
||||
|
||||
if not self._implemented_percentage:
|
||||
if speed in self._speeds_list:
|
||||
self._percentage = ordered_list_item_to_percentage(
|
||||
self._speeds_list, speed
|
||||
)
|
||||
elif speed == SPEED_OFF:
|
||||
self._percentage = 0
|
||||
if speed in self._legacy_speeds_list_no_off:
|
||||
self._percentage = ordered_list_item_to_percentage(
|
||||
self._legacy_speeds_list_no_off, speed
|
||||
)
|
||||
elif speed == SPEED_OFF:
|
||||
self._percentage = 0
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -506,19 +492,9 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
"""Return true if device is on."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def _implemented_percentage(self):
|
||||
"""Return true if percentage has been implemented."""
|
||||
return self._feature_percentage
|
||||
|
||||
@property
|
||||
def _implemented_preset_mode(self):
|
||||
"""Return true if preset_mode has been implemented."""
|
||||
return self._feature_preset_mode
|
||||
|
||||
# The use of legacy speeds is deprecated in the schema, support will be removed after a quarter (2021.7)
|
||||
@property
|
||||
def _implemented_speed(self):
|
||||
def _implemented_speed(self) -> bool:
|
||||
"""Return true if speed has been implemented."""
|
||||
return self._feature_legacy_speeds
|
||||
|
||||
@@ -541,7 +517,7 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
@property
|
||||
def speed_list(self) -> list:
|
||||
"""Get the list of available speeds."""
|
||||
return self._speeds_list
|
||||
return self._legacy_speeds_list_no_off
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
@@ -555,7 +531,7 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
|
||||
@property
|
||||
def speed_count(self) -> int:
|
||||
"""Return the number of speeds the fan supports or 100 if percentage is supported."""
|
||||
"""Return the number of speeds the fan supports."""
|
||||
return self._speed_count
|
||||
|
||||
@property
|
||||
@@ -616,24 +592,12 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
percentage_payload = int(
|
||||
percentage_payload = math.ceil(
|
||||
percentage_to_ranged_value(self._speed_range, percentage)
|
||||
)
|
||||
mqtt_payload = self._command_templates[ATTR_PERCENTAGE](percentage_payload)
|
||||
if self._implemented_preset_mode:
|
||||
if percentage:
|
||||
await self.async_set_preset_mode(
|
||||
preset_mode=percentage_to_ordered_list_item(
|
||||
self.speed_list, percentage
|
||||
)
|
||||
)
|
||||
# Legacy are deprecated in the schema, support will be removed after a quarter (2021.7)
|
||||
elif self._feature_legacy_speeds and (
|
||||
SPEED_OFF in self._legacy_speeds_list
|
||||
):
|
||||
await self.async_set_preset_mode(SPEED_OFF)
|
||||
# Legacy are deprecated in the schema, support will be removed after a quarter (2021.7)
|
||||
elif self._feature_legacy_speeds:
|
||||
if self._feature_legacy_speeds:
|
||||
if percentage:
|
||||
await self.async_set_speed(
|
||||
percentage_to_ordered_list_item(
|
||||
@@ -644,7 +608,7 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
elif SPEED_OFF in self._legacy_speeds_list:
|
||||
await self.async_set_speed(SPEED_OFF)
|
||||
|
||||
if self._implemented_percentage:
|
||||
if self._feature_percentage:
|
||||
mqtt.async_publish(
|
||||
self.hass,
|
||||
self._topic[CONF_PERCENTAGE_COMMAND_TOPIC],
|
||||
@@ -665,13 +629,7 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
if preset_mode not in self.preset_modes:
|
||||
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
|
||||
return
|
||||
# Legacy are deprecated in the schema, support will be removed after a quarter (2021.7)
|
||||
if preset_mode in self._legacy_speeds_list:
|
||||
await self.async_set_speed(speed=preset_mode)
|
||||
if not self._implemented_percentage and preset_mode in self.speed_list:
|
||||
self._percentage = ordered_list_item_to_percentage(
|
||||
self.speed_list, preset_mode
|
||||
)
|
||||
|
||||
mqtt_payload = self._command_templates[ATTR_PRESET_MODE](preset_mode)
|
||||
|
||||
mqtt.async_publish(
|
||||
@@ -693,18 +651,18 @@ class MqttFan(MqttEntity, FanEntity):
|
||||
This method is a coroutine.
|
||||
"""
|
||||
speed_payload = None
|
||||
if self._feature_legacy_speeds:
|
||||
if speed in self._legacy_speeds_list:
|
||||
if speed == SPEED_LOW:
|
||||
speed_payload = self._payload["SPEED_LOW"]
|
||||
elif speed == SPEED_MEDIUM:
|
||||
speed_payload = self._payload["SPEED_MEDIUM"]
|
||||
elif speed == SPEED_HIGH:
|
||||
speed_payload = self._payload["SPEED_HIGH"]
|
||||
elif speed == SPEED_OFF:
|
||||
speed_payload = self._payload["SPEED_OFF"]
|
||||
else:
|
||||
_LOGGER.warning("'%s'is not a valid speed", speed)
|
||||
return
|
||||
speed_payload = self._payload["SPEED_OFF"]
|
||||
else:
|
||||
_LOGGER.warning("'%s' is not a valid speed", speed)
|
||||
return
|
||||
|
||||
if speed_payload:
|
||||
mqtt.async_publish(
|
||||
|
||||
@@ -35,6 +35,7 @@ from homeassistant.components.light import (
|
||||
SUPPORT_WHITE_VALUE,
|
||||
VALID_COLOR_MODES,
|
||||
LightEntity,
|
||||
legacy_supported_features,
|
||||
valid_supported_color_modes,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
@@ -458,7 +459,9 @@ class MqttLightJson(MqttEntity, LightEntity, RestoreEntity):
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
return self._supported_features
|
||||
return legacy_supported_features(
|
||||
self._supported_features, self._config.get(CONF_SUPPORTED_COLOR_MODES)
|
||||
)
|
||||
|
||||
def _set_flash_and_transition(self, message, **kwargs):
|
||||
if ATTR_TRANSITION in kwargs:
|
||||
|
||||
@@ -7,6 +7,11 @@ from homeassistant.components.mqtt import valid_publish_topic, valid_subscribe_t
|
||||
from homeassistant.const import (
|
||||
ATTR_SERVICE_DATA,
|
||||
EVENT_CALL_SERVICE,
|
||||
EVENT_HOMEASSISTANT_CLOSE,
|
||||
EVENT_HOMEASSISTANT_FINAL_WRITE,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
EVENT_STATE_CHANGED,
|
||||
EVENT_TIME_CHANGED,
|
||||
MATCH_ALL,
|
||||
@@ -37,6 +42,14 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
BLOCKED_EVENTS = [
|
||||
EVENT_HOMEASSISTANT_CLOSE,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
EVENT_HOMEASSISTANT_FINAL_WRITE,
|
||||
]
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the MQTT eventstream component."""
|
||||
@@ -45,16 +58,15 @@ async def async_setup(hass, config):
|
||||
pub_topic = conf.get(CONF_PUBLISH_TOPIC)
|
||||
sub_topic = conf.get(CONF_SUBSCRIBE_TOPIC)
|
||||
ignore_event = conf.get(CONF_IGNORE_EVENT)
|
||||
ignore_event.append(EVENT_TIME_CHANGED)
|
||||
|
||||
@callback
|
||||
def _event_publisher(event):
|
||||
"""Handle events by publishing them on the MQTT queue."""
|
||||
if event.origin != EventOrigin.local:
|
||||
return
|
||||
if event.event_type == EVENT_TIME_CHANGED:
|
||||
return
|
||||
|
||||
# User-defined events to ignore
|
||||
# Events to ignore
|
||||
if event.event_type in ignore_event:
|
||||
return
|
||||
|
||||
@@ -84,6 +96,10 @@ async def async_setup(hass, config):
|
||||
event_type = event.get("event_type")
|
||||
event_data = event.get("event_data")
|
||||
|
||||
# Don't fire HOMEASSISTANT_* events on this instance
|
||||
if event_type in BLOCKED_EVENTS:
|
||||
return
|
||||
|
||||
# Special case handling for event STATE_CHANGED
|
||||
# We will try to convert state dicts back to State objects
|
||||
# Copied over from the _handle_api_post_events_event method
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Support for MySensors sensors."""
|
||||
from typing import Callable
|
||||
|
||||
from awesomeversion import AwesomeVersion
|
||||
|
||||
from homeassistant.components import mysensors
|
||||
from homeassistant.components.mysensors import on_unload
|
||||
from homeassistant.components.mysensors.const import MYSENSORS_DISCOVERY
|
||||
@@ -115,7 +117,7 @@ class MySensorsSensor(mysensors.device.MySensorsEntity, SensorEntity):
|
||||
"""Return the unit of measurement of this entity."""
|
||||
set_req = self.gateway.const.SetReq
|
||||
if (
|
||||
float(self.gateway.protocol_version) >= 1.5
|
||||
AwesomeVersion(self.gateway.protocol_version) >= AwesomeVersion("1.5")
|
||||
and set_req.V_UNIT_PREFIX in self._values
|
||||
):
|
||||
return self._values[set_req.V_UNIT_PREFIX]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "nexia",
|
||||
"name": "Nexia",
|
||||
"requirements": ["nexia==0.9.5"],
|
||||
"requirements": ["nexia==0.9.6"],
|
||||
"codeowners": ["@bdraco"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/nexia",
|
||||
"config_flow": true,
|
||||
|
||||
@@ -13,4 +13,6 @@ def is_invalid_auth_code(http_status_code):
|
||||
|
||||
def percent_conv(val):
|
||||
"""Convert an actual percentage (0.0-1.0) to 0-100 scale."""
|
||||
if val is None:
|
||||
return None
|
||||
return round(val * 100.0, 1)
|
||||
|
||||
@@ -134,8 +134,12 @@ class PhilipsTVDataUpdateCoordinator(DataUpdateCoordinator[None]):
|
||||
|
||||
async def _notify_task(self):
|
||||
while self.api.on and self.api.notify_change_supported:
|
||||
if await self.api.notifyChange(130):
|
||||
res = await self.api.notifyChange(130)
|
||||
if res:
|
||||
self.async_set_updated_data(None)
|
||||
elif res is None:
|
||||
LOGGER.debug("Aborting notify due to unexpected return")
|
||||
break
|
||||
|
||||
@callback
|
||||
def _async_notify_stop(self):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Philips TV",
|
||||
"documentation": "https://www.home-assistant.io/integrations/philips_js",
|
||||
"requirements": [
|
||||
"ha-philipsjs==2.3.2"
|
||||
"ha-philipsjs==2.7.0"
|
||||
],
|
||||
"codeowners": [
|
||||
"@elupus"
|
||||
|
||||
@@ -24,20 +24,22 @@ async def async_setup(hass, config):
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_next_ping_id(hass):
|
||||
def async_get_next_ping_id(hass, count=1):
|
||||
"""Find the next id to use in the outbound ping.
|
||||
|
||||
When using multiping, we increment the id
|
||||
by the number of ids that multiping
|
||||
will use.
|
||||
|
||||
Must be called in async
|
||||
"""
|
||||
current_id = hass.data[DOMAIN][PING_ID]
|
||||
if current_id == MAX_PING_ID:
|
||||
next_id = DEFAULT_START_ID
|
||||
else:
|
||||
next_id = current_id + 1
|
||||
|
||||
hass.data[DOMAIN][PING_ID] = next_id
|
||||
|
||||
return next_id
|
||||
allocated_id = hass.data[DOMAIN][PING_ID] + 1
|
||||
if allocated_id > MAX_PING_ID:
|
||||
allocated_id -= MAX_PING_ID - DEFAULT_START_ID
|
||||
hass.data[DOMAIN][PING_ID] += count
|
||||
if hass.data[DOMAIN][PING_ID] > MAX_PING_ID:
|
||||
hass.data[DOMAIN][PING_ID] -= MAX_PING_ID - DEFAULT_START_ID
|
||||
return allocated_id
|
||||
|
||||
|
||||
def _can_use_icmp_lib_with_privilege() -> None | bool:
|
||||
|
||||
@@ -125,7 +125,7 @@ async def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
||||
count=PING_ATTEMPTS_COUNT,
|
||||
timeout=ICMP_TIMEOUT,
|
||||
privileged=privileged,
|
||||
id=async_get_next_ping_id(hass),
|
||||
id=async_get_next_ping_id(hass, len(ip_to_dev_id)),
|
||||
)
|
||||
)
|
||||
_LOGGER.debug("Multiping responses: %s", responses)
|
||||
|
||||
@@ -47,10 +47,12 @@ async def async_setup(hass: HomeAssistantType, config: dict) -> bool:
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
||||
"""Set up Roku from a config entry."""
|
||||
coordinator = RokuDataUpdateCoordinator(hass, host=entry.data[CONF_HOST])
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
coordinator = hass.data[DOMAIN].get(entry.entry_id)
|
||||
if not coordinator:
|
||||
coordinator = RokuDataUpdateCoordinator(hass, host=entry.data[CONF_HOST])
|
||||
hass.data[DOMAIN][entry.entry_id] = coordinator
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = coordinator
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
for platform in PLATFORMS:
|
||||
hass.async_create_task(
|
||||
|
||||
@@ -195,9 +195,15 @@ class ScreenlogicEntity(CoordinatorEntity):
|
||||
"""Return device information for the controller."""
|
||||
controller_type = self.config_data["controller_type"]
|
||||
hardware_type = self.config_data["hardware_type"]
|
||||
try:
|
||||
equipment_model = EQUIPMENT.CONTROLLER_HARDWARE[controller_type][
|
||||
hardware_type
|
||||
]
|
||||
except KeyError:
|
||||
equipment_model = f"Unknown Model C:{controller_type} H:{hardware_type}"
|
||||
return {
|
||||
"connections": {(dr.CONNECTION_NETWORK_MAC, self.mac)},
|
||||
"name": self.gateway_name,
|
||||
"manufacturer": "Pentair",
|
||||
"model": EQUIPMENT.CONTROLLER_HARDWARE[controller_type][hardware_type],
|
||||
"model": equipment_model,
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ from .const import (
|
||||
DOMAIN,
|
||||
EVENT_SHELLY_CLICK,
|
||||
INPUTS_EVENTS_SUBTYPES,
|
||||
SHBTN_1_INPUTS_EVENTS_TYPES,
|
||||
SUPPORTED_INPUTS_EVENTS_TYPES,
|
||||
)
|
||||
from .utils import get_device_wrapper, get_input_triggers
|
||||
@@ -45,7 +46,7 @@ async def async_validate_trigger_config(hass, config):
|
||||
|
||||
# if device is available verify parameters against device capabilities
|
||||
wrapper = get_device_wrapper(hass, config[CONF_DEVICE_ID])
|
||||
if not wrapper:
|
||||
if not wrapper or not wrapper.device.initialized:
|
||||
return config
|
||||
|
||||
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
||||
@@ -68,6 +69,19 @@ async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
|
||||
if not wrapper:
|
||||
raise InvalidDeviceAutomationConfig(f"Device not found: {device_id}")
|
||||
|
||||
if wrapper.model in ("SHBTN-1", "SHBTN-2"):
|
||||
for trigger in SHBTN_1_INPUTS_EVENTS_TYPES:
|
||||
triggers.append(
|
||||
{
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_DEVICE_ID: device_id,
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
CONF_TYPE: trigger,
|
||||
CONF_SUBTYPE: "button",
|
||||
}
|
||||
)
|
||||
return triggers
|
||||
|
||||
for block in wrapper.device.blocks:
|
||||
input_triggers = get_input_triggers(wrapper.device, block)
|
||||
|
||||
|
||||
@@ -118,15 +118,16 @@ class ShellyLight(ShellyBlockEntity, LightEntity):
|
||||
"""Brightness of light."""
|
||||
if self.mode == "color":
|
||||
if self.control_result:
|
||||
brightness = self.control_result["gain"]
|
||||
brightness_pct = self.control_result["gain"]
|
||||
else:
|
||||
brightness = self.block.gain
|
||||
brightness_pct = self.block.gain
|
||||
else:
|
||||
if self.control_result:
|
||||
brightness = self.control_result["brightness"]
|
||||
brightness_pct = self.control_result["brightness"]
|
||||
else:
|
||||
brightness = self.block.brightness
|
||||
return int(brightness / 100 * 255)
|
||||
brightness_pct = self.block.brightness
|
||||
|
||||
return round(255 * brightness_pct / 100)
|
||||
|
||||
@property
|
||||
def white_value(self) -> int:
|
||||
@@ -188,11 +189,11 @@ class ShellyLight(ShellyBlockEntity, LightEntity):
|
||||
set_mode = None
|
||||
params = {"turn": "on"}
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
tmp_brightness = int(kwargs[ATTR_BRIGHTNESS] / 255 * 100)
|
||||
brightness_pct = int(100 * (kwargs[ATTR_BRIGHTNESS] + 1) / 255)
|
||||
if hasattr(self.block, "gain"):
|
||||
params["gain"] = tmp_brightness
|
||||
params["gain"] = brightness_pct
|
||||
if hasattr(self.block, "brightness"):
|
||||
params["brightness"] = tmp_brightness
|
||||
params["brightness"] = brightness_pct
|
||||
if ATTR_COLOR_TEMP in kwargs:
|
||||
color_temp = color_temperature_mired_to_kelvin(kwargs[ATTR_COLOR_TEMP])
|
||||
color_temp = min(self._max_kelvin, max(self._min_kelvin, color_temp))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"dependencies": [],
|
||||
"codeowners": ["@mdz"],
|
||||
"requirements": [
|
||||
"python-smarttub==0.0.19"
|
||||
"python-smarttub==0.0.23"
|
||||
],
|
||||
"quality_scale": "platinum"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"domain": "spotify",
|
||||
"name": "Spotify",
|
||||
"documentation": "https://www.home-assistant.io/integrations/spotify",
|
||||
"requirements": ["spotipy==2.17.1"],
|
||||
"requirements": ["spotipy==2.18.0"],
|
||||
"zeroconf": ["_spotify-connect._tcp.local."],
|
||||
"dependencies": ["http"],
|
||||
"codeowners": ["@frenck"],
|
||||
|
||||
@@ -68,7 +68,7 @@ async def _process_config(hass, config):
|
||||
|
||||
async def init_coordinator(hass, conf):
|
||||
coordinator = TriggerUpdateCoordinator(hass, conf)
|
||||
await coordinator.async_setup(conf)
|
||||
await coordinator.async_setup(config)
|
||||
return coordinator
|
||||
|
||||
hass.data[DOMAIN] = await asyncio.gather(
|
||||
|
||||
@@ -31,6 +31,7 @@ from homeassistant.const import (
|
||||
CONF_PLATFORM,
|
||||
HTTP_BAD_REQUEST,
|
||||
HTTP_NOT_FOUND,
|
||||
PLATFORM_FORMAT,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@@ -316,6 +317,10 @@ class SpeechManager:
|
||||
provider.name = engine
|
||||
self.providers[engine] = provider
|
||||
|
||||
self.hass.config.components.add(
|
||||
PLATFORM_FORMAT.format(domain=engine, platform=DOMAIN)
|
||||
)
|
||||
|
||||
async def async_get_url_path(
|
||||
self, engine, message, cache=None, language=None, options=None
|
||||
):
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
"requirements": ["mutagen==1.45.1"],
|
||||
"dependencies": ["http"],
|
||||
"after_dependencies": ["media_player"],
|
||||
"quality_scale": "internal",
|
||||
"codeowners": ["@pvizeli"]
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
||||
THERMOSTAT_OPERATING_STATE_PROPERTY,
|
||||
command_class=CommandClass.THERMOSTAT_OPERATING_STATE,
|
||||
add_to_watched_value_ids=True,
|
||||
check_all_endpoints=True,
|
||||
)
|
||||
self._current_temp = self.get_zwave_value(
|
||||
THERMOSTAT_CURRENT_TEMP_PROPERTY,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 2021
|
||||
MINOR_VERSION = 4
|
||||
PATCH_VERSION = "2"
|
||||
PATCH_VERSION = "5"
|
||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER = (3, 8, 0)
|
||||
|
||||
@@ -1144,10 +1144,7 @@ class Script:
|
||||
self._log("Already running", level=LOGSEVERITY[self._max_exceeded])
|
||||
script_execution_set("failed_single")
|
||||
return
|
||||
if self.script_mode == SCRIPT_MODE_RESTART:
|
||||
self._log("Restarting")
|
||||
await self.async_stop(update_state=False)
|
||||
elif len(self._runs) == self.max_runs:
|
||||
if self.script_mode != SCRIPT_MODE_RESTART and self.runs == self.max_runs:
|
||||
if self._max_exceeded != "SILENT":
|
||||
self._log(
|
||||
"Maximum number of runs exceeded",
|
||||
@@ -1186,6 +1183,14 @@ class Script:
|
||||
self._hass, self, cast(dict, variables), context, self._log_exceptions
|
||||
)
|
||||
self._runs.append(run)
|
||||
if self.script_mode == SCRIPT_MODE_RESTART:
|
||||
# When script mode is SCRIPT_MODE_RESTART, first add the new run and then
|
||||
# stop any other runs. If we stop other runs first, self.is_running will
|
||||
# return false after the other script runs were stopped until our task
|
||||
# resumes running.
|
||||
self._log("Restarting")
|
||||
await self.async_stop(update_state=False, spare=run)
|
||||
|
||||
if started_action:
|
||||
self._hass.async_run_job(started_action)
|
||||
self.last_triggered = utcnow()
|
||||
@@ -1198,17 +1203,21 @@ class Script:
|
||||
self._changed()
|
||||
raise
|
||||
|
||||
async def _async_stop(self, update_state):
|
||||
aws = [asyncio.create_task(run.async_stop()) for run in self._runs]
|
||||
async def _async_stop(self, update_state, spare=None):
|
||||
aws = [
|
||||
asyncio.create_task(run.async_stop()) for run in self._runs if run != spare
|
||||
]
|
||||
if not aws:
|
||||
return
|
||||
await asyncio.wait(aws)
|
||||
if update_state:
|
||||
self._changed()
|
||||
|
||||
async def async_stop(self, update_state: bool = True) -> None:
|
||||
async def async_stop(
|
||||
self, update_state: bool = True, spare: _ScriptRun | None = None
|
||||
) -> None:
|
||||
"""Stop running script."""
|
||||
await asyncio.shield(self._async_stop(update_state))
|
||||
await asyncio.shield(self._async_stop(update_state, spare))
|
||||
|
||||
async def _async_get_condition(self, config):
|
||||
if isinstance(config, template.Template):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
PyJWT==1.7.1
|
||||
PyNaCl==1.3.0
|
||||
aiodiscover==1.3.3
|
||||
aiodiscover==1.3.4
|
||||
aiohttp==3.7.4.post0
|
||||
aiohttp_cors==0.7.0
|
||||
astral==1.10.1
|
||||
|
||||
@@ -22,6 +22,7 @@ BASE_PLATFORMS = {
|
||||
"air_quality",
|
||||
"alarm_control_panel",
|
||||
"binary_sensor",
|
||||
"camera",
|
||||
"climate",
|
||||
"cover",
|
||||
"device_tracker",
|
||||
@@ -36,6 +37,7 @@ BASE_PLATFORMS = {
|
||||
"scene",
|
||||
"sensor",
|
||||
"switch",
|
||||
"tts",
|
||||
"vacuum",
|
||||
"water_heater",
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ aioazuredevops==1.3.5
|
||||
aiobotocore==0.11.1
|
||||
|
||||
# homeassistant.components.dhcp
|
||||
aiodiscover==1.3.3
|
||||
aiodiscover==1.3.4
|
||||
|
||||
# homeassistant.components.dnsip
|
||||
# homeassistant.components.minecraft_server
|
||||
@@ -172,7 +172,7 @@ aioguardian==1.0.4
|
||||
aioharmony==0.2.7
|
||||
|
||||
# homeassistant.components.homekit_controller
|
||||
aiohomekit==0.2.60
|
||||
aiohomekit==0.2.61
|
||||
|
||||
# homeassistant.components.emulated_hue
|
||||
# homeassistant.components.http
|
||||
@@ -479,7 +479,7 @@ deluge-client==1.7.1
|
||||
denonavr==0.9.10
|
||||
|
||||
# homeassistant.components.devolo_home_control
|
||||
devolo-home-control-api==0.17.1
|
||||
devolo-home-control-api==0.17.3
|
||||
|
||||
# homeassistant.components.directv
|
||||
directv==0.4.0
|
||||
@@ -721,7 +721,7 @@ guppy3==3.1.0
|
||||
ha-ffmpeg==3.0.2
|
||||
|
||||
# homeassistant.components.philips_js
|
||||
ha-philipsjs==2.3.2
|
||||
ha-philipsjs==2.7.0
|
||||
|
||||
# homeassistant.components.habitica
|
||||
habitipy==0.2.0
|
||||
@@ -916,7 +916,7 @@ magicseaweed==1.0.3
|
||||
matrix-client==0.3.2
|
||||
|
||||
# homeassistant.components.maxcube
|
||||
maxcube-api==0.4.1
|
||||
maxcube-api==0.4.2
|
||||
|
||||
# homeassistant.components.mythicbeastsdns
|
||||
mbddns==0.1.2
|
||||
@@ -986,7 +986,7 @@ netdisco==2.8.2
|
||||
neurio==0.3.1
|
||||
|
||||
# homeassistant.components.nexia
|
||||
nexia==0.9.5
|
||||
nexia==0.9.6
|
||||
|
||||
# homeassistant.components.nextcloud
|
||||
nextcloudmonitor==1.1.0
|
||||
@@ -1822,7 +1822,7 @@ python-qbittorrent==0.4.2
|
||||
python-ripple-api==0.0.3
|
||||
|
||||
# homeassistant.components.smarttub
|
||||
python-smarttub==0.0.19
|
||||
python-smarttub==0.0.23
|
||||
|
||||
# homeassistant.components.sochain
|
||||
python-sochain-api==0.0.2
|
||||
@@ -2117,7 +2117,7 @@ spiderpy==1.4.2
|
||||
spotcrime==1.0.4
|
||||
|
||||
# homeassistant.components.spotify
|
||||
spotipy==2.17.1
|
||||
spotipy==2.18.0
|
||||
|
||||
# homeassistant.components.recorder
|
||||
# homeassistant.components.sql
|
||||
|
||||
@@ -84,7 +84,7 @@ aioazuredevops==1.3.5
|
||||
aiobotocore==0.11.1
|
||||
|
||||
# homeassistant.components.dhcp
|
||||
aiodiscover==1.3.3
|
||||
aiodiscover==1.3.4
|
||||
|
||||
# homeassistant.components.dnsip
|
||||
# homeassistant.components.minecraft_server
|
||||
@@ -106,7 +106,7 @@ aioguardian==1.0.4
|
||||
aioharmony==0.2.7
|
||||
|
||||
# homeassistant.components.homekit_controller
|
||||
aiohomekit==0.2.60
|
||||
aiohomekit==0.2.61
|
||||
|
||||
# homeassistant.components.emulated_hue
|
||||
# homeassistant.components.http
|
||||
@@ -261,7 +261,7 @@ defusedxml==0.6.0
|
||||
denonavr==0.9.10
|
||||
|
||||
# homeassistant.components.devolo_home_control
|
||||
devolo-home-control-api==0.17.1
|
||||
devolo-home-control-api==0.17.3
|
||||
|
||||
# homeassistant.components.directv
|
||||
directv==0.4.0
|
||||
@@ -382,7 +382,7 @@ guppy3==3.1.0
|
||||
ha-ffmpeg==3.0.2
|
||||
|
||||
# homeassistant.components.philips_js
|
||||
ha-philipsjs==2.3.2
|
||||
ha-philipsjs==2.7.0
|
||||
|
||||
# homeassistant.components.habitica
|
||||
habitipy==0.2.0
|
||||
@@ -476,7 +476,7 @@ logi_circle==0.2.2
|
||||
luftdaten==0.6.4
|
||||
|
||||
# homeassistant.components.maxcube
|
||||
maxcube-api==0.4.1
|
||||
maxcube-api==0.4.2
|
||||
|
||||
# homeassistant.components.mythicbeastsdns
|
||||
mbddns==0.1.2
|
||||
@@ -516,7 +516,7 @@ nessclient==0.9.15
|
||||
netdisco==2.8.2
|
||||
|
||||
# homeassistant.components.nexia
|
||||
nexia==0.9.5
|
||||
nexia==0.9.6
|
||||
|
||||
# homeassistant.components.notify_events
|
||||
notify-events==1.0.4
|
||||
@@ -959,7 +959,7 @@ python-nest==4.1.0
|
||||
python-openzwave-mqtt[mqtt-client]==1.4.0
|
||||
|
||||
# homeassistant.components.smarttub
|
||||
python-smarttub==0.0.19
|
||||
python-smarttub==0.0.23
|
||||
|
||||
# homeassistant.components.songpal
|
||||
python-songpal==0.12
|
||||
@@ -1104,7 +1104,7 @@ speedtest-cli==2.1.3
|
||||
spiderpy==1.4.2
|
||||
|
||||
# homeassistant.components.spotify
|
||||
spotipy==2.17.1
|
||||
spotipy==2.18.0
|
||||
|
||||
# homeassistant.components.recorder
|
||||
# homeassistant.components.sql
|
||||
|
||||
@@ -156,8 +156,8 @@ async def test_motion_light(hass):
|
||||
# Turn on motion
|
||||
hass.states.async_set("binary_sensor.kitchen", "on")
|
||||
# Can't block till done because delay is active
|
||||
# So wait 5 event loop iterations to process script
|
||||
for _ in range(5):
|
||||
# So wait 10 event loop iterations to process script
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_on_calls) == 1
|
||||
@@ -165,7 +165,7 @@ async def test_motion_light(hass):
|
||||
# Test light doesn't turn off if motion stays
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=200))
|
||||
|
||||
for _ in range(5):
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_off_calls) == 0
|
||||
@@ -173,7 +173,7 @@ async def test_motion_light(hass):
|
||||
# Test light turns off off 120s after last motion
|
||||
hass.states.async_set("binary_sensor.kitchen", "off")
|
||||
|
||||
for _ in range(5):
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=120))
|
||||
@@ -184,7 +184,7 @@ async def test_motion_light(hass):
|
||||
# Test restarting the script
|
||||
hass.states.async_set("binary_sensor.kitchen", "on")
|
||||
|
||||
for _ in range(5):
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert len(turn_on_calls) == 2
|
||||
@@ -192,7 +192,7 @@ async def test_motion_light(hass):
|
||||
|
||||
hass.states.async_set("binary_sensor.kitchen", "off")
|
||||
|
||||
for _ in range(5):
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
|
||||
hass.states.async_set("binary_sensor.kitchen", "on")
|
||||
|
||||
244
tests/components/cast/test_config_flow.py
Normal file
244
tests/components/cast/test_config_flow.py
Normal file
@@ -0,0 +1,244 @@
|
||||
"""Tests for the Cast config flow."""
|
||||
from unittest.mock import ANY, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components import cast
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_creating_entry_sets_up_media_player(hass):
|
||||
"""Test setting up Cast loads the media player."""
|
||||
with patch(
|
||||
"homeassistant.components.cast.media_player.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup, patch(
|
||||
"pychromecast.discovery.discover_chromecasts", return_value=(True, None)
|
||||
), patch(
|
||||
"pychromecast.discovery.stop_discovery"
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
cast.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
# Confirmation form
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("source", ["import", "user", "zeroconf"])
|
||||
async def test_single_instance(hass, source):
|
||||
"""Test we only allow a single config flow."""
|
||||
MockConfigEntry(domain="cast").add_to_hass(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": source}
|
||||
)
|
||||
assert result["type"] == "abort"
|
||||
assert result["reason"] == "single_instance_allowed"
|
||||
|
||||
|
||||
async def test_user_setup(hass):
|
||||
"""Test we can finish a config flow."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "user"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
|
||||
users = await hass.auth.async_get_users()
|
||||
assert len(users) == 1
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["result"].data == {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
"user_id": users[0].id, # Home Assistant cast user
|
||||
}
|
||||
|
||||
|
||||
async def test_user_setup_options(hass):
|
||||
"""Test we can finish a config flow."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "user"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"known_hosts": "192.168.0.1, , 192.168.0.2 "}
|
||||
)
|
||||
|
||||
users = await hass.auth.async_get_users()
|
||||
assert len(users) == 1
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["result"].data == {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": ["192.168.0.1", "192.168.0.2"],
|
||||
"uuid": [],
|
||||
"user_id": users[0].id, # Home Assistant cast user
|
||||
}
|
||||
|
||||
|
||||
async def test_zeroconf_setup(hass):
|
||||
"""Test we can finish a config flow through zeroconf."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "zeroconf"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
|
||||
users = await hass.auth.async_get_users()
|
||||
assert len(users) == 1
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["result"].data == {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
"user_id": users[0].id, # Home Assistant cast user
|
||||
}
|
||||
|
||||
|
||||
def get_suggested(schema, key):
|
||||
"""Get suggested value for key in voluptuous schema."""
|
||||
for k in schema.keys():
|
||||
if k == key:
|
||||
if k.description is None or "suggested_value" not in k.description:
|
||||
return None
|
||||
return k.description["suggested_value"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"parameter_data",
|
||||
[
|
||||
(
|
||||
"known_hosts",
|
||||
["192.168.0.10", "192.168.0.11"],
|
||||
"192.168.0.10,192.168.0.11",
|
||||
"192.168.0.1, , 192.168.0.2 ",
|
||||
["192.168.0.1", "192.168.0.2"],
|
||||
),
|
||||
(
|
||||
"uuid",
|
||||
["bla", "blu"],
|
||||
"bla,blu",
|
||||
"foo, , bar ",
|
||||
["foo", "bar"],
|
||||
),
|
||||
(
|
||||
"ignore_cec",
|
||||
["cast1", "cast2"],
|
||||
"cast1,cast2",
|
||||
"other_cast, , some_cast ",
|
||||
["other_cast", "some_cast"],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_option_flow(hass, parameter_data):
|
||||
"""Test config flow options."""
|
||||
all_parameters = ["ignore_cec", "known_hosts", "uuid"]
|
||||
parameter, initial, suggested, user_input, updated = parameter_data
|
||||
|
||||
data = {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
}
|
||||
data[parameter] = initial
|
||||
config_entry = MockConfigEntry(domain="cast", data=data)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Test ignore_cec and uuid options are hidden if advanced options are disabled
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "options"
|
||||
data_schema = result["data_schema"].schema
|
||||
assert set(data_schema) == {"known_hosts"}
|
||||
orig_data = dict(config_entry.data)
|
||||
|
||||
# Reconfigure ignore_cec, known_hosts, uuid
|
||||
context = {"source": "user", "show_advanced_options": True}
|
||||
result = await hass.config_entries.options.async_init(
|
||||
config_entry.entry_id, context=context
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "options"
|
||||
data_schema = result["data_schema"].schema
|
||||
for other_param in all_parameters:
|
||||
if other_param == parameter:
|
||||
continue
|
||||
assert get_suggested(data_schema, other_param) == ""
|
||||
assert get_suggested(data_schema, parameter) == suggested
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={parameter: user_input},
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["data"] is None
|
||||
for other_param in all_parameters:
|
||||
if other_param == parameter:
|
||||
continue
|
||||
assert config_entry.data[other_param] == []
|
||||
assert config_entry.data[parameter] == updated
|
||||
|
||||
# Clear known_hosts
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"known_hosts": ""},
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["data"] is None
|
||||
assert config_entry.data == {
|
||||
**orig_data,
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
}
|
||||
|
||||
|
||||
async def test_known_hosts(hass, castbrowser_mock, castbrowser_constructor_mock):
|
||||
"""Test known hosts is passed to pychromecasts."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "user"}
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"known_hosts": "192.168.0.1, 192.168.0.2"}
|
||||
)
|
||||
assert result["type"] == "create_entry"
|
||||
await hass.async_block_till_done()
|
||||
config_entry = hass.config_entries.async_entries("cast")[0]
|
||||
|
||||
assert castbrowser_mock.start_discovery.call_count == 1
|
||||
castbrowser_constructor_mock.assert_called_once_with(
|
||||
ANY, ANY, ["192.168.0.1", "192.168.0.2"]
|
||||
)
|
||||
castbrowser_mock.reset_mock()
|
||||
castbrowser_constructor_mock.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"known_hosts": "192.168.0.11, 192.168.0.12"},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
castbrowser_mock.start_discovery.assert_not_called()
|
||||
castbrowser_constructor_mock.assert_not_called()
|
||||
castbrowser_mock.host_browser.update_hosts.assert_called_once_with(
|
||||
["192.168.0.11", "192.168.0.12"]
|
||||
)
|
||||
@@ -1,39 +1,9 @@
|
||||
"""Tests for the Cast config flow."""
|
||||
from unittest.mock import ANY, patch
|
||||
"""Tests for the Cast integration."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components import cast
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_creating_entry_sets_up_media_player(hass):
|
||||
"""Test setting up Cast loads the media player."""
|
||||
with patch(
|
||||
"homeassistant.components.cast.media_player.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup, patch(
|
||||
"pychromecast.discovery.discover_chromecasts", return_value=(True, None)
|
||||
), patch(
|
||||
"pychromecast.discovery.stop_discovery"
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
cast.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
# Confirmation form
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_import(hass, caplog):
|
||||
"""Test that specifying config will create an entry."""
|
||||
@@ -67,7 +37,7 @@ async def test_import(hass, caplog):
|
||||
|
||||
|
||||
async def test_not_configuring_cast_not_creates_entry(hass):
|
||||
"""Test that no config will not create an entry."""
|
||||
"""Test that an empty config does not create an entry."""
|
||||
with patch(
|
||||
"homeassistant.components.cast.async_setup_entry", return_value=True
|
||||
) as mock_setup:
|
||||
@@ -75,207 +45,3 @@ async def test_not_configuring_cast_not_creates_entry(hass):
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_setup.mock_calls) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("source", ["import", "user", "zeroconf"])
|
||||
async def test_single_instance(hass, source):
|
||||
"""Test we only allow a single config flow."""
|
||||
MockConfigEntry(domain="cast").add_to_hass(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": source}
|
||||
)
|
||||
assert result["type"] == "abort"
|
||||
assert result["reason"] == "single_instance_allowed"
|
||||
|
||||
|
||||
async def test_user_setup(hass):
|
||||
"""Test we can finish a config flow."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "user"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
|
||||
users = await hass.auth.async_get_users()
|
||||
assert len(users) == 1
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["result"].data == {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
"user_id": users[0].id, # Home Assistant cast user
|
||||
}
|
||||
|
||||
|
||||
async def test_user_setup_options(hass):
|
||||
"""Test we can finish a config flow."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "user"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"known_hosts": "192.168.0.1, , 192.168.0.2 "}
|
||||
)
|
||||
|
||||
users = await hass.auth.async_get_users()
|
||||
assert len(users) == 1
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["result"].data == {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": ["192.168.0.1", "192.168.0.2"],
|
||||
"uuid": [],
|
||||
"user_id": users[0].id, # Home Assistant cast user
|
||||
}
|
||||
|
||||
|
||||
async def test_zeroconf_setup(hass):
|
||||
"""Test we can finish a config flow through zeroconf."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "zeroconf"}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
|
||||
users = await hass.auth.async_get_users()
|
||||
assert len(users) == 1
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["result"].data == {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
"user_id": users[0].id, # Home Assistant cast user
|
||||
}
|
||||
|
||||
|
||||
def get_suggested(schema, key):
|
||||
"""Get suggested value for key in voluptuous schema."""
|
||||
for k in schema.keys():
|
||||
if k == key:
|
||||
if k.description is None or "suggested_value" not in k.description:
|
||||
return None
|
||||
return k.description["suggested_value"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"parameter_data",
|
||||
[
|
||||
(
|
||||
"known_hosts",
|
||||
["192.168.0.10", "192.168.0.11"],
|
||||
"192.168.0.10,192.168.0.11",
|
||||
"192.168.0.1, , 192.168.0.2 ",
|
||||
["192.168.0.1", "192.168.0.2"],
|
||||
),
|
||||
(
|
||||
"uuid",
|
||||
["bla", "blu"],
|
||||
"bla,blu",
|
||||
"foo, , bar ",
|
||||
["foo", "bar"],
|
||||
),
|
||||
(
|
||||
"ignore_cec",
|
||||
["cast1", "cast2"],
|
||||
"cast1,cast2",
|
||||
"other_cast, , some_cast ",
|
||||
["other_cast", "some_cast"],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_option_flow(hass, parameter_data):
|
||||
"""Test config flow options."""
|
||||
all_parameters = ["ignore_cec", "known_hosts", "uuid"]
|
||||
parameter, initial, suggested, user_input, updated = parameter_data
|
||||
|
||||
data = {
|
||||
"ignore_cec": [],
|
||||
"known_hosts": [],
|
||||
"uuid": [],
|
||||
}
|
||||
data[parameter] = initial
|
||||
config_entry = MockConfigEntry(domain="cast", data=data)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Test ignore_cec and uuid options are hidden if advanced options are disabled
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "options"
|
||||
data_schema = result["data_schema"].schema
|
||||
assert set(data_schema) == {"known_hosts"}
|
||||
|
||||
# Reconfigure ignore_cec, known_hosts, uuid
|
||||
context = {"source": "user", "show_advanced_options": True}
|
||||
result = await hass.config_entries.options.async_init(
|
||||
config_entry.entry_id, context=context
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "options"
|
||||
data_schema = result["data_schema"].schema
|
||||
for other_param in all_parameters:
|
||||
if other_param == parameter:
|
||||
continue
|
||||
assert get_suggested(data_schema, other_param) == ""
|
||||
assert get_suggested(data_schema, parameter) == suggested
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={parameter: user_input},
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["data"] is None
|
||||
for other_param in all_parameters:
|
||||
if other_param == parameter:
|
||||
continue
|
||||
assert config_entry.data[other_param] == []
|
||||
assert config_entry.data[parameter] == updated
|
||||
|
||||
# Clear known_hosts
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"known_hosts": ""},
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["data"] is None
|
||||
assert config_entry.data == {"ignore_cec": [], "known_hosts": [], "uuid": []}
|
||||
|
||||
|
||||
async def test_known_hosts(hass, castbrowser_mock, castbrowser_constructor_mock):
|
||||
"""Test known hosts is passed to pychromecasts."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"cast", context={"source": "user"}
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"known_hosts": "192.168.0.1, 192.168.0.2"}
|
||||
)
|
||||
assert result["type"] == "create_entry"
|
||||
await hass.async_block_till_done()
|
||||
config_entry = hass.config_entries.async_entries("cast")[0]
|
||||
|
||||
assert castbrowser_mock.start_discovery.call_count == 1
|
||||
castbrowser_constructor_mock.assert_called_once_with(
|
||||
ANY, ANY, ["192.168.0.1", "192.168.0.2"]
|
||||
)
|
||||
castbrowser_mock.reset_mock()
|
||||
castbrowser_constructor_mock.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"known_hosts": "192.168.0.11, 192.168.0.12"},
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
castbrowser_mock.start_discovery.assert_not_called()
|
||||
castbrowser_constructor_mock.assert_not_called()
|
||||
castbrowser_mock.host_browser.update_hosts.assert_called_once_with(
|
||||
["192.168.0.11", "192.168.0.12"]
|
||||
)
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
"""Test the Coronavirus config flow."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from aiohttp import ClientError
|
||||
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.components.coronavirus.const import DOMAIN, OPTION_WORLDWIDE
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
|
||||
async def test_form(hass):
|
||||
async def test_form(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@@ -24,3 +29,22 @@ async def test_form(hass):
|
||||
}
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all()) == 4
|
||||
|
||||
|
||||
@patch(
|
||||
"coronavirus.get_cases",
|
||||
side_effect=ClientError,
|
||||
)
|
||||
async def test_abort_on_connection_error(
|
||||
mock_get_cases: MagicMock, hass: HomeAssistant
|
||||
) -> None:
|
||||
"""Test we abort on connection error."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert "type" in result
|
||||
assert result["type"] == "abort"
|
||||
assert "reason" in result
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
"""Test init of Coronavirus integration."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from aiohttp import ClientError
|
||||
|
||||
from homeassistant.components.coronavirus.const import DOMAIN, OPTION_WORLDWIDE
|
||||
from homeassistant.config_entries import ENTRY_STATE_SETUP_RETRY
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry, mock_registry
|
||||
|
||||
|
||||
async def test_migration(hass):
|
||||
async def test_migration(hass: HomeAssistant) -> None:
|
||||
"""Test that we can migrate coronavirus to stable unique ID."""
|
||||
nl_entry = MockConfigEntry(domain=DOMAIN, title="Netherlands", data={"country": 34})
|
||||
nl_entry.add_to_hass(hass)
|
||||
@@ -47,3 +53,20 @@ async def test_migration(hass):
|
||||
|
||||
assert nl_entry.unique_id == "Netherlands"
|
||||
assert worldwide_entry.unique_id == OPTION_WORLDWIDE
|
||||
|
||||
|
||||
@patch(
|
||||
"coronavirus.get_cases",
|
||||
side_effect=ClientError,
|
||||
)
|
||||
async def test_config_entry_not_ready(
|
||||
mock_get_cases: MagicMock, hass: HomeAssistant
|
||||
) -> None:
|
||||
"""Test the configuration entry not ready."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, title="Netherlands", data={"country": 34})
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state == ENTRY_STATE_SETUP_RETRY
|
||||
|
||||
@@ -145,6 +145,8 @@ async def test_setup_creates_entries_for_accessory_mode_devices(hass):
|
||||
hass.states.async_set("camera.one", "on")
|
||||
hass.states.async_set("camera.existing", "on")
|
||||
hass.states.async_set("media_player.two", "on", {"device_class": "tv"})
|
||||
hass.states.async_set("remote.standard", "on")
|
||||
hass.states.async_set("remote.activity", "on", {"supported_features": 4})
|
||||
|
||||
bridge_mode_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
@@ -178,7 +180,7 @@ async def test_setup_creates_entries_for_accessory_mode_devices(hass):
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{"include_domains": ["camera", "media_player", "light"]},
|
||||
{"include_domains": ["camera", "media_player", "light", "remote"]},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "pairing"
|
||||
@@ -205,7 +207,7 @@ async def test_setup_creates_entries_for_accessory_mode_devices(hass):
|
||||
"filter": {
|
||||
"exclude_domains": [],
|
||||
"exclude_entities": [],
|
||||
"include_domains": ["media_player", "light"],
|
||||
"include_domains": ["media_player", "light", "remote"],
|
||||
"include_entities": [],
|
||||
},
|
||||
"exclude_accessory_mode": True,
|
||||
@@ -222,7 +224,8 @@ async def test_setup_creates_entries_for_accessory_mode_devices(hass):
|
||||
# 3 - new bridge
|
||||
# 4 - camera.one in accessory mode
|
||||
# 5 - media_player.two in accessory mode
|
||||
assert len(mock_setup_entry.mock_calls) == 5
|
||||
# 6 - remote.activity in accessory mode
|
||||
assert len(mock_setup_entry.mock_calls) == 6
|
||||
|
||||
|
||||
async def test_import(hass):
|
||||
|
||||
@@ -42,6 +42,7 @@ async def test_log_filtering(hass, caplog):
|
||||
"doesntmatchanything",
|
||||
".*shouldfilterall.*",
|
||||
"^filterthis:.*",
|
||||
"in the middle",
|
||||
],
|
||||
"test.other_filter": [".*otherfilterer"],
|
||||
},
|
||||
@@ -62,6 +63,7 @@ async def test_log_filtering(hass, caplog):
|
||||
filter_logger, False, "this line containing shouldfilterall should be filtered"
|
||||
)
|
||||
msg_test(filter_logger, True, "this line should not be filtered filterthis:")
|
||||
msg_test(filter_logger, False, "this in the middle should be filtered")
|
||||
msg_test(filter_logger, False, "filterthis: should be filtered")
|
||||
msg_test(filter_logger, False, "format string shouldfilter%s", "all")
|
||||
msg_test(filter_logger, True, "format string shouldfilter%s", "not")
|
||||
|
||||
@@ -10,6 +10,7 @@ import pytest
|
||||
|
||||
from homeassistant.components.maxcube import DOMAIN
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.dt import now
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -105,5 +106,5 @@ async def cube(hass, hass_config, room, thermostat, wallthermostat, windowshutte
|
||||
assert await async_setup_component(hass, DOMAIN, hass_config)
|
||||
await hass.async_block_till_done()
|
||||
gateway = hass_config[DOMAIN]["gateways"][0]
|
||||
mock.assert_called_with(gateway["host"], gateway.get("port", 62910))
|
||||
mock.assert_called_with(gateway["host"], gateway.get("port", 62910), now=now)
|
||||
return cube
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Test Media Source initialization."""
|
||||
from unittest.mock import patch
|
||||
from urllib.parse import quote
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -45,7 +46,7 @@ async def test_async_browse_media(hass):
|
||||
media = await media_source.async_browse_media(hass, "")
|
||||
assert isinstance(media, media_source.models.BrowseMediaSource)
|
||||
assert media.title == "media/"
|
||||
assert len(media.children) == 1
|
||||
assert len(media.children) == 2
|
||||
|
||||
# Test invalid media content
|
||||
with pytest.raises(ValueError):
|
||||
@@ -133,14 +134,15 @@ async def test_websocket_browse_media(hass, hass_ws_client):
|
||||
assert msg["error"]["message"] == "test"
|
||||
|
||||
|
||||
async def test_websocket_resolve_media(hass, hass_ws_client):
|
||||
@pytest.mark.parametrize("filename", ["test.mp3", "Epic Sax Guy 10 Hours.mp4"])
|
||||
async def test_websocket_resolve_media(hass, hass_ws_client, filename):
|
||||
"""Test browse media websocket."""
|
||||
assert await async_setup_component(hass, const.DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
client = await hass_ws_client(hass)
|
||||
|
||||
media = media_source.models.PlayMedia("/media/local/test.mp3", "audio/mpeg")
|
||||
media = media_source.models.PlayMedia(f"/media/local/{filename}", "audio/mpeg")
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.media_source.async_resolve_media",
|
||||
@@ -150,7 +152,7 @@ async def test_websocket_resolve_media(hass, hass_ws_client):
|
||||
{
|
||||
"id": 1,
|
||||
"type": "media_source/resolve_media",
|
||||
"media_content_id": f"{const.URI_SCHEME}{const.DOMAIN}/local/test.mp3",
|
||||
"media_content_id": f"{const.URI_SCHEME}{const.DOMAIN}/local/{filename}",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -158,7 +160,7 @@ async def test_websocket_resolve_media(hass, hass_ws_client):
|
||||
|
||||
assert msg["success"]
|
||||
assert msg["id"] == 1
|
||||
assert msg["result"]["url"].startswith(media.url)
|
||||
assert msg["result"]["url"].startswith(quote(media.url))
|
||||
assert msg["result"]["mime_type"] == media.mime_type
|
||||
|
||||
with patch(
|
||||
|
||||
@@ -95,5 +95,8 @@ async def test_media_view(hass, hass_client):
|
||||
resp = await client.get("/media/local/test.mp3")
|
||||
assert resp.status == 200
|
||||
|
||||
resp = await client.get("/media/local/Epic Sax Guy 10 Hours.mp4")
|
||||
assert resp.status == 200
|
||||
|
||||
resp = await client.get("/media/recordings/test.mp3")
|
||||
assert resp.status == 200
|
||||
|
||||
@@ -85,11 +85,11 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
|
||||
"preset_mode_state_topic": "preset-mode-state-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": [
|
||||
"medium",
|
||||
"medium-high",
|
||||
"high",
|
||||
"very-high",
|
||||
"freaking-high",
|
||||
"auto",
|
||||
"smart",
|
||||
"whoosh",
|
||||
"eco",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
"speed_range_min": 1,
|
||||
@@ -126,6 +126,8 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("oscillating") is False
|
||||
|
||||
assert state.attributes.get("percentage_step") == 1.0
|
||||
|
||||
async_fire_mqtt_message(hass, "percentage-state-topic", "0")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
|
||||
@@ -151,16 +153,16 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "low")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "low"
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "medium")
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "auto")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "medium"
|
||||
assert state.attributes.get("preset_mode") == "auto"
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "very-high")
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "eco")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "very-high"
|
||||
assert state.attributes.get("preset_mode") == "eco"
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "silent")
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -256,7 +258,9 @@ async def test_controlling_state_via_topic_with_different_speed_range(
|
||||
caplog.clear()
|
||||
|
||||
|
||||
async def test_controlling_state_via_topic_no_percentage_topics(hass, mqtt_mock):
|
||||
async def test_controlling_state_via_topic_no_percentage_topics(
|
||||
hass, mqtt_mock, caplog
|
||||
):
|
||||
"""Test the controlling state via topic without percentage topics."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -273,9 +277,11 @@ async def test_controlling_state_via_topic_no_percentage_topics(hass, mqtt_mock)
|
||||
"preset_mode_state_topic": "preset-mode-state-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": [
|
||||
"high",
|
||||
"freaking-high",
|
||||
"silent",
|
||||
"auto",
|
||||
"smart",
|
||||
"whoosh",
|
||||
"eco",
|
||||
"breeze",
|
||||
],
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
"speeds": ["off", "low", "medium"],
|
||||
@@ -288,57 +294,51 @@ async def test_controlling_state_via_topic_no_percentage_topics(hass, mqtt_mock)
|
||||
assert state.state == STATE_OFF
|
||||
assert not state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "freaking-high")
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "smart")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "freaking-high"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||
assert state.attributes.get("preset_mode") == "smart"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) is None
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get("speed") == fan.SPEED_OFF
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "high")
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "auto")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "high"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 75
|
||||
assert state.attributes.get("preset_mode") == "auto"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) is None
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get("speed") == fan.SPEED_OFF
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "silent")
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "whoosh")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "silent"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 75
|
||||
assert state.attributes.get("preset_mode") == "whoosh"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) is None
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get("speed") == fan.SPEED_OFF
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "medium")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "medium"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get("speed") == fan.SPEED_OFF
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", "low")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "low"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 25
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get("speed") == fan.SPEED_OFF
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
async_fire_mqtt_message(hass, "speed-state-topic", "medium")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "low"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50
|
||||
assert state.attributes.get("preset_mode") == "whoosh"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||
assert state.attributes.get("speed") == fan.SPEED_MEDIUM
|
||||
|
||||
async_fire_mqtt_message(hass, "speed-state-topic", "low")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "low"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 25
|
||||
assert state.attributes.get("preset_mode") == "whoosh"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50
|
||||
assert state.attributes.get("speed") == fan.SPEED_LOW
|
||||
|
||||
async_fire_mqtt_message(hass, "speed-state-topic", "off")
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "low"
|
||||
assert state.attributes.get("preset_mode") == "whoosh"
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
|
||||
assert state.attributes.get("speed") == fan.SPEED_OFF
|
||||
|
||||
@@ -361,11 +361,11 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
|
||||
"preset_mode_state_topic": "preset-mode-state-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": [
|
||||
"medium",
|
||||
"medium-high",
|
||||
"high",
|
||||
"very-high",
|
||||
"freaking-high",
|
||||
"auto",
|
||||
"smart",
|
||||
"whoosh",
|
||||
"eco",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
"state_value_template": "{{ value_json.val }}",
|
||||
@@ -412,20 +412,20 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "medium"}')
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "auto"}')
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "medium"
|
||||
assert state.attributes.get("preset_mode") == "auto"
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "freaking-high"}')
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "breeze"}')
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "freaking-high"
|
||||
assert state.attributes.get("preset_mode") == "breeze"
|
||||
|
||||
async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "silent"}')
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get("preset_mode") == "silent"
|
||||
|
||||
|
||||
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
|
||||
"""Test optimistic mode without state topic."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -447,8 +447,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
"speeds": ["off", "low", "medium"],
|
||||
"preset_modes": [
|
||||
"high",
|
||||
"freaking-high",
|
||||
"whoosh",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
@@ -510,7 +510,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
"speed-command-topic", "speed_mEdium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -518,11 +518,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 0)
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "0", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "off", 0, False
|
||||
)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"speed-command-topic", "speed_OfF", 0, False
|
||||
@@ -534,54 +531,32 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
assert state.attributes.get(fan.ATTR_SPEED) == fan.SPEED_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
await common.async_set_preset_mode(hass, "fan.test", "low")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"speed-command-topic", "speed_lOw", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "low", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "low"
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get(fan.ATTR_SPEED) == fan.SPEED_LOW
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
await common.async_set_preset_mode(hass, "fan.test", "medium")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"speed-command-topic", "speed_mEdium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "medium"
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
assert state.attributes.get(fan.ATTR_SPEED) == fan.SPEED_MEDIUM
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "whoosh"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "breeze")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
"preset-mode-command-topic", "breeze", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "high"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high"
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "breeze"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "silent")
|
||||
@@ -615,13 +590,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
await common.async_set_speed(hass, "fan.test", fan.SPEED_HIGH)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"speed-command-topic", "speed_High", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
assert "not a valid speed" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
await common.async_set_speed(hass, "fan.test", fan.SPEED_OFF)
|
||||
@@ -648,7 +618,7 @@ async def test_sending_mqtt_commands_with_alternate_speed_range(hass, mqtt_mock)
|
||||
"percentage_state_topic": "percentage-state-topic1",
|
||||
"percentage_command_topic": "percentage-command-topic1",
|
||||
"speed_range_min": 1,
|
||||
"speed_range_max": 100,
|
||||
"speed_range_max": 3,
|
||||
},
|
||||
{
|
||||
"platform": "mqtt",
|
||||
@@ -681,9 +651,25 @@ async def test_sending_mqtt_commands_with_alternate_speed_range(hass, mqtt_mock)
|
||||
state = hass.states.get("fan.test1")
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test1", 33)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"percentage-command-topic1", "1", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test1")
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test1", 66)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"percentage-command-topic1", "2", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test1")
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test1", 100)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"percentage-command-topic1", "100", 0, False
|
||||
"percentage-command-topic1", "3", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test1")
|
||||
@@ -735,8 +721,8 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
|
||||
"percentage_command_topic": "percentage-command-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": [
|
||||
"high",
|
||||
"freaking-high",
|
||||
"whoosh",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
}
|
||||
@@ -769,14 +755,12 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
|
||||
await common.async_set_percentage(hass, "fan.test", 101)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 100)
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"percentage-command-topic", "100", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 0)
|
||||
@@ -793,26 +777,26 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "medium")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "auto")
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
"preset-mode-command-topic", "whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "high"
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "whoosh"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "breeze")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
"preset-mode-command-topic", "breeze", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high"
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "breeze"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "silent")
|
||||
@@ -825,12 +809,9 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", percentage=25)
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "25", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_ON
|
||||
@@ -843,11 +824,11 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="high")
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="whoosh")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
"preset-mode-command-topic", "whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -855,7 +836,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
with pytest.raises(NotValidPresetModeError):
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="low")
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="freaking-high")
|
||||
|
||||
|
||||
async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
@@ -876,8 +857,8 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_mode_command_template": "preset_mode: {{ value }}",
|
||||
"preset_modes": [
|
||||
"high",
|
||||
"freaking-high",
|
||||
"whoosh",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
}
|
||||
@@ -914,16 +895,12 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
await common.async_set_percentage(hass, "fan.test", 101)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 100)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"percentage-command-topic", "percentage: 100", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "preset_mode: freaking-high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 0)
|
||||
@@ -944,22 +921,22 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "preset_mode: high", 0, False
|
||||
"preset-mode-command-topic", "preset_mode: whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "high"
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "whoosh"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "breeze")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "preset_mode: freaking-high", 0, False
|
||||
"preset-mode-command-topic", "preset_mode: breeze", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high"
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) == "breeze"
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "silent")
|
||||
@@ -972,14 +949,11 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", percentage=25)
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "state: ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"percentage-command-topic", "percentage: 25", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "preset_mode: high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_ON
|
||||
@@ -992,11 +966,11 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="high")
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="whoosh")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "state: ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "preset_mode: high", 0, False
|
||||
"preset-mode-command-topic", "preset_mode: whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -1008,7 +982,7 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
|
||||
|
||||
|
||||
async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
|
||||
hass, mqtt_mock
|
||||
hass, mqtt_mock, caplog
|
||||
):
|
||||
"""Test optimistic mode without state topic without percentage command topic."""
|
||||
assert await async_setup_component(
|
||||
@@ -1027,9 +1001,10 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
"speeds": ["off", "low", "medium"],
|
||||
"preset_modes": [
|
||||
"high",
|
||||
"freaking-high",
|
||||
"whoosh",
|
||||
"breeze",
|
||||
"silent",
|
||||
"high",
|
||||
],
|
||||
}
|
||||
},
|
||||
@@ -1047,9 +1022,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
|
||||
await common.async_set_percentage(hass, "fan.test", 101)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 100)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100
|
||||
@@ -1063,41 +1036,27 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
|
||||
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "low")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "low", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) is None
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
await common.async_set_preset_mode(hass, "fan.test", "low")
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "medium")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) is None
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "breeze")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.attributes.get(fan.ATTR_PRESET_MODE) is None
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
"preset-mode-command-topic", "breeze", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -1133,14 +1092,8 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_speed(hass, "fan.test", fan.SPEED_HIGH)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"speed-command-topic", "high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
assert "not a valid speed" in caplog.text
|
||||
caplog.clear()
|
||||
await common.async_set_speed(hass, "fan.test", fan.SPEED_OFF)
|
||||
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "off", 0, False)
|
||||
@@ -1150,13 +1103,10 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", speed="medium")
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_ON
|
||||
@@ -1325,8 +1275,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
"speeds": ["off", "low", "medium"],
|
||||
"preset_modes": [
|
||||
"high",
|
||||
"freaking-high",
|
||||
"whoosh",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
"optimistic": True,
|
||||
@@ -1358,9 +1308,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_ON
|
||||
@@ -1374,11 +1322,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", percentage=25)
|
||||
assert mqtt_mock.async_publish.call_count == 4
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "low", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "25", 0, False)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False)
|
||||
@@ -1394,24 +1339,15 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="medium")
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
with pytest.raises(NotValidPresetModeError):
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="auto")
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="high")
|
||||
await common.async_turn_on(hass, "fan.test", preset_mode="whoosh")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
"preset-mode-command-topic", "whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -1471,14 +1407,11 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "fan.test", percentage=50)
|
||||
assert mqtt_mock.async_publish.call_count == 4
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "50", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_ON
|
||||
@@ -1501,26 +1434,20 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 33)
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "33", 0, False)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 50)
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "50", 0, False)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
@@ -1529,22 +1456,18 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
await common.async_set_percentage(hass, "fan.test", 100)
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "freaking-high", 0, False
|
||||
)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_percentage(hass, "fan.test", 0)
|
||||
assert mqtt_mock.async_publish.call_count == 3
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "0", 0, False)
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "off", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "off", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
@@ -1554,32 +1477,16 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
await common.async_set_percentage(hass, "fan.test", 101)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "low")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "low", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "medium")
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
# use of speeds is deprecated, support will be removed after a quarter (2021.7)
|
||||
mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False)
|
||||
mqtt_mock.async_publish.assert_any_call(
|
||||
"preset-mode-command-topic", "medium", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "high")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"preset-mode-command-topic", "high", 0, False
|
||||
"preset-mode-command-topic", "whoosh", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
@@ -1595,7 +1502,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_preset_mode(hass, "fan.test", "ModeX")
|
||||
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
|
||||
assert "not a valid preset mode" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
@@ -1615,13 +1522,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_set_speed(hass, "fan.test", fan.SPEED_HIGH)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
"speed-command-topic", "high", 0, False
|
||||
)
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
state = hass.states.get("fan.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
assert "not a valid speed" in caplog.text
|
||||
caplog.clear()
|
||||
|
||||
await common.async_set_speed(hass, "fan.test", fan.SPEED_OFF)
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
@@ -1653,7 +1555,7 @@ async def test_attributes(hass, mqtt_mock, caplog):
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"percentage_command_topic": "percentage-command-topic",
|
||||
"preset_modes": [
|
||||
"freaking-high",
|
||||
"breeze",
|
||||
"silent",
|
||||
],
|
||||
}
|
||||
@@ -1667,7 +1569,6 @@ async def test_attributes(hass, mqtt_mock, caplog):
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"freaking-high",
|
||||
]
|
||||
|
||||
await common.async_turn_on(hass, "fan.test")
|
||||
@@ -1821,14 +1722,14 @@ async def test_supported_features(hass, mqtt_mock):
|
||||
"name": "test3c2",
|
||||
"command_topic": "command-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": ["very-fast", "auto"],
|
||||
"preset_modes": ["eco", "auto"],
|
||||
},
|
||||
{
|
||||
"platform": "mqtt",
|
||||
"name": "test3c3",
|
||||
"command_topic": "command-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": ["off", "on", "auto"],
|
||||
"preset_modes": ["eco", "smart", "auto"],
|
||||
},
|
||||
{
|
||||
"platform": "mqtt",
|
||||
@@ -1863,7 +1764,7 @@ async def test_supported_features(hass, mqtt_mock):
|
||||
"name": "test5pr_mb",
|
||||
"command_topic": "command-topic",
|
||||
"preset_mode_command_topic": "preset-mode-command-topic",
|
||||
"preset_modes": ["off", "on", "auto"],
|
||||
"preset_modes": ["whoosh", "silent", "auto"],
|
||||
},
|
||||
{
|
||||
"platform": "mqtt",
|
||||
@@ -1927,10 +1828,7 @@ async def test_supported_features(hass, mqtt_mock):
|
||||
assert state is None
|
||||
|
||||
state = hass.states.get("fan.test3c2")
|
||||
assert (
|
||||
state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||
== fan.SUPPORT_PRESET_MODE | fan.SUPPORT_SET_SPEED
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE
|
||||
state = hass.states.get("fan.test3c3")
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE
|
||||
|
||||
@@ -1949,21 +1847,19 @@ async def test_supported_features(hass, mqtt_mock):
|
||||
)
|
||||
|
||||
state = hass.states.get("fan.test5pr_ma")
|
||||
assert (
|
||||
state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||
== fan.SUPPORT_SET_SPEED | fan.SUPPORT_PRESET_MODE
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE
|
||||
state = hass.states.get("fan.test5pr_mb")
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE
|
||||
|
||||
state = hass.states.get("fan.test5pr_mc")
|
||||
assert (
|
||||
state.attributes.get(ATTR_SUPPORTED_FEATURES)
|
||||
== fan.SUPPORT_OSCILLATE | fan.SUPPORT_SET_SPEED | fan.SUPPORT_PRESET_MODE
|
||||
== fan.SUPPORT_OSCILLATE | fan.SUPPORT_PRESET_MODE
|
||||
)
|
||||
|
||||
state = hass.states.get("fan.test6spd_range_a")
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_SET_SPEED
|
||||
assert state.attributes.get("percentage_step") == 2.5
|
||||
state = hass.states.get("fan.test6spd_range_b")
|
||||
assert state is None
|
||||
state = hass.states.get("fan.test6spd_range_c")
|
||||
|
||||
@@ -234,10 +234,10 @@ async def test_rgb_light(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
expected_features = (
|
||||
light.SUPPORT_TRANSITION
|
||||
light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_COLOR
|
||||
| light.SUPPORT_FLASH
|
||||
| light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_TRANSITION
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
|
||||
@@ -261,7 +261,8 @@ async def test_no_color_brightness_color_temp_white_val_if_no_topics(hass, mqtt_
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 40
|
||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get("rgb_color") is None
|
||||
assert state.attributes.get("brightness") is None
|
||||
assert state.attributes.get("color_temp") is None
|
||||
@@ -310,7 +311,16 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 191
|
||||
expected_features = (
|
||||
light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_COLOR
|
||||
| light.SUPPORT_COLOR_TEMP
|
||||
| light.SUPPORT_EFFECT
|
||||
| light.SUPPORT_FLASH
|
||||
| light.SUPPORT_TRANSITION
|
||||
| light.SUPPORT_WHITE_VALUE
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get("rgb_color") is None
|
||||
assert state.attributes.get("brightness") is None
|
||||
assert state.attributes.get("color_temp") is None
|
||||
@@ -429,7 +439,15 @@ async def test_controlling_state_via_topic2(hass, mqtt_mock, caplog):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 44
|
||||
expected_features = (
|
||||
light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_COLOR
|
||||
| light.SUPPORT_COLOR_TEMP
|
||||
| light.SUPPORT_EFFECT
|
||||
| light.SUPPORT_FLASH
|
||||
| light.SUPPORT_TRANSITION
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get("brightness") is None
|
||||
assert state.attributes.get("color_mode") is None
|
||||
assert state.attributes.get("color_temp") is None
|
||||
@@ -610,7 +628,16 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
|
||||
assert state.attributes.get("effect") == "random"
|
||||
assert state.attributes.get("color_temp") == 100
|
||||
assert state.attributes.get("white_value") == 50
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 191
|
||||
expected_features = (
|
||||
light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_COLOR
|
||||
| light.SUPPORT_COLOR_TEMP
|
||||
| light.SUPPORT_EFFECT
|
||||
| light.SUPPORT_FLASH
|
||||
| light.SUPPORT_TRANSITION
|
||||
| light.SUPPORT_WHITE_VALUE
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get(ATTR_ASSUMED_STATE)
|
||||
|
||||
await common.async_turn_on(hass, "light.test")
|
||||
@@ -738,7 +765,15 @@ async def test_sending_mqtt_commands_and_optimistic2(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 44
|
||||
expected_features = (
|
||||
light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_COLOR
|
||||
| light.SUPPORT_COLOR_TEMP
|
||||
| light.SUPPORT_EFFECT
|
||||
| light.SUPPORT_FLASH
|
||||
| light.SUPPORT_TRANSITION
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get("brightness") == 95
|
||||
assert state.attributes.get("color_mode") == "rgb"
|
||||
assert state.attributes.get("color_temp") is None
|
||||
@@ -1313,7 +1348,10 @@ async def test_effect(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 44
|
||||
expected_features = (
|
||||
light.SUPPORT_EFFECT | light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
|
||||
await common.async_turn_on(hass, "light.test")
|
||||
|
||||
@@ -1373,7 +1411,8 @@ async def test_flash_short_and_long(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 40
|
||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
|
||||
await common.async_turn_on(hass, "light.test", flash="short")
|
||||
|
||||
@@ -1431,8 +1470,8 @@ async def test_transition(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 40
|
||||
|
||||
expected_features = light.SUPPORT_FLASH | light.SUPPORT_TRANSITION
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
await common.async_turn_on(hass, "light.test", transition=15)
|
||||
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
@@ -1523,7 +1562,15 @@ async def test_invalid_values(hass, mqtt_mock):
|
||||
|
||||
state = hass.states.get("light.test")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 187
|
||||
expected_features = (
|
||||
light.SUPPORT_BRIGHTNESS
|
||||
| light.SUPPORT_COLOR
|
||||
| light.SUPPORT_COLOR_TEMP
|
||||
| light.SUPPORT_FLASH
|
||||
| light.SUPPORT_TRANSITION
|
||||
| light.SUPPORT_WHITE_VALUE
|
||||
)
|
||||
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
|
||||
assert state.attributes.get("rgb_color") is None
|
||||
assert state.attributes.get("brightness") is None
|
||||
assert state.attributes.get("white_value") is None
|
||||
|
||||
@@ -3,7 +3,7 @@ import json
|
||||
from unittest.mock import ANY, patch
|
||||
|
||||
import homeassistant.components.mqtt_eventstream as eventstream
|
||||
from homeassistant.const import EVENT_STATE_CHANGED
|
||||
from homeassistant.const import EVENT_STATE_CHANGED, MATCH_ALL
|
||||
from homeassistant.core import State, callback
|
||||
from homeassistant.helpers.json import JSONEncoder
|
||||
from homeassistant.setup import async_setup_component
|
||||
@@ -114,6 +114,7 @@ async def test_time_event_does_not_send_message(hass, mqtt_mock):
|
||||
mqtt_mock.async_publish.reset_mock()
|
||||
|
||||
async_fire_time_changed(hass, dt_util.utcnow())
|
||||
await hass.async_block_till_done()
|
||||
assert not mqtt_mock.async_publish.called
|
||||
|
||||
|
||||
@@ -140,6 +141,33 @@ async def test_receiving_remote_event_fires_hass_event(hass, mqtt_mock):
|
||||
|
||||
assert len(calls) == 1
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_receiving_blocked_event_fires_hass_event(hass, mqtt_mock):
|
||||
"""Test the receiving of blocked event does not fire."""
|
||||
sub_topic = "foo"
|
||||
assert await add_eventstream(hass, sub_topic=sub_topic)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
calls = []
|
||||
|
||||
@callback
|
||||
def listener(_):
|
||||
calls.append(1)
|
||||
|
||||
hass.bus.async_listen(MATCH_ALL, listener)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
for event in eventstream.BLOCKED_EVENTS:
|
||||
payload = json.dumps({"event_type": event, "event_data": {}}, cls=JSONEncoder)
|
||||
async_fire_mqtt_message(hass, sub_topic, payload)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 0
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_ignored_event_doesnt_send_over_stream(hass, mqtt_mock):
|
||||
"""Test the ignoring of sending events if defined."""
|
||||
@@ -159,6 +187,7 @@ async def test_ignored_event_doesnt_send_over_stream(hass, mqtt_mock):
|
||||
# Set a state of an entity
|
||||
mock_state_change_event(hass, State(e_id, "on"))
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert not mqtt_mock.async_publish.called
|
||||
|
||||
|
||||
27
tests/components/ping/test_init.py
Normal file
27
tests/components/ping/test_init.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""Test ping id allocation."""
|
||||
|
||||
from homeassistant.components.ping import async_get_next_ping_id
|
||||
from homeassistant.components.ping.const import (
|
||||
DEFAULT_START_ID,
|
||||
DOMAIN,
|
||||
MAX_PING_ID,
|
||||
PING_ID,
|
||||
)
|
||||
|
||||
|
||||
async def test_async_get_next_ping_id(hass):
|
||||
"""Verify we allocate ping ids as expected."""
|
||||
hass.data[DOMAIN] = {PING_ID: DEFAULT_START_ID}
|
||||
|
||||
assert async_get_next_ping_id(hass) == DEFAULT_START_ID + 1
|
||||
assert async_get_next_ping_id(hass) == DEFAULT_START_ID + 2
|
||||
assert async_get_next_ping_id(hass, 2) == DEFAULT_START_ID + 3
|
||||
assert async_get_next_ping_id(hass) == DEFAULT_START_ID + 5
|
||||
|
||||
hass.data[DOMAIN][PING_ID] = MAX_PING_ID
|
||||
assert async_get_next_ping_id(hass) == DEFAULT_START_ID + 1
|
||||
assert async_get_next_ping_id(hass) == DEFAULT_START_ID + 2
|
||||
|
||||
hass.data[DOMAIN][PING_ID] = MAX_PING_ID
|
||||
assert async_get_next_ping_id(hass, 2) == DEFAULT_START_ID + 1
|
||||
assert async_get_next_ping_id(hass) == DEFAULT_START_ID + 3
|
||||
@@ -1,4 +1,6 @@
|
||||
"""The tests for Shelly device triggers."""
|
||||
from unittest.mock import AsyncMock, Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import setup
|
||||
@@ -6,10 +8,13 @@ from homeassistant.components import automation
|
||||
from homeassistant.components.device_automation.exceptions import (
|
||||
InvalidDeviceAutomationConfig,
|
||||
)
|
||||
from homeassistant.components.shelly import ShellyDeviceWrapper
|
||||
from homeassistant.components.shelly.const import (
|
||||
ATTR_CHANNEL,
|
||||
ATTR_CLICK_TYPE,
|
||||
COAP,
|
||||
CONF_SUBTYPE,
|
||||
DATA_CONFIG_ENTRY,
|
||||
DOMAIN,
|
||||
EVENT_SHELLY_CLICK,
|
||||
)
|
||||
@@ -52,6 +57,71 @@ async def test_get_triggers(hass, coap_wrapper):
|
||||
assert_lists_same(triggers, expected_triggers)
|
||||
|
||||
|
||||
async def test_get_triggers_button(hass):
|
||||
"""Test we get the expected triggers from a shelly button."""
|
||||
await async_setup_component(hass, "shelly", {})
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={"sleep_period": 43200, "model": "SHBTN-1"},
|
||||
unique_id="12345678",
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
device = Mock(
|
||||
blocks=None,
|
||||
settings=None,
|
||||
shelly=None,
|
||||
update=AsyncMock(),
|
||||
initialized=False,
|
||||
)
|
||||
|
||||
hass.data[DOMAIN] = {DATA_CONFIG_ENTRY: {}}
|
||||
hass.data[DOMAIN][DATA_CONFIG_ENTRY][config_entry.entry_id] = {}
|
||||
coap_wrapper = hass.data[DOMAIN][DATA_CONFIG_ENTRY][config_entry.entry_id][
|
||||
COAP
|
||||
] = ShellyDeviceWrapper(hass, config_entry, device)
|
||||
|
||||
await coap_wrapper.async_setup()
|
||||
|
||||
expected_triggers = [
|
||||
{
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_DEVICE_ID: coap_wrapper.device_id,
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
CONF_TYPE: "single",
|
||||
CONF_SUBTYPE: "button",
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_DEVICE_ID: coap_wrapper.device_id,
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
CONF_TYPE: "double",
|
||||
CONF_SUBTYPE: "button",
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_DEVICE_ID: coap_wrapper.device_id,
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
CONF_TYPE: "triple",
|
||||
CONF_SUBTYPE: "button",
|
||||
},
|
||||
{
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_DEVICE_ID: coap_wrapper.device_id,
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
CONF_TYPE: "long",
|
||||
CONF_SUBTYPE: "button",
|
||||
},
|
||||
]
|
||||
|
||||
triggers = await async_get_device_automations(
|
||||
hass, "trigger", coap_wrapper.device_id
|
||||
)
|
||||
|
||||
assert_lists_same(triggers, expected_triggers)
|
||||
|
||||
|
||||
async def test_get_triggers_for_invalid_device_id(hass, device_reg, coap_wrapper):
|
||||
"""Test error raised for invalid shelly device_id."""
|
||||
assert coap_wrapper
|
||||
|
||||
@@ -102,6 +102,7 @@ async def test_setup_component_demo(hass):
|
||||
|
||||
assert hass.services.has_service(tts.DOMAIN, "demo_say")
|
||||
assert hass.services.has_service(tts.DOMAIN, "clear_cache")
|
||||
assert f"{tts.DOMAIN}.demo" in hass.config.components
|
||||
|
||||
|
||||
async def test_setup_component_demo_no_access_cache_folder(hass, mock_init_cache_dir):
|
||||
|
||||
@@ -12,6 +12,7 @@ from homeassistant.components.climate.const import (
|
||||
ATTR_PRESET_MODE,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
CURRENT_HVAC_COOL,
|
||||
CURRENT_HVAC_IDLE,
|
||||
DOMAIN as CLIMATE_DOMAIN,
|
||||
HVAC_MODE_COOL,
|
||||
@@ -351,6 +352,7 @@ async def test_thermostat_different_endpoints(
|
||||
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 22.8
|
||||
assert state.attributes[ATTR_FAN_MODE] == "Auto low"
|
||||
assert state.attributes[ATTR_FAN_STATE] == "Idle / off"
|
||||
assert state.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_COOL
|
||||
|
||||
|
||||
async def test_setpoint_thermostat(hass, client, climate_danfoss_lc_13, integration):
|
||||
|
||||
@@ -528,7 +528,7 @@ async def test_poll_value(
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(client.async_send_command.call_args_list) == 7
|
||||
assert len(client.async_send_command.call_args_list) == 8
|
||||
|
||||
# Test polling against an invalid entity raises ValueError
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
1
tests/testing_config/media/Epic Sax Guy 10 Hours.mp4
Normal file
1
tests/testing_config/media/Epic Sax Guy 10 Hours.mp4
Normal file
@@ -0,0 +1 @@
|
||||
I play the sax
|
||||
Reference in New Issue
Block a user