Compare commits

..

7 Commits

Author SHA1 Message Date
Paulus Schoutsen
d702b17a4f Bumped version to 0.97.0b3 2019-08-06 09:00:20 -07:00
Robert Svensson
27cfda11f7 UniFi - handle device not having a name (#25713)
* Handle device not having a name
2019-08-06 08:59:00 -07:00
Paulus Schoutsen
fee1568a85 Update HTTP defaults (#25702)
* Update HTTP defaults

* Fix tests
2019-08-06 08:58:59 -07:00
Paulus Schoutsen
eceef82ffa Add service to reload scenes from configuration.yaml (#25680)
* Allow reloading scenes

* Update requirements

* address comments

* fix typing

* fix tests

* Update homeassistant/components/homeassistant/scene.py

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Address comments
2019-08-06 08:57:54 -07:00
Jesse Rizzo
b011dd0b02 Bump envoy_reader to 0.8.6, fix missing dependency (#25679)
* Bump envoy_reader to 0.8.6, fix missing dependency

* Bump envoy_reader to 0.8.6, fix missing dependency
2019-08-06 08:56:22 -07:00
SukramJ
e1c23b1686 Add HmIP-SCI to Homematic IP Cloud, Fix HmIP-SWDM (#25639)
* Add HmIP-SCI to Homematic IP Cloud

* Bump upstream dependency

* Fix HmIP-SWDM
2019-08-06 08:56:21 -07:00
Paulus Schoutsen
387323a8c1 Updated frontend to 20190805.0 2019-08-05 22:32:18 -07:00
21 changed files with 204 additions and 79 deletions

View File

@@ -3,7 +3,7 @@
"name": "Enphase envoy",
"documentation": "https://www.home-assistant.io/components/enphase_envoy",
"requirements": [
"envoy_reader==0.8"
"envoy_reader==0.8.6"
],
"dependencies": [],
"codeowners": []

View File

@@ -3,7 +3,7 @@
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/components/frontend",
"requirements": [
"home-assistant-frontend==20190804.0"
"home-assistant-frontend==20190805.0"
],
"dependencies": [
"api",

View File

@@ -1,5 +1,6 @@
"""Allow users to set and activate scenes."""
from collections import namedtuple
import logging
import voluptuous as vol
@@ -11,12 +12,19 @@ from homeassistant.const import (
CONF_PLATFORM,
STATE_OFF,
STATE_ON,
SERVICE_RELOAD,
)
from homeassistant.core import State, DOMAIN
from homeassistant import config as conf_util
from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import async_get_integration
from homeassistant.helpers import (
config_per_platform,
config_validation as cv,
entity_platform,
)
from homeassistant.core import State
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.state import HASS_DOMAIN, async_reproduce_state
from homeassistant.components.scene import STATES, Scene
from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN, STATES, Scene
PLATFORM_SCHEMA = vol.Schema(
{
@@ -37,19 +45,63 @@ PLATFORM_SCHEMA = vol.Schema(
)
SCENECONFIG = namedtuple("SceneConfig", [CONF_NAME, STATES])
_LOGGER = logging.getLogger(__name__)
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up home assistant scene entries."""
scene_config = config.get(STATES)
_process_scenes_config(hass, async_add_entities, config)
# This platform can be loaded multiple times. Only first time register the service.
if hass.services.has_service(SCENE_DOMAIN, SERVICE_RELOAD):
return
# Store platform for later.
platform = entity_platform.current_platform.get()
async def reload_config(call):
"""Reload the scene config."""
try:
conf = await conf_util.async_hass_config_yaml(hass)
except HomeAssistantError as err:
_LOGGER.error(err)
return
integration = await async_get_integration(hass, SCENE_DOMAIN)
conf = await conf_util.async_process_component_config(hass, conf, integration)
if not conf or not platform:
return
await platform.async_reset()
# Extract only the config for the Home Assistant platform, ignore the rest.
for p_type, p_config in config_per_platform(conf, SCENE_DOMAIN):
if p_type != DOMAIN:
continue
_process_scenes_config(hass, async_add_entities, p_config)
hass.helpers.service.async_register_admin_service(
SCENE_DOMAIN, SERVICE_RELOAD, reload_config
)
def _process_scenes_config(hass, async_add_entities, config):
"""Process multiple scenes and add them."""
scene_config = config[STATES]
# Check empty list
if not scene_config:
return
async_add_entities(
HomeAssistantScene(hass, _process_config(scene)) for scene in scene_config
HomeAssistantScene(hass, _process_scene_config(scene)) for scene in scene_config
)
return True
def _process_config(scene_config):
def _process_scene_config(scene_config):
"""Process passed in config into a format to work with.
Async friendly.

View File

@@ -2,6 +2,7 @@
import logging
from homematicip.aio.device import (
AsyncContactInterface,
AsyncDevice,
AsyncFullFlushContactInterface,
AsyncMotionDetectorIndoor,
@@ -10,6 +11,7 @@ from homematicip.aio.device import (
AsyncPresenceDetectorIndoor,
AsyncRotaryHandleSensor,
AsyncShutterContact,
AsyncShutterContactMagnetic,
AsyncSmokeDetector,
AsyncWaterSensor,
AsyncWeatherSensor,
@@ -63,9 +65,12 @@ async def async_setup_entry(
home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home
devices = []
for device in home.devices:
if isinstance(device, AsyncFullFlushContactInterface):
if isinstance(device, (AsyncContactInterface, AsyncFullFlushContactInterface)):
devices.append(HomematicipContactInterface(home, device))
if isinstance(device, (AsyncShutterContact, AsyncRotaryHandleSensor)):
if isinstance(
device,
(AsyncShutterContact, AsyncShutterContactMagnetic, AsyncRotaryHandleSensor),
):
devices.append(HomematicipShutterContact(home, device))
if isinstance(
device,

View File

@@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/homematicip_cloud",
"requirements": [
"homematicip==0.10.9"
"homematicip==0.10.10"
],
"dependencies": [],
"codeowners": []

View File

@@ -51,6 +51,8 @@ _LOGGER = logging.getLogger(__name__)
DEFAULT_SERVER_HOST = "0.0.0.0"
DEFAULT_DEVELOPMENT = "0"
# To be able to load custom cards.
DEFAULT_CORS = "https://cast.home-assistant.io"
NO_LOGIN_ATTEMPT_THRESHOLD = -1
@@ -91,7 +93,7 @@ HTTP_SCHEMA = vol.Schema(
vol.Optional(CONF_SSL_CERTIFICATE): cv.isfile,
vol.Optional(CONF_SSL_PEER_CERTIFICATE): cv.isfile,
vol.Optional(CONF_SSL_KEY): cv.isfile,
vol.Optional(CONF_CORS_ORIGINS, default=[]): vol.All(
vol.Optional(CONF_CORS_ORIGINS, default=[DEFAULT_CORS]): vol.All(
cv.ensure_list, [cv.string]
),
vol.Inclusive(CONF_USE_X_FORWARDED_FOR, "proxy"): cv.boolean,

View File

@@ -45,6 +45,9 @@ def setup_cors(app, origins):
path = path.canonical
if path.startswith("/api/hassio_ingress/"):
return
if path in cors_added:
return

View File

@@ -5,6 +5,7 @@ import logging
import voluptuous as vol
from homeassistant.core import DOMAIN as HA_DOMAIN
from homeassistant.const import CONF_PLATFORM, SERVICE_TURN_ON
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
from homeassistant.helpers.entity import Entity
@@ -60,6 +61,10 @@ async def async_setup(hass, config):
component = hass.data[DOMAIN] = EntityComponent(logger, DOMAIN, hass)
await component.async_setup(config)
# Ensure Home Assistant platform always loaded.
await component.async_setup_platform(
HA_DOMAIN, {"platform": "homeasistant", STATES: []}
)
async def async_handle_scene_service(service):
"""Handle calls to the switch services."""

View File

@@ -188,7 +188,9 @@ def update_items(controller, async_add_entities, tracked):
tracked[client_id] = UniFiClientTracker(client, controller)
new_tracked.append(tracked[client_id])
LOGGER.debug(
"New UniFi client tracker %s (%s)", client.hostname, client.mac
"New UniFi client tracker %s (%s)",
client.name or client.hostname,
client.mac,
)
if not controller.unifi_config.get(CONF_DONT_TRACK_DEVICES, False):
@@ -208,7 +210,11 @@ def update_items(controller, async_add_entities, tracked):
tracked[device_id] = UniFiDeviceTracker(device, controller)
new_tracked.append(tracked[device_id])
LOGGER.debug("New UniFi device tracker %s (%s)", device.name, device.mac)
LOGGER.debug(
"New UniFi device tracker %s (%s)",
device.name or device.model,
device.mac,
)
if new_tracked:
async_add_entities(new_tracked)
@@ -311,7 +317,7 @@ class UniFiDeviceTracker(ScannerEntity):
@property
def name(self) -> str:
"""Return the name of the device."""
return self.device.name
return self.device.name or self.device.model
@property
def unique_id(self) -> str:
@@ -326,14 +332,18 @@ class UniFiDeviceTracker(ScannerEntity):
@property
def device_info(self):
"""Return a device description for device registry."""
return {
info = {
"connections": {(CONNECTION_NETWORK_MAC, self.device.mac)},
"manufacturer": ATTR_MANUFACTURER,
"model": self.device.model,
"name": self.device.name,
"sw_version": self.device.version,
}
if self.device.name:
info["name"] = self.device.name
return info
@property
def device_state_attributes(self):
"""Return the device state attributes."""

View File

@@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/unifi",
"requirements": [
"aiounifi==9"
"aiounifi==10"
],
"dependencies": [],
"codeowners": [

View File

@@ -2,7 +2,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 97
PATCH_VERSION = "0b2"
PATCH_VERSION = "0b3"
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 6, 0)

View File

@@ -114,7 +114,7 @@ class EntityComponent:
# Look in config for Domain, Domain 2, Domain 3 etc and load them
tasks = []
for p_type, p_config in config_per_platform(config, self.domain):
tasks.append(self._async_setup_platform(p_type, p_config))
tasks.append(self.async_setup_platform(p_type, p_config))
if tasks:
await asyncio.wait(tasks)
@@ -123,7 +123,7 @@ class EntityComponent:
# Refer to: homeassistant.components.discovery.load_platform()
async def component_platform_discovered(platform, info):
"""Handle the loading of a platform."""
await self._async_setup_platform(platform, {}, info)
await self.async_setup_platform(platform, {}, info)
discovery.async_listen_platform(
self.hass, self.domain, component_platform_discovered
@@ -212,10 +212,13 @@ class EntityComponent:
self.hass.services.async_register(self.domain, name, handle_service, schema)
async def _async_setup_platform(
async def async_setup_platform(
self, platform_type, platform_config, discovery_info=None
):
"""Set up a platform for this component."""
if self.config is None:
raise RuntimeError("async_setup needs to be called first")
platform = await async_prepare_setup_platform(
self.hass, self.config, self.domain, platform_type
)

View File

@@ -1,5 +1,7 @@
"""Class to manage the entities for a single platform."""
import asyncio
from contextvars import ContextVar
from typing import Optional
from homeassistant.const import DEVICE_DEFAULT_NAME
from homeassistant.core import callback, valid_entity_id, split_entity_id
@@ -127,6 +129,7 @@ class EntityPlatform:
async_create_setup_task creates a coroutine that sets up platform.
"""
current_platform.set(self)
logger = self.logger
hass = self.hass
full_name = "{}.{}".format(self.domain, self.platform_name)
@@ -457,3 +460,8 @@ class EntityPlatform:
if tasks:
await asyncio.wait(tasks)
current_platform: ContextVar[Optional[EntityPlatform]] = ContextVar(
"current_platform", default=None
)

View File

@@ -7,10 +7,11 @@ async_timeout==3.0.1
attrs==19.1.0
bcrypt==3.1.7
certifi>=2019.6.16
contextvars==2.4;python_version<"3.7"
cryptography==2.7
distro==1.4.0
hass-nabucasa==0.16
home-assistant-frontend==20190804.0
home-assistant-frontend==20190805.0
importlib-metadata==0.18
jinja2>=2.10.1
netdisco==2.6.0

View File

@@ -5,6 +5,7 @@ async_timeout==3.0.1
attrs==19.1.0
bcrypt==3.1.7
certifi>=2019.6.16
contextvars==2.4;python_version<"3.7"
importlib-metadata==0.18
jinja2>=2.10.1
PyJWT==1.7.1
@@ -169,7 +170,7 @@ aiopvapi==1.6.14
aioswitcher==2019.4.26
# homeassistant.components.unifi
aiounifi==9
aiounifi==10
# homeassistant.components.wwlln
aiowwlln==1.0.0
@@ -442,7 +443,7 @@ env_canada==0.0.20
# envirophat==0.0.6
# homeassistant.components.enphase_envoy
envoy_reader==0.8
envoy_reader==0.8.6
# homeassistant.components.season
ephem==3.7.6.0
@@ -622,7 +623,7 @@ hole==0.3.0
holidays==0.9.11
# homeassistant.components.frontend
home-assistant-frontend==20190804.0
home-assistant-frontend==20190805.0
# homeassistant.components.zwave
homeassistant-pyozw==0.1.4
@@ -631,7 +632,7 @@ homeassistant-pyozw==0.1.4
homekit[IP]==0.15.0
# homeassistant.components.homematicip_cloud
homematicip==0.10.9
homematicip==0.10.10
# homeassistant.components.horizon
horimote==0.4.1

View File

@@ -68,7 +68,7 @@ aionotion==1.1.0
aioswitcher==2019.4.26
# homeassistant.components.unifi
aiounifi==9
aiounifi==10
# homeassistant.components.wwlln
aiowwlln==1.0.0
@@ -169,13 +169,13 @@ hdate==0.8.8
holidays==0.9.11
# homeassistant.components.frontend
home-assistant-frontend==20190804.0
home-assistant-frontend==20190805.0
# homeassistant.components.homekit_controller
homekit[IP]==0.15.0
# homeassistant.components.homematicip_cloud
homematicip==0.10.9
homematicip==0.10.10
# homeassistant.components.google
# homeassistant.components.remember_the_milk

View File

@@ -5,55 +5,55 @@ from setuptools import setup, find_packages
import homeassistant.const as hass_const
PROJECT_NAME = 'Home Assistant'
PROJECT_PACKAGE_NAME = 'homeassistant'
PROJECT_LICENSE = 'Apache License 2.0'
PROJECT_AUTHOR = 'The Home Assistant Authors'
PROJECT_COPYRIGHT = ' 2013-{}, {}'.format(dt.now().year, PROJECT_AUTHOR)
PROJECT_URL = 'https://home-assistant.io/'
PROJECT_EMAIL = 'hello@home-assistant.io'
PROJECT_NAME = "Home Assistant"
PROJECT_PACKAGE_NAME = "homeassistant"
PROJECT_LICENSE = "Apache License 2.0"
PROJECT_AUTHOR = "The Home Assistant Authors"
PROJECT_COPYRIGHT = " 2013-{}, {}".format(dt.now().year, PROJECT_AUTHOR)
PROJECT_URL = "https://home-assistant.io/"
PROJECT_EMAIL = "hello@home-assistant.io"
PROJECT_GITHUB_USERNAME = 'home-assistant'
PROJECT_GITHUB_REPOSITORY = 'home-assistant'
PROJECT_GITHUB_USERNAME = "home-assistant"
PROJECT_GITHUB_REPOSITORY = "home-assistant"
PYPI_URL = 'https://pypi.python.org/pypi/{}'.format(PROJECT_PACKAGE_NAME)
GITHUB_PATH = '{}/{}'.format(
PROJECT_GITHUB_USERNAME, PROJECT_GITHUB_REPOSITORY)
GITHUB_URL = 'https://github.com/{}'.format(GITHUB_PATH)
PYPI_URL = "https://pypi.python.org/pypi/{}".format(PROJECT_PACKAGE_NAME)
GITHUB_PATH = "{}/{}".format(PROJECT_GITHUB_USERNAME, PROJECT_GITHUB_REPOSITORY)
GITHUB_URL = "https://github.com/{}".format(GITHUB_PATH)
DOWNLOAD_URL = '{}/archive/{}.zip'.format(GITHUB_URL, hass_const.__version__)
DOWNLOAD_URL = "{}/archive/{}.zip".format(GITHUB_URL, hass_const.__version__)
PROJECT_URLS = {
'Bug Reports': '{}/issues'.format(GITHUB_URL),
'Dev Docs': 'https://developers.home-assistant.io/',
'Discord': 'https://discordapp.com/invite/c5DvZ4e',
'Forum': 'https://community.home-assistant.io/',
"Bug Reports": "{}/issues".format(GITHUB_URL),
"Dev Docs": "https://developers.home-assistant.io/",
"Discord": "https://discordapp.com/invite/c5DvZ4e",
"Forum": "https://community.home-assistant.io/",
}
PACKAGES = find_packages(exclude=['tests', 'tests.*'])
PACKAGES = find_packages(exclude=["tests", "tests.*"])
REQUIRES = [
'aiohttp==3.5.4',
'astral==1.10.1',
'async_timeout==3.0.1',
'attrs==19.1.0',
'bcrypt==3.1.7',
'certifi>=2019.6.16',
'importlib-metadata==0.18',
'jinja2>=2.10.1',
'PyJWT==1.7.1',
"aiohttp==3.5.4",
"astral==1.10.1",
"async_timeout==3.0.1",
"attrs==19.1.0",
"bcrypt==3.1.7",
"certifi>=2019.6.16",
'contextvars==2.4;python_version<"3.7"',
"importlib-metadata==0.18",
"jinja2>=2.10.1",
"PyJWT==1.7.1",
# PyJWT has loose dependency. We want the latest one.
'cryptography==2.7',
'pip>=8.0.3',
'python-slugify==3.0.2',
'pytz>=2019.01',
'pyyaml==5.1.1',
'requests==2.22.0',
'ruamel.yaml==0.15.99',
'voluptuous==0.11.5',
'voluptuous-serialize==2.1.0',
"cryptography==2.7",
"pip>=8.0.3",
"python-slugify==3.0.2",
"pytz>=2019.01",
"pyyaml==5.1.1",
"requests==2.22.0",
"ruamel.yaml==0.15.99",
"voluptuous==0.11.5",
"voluptuous-serialize==2.1.0",
]
MIN_PY_VERSION = '.'.join(map(str, hass_const.REQUIRED_PYTHON_VER))
MIN_PY_VERSION = ".".join(map(str, hass_const.REQUIRED_PYTHON_VER))
setup(
name=PROJECT_PACKAGE_NAME,
@@ -67,11 +67,7 @@ setup(
include_package_data=True,
zip_safe=False,
install_requires=REQUIRES,
python_requires='>={}'.format(MIN_PY_VERSION),
test_suite='tests',
entry_points={
'console_scripts': [
'hass = homeassistant.__main__:main'
]
},
python_requires=">={}".format(MIN_PY_VERSION),
test_suite="tests",
entry_points={"console_scripts": ["hass = homeassistant.__main__:main"]},
)

View File

@@ -0,0 +1,30 @@
"""Test Home Assistant scenes."""
from unittest.mock import patch
from homeassistant.setup import async_setup_component
async def test_reload_config_service(hass):
"""Test the reload config service."""
assert await async_setup_component(hass, "scene", {})
with patch(
"homeassistant.config.load_yaml_config_file",
autospec=True,
return_value={"scene": {"name": "Hallo", "entities": {"light.kitchen": "on"}}},
), patch("homeassistant.config.find_config_file", return_value=""):
await hass.services.async_call("scene", "reload", blocking=True)
await hass.async_block_till_done()
assert hass.states.get("scene.hallo") is not None
with patch(
"homeassistant.config.load_yaml_config_file",
autospec=True,
return_value={"scene": {"name": "Bye", "entities": {"light.kitchen": "on"}}},
), patch("homeassistant.config.find_config_file", return_value=""):
await hass.services.async_call("scene", "reload", blocking=True)
await hass.async_block_till_done()
assert hass.states.get("scene.hallo") is None
assert hass.states.get("scene.bye") is not None

View File

@@ -232,3 +232,12 @@ async def test_ssl_profile_change_modern(hass):
await hass.async_block_till_done()
assert len(mock_context.mock_calls) == 1
async def test_cors_defaults(hass):
"""Test the CORS default settings."""
with patch("homeassistant.components.http.setup_cors") as mock_setup:
assert await async_setup_component(hass, "http", {})
assert len(mock_setup.mock_calls) == 1
assert mock_setup.mock_calls[0][1][1] == ["https://cast.home-assistant.io"]

View File

@@ -116,7 +116,7 @@ async def test_setup_recovers_when_setup_raises(hass):
@asynctest.patch(
"homeassistant.helpers.entity_component.EntityComponent" "._async_setup_platform",
"homeassistant.helpers.entity_component.EntityComponent" ".async_setup_platform",
return_value=mock_coro(),
)
@asynctest.patch(

View File

@@ -103,7 +103,7 @@ def test_secrets(isfile_patch, loop):
assert res["components"].keys() == {"homeassistant", "http"}
assert res["components"]["http"] == {
"api_password": "abc123",
"cors_allowed_origins": [],
"cors_allowed_origins": ["https://cast.home-assistant.io"],
"ip_ban_enabled": True,
"login_attempts_threshold": -1,
"server_host": "0.0.0.0",