mirror of
https://github.com/home-assistant/core.git
synced 2025-09-22 03:19:33 +00:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a48ac4d18f | ||
![]() |
a0443b0238 | ||
![]() |
b2a5c75fbd | ||
![]() |
2814a24f9e | ||
![]() |
f5306f769c | ||
![]() |
1618c5c040 | ||
![]() |
6c138e2982 | ||
![]() |
969b36a447 | ||
![]() |
3f8dc5ed75 | ||
![]() |
fc7d43269c | ||
![]() |
b88c0cf314 | ||
![]() |
9e9537a3d0 | ||
![]() |
84e4e94d8e | ||
![]() |
c10e046323 | ||
![]() |
633d006554 | ||
![]() |
4e2a8fde86 | ||
![]() |
d57fe0334f | ||
![]() |
75b8070c99 | ||
![]() |
b71e1affdb | ||
![]() |
d92060a461 | ||
![]() |
3c9482b2d3 | ||
![]() |
5571c0c60a | ||
![]() |
54481598b7 | ||
![]() |
2d7208470e | ||
![]() |
7eceedea10 | ||
![]() |
8aee92347f |
@@ -23,14 +23,12 @@ from homeassistant.const import (
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import ATTRIBUTION, DOMAIN
|
||||
from .const import ATTRIBUTION, DOMAIN, DEFAULT_CACHEDB
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_POLLING = "polling"
|
||||
|
||||
DEFAULT_CACHEDB = "./abodepy_cache.pickle"
|
||||
|
||||
SERVICE_SETTINGS = "change_setting"
|
||||
SERVICE_CAPTURE_IMAGE = "capture_image"
|
||||
SERVICE_TRIGGER = "trigger_quick_action"
|
||||
|
@@ -10,7 +10,7 @@ from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .const import DOMAIN # pylint: disable=W0611
|
||||
from .const import DOMAIN, DEFAULT_CACHEDB # pylint: disable=W0611
|
||||
|
||||
CONF_POLLING = "polling"
|
||||
|
||||
@@ -42,9 +42,12 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
username = user_input[CONF_USERNAME]
|
||||
password = user_input[CONF_PASSWORD]
|
||||
polling = user_input.get(CONF_POLLING, False)
|
||||
cache = self.hass.config.path(DEFAULT_CACHEDB)
|
||||
|
||||
try:
|
||||
await self.hass.async_add_executor_job(Abode, username, password, True)
|
||||
await self.hass.async_add_executor_job(
|
||||
Abode, username, password, True, True, True, cache
|
||||
)
|
||||
|
||||
except (AbodeException, ConnectTimeout, HTTPError) as ex:
|
||||
_LOGGER.error("Unable to connect to Abode: %s", str(ex))
|
||||
|
@@ -1,3 +1,5 @@
|
||||
"""Constants for the Abode Security System component."""
|
||||
DOMAIN = "abode"
|
||||
ATTRIBUTION = "Data provided by goabode.com"
|
||||
|
||||
DEFAULT_CACHEDB = "abodepy_cache.pickle"
|
||||
|
@@ -1,15 +1,16 @@
|
||||
"""The Airly component."""
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import async_timeout
|
||||
from aiohttp.client_exceptions import ClientConnectorError
|
||||
from airly import Airly
|
||||
from airly.exceptions import AirlyError
|
||||
import async_timeout
|
||||
|
||||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE
|
||||
from homeassistant.core import Config, HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
@@ -30,6 +31,8 @@ DEFAULT_SCAN_INTERVAL = timedelta(minutes=10)
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: Config) -> bool:
|
||||
"""Set up configured Airly."""
|
||||
hass.data[DOMAIN] = {}
|
||||
hass.data[DOMAIN][DATA_CLIENT] = {}
|
||||
return True
|
||||
|
||||
|
||||
@@ -45,8 +48,9 @@ async def async_setup_entry(hass, config_entry):
|
||||
|
||||
await airly.async_update()
|
||||
|
||||
hass.data[DOMAIN] = {}
|
||||
hass.data[DOMAIN][DATA_CLIENT] = {}
|
||||
if not airly.data:
|
||||
raise ConfigEntryNotReady()
|
||||
|
||||
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = airly
|
||||
|
||||
hass.async_create_task(
|
||||
@@ -81,7 +85,7 @@ class AirlyData:
|
||||
"""Update Airly data."""
|
||||
|
||||
try:
|
||||
with async_timeout.timeout(10):
|
||||
with async_timeout.timeout(20):
|
||||
measurements = self.airly.create_measurements_session_point(
|
||||
self.latitude, self.longitude
|
||||
)
|
||||
@@ -104,11 +108,8 @@ class AirlyData:
|
||||
self.data[ATTR_API_CAQI_DESCRIPTION] = index["description"]
|
||||
self.data[ATTR_API_ADVICE] = index["advice"]
|
||||
_LOGGER.debug("Data retrieved from Airly")
|
||||
except (
|
||||
ValueError,
|
||||
AirlyError,
|
||||
asyncio.TimeoutError,
|
||||
ClientConnectorError,
|
||||
) as error:
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Asyncio Timeout Error")
|
||||
except (ValueError, AirlyError, ClientConnectorError) as error:
|
||||
_LOGGER.error(error)
|
||||
self.data = {}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
"""Support for Decora dimmers."""
|
||||
import copy
|
||||
from functools import wraps
|
||||
import logging
|
||||
import time
|
||||
@@ -15,17 +16,34 @@ from homeassistant.components.light import (
|
||||
)
|
||||
from homeassistant.const import CONF_API_KEY, CONF_DEVICES, CONF_NAME
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import homeassistant.util as util
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SUPPORT_DECORA_LED = SUPPORT_BRIGHTNESS
|
||||
|
||||
|
||||
def _name_validator(config):
|
||||
"""Validate the name."""
|
||||
config = copy.deepcopy(config)
|
||||
for address, device_config in config[CONF_DEVICES].items():
|
||||
if CONF_NAME not in device_config:
|
||||
device_config[CONF_NAME] = util.slugify(address)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
DEVICE_SCHEMA = vol.Schema(
|
||||
{vol.Optional(CONF_NAME): cv.string, vol.Required(CONF_API_KEY): cv.string}
|
||||
)
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA}}
|
||||
PLATFORM_SCHEMA = vol.Schema(
|
||||
vol.All(
|
||||
PLATFORM_SCHEMA.extend(
|
||||
{vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA}}
|
||||
),
|
||||
_name_validator,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
@@ -2,11 +2,7 @@
|
||||
"domain": "environment_canada",
|
||||
"name": "Environment Canada",
|
||||
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
|
||||
"requirements": [
|
||||
"env_canada==0.0.27"
|
||||
],
|
||||
"requirements": ["env_canada==0.0.29"],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
"@michaeldavie"
|
||||
]
|
||||
"codeowners": ["@michaeldavie"]
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "Jewish calendar",
|
||||
"documentation": "https://www.home-assistant.io/integrations/jewish_calendar",
|
||||
"requirements": [
|
||||
"hdate==0.9.1"
|
||||
"hdate==0.9.3"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
|
@@ -180,13 +180,9 @@ class KNXLight(Light):
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
if self.device.supports_brightness:
|
||||
return self.device.current_brightness
|
||||
if (
|
||||
self.device.supports_color or self.device.supports_rgbw
|
||||
) and self.device.current_color:
|
||||
return max(self.device.current_color)
|
||||
return None
|
||||
if not self.device.supports_brightness:
|
||||
return None
|
||||
return self.device.current_brightness
|
||||
|
||||
@property
|
||||
def hs_color(self):
|
||||
|
@@ -17,10 +17,16 @@ from homeassistant.helpers.typing import HomeAssistantType
|
||||
from . import (
|
||||
DOMAIN,
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
ATTR_COLOR_NAME,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_FLASH,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_KELVIN,
|
||||
ATTR_PROFILE,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_WHITE_VALUE,
|
||||
ATTR_XY_COLOR,
|
||||
)
|
||||
@@ -28,8 +34,36 @@ from . import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
VALID_STATES = {STATE_ON, STATE_OFF}
|
||||
ATTR_GROUP = [ATTR_BRIGHTNESS, ATTR_EFFECT, ATTR_WHITE_VALUE]
|
||||
COLOR_GROUP = [ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_RGB_COLOR, ATTR_XY_COLOR]
|
||||
|
||||
ATTR_GROUP = [
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
ATTR_EFFECT,
|
||||
ATTR_FLASH,
|
||||
ATTR_WHITE_VALUE,
|
||||
ATTR_TRANSITION,
|
||||
]
|
||||
|
||||
COLOR_GROUP = [
|
||||
ATTR_COLOR_NAME,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_KELVIN,
|
||||
ATTR_PROFILE,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_XY_COLOR,
|
||||
]
|
||||
|
||||
DEPRECATED_GROUP = [
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
ATTR_COLOR_NAME,
|
||||
ATTR_FLASH,
|
||||
ATTR_KELVIN,
|
||||
ATTR_PROFILE,
|
||||
ATTR_TRANSITION,
|
||||
]
|
||||
|
||||
DEPRECATION_WARNING = "The use of other attributes than device state attributes is deprecated and will be removed in a future release. Read the logs for further details: https://www.home-assistant.io/integrations/scene/"
|
||||
|
||||
|
||||
async def _async_reproduce_state(
|
||||
@@ -48,6 +82,10 @@ async def _async_reproduce_state(
|
||||
)
|
||||
return
|
||||
|
||||
# Warn if deprecated attributes are used
|
||||
if any(attr in DEPRECATED_GROUP for attr in state.attributes):
|
||||
_LOGGER.warning(DEPRECATION_WARNING)
|
||||
|
||||
# Return if we are already at the right state.
|
||||
if cur_state.state == state.state and all(
|
||||
check_attr_equal(cur_state.attributes, state.attributes, attr)
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "Myq",
|
||||
"documentation": "https://www.home-assistant.io/integrations/myq",
|
||||
"requirements": [
|
||||
"pymyq==2.0.0"
|
||||
"pymyq==2.0.1"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
|
@@ -6,7 +6,7 @@ from xml.etree.ElementTree import ParseError
|
||||
import plexapi.exceptions
|
||||
import requests.exceptions
|
||||
|
||||
from homeassistant.components.media_player import MediaPlayerDevice
|
||||
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN, MediaPlayerDevice
|
||||
from homeassistant.components.media_player.const import (
|
||||
MEDIA_TYPE_MOVIE,
|
||||
MEDIA_TYPE_MUSIC,
|
||||
@@ -30,6 +30,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_registry import async_get_registry
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import (
|
||||
@@ -56,10 +57,11 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up Plex media_player from a config entry."""
|
||||
server_id = config_entry.data[CONF_SERVER_IDENTIFIER]
|
||||
registry = await async_get_registry(hass)
|
||||
|
||||
def async_new_media_players(new_entities):
|
||||
_async_add_entities(
|
||||
hass, config_entry, async_add_entities, server_id, new_entities
|
||||
hass, registry, config_entry, async_add_entities, server_id, new_entities
|
||||
)
|
||||
|
||||
unsub = async_dispatcher_connect(
|
||||
@@ -70,7 +72,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
|
||||
@callback
|
||||
def _async_add_entities(
|
||||
hass, config_entry, async_add_entities, server_id, new_entities
|
||||
hass, registry, config_entry, async_add_entities, server_id, new_entities
|
||||
):
|
||||
"""Set up Plex media_player entities."""
|
||||
entities = []
|
||||
@@ -79,6 +81,19 @@ def _async_add_entities(
|
||||
plex_mp = PlexMediaPlayer(plexserver, **entity_params)
|
||||
entities.append(plex_mp)
|
||||
|
||||
# Migration to per-server unique_ids
|
||||
old_entity_id = registry.async_get_entity_id(
|
||||
MP_DOMAIN, PLEX_DOMAIN, plex_mp.machine_identifier
|
||||
)
|
||||
if old_entity_id is not None:
|
||||
new_unique_id = f"{server_id}:{plex_mp.machine_identifier}"
|
||||
_LOGGER.debug(
|
||||
"Migrating unique_id from [%s] to [%s]",
|
||||
plex_mp.machine_identifier,
|
||||
new_unique_id,
|
||||
)
|
||||
registry.async_update_entity(old_entity_id, new_unique_id=new_unique_id)
|
||||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
|
||||
@@ -126,6 +141,7 @@ class PlexMediaPlayer(MediaPlayerDevice):
|
||||
async def async_added_to_hass(self):
|
||||
"""Run when about to be added to hass."""
|
||||
server_id = self.plex_server.machine_identifier
|
||||
|
||||
unsub = async_dispatcher_connect(
|
||||
self.hass,
|
||||
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL.format(self.unique_id),
|
||||
@@ -315,6 +331,11 @@ class PlexMediaPlayer(MediaPlayerDevice):
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the id of this plex client."""
|
||||
return f"{self.plex_server.machine_identifier}:{self._machine_identifier}"
|
||||
|
||||
@property
|
||||
def machine_identifier(self):
|
||||
"""Return the Plex-provided identifier of this plex client."""
|
||||
return self._machine_identifier
|
||||
|
||||
@property
|
||||
|
@@ -94,9 +94,10 @@ class PlexServer:
|
||||
|
||||
def refresh_entity(self, machine_identifier, device, session):
|
||||
"""Forward refresh dispatch to media_player."""
|
||||
unique_id = f"{self.machine_identifier}:{machine_identifier}"
|
||||
dispatcher_send(
|
||||
self._hass,
|
||||
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL.format(machine_identifier),
|
||||
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL.format(unique_id),
|
||||
device,
|
||||
session,
|
||||
)
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "SAJ",
|
||||
"documentation": "https://www.home-assistant.io/integrations/saj",
|
||||
"requirements": [
|
||||
"pysaj==0.0.12"
|
||||
"pysaj==0.0.13"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
|
@@ -1,6 +1,8 @@
|
||||
"""Support for SNMP enabled switch."""
|
||||
import logging
|
||||
|
||||
from pyasn1.type.univ import Integer
|
||||
|
||||
import pysnmp.hlapi.asyncio as hlapi
|
||||
from pysnmp.hlapi.asyncio import (
|
||||
CommunityData,
|
||||
@@ -190,15 +192,20 @@ class SnmpSwitch(SwitchDevice):
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn on the switch."""
|
||||
await self._set(self._command_payload_on)
|
||||
if self._command_payload_on.isdigit():
|
||||
await self._set(Integer(self._command_payload_on))
|
||||
else:
|
||||
await self._set(self._command_payload_on)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn off the switch."""
|
||||
await self._set(self._command_payload_off)
|
||||
if self._command_payload_on.isdigit():
|
||||
await self._set(Integer(self._command_payload_off))
|
||||
else:
|
||||
await self._set(self._command_payload_off)
|
||||
|
||||
async def async_update(self):
|
||||
"""Update the state."""
|
||||
|
||||
errindication, errstatus, errindex, restable = await getCmd(
|
||||
*self._request_args, ObjectType(ObjectIdentity(self._baseoid))
|
||||
)
|
||||
@@ -215,8 +222,12 @@ class SnmpSwitch(SwitchDevice):
|
||||
for resrow in restable:
|
||||
if resrow[-1] == self._payload_on:
|
||||
self._state = True
|
||||
elif resrow[-1] == Integer(self._payload_on):
|
||||
self._state = True
|
||||
elif resrow[-1] == self._payload_off:
|
||||
self._state = False
|
||||
elif resrow[-1] == Integer(self._payload_off):
|
||||
self._state = False
|
||||
else:
|
||||
self._state = None
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "Songpal",
|
||||
"documentation": "https://www.home-assistant.io/integrations/songpal",
|
||||
"requirements": [
|
||||
"python-songpal==0.11.1"
|
||||
"python-songpal==0.11.2"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
|
@@ -8,6 +8,7 @@ import urllib
|
||||
|
||||
import async_timeout
|
||||
import pysonos
|
||||
from pysonos import alarms
|
||||
from pysonos.exceptions import SoCoException, SoCoUPnPException
|
||||
import pysonos.snapshot
|
||||
|
||||
@@ -1163,7 +1164,7 @@ class SonosEntity(MediaPlayerDevice):
|
||||
"""Set the alarm clock on the player."""
|
||||
|
||||
alarm = None
|
||||
for one_alarm in pysonos.alarms.get_alarms(self.soco):
|
||||
for one_alarm in alarms.get_alarms(self.soco):
|
||||
# pylint: disable=protected-access
|
||||
if one_alarm._alarm_id == str(data[ATTR_ALARM_ID]):
|
||||
alarm = one_alarm
|
||||
|
@@ -1,7 +1,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 101
|
||||
PATCH_VERSION = "0b4"
|
||||
PATCH_VERSION = "3"
|
||||
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
|
||||
REQUIRED_PYTHON_VER = (3, 6, 1)
|
||||
|
@@ -35,13 +35,25 @@ async def async_get_integration_with_requirements(
|
||||
This can raise IntegrationNotFound if manifest or integration
|
||||
is invalid, RequirementNotFound if there was some type of
|
||||
failure to install requirements.
|
||||
|
||||
Does not handle circular dependencies.
|
||||
"""
|
||||
integration = await async_get_integration(hass, domain)
|
||||
|
||||
if hass.config.skip_pip or not integration.requirements:
|
||||
if hass.config.skip_pip:
|
||||
return integration
|
||||
|
||||
await async_process_requirements(hass, integration.domain, integration.requirements)
|
||||
if integration.requirements:
|
||||
await async_process_requirements(
|
||||
hass, integration.domain, integration.requirements
|
||||
)
|
||||
|
||||
deps = integration.dependencies + (integration.after_dependencies or [])
|
||||
|
||||
if deps:
|
||||
await asyncio.gather(
|
||||
*[async_get_integration_with_requirements(hass, dep) for dep in deps]
|
||||
)
|
||||
|
||||
return integration
|
||||
|
||||
|
@@ -132,6 +132,17 @@ async def _async_setup_component(
|
||||
log_error(str(err))
|
||||
return False
|
||||
|
||||
# Some integrations fail on import because they call functions incorrectly.
|
||||
# So we do it before validating config to catch these errors.
|
||||
try:
|
||||
component = integration.get_component()
|
||||
except ImportError:
|
||||
log_error("Unable to import component", False)
|
||||
return False
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Setup failed for %s: unknown error", domain)
|
||||
return False
|
||||
|
||||
processed_config = await conf_util.async_process_component_config(
|
||||
hass, config, integration
|
||||
)
|
||||
@@ -143,12 +154,6 @@ async def _async_setup_component(
|
||||
start = timer()
|
||||
_LOGGER.info("Setting up %s", domain)
|
||||
|
||||
try:
|
||||
component = integration.get_component()
|
||||
except ImportError:
|
||||
log_error("Unable to import component", False)
|
||||
return False
|
||||
|
||||
if hasattr(component, "PLATFORM_SCHEMA"):
|
||||
# Entity components have their own warning
|
||||
warn_task = None
|
||||
|
@@ -456,7 +456,7 @@ enocean==0.50
|
||||
enturclient==0.2.0
|
||||
|
||||
# homeassistant.components.environment_canada
|
||||
env_canada==0.0.27
|
||||
env_canada==0.0.29
|
||||
|
||||
# homeassistant.components.envirophat
|
||||
# envirophat==0.0.6
|
||||
@@ -622,7 +622,7 @@ hass-nabucasa==0.22
|
||||
hbmqtt==0.9.5
|
||||
|
||||
# homeassistant.components.jewish_calendar
|
||||
hdate==0.9.1
|
||||
hdate==0.9.3
|
||||
|
||||
# homeassistant.components.heatmiser
|
||||
heatmiserV3==0.9.1
|
||||
@@ -1328,7 +1328,7 @@ pymsteams==0.1.12
|
||||
pymusiccast==0.1.6
|
||||
|
||||
# homeassistant.components.myq
|
||||
pymyq==2.0.0
|
||||
pymyq==2.0.1
|
||||
|
||||
# homeassistant.components.mysensors
|
||||
pymysensors==0.18.0
|
||||
@@ -1423,7 +1423,7 @@ pyrepetier==3.0.5
|
||||
pysabnzbd==1.1.0
|
||||
|
||||
# homeassistant.components.saj
|
||||
pysaj==0.0.12
|
||||
pysaj==0.0.13
|
||||
|
||||
# homeassistant.components.sony_projector
|
||||
pysdcp==1
|
||||
@@ -1564,7 +1564,7 @@ python-ripple-api==0.0.3
|
||||
python-sochain-api==0.0.2
|
||||
|
||||
# homeassistant.components.songpal
|
||||
python-songpal==0.11.1
|
||||
python-songpal==0.11.2
|
||||
|
||||
# homeassistant.components.synologydsm
|
||||
python-synology==0.2.0
|
||||
|
@@ -230,7 +230,7 @@ hass-nabucasa==0.22
|
||||
hbmqtt==0.9.5
|
||||
|
||||
# homeassistant.components.jewish_calendar
|
||||
hdate==0.9.1
|
||||
hdate==0.9.3
|
||||
|
||||
# homeassistant.components.here_travel_time
|
||||
herepy==0.6.3.1
|
||||
|
@@ -1,13 +1,19 @@
|
||||
"""Test reproduce state for Light."""
|
||||
from homeassistant.components.light.reproduce_state import DEPRECATION_WARNING
|
||||
from homeassistant.core import State
|
||||
|
||||
from tests.common import async_mock_service
|
||||
|
||||
VALID_BRIGHTNESS = {"brightness": 180}
|
||||
VALID_WHITE_VALUE = {"white_value": 200}
|
||||
VALID_FLASH = {"flash": "short"}
|
||||
VALID_EFFECT = {"effect": "random"}
|
||||
VALID_TRANSITION = {"transition": 15}
|
||||
VALID_COLOR_NAME = {"color_name": "red"}
|
||||
VALID_COLOR_TEMP = {"color_temp": 240}
|
||||
VALID_HS_COLOR = {"hs_color": (345, 75)}
|
||||
VALID_KELVIN = {"kelvin": 4000}
|
||||
VALID_PROFILE = {"profile": "relax"}
|
||||
VALID_RGB_COLOR = {"rgb_color": (255, 63, 111)}
|
||||
VALID_XY_COLOR = {"xy_color": (0.59, 0.274)}
|
||||
|
||||
@@ -17,9 +23,14 @@ async def test_reproducing_states(hass, caplog):
|
||||
hass.states.async_set("light.entity_off", "off", {})
|
||||
hass.states.async_set("light.entity_bright", "on", VALID_BRIGHTNESS)
|
||||
hass.states.async_set("light.entity_white", "on", VALID_WHITE_VALUE)
|
||||
hass.states.async_set("light.entity_flash", "on", VALID_FLASH)
|
||||
hass.states.async_set("light.entity_effect", "on", VALID_EFFECT)
|
||||
hass.states.async_set("light.entity_trans", "on", VALID_TRANSITION)
|
||||
hass.states.async_set("light.entity_name", "on", VALID_COLOR_NAME)
|
||||
hass.states.async_set("light.entity_temp", "on", VALID_COLOR_TEMP)
|
||||
hass.states.async_set("light.entity_hs", "on", VALID_HS_COLOR)
|
||||
hass.states.async_set("light.entity_kelvin", "on", VALID_KELVIN)
|
||||
hass.states.async_set("light.entity_profile", "on", VALID_PROFILE)
|
||||
hass.states.async_set("light.entity_rgb", "on", VALID_RGB_COLOR)
|
||||
hass.states.async_set("light.entity_xy", "on", VALID_XY_COLOR)
|
||||
|
||||
@@ -32,9 +43,14 @@ async def test_reproducing_states(hass, caplog):
|
||||
State("light.entity_off", "off"),
|
||||
State("light.entity_bright", "on", VALID_BRIGHTNESS),
|
||||
State("light.entity_white", "on", VALID_WHITE_VALUE),
|
||||
State("light.entity_flash", "on", VALID_FLASH),
|
||||
State("light.entity_effect", "on", VALID_EFFECT),
|
||||
State("light.entity_trans", "on", VALID_TRANSITION),
|
||||
State("light.entity_name", "on", VALID_COLOR_NAME),
|
||||
State("light.entity_temp", "on", VALID_COLOR_TEMP),
|
||||
State("light.entity_hs", "on", VALID_HS_COLOR),
|
||||
State("light.entity_kelvin", "on", VALID_KELVIN),
|
||||
State("light.entity_profile", "on", VALID_PROFILE),
|
||||
State("light.entity_rgb", "on", VALID_RGB_COLOR),
|
||||
State("light.entity_xy", "on", VALID_XY_COLOR),
|
||||
],
|
||||
@@ -59,16 +75,21 @@ async def test_reproducing_states(hass, caplog):
|
||||
State("light.entity_xy", "off"),
|
||||
State("light.entity_off", "on", VALID_BRIGHTNESS),
|
||||
State("light.entity_bright", "on", VALID_WHITE_VALUE),
|
||||
State("light.entity_white", "on", VALID_EFFECT),
|
||||
State("light.entity_effect", "on", VALID_COLOR_TEMP),
|
||||
State("light.entity_white", "on", VALID_FLASH),
|
||||
State("light.entity_flash", "on", VALID_EFFECT),
|
||||
State("light.entity_effect", "on", VALID_TRANSITION),
|
||||
State("light.entity_trans", "on", VALID_COLOR_NAME),
|
||||
State("light.entity_name", "on", VALID_COLOR_TEMP),
|
||||
State("light.entity_temp", "on", VALID_HS_COLOR),
|
||||
State("light.entity_hs", "on", VALID_RGB_COLOR),
|
||||
State("light.entity_hs", "on", VALID_KELVIN),
|
||||
State("light.entity_kelvin", "on", VALID_PROFILE),
|
||||
State("light.entity_profile", "on", VALID_RGB_COLOR),
|
||||
State("light.entity_rgb", "on", VALID_XY_COLOR),
|
||||
],
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(turn_on_calls) == 7
|
||||
assert len(turn_on_calls) == 12
|
||||
|
||||
expected_calls = []
|
||||
|
||||
@@ -80,22 +101,42 @@ async def test_reproducing_states(hass, caplog):
|
||||
expected_bright["entity_id"] = "light.entity_bright"
|
||||
expected_calls.append(expected_bright)
|
||||
|
||||
expected_white = VALID_EFFECT
|
||||
expected_white = VALID_FLASH
|
||||
expected_white["entity_id"] = "light.entity_white"
|
||||
expected_calls.append(expected_white)
|
||||
|
||||
expected_effect = VALID_COLOR_TEMP
|
||||
expected_flash = VALID_EFFECT
|
||||
expected_flash["entity_id"] = "light.entity_flash"
|
||||
expected_calls.append(expected_flash)
|
||||
|
||||
expected_effect = VALID_TRANSITION
|
||||
expected_effect["entity_id"] = "light.entity_effect"
|
||||
expected_calls.append(expected_effect)
|
||||
|
||||
expected_trans = VALID_COLOR_NAME
|
||||
expected_trans["entity_id"] = "light.entity_trans"
|
||||
expected_calls.append(expected_trans)
|
||||
|
||||
expected_name = VALID_COLOR_TEMP
|
||||
expected_name["entity_id"] = "light.entity_name"
|
||||
expected_calls.append(expected_name)
|
||||
|
||||
expected_temp = VALID_HS_COLOR
|
||||
expected_temp["entity_id"] = "light.entity_temp"
|
||||
expected_calls.append(expected_temp)
|
||||
|
||||
expected_hs = VALID_RGB_COLOR
|
||||
expected_hs = VALID_KELVIN
|
||||
expected_hs["entity_id"] = "light.entity_hs"
|
||||
expected_calls.append(expected_hs)
|
||||
|
||||
expected_kelvin = VALID_PROFILE
|
||||
expected_kelvin["entity_id"] = "light.entity_kelvin"
|
||||
expected_calls.append(expected_kelvin)
|
||||
|
||||
expected_profile = VALID_RGB_COLOR
|
||||
expected_profile["entity_id"] = "light.entity_profile"
|
||||
expected_calls.append(expected_profile)
|
||||
|
||||
expected_rgb = VALID_XY_COLOR
|
||||
expected_rgb["entity_id"] = "light.entity_rgb"
|
||||
expected_calls.append(expected_rgb)
|
||||
@@ -115,3 +156,14 @@ async def test_reproducing_states(hass, caplog):
|
||||
assert len(turn_off_calls) == 1
|
||||
assert turn_off_calls[0].domain == "light"
|
||||
assert turn_off_calls[0].data == {"entity_id": "light.entity_xy"}
|
||||
|
||||
|
||||
async def test_deprecation_warning(hass, caplog):
|
||||
"""Test deprecation warning."""
|
||||
hass.states.async_set("light.entity_off", "off", {})
|
||||
turn_on_calls = async_mock_service(hass, "light", "turn_on")
|
||||
await hass.helpers.state.async_reproduce_state(
|
||||
[State("light.entity_off", "on", {"brightness_pct": 80})], blocking=True
|
||||
)
|
||||
assert len(turn_on_calls) == 1
|
||||
assert DEPRECATION_WARNING in caplog.text
|
||||
|
@@ -112,7 +112,24 @@ async def test_install_missing_package(hass):
|
||||
async def test_get_integration_with_requirements(hass):
|
||||
"""Check getting an integration with loaded requirements."""
|
||||
hass.config.skip_pip = False
|
||||
mock_integration(hass, MockModule("test_component", requirements=["hello==1.0.0"]))
|
||||
mock_integration(
|
||||
hass, MockModule("test_component_dep", requirements=["test-comp-dep==1.0.0"])
|
||||
)
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test_component_after_dep", requirements=["test-comp-after-dep==1.0.0"]
|
||||
),
|
||||
)
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test_component",
|
||||
requirements=["test-comp==1.0.0"],
|
||||
dependencies=["test_component_dep"],
|
||||
partial_manifest={"after_dependencies": ["test_component_after_dep"]},
|
||||
),
|
||||
)
|
||||
|
||||
with patch(
|
||||
"homeassistant.util.package.is_installed", return_value=False
|
||||
@@ -126,8 +143,19 @@ async def test_get_integration_with_requirements(hass):
|
||||
assert integration
|
||||
assert integration.domain == "test_component"
|
||||
|
||||
assert len(mock_is_installed.mock_calls) == 1
|
||||
assert len(mock_inst.mock_calls) == 1
|
||||
assert len(mock_is_installed.mock_calls) == 3
|
||||
assert sorted(mock_call[1][0] for mock_call in mock_is_installed.mock_calls) == [
|
||||
"test-comp-after-dep==1.0.0",
|
||||
"test-comp-dep==1.0.0",
|
||||
"test-comp==1.0.0",
|
||||
]
|
||||
|
||||
assert len(mock_inst.mock_calls) == 3
|
||||
assert sorted(mock_call[1][0] for mock_call in mock_inst.mock_calls) == [
|
||||
"test-comp-after-dep==1.0.0",
|
||||
"test-comp-dep==1.0.0",
|
||||
"test-comp==1.0.0",
|
||||
]
|
||||
|
||||
|
||||
async def test_install_with_wheels_index(hass):
|
||||
|
@@ -527,3 +527,11 @@ async def test_when_setup_already_loaded(hass):
|
||||
setup.async_when_setup(hass, "test", mock_callback)
|
||||
await hass.async_block_till_done()
|
||||
assert calls == ["test", "test"]
|
||||
|
||||
|
||||
async def test_setup_import_blows_up(hass):
|
||||
"""Test that we handle it correctly when importing integration blows up."""
|
||||
with mock.patch(
|
||||
"homeassistant.loader.Integration.get_component", side_effect=ValueError
|
||||
):
|
||||
assert not await setup.async_setup_component(hass, "sun", {})
|
||||
|
Reference in New Issue
Block a user