mirror of
https://github.com/home-assistant/core.git
synced 2025-09-22 11:29:33 +00:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2d7208470e | ||
![]() |
7eceedea10 | ||
![]() |
8aee92347f | ||
![]() |
cf6d11db8d | ||
![]() |
c104efc18d | ||
![]() |
f021e5832a | ||
![]() |
070790ccc9 | ||
![]() |
0e2b55e60e | ||
![]() |
4a25bab1b3 | ||
![]() |
3cedee3fea | ||
![]() |
82ed84ba43 | ||
![]() |
c456b725fd | ||
![]() |
524f5a7264 | ||
![]() |
637a16799f | ||
![]() |
4df6b3c76a | ||
![]() |
05ee15c28c |
@@ -514,6 +514,7 @@ omit =
|
||||
homeassistant/components/plex/media_player.py
|
||||
homeassistant/components/plex/sensor.py
|
||||
homeassistant/components/plex/server.py
|
||||
homeassistant/components/plex/websockets.py
|
||||
homeassistant/components/plugwise/*
|
||||
homeassistant/components/plum_lightpad/*
|
||||
homeassistant/components/pocketcasts/sensor.py
|
||||
|
@@ -235,6 +235,7 @@ async def async_attach_trigger(hass, config, action, automation_info):
|
||||
event_id = deconz_event.serial
|
||||
|
||||
event_config = {
|
||||
event.CONF_PLATFORM: "event",
|
||||
event.CONF_EVENT_TYPE: CONF_DECONZ_EVENT,
|
||||
event.CONF_EVENT_DATA: {CONF_UNIQUE_ID: event_id, CONF_EVENT: trigger},
|
||||
}
|
||||
|
@@ -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,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
@@ -156,7 +156,11 @@ async def _async_get_device_automation_capabilities(hass, automation_type, autom
|
||||
# The device automation has no capabilities
|
||||
return {}
|
||||
|
||||
capabilities = await getattr(platform, function_name)(hass, automation)
|
||||
try:
|
||||
capabilities = await getattr(platform, function_name)(hass, automation)
|
||||
except InvalidDeviceAutomationConfig:
|
||||
return {}
|
||||
|
||||
capabilities = capabilities.copy()
|
||||
|
||||
extra_fields = capabilities.get("extra_fields")
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "Environment Canada",
|
||||
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
|
||||
"requirements": [
|
||||
"env_canada==0.0.25"
|
||||
"env_canada==0.0.27"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "Home Assistant Frontend",
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"requirements": [
|
||||
"home-assistant-frontend==20191023.0"
|
||||
"home-assistant-frontend==20191025.1"
|
||||
],
|
||||
"dependencies": [
|
||||
"api",
|
||||
|
@@ -167,7 +167,14 @@ def _init_header(
|
||||
|
||||
# filter flags
|
||||
for name, value in request.headers.items():
|
||||
if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_ENCODING):
|
||||
if name in (
|
||||
hdrs.CONTENT_LENGTH,
|
||||
hdrs.CONTENT_ENCODING,
|
||||
hdrs.SEC_WEBSOCKET_EXTENSIONS,
|
||||
hdrs.SEC_WEBSOCKET_PROTOCOL,
|
||||
hdrs.SEC_WEBSOCKET_VERSION,
|
||||
hdrs.SEC_WEBSOCKET_KEY,
|
||||
):
|
||||
continue
|
||||
headers[name] = value
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"name": "Microsoft",
|
||||
"documentation": "https://www.home-assistant.io/integrations/microsoft",
|
||||
"requirements": [
|
||||
"pycsspeechtts==1.0.2"
|
||||
"pycsspeechtts==1.0.3"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
|
@@ -14,6 +14,7 @@ CONF_RATE = "rate"
|
||||
CONF_VOLUME = "volume"
|
||||
CONF_PITCH = "pitch"
|
||||
CONF_CONTOUR = "contour"
|
||||
CONF_REGION = "region"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -72,6 +73,7 @@ DEFAULT_RATE = 0
|
||||
DEFAULT_VOLUME = 0
|
||||
DEFAULT_PITCH = "default"
|
||||
DEFAULT_CONTOUR = ""
|
||||
DEFAULT_REGION = "eastus"
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
@@ -87,6 +89,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
),
|
||||
vol.Optional(CONF_PITCH, default=DEFAULT_PITCH): cv.string,
|
||||
vol.Optional(CONF_CONTOUR, default=DEFAULT_CONTOUR): cv.string,
|
||||
vol.Optional(CONF_REGION, default=DEFAULT_REGION): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -102,13 +105,16 @@ def get_engine(hass, config):
|
||||
config[CONF_VOLUME],
|
||||
config[CONF_PITCH],
|
||||
config[CONF_CONTOUR],
|
||||
config[CONF_REGION],
|
||||
)
|
||||
|
||||
|
||||
class MicrosoftProvider(Provider):
|
||||
"""The Microsoft speech API provider."""
|
||||
|
||||
def __init__(self, apikey, lang, gender, ttype, rate, volume, pitch, contour):
|
||||
def __init__(
|
||||
self, apikey, lang, gender, ttype, rate, volume, pitch, contour, region
|
||||
):
|
||||
"""Init Microsoft TTS service."""
|
||||
self._apikey = apikey
|
||||
self._lang = lang
|
||||
@@ -119,6 +125,7 @@ class MicrosoftProvider(Provider):
|
||||
self._volume = f"{volume}%"
|
||||
self._pitch = pitch
|
||||
self._contour = contour
|
||||
self._region = region
|
||||
self.name = "Microsoft"
|
||||
|
||||
@property
|
||||
@@ -138,7 +145,7 @@ class MicrosoftProvider(Provider):
|
||||
from pycsspeechtts import pycsspeechtts
|
||||
|
||||
try:
|
||||
trans = pycsspeechtts.TTSTranslator(self._apikey)
|
||||
trans = pycsspeechtts.TTSTranslator(self._apikey, self._region)
|
||||
data = trans.speak(
|
||||
language=language,
|
||||
gender=self._gender,
|
||||
|
@@ -1,9 +1,9 @@
|
||||
"""Support to embed Plex."""
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import plexapi.exceptions
|
||||
from plexwebsocket import PlexWebsocket
|
||||
import requests.exceptions
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -16,9 +16,14 @@ from homeassistant.const import (
|
||||
CONF_TOKEN,
|
||||
CONF_URL,
|
||||
CONF_VERIFY_SSL,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
)
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
CONF_USE_EPISODE_ART,
|
||||
@@ -33,8 +38,9 @@ from .const import (
|
||||
PLATFORMS,
|
||||
PLEX_MEDIA_PLAYER_OPTIONS,
|
||||
PLEX_SERVER_CONFIG,
|
||||
REFRESH_LISTENERS,
|
||||
PLEX_UPDATE_PLATFORMS_SIGNAL,
|
||||
SERVERS,
|
||||
WEBSOCKETS,
|
||||
)
|
||||
from .server import PlexServer
|
||||
|
||||
@@ -67,9 +73,7 @@ _LOGGER = logging.getLogger(__package__)
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up the Plex component."""
|
||||
hass.data.setdefault(
|
||||
PLEX_DOMAIN, {SERVERS: {}, REFRESH_LISTENERS: {}, DISPATCHERS: {}}
|
||||
)
|
||||
hass.data.setdefault(PLEX_DOMAIN, {SERVERS: {}, DISPATCHERS: {}, WEBSOCKETS: {}})
|
||||
|
||||
plex_config = config.get(PLEX_DOMAIN, {})
|
||||
if plex_config:
|
||||
@@ -136,7 +140,6 @@ async def async_setup_entry(hass, entry):
|
||||
)
|
||||
server_id = plex_server.machine_identifier
|
||||
hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
|
||||
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id] = []
|
||||
|
||||
for platform in PLATFORMS:
|
||||
hass.async_create_task(
|
||||
@@ -145,9 +148,29 @@ async def async_setup_entry(hass, entry):
|
||||
|
||||
entry.add_update_listener(async_options_updated)
|
||||
|
||||
hass.data[PLEX_DOMAIN][REFRESH_LISTENERS][server_id] = async_track_time_interval(
|
||||
hass, lambda now: plex_server.update_platforms(), timedelta(seconds=10)
|
||||
unsub = async_dispatcher_connect(
|
||||
hass,
|
||||
PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id),
|
||||
plex_server.update_platforms,
|
||||
)
|
||||
hass.data[PLEX_DOMAIN][DISPATCHERS].setdefault(server_id, [])
|
||||
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)
|
||||
|
||||
def update_plex():
|
||||
async_dispatcher_send(hass, PLEX_UPDATE_PLATFORMS_SIGNAL.format(server_id))
|
||||
|
||||
session = async_get_clientsession(hass)
|
||||
websocket = PlexWebsocket(plex_server.plex_server, update_plex, session)
|
||||
hass.loop.create_task(websocket.listen())
|
||||
hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket
|
||||
|
||||
def close_websocket_session(_):
|
||||
websocket.close()
|
||||
|
||||
unsub = hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STOP, close_websocket_session
|
||||
)
|
||||
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)
|
||||
|
||||
return True
|
||||
|
||||
@@ -156,8 +179,8 @@ async def async_unload_entry(hass, entry):
|
||||
"""Unload a config entry."""
|
||||
server_id = entry.data[CONF_SERVER_IDENTIFIER]
|
||||
|
||||
cancel = hass.data[PLEX_DOMAIN][REFRESH_LISTENERS].pop(server_id)
|
||||
cancel()
|
||||
websocket = hass.data[PLEX_DOMAIN][WEBSOCKETS].pop(server_id)
|
||||
websocket.close()
|
||||
|
||||
dispatchers = hass.data[PLEX_DOMAIN][DISPATCHERS].pop(server_id)
|
||||
for unsub in dispatchers:
|
||||
|
@@ -10,8 +10,8 @@ DEFAULT_VERIFY_SSL = True
|
||||
|
||||
DISPATCHERS = "dispatchers"
|
||||
PLATFORMS = ["media_player", "sensor"]
|
||||
REFRESH_LISTENERS = "refresh_listeners"
|
||||
SERVERS = "servers"
|
||||
WEBSOCKETS = "websockets"
|
||||
|
||||
PLEX_CONFIG_FILE = "plex.conf"
|
||||
PLEX_MEDIA_PLAYER_OPTIONS = "plex_mp_options"
|
||||
@@ -19,6 +19,7 @@ PLEX_SERVER_CONFIG = "server_config"
|
||||
|
||||
PLEX_NEW_MP_SIGNAL = "plex_new_mp_signal.{}"
|
||||
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL = "plex_update_mp_signal.{}"
|
||||
PLEX_UPDATE_PLATFORMS_SIGNAL = "plex_update_platforms_signal.{}"
|
||||
PLEX_UPDATE_SENSOR_SIGNAL = "plex_update_sensor_signal.{}"
|
||||
|
||||
CONF_CLIENT_IDENTIFIER = "client_id"
|
||||
|
@@ -5,7 +5,8 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/plex",
|
||||
"requirements": [
|
||||
"plexapi==3.0.6",
|
||||
"plexauth==0.0.5"
|
||||
"plexauth==0.0.5",
|
||||
"plexwebsocket==0.0.3"
|
||||
],
|
||||
"dependencies": [
|
||||
"http"
|
||||
|
@@ -103,6 +103,8 @@ class PlexServer:
|
||||
|
||||
def update_platforms(self):
|
||||
"""Update the platform entities."""
|
||||
_LOGGER.debug("Updating devices")
|
||||
|
||||
available_clients = {}
|
||||
new_clients = set()
|
||||
|
||||
@@ -164,6 +166,11 @@ class PlexServer:
|
||||
sessions,
|
||||
)
|
||||
|
||||
@property
|
||||
def plex_server(self):
|
||||
"""Return the plexapi PlexServer instance."""
|
||||
return self._plex_server
|
||||
|
||||
@property
|
||||
def friendly_name(self):
|
||||
"""Return name of connected Plex server."""
|
||||
|
@@ -2,6 +2,9 @@
|
||||
from typing import Dict, List
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.device_automation.exceptions import (
|
||||
InvalidDeviceAutomationConfig,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
@@ -141,3 +144,27 @@ def async_condition_from_config(
|
||||
numeric_state_config[condition.CONF_BELOW] = config[CONF_BELOW]
|
||||
|
||||
return condition.async_numeric_state_from_config(numeric_state_config)
|
||||
|
||||
|
||||
async def async_get_condition_capabilities(hass, config):
|
||||
"""List condition capabilities."""
|
||||
state = hass.states.get(config[CONF_ENTITY_ID])
|
||||
unit_of_measurement = (
|
||||
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) if state else None
|
||||
)
|
||||
|
||||
if not state or not unit_of_measurement:
|
||||
raise InvalidDeviceAutomationConfig
|
||||
|
||||
return {
|
||||
"extra_fields": vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_ABOVE, description={"suffix": unit_of_measurement}
|
||||
): vol.Coerce(float),
|
||||
vol.Optional(
|
||||
CONF_BELOW, description={"suffix": unit_of_measurement}
|
||||
): vol.Coerce(float),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@@ -3,6 +3,9 @@ import voluptuous as vol
|
||||
|
||||
import homeassistant.components.automation.numeric_state as numeric_state_automation
|
||||
from homeassistant.components.device_automation import TRIGGER_BASE_SCHEMA
|
||||
from homeassistant.components.device_automation.exceptions import (
|
||||
InvalidDeviceAutomationConfig,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
@@ -146,9 +149,12 @@ async def async_get_trigger_capabilities(hass, config):
|
||||
"""List trigger capabilities."""
|
||||
state = hass.states.get(config[CONF_ENTITY_ID])
|
||||
unit_of_measurement = (
|
||||
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) if state else ""
|
||||
state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) if state else None
|
||||
)
|
||||
|
||||
if not state or not unit_of_measurement:
|
||||
raise InvalidDeviceAutomationConfig
|
||||
|
||||
return {
|
||||
"extra_fields": vol.Schema(
|
||||
{
|
||||
|
@@ -1,23 +1,12 @@
|
||||
"""Support for performing TensorFlow classification on images."""
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import io
|
||||
import voluptuous as vol
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
import cv2
|
||||
except ImportError:
|
||||
cv2 = None
|
||||
|
||||
try:
|
||||
# Verify that the TensorFlow Object Detection API is pre-installed
|
||||
import tensorflow as tf # noqa
|
||||
from object_detection.utils import label_map_util # noqa
|
||||
except ImportError:
|
||||
label_map_util = None
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.image_processing import (
|
||||
CONF_CONFIDENCE,
|
||||
@@ -98,8 +87,16 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
# append custom model path to sys.path
|
||||
sys.path.append(model_dir)
|
||||
|
||||
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
|
||||
if label_map_util is None:
|
||||
try:
|
||||
# Verify that the TensorFlow Object Detection API is pre-installed
|
||||
# pylint: disable=unused-import,unused-variable
|
||||
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
|
||||
# These imports shouldn't be moved to the top, because they depend on code from the model_dir.
|
||||
# (The model_dir is created during the manual setup process. See integration docs.)
|
||||
import tensorflow as tf # noqa
|
||||
from object_detection.utils import label_map_util # noqa
|
||||
except ImportError:
|
||||
# pylint: disable=line-too-long
|
||||
_LOGGER.error(
|
||||
"No TensorFlow Object Detection library found! Install or compile "
|
||||
"for your system following instructions here: "
|
||||
@@ -107,7 +104,11 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
) # noqa
|
||||
return
|
||||
|
||||
if cv2 is None:
|
||||
try:
|
||||
# Display warning that PIL will be used if no OpenCV is found.
|
||||
# pylint: disable=unused-import,unused-variable
|
||||
import cv2 # noqa
|
||||
except ImportError:
|
||||
_LOGGER.warning(
|
||||
"No OpenCV library found. TensorFlow will process image with "
|
||||
"PIL at reduced resolution"
|
||||
@@ -282,7 +283,13 @@ class TensorFlowImageProcessor(ImageProcessingEntity):
|
||||
def process_image(self, image):
|
||||
"""Process the image."""
|
||||
|
||||
if cv2 is None:
|
||||
try:
|
||||
import cv2 # pylint: disable=import-error
|
||||
|
||||
img = cv2.imdecode(np.asarray(bytearray(image)), cv2.IMREAD_UNCHANGED)
|
||||
inp = img[:, :, [2, 1, 0]] # BGR->RGB
|
||||
inp_expanded = inp.reshape(1, inp.shape[0], inp.shape[1], 3)
|
||||
except ImportError:
|
||||
img = Image.open(io.BytesIO(bytearray(image))).convert("RGB")
|
||||
img.thumbnail((460, 460), Image.ANTIALIAS)
|
||||
img_width, img_height = img.size
|
||||
@@ -292,10 +299,6 @@ class TensorFlowImageProcessor(ImageProcessingEntity):
|
||||
.astype(np.uint8)
|
||||
)
|
||||
inp_expanded = np.expand_dims(inp, axis=0)
|
||||
else:
|
||||
img = cv2.imdecode(np.asarray(bytearray(image)), cv2.IMREAD_UNCHANGED)
|
||||
inp = img[:, :, [2, 1, 0]] # BGR->RGB
|
||||
inp_expanded = inp.reshape(1, inp.shape[0], inp.shape[1], 3)
|
||||
|
||||
image_tensor = self._graph.get_tensor_by_name("image_tensor:0")
|
||||
boxes = self._graph.get_tensor_by_name("detection_boxes:0")
|
||||
|
@@ -1,7 +1,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 101
|
||||
PATCH_VERSION = "0b1"
|
||||
PATCH_VERSION = "0"
|
||||
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
|
||||
REQUIRED_PYTHON_VER = (3, 6, 1)
|
||||
|
@@ -11,7 +11,7 @@ contextvars==2.4;python_version<"3.7"
|
||||
cryptography==2.8
|
||||
distro==1.4.0
|
||||
hass-nabucasa==0.22
|
||||
home-assistant-frontend==20191023.0
|
||||
home-assistant-frontend==20191025.1
|
||||
importlib-metadata==0.23
|
||||
jinja2>=2.10.1
|
||||
netdisco==2.6.0
|
||||
|
@@ -456,7 +456,7 @@ enocean==0.50
|
||||
enturclient==0.2.0
|
||||
|
||||
# homeassistant.components.environment_canada
|
||||
env_canada==0.0.25
|
||||
env_canada==0.0.27
|
||||
|
||||
# homeassistant.components.envirophat
|
||||
# envirophat==0.0.6
|
||||
@@ -646,7 +646,7 @@ hole==0.5.0
|
||||
holidays==0.9.11
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20191023.0
|
||||
home-assistant-frontend==20191025.1
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.4
|
||||
@@ -973,6 +973,9 @@ plexapi==3.0.6
|
||||
# homeassistant.components.plex
|
||||
plexauth==0.0.5
|
||||
|
||||
# homeassistant.components.plex
|
||||
plexwebsocket==0.0.3
|
||||
|
||||
# homeassistant.components.plum_lightpad
|
||||
plumlightpad==0.0.11
|
||||
|
||||
@@ -1129,7 +1132,7 @@ pycomfoconnect==0.3
|
||||
pycoolmasternet==0.0.4
|
||||
|
||||
# homeassistant.components.microsoft
|
||||
pycsspeechtts==1.0.2
|
||||
pycsspeechtts==1.0.3
|
||||
|
||||
# homeassistant.components.cups
|
||||
# pycups==1.9.73
|
||||
|
@@ -242,7 +242,7 @@ hole==0.5.0
|
||||
holidays==0.9.11
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20191023.0
|
||||
home-assistant-frontend==20191025.1
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.4
|
||||
@@ -345,6 +345,9 @@ plexapi==3.0.6
|
||||
# homeassistant.components.plex
|
||||
plexauth==0.0.5
|
||||
|
||||
# homeassistant.components.plex
|
||||
plexwebsocket==0.0.3
|
||||
|
||||
# homeassistant.components.mhz19
|
||||
# homeassistant.components.serial_pm
|
||||
pmsensor==0.4
|
||||
|
@@ -14,6 +14,7 @@ from tests.common import (
|
||||
mock_device_registry,
|
||||
mock_registry,
|
||||
async_get_device_automations,
|
||||
async_get_device_automation_capabilities,
|
||||
)
|
||||
from tests.testing_config.custom_components.test.sensor import DEVICE_CLASSES
|
||||
|
||||
@@ -73,6 +74,86 @@ async def test_get_conditions(hass, device_reg, entity_reg):
|
||||
assert conditions == expected_conditions
|
||||
|
||||
|
||||
async def test_get_condition_capabilities(hass, device_reg, entity_reg):
|
||||
"""Test we get the expected capabilities from a sensor condition."""
|
||||
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||
platform.init()
|
||||
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_reg.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
)
|
||||
entity_reg.async_get_or_create(
|
||||
DOMAIN,
|
||||
"test",
|
||||
platform.ENTITIES["battery"].unique_id,
|
||||
device_id=device_entry.id,
|
||||
)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
||||
|
||||
expected_capabilities = {
|
||||
"extra_fields": [
|
||||
{
|
||||
"description": {"suffix": "%"},
|
||||
"name": "above",
|
||||
"optional": True,
|
||||
"type": "float",
|
||||
},
|
||||
{
|
||||
"description": {"suffix": "%"},
|
||||
"name": "below",
|
||||
"optional": True,
|
||||
"type": "float",
|
||||
},
|
||||
]
|
||||
}
|
||||
conditions = await async_get_device_automations(hass, "condition", device_entry.id)
|
||||
assert len(conditions) == 1
|
||||
for condition in conditions:
|
||||
capabilities = await async_get_device_automation_capabilities(
|
||||
hass, "condition", condition
|
||||
)
|
||||
assert capabilities == expected_capabilities
|
||||
|
||||
|
||||
async def test_get_condition_capabilities_none(hass, device_reg, entity_reg):
|
||||
"""Test we get the expected capabilities from a sensor condition."""
|
||||
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||
platform.init()
|
||||
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
||||
|
||||
conditions = [
|
||||
{
|
||||
"condition": "device",
|
||||
"device_id": "8770c43885354d5fa27604db6817f63f",
|
||||
"domain": "sensor",
|
||||
"entity_id": "sensor.beer",
|
||||
"type": "is_battery_level",
|
||||
},
|
||||
{
|
||||
"condition": "device",
|
||||
"device_id": "8770c43885354d5fa27604db6817f63f",
|
||||
"domain": "sensor",
|
||||
"entity_id": platform.ENTITIES["none"].entity_id,
|
||||
"type": "is_battery_level",
|
||||
},
|
||||
]
|
||||
|
||||
expected_capabilities = {}
|
||||
for condition in conditions:
|
||||
capabilities = await async_get_device_automation_capabilities(
|
||||
hass, "condition", condition
|
||||
)
|
||||
assert capabilities == expected_capabilities
|
||||
|
||||
|
||||
async def test_if_state_not_above_below(hass, calls, caplog):
|
||||
"""Test for bad value conditions."""
|
||||
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||
|
@@ -124,6 +124,41 @@ async def test_get_trigger_capabilities(hass, device_reg, entity_reg):
|
||||
assert capabilities == expected_capabilities
|
||||
|
||||
|
||||
async def test_get_trigger_capabilities_none(hass, device_reg, entity_reg):
|
||||
"""Test we get the expected capabilities from a sensor trigger."""
|
||||
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||
platform.init()
|
||||
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
||||
|
||||
triggers = [
|
||||
{
|
||||
"platform": "device",
|
||||
"device_id": "8770c43885354d5fa27604db6817f63f",
|
||||
"domain": "sensor",
|
||||
"entity_id": "sensor.beer",
|
||||
"type": "is_battery_level",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"device_id": "8770c43885354d5fa27604db6817f63f",
|
||||
"domain": "sensor",
|
||||
"entity_id": platform.ENTITIES["none"].entity_id,
|
||||
"type": "is_battery_level",
|
||||
},
|
||||
]
|
||||
|
||||
expected_capabilities = {}
|
||||
for trigger in triggers:
|
||||
capabilities = await async_get_device_automation_capabilities(
|
||||
hass, "trigger", trigger
|
||||
)
|
||||
assert capabilities == expected_capabilities
|
||||
|
||||
|
||||
async def test_if_fires_not_on_above_below(hass, calls, caplog):
|
||||
"""Test for value triggers firing."""
|
||||
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||
|
Reference in New Issue
Block a user