Compare commits

..

10 Commits

Author SHA1 Message Date
Paulus Schoutsen
88e3e73bb4 Merge pull request #32964 from home-assistant/rc
0.107.1
2020-03-18 22:14:25 -07:00
Paulus Schoutsen
3aa1bcbb77 Fix mobile app test 2020-03-18 22:13:49 -07:00
Paulus Schoutsen
f973b35cef Bumped version to 0.107.1 2020-03-18 18:19:33 -07:00
Paulus Schoutsen
4e08aa8b05 Fix zone config (#32963)
* Fix zone config

* Add zone as dependency again to device tracker

* Fix tests
2020-03-18 18:18:57 -07:00
Paulus Schoutsen
8e917ccf73 Add device automation as frontend dependency (#32962) 2020-03-18 18:17:11 -07:00
Bram Kragten
0b62011626 Updated frontend to 20200318.1 (#32957) 2020-03-18 18:17:11 -07:00
Franck Nijhof
d520a02b8c Merge pull request #32932 from home-assistant/rc
0.107.0
2020-03-18 15:35:44 +01:00
SukramJ
1e469b39ad Fix flaky tests for HMIPC (#32806) 2020-03-18 14:44:29 +01:00
Franck Nijhof
c2f615839d Bumped version to 0.107.0 2020-03-18 13:31:02 +01:00
Bram Kragten
657bf33e32 Updated frontend to 20200318.0 (#32931) 2020-03-18 13:27:21 +01:00
16 changed files with 121 additions and 69 deletions

View File

@@ -3,8 +3,8 @@
"name": "Device Tracker",
"documentation": "https://www.home-assistant.io/integrations/device_tracker",
"requirements": [],
"dependencies": [],
"after_dependencies": ["zone"],
"dependencies": ["zone"],
"after_dependencies": [],
"codeowners": [],
"quality_scale": "internal"
}

View File

@@ -3,11 +3,12 @@
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": [
"home-assistant-frontend==20200316.1"
"home-assistant-frontend==20200318.1"
],
"dependencies": [
"api",
"auth",
"device_automation",
"http",
"lovelace",
"onboarding",
@@ -19,4 +20,4 @@
"@home-assistant/frontend"
],
"quality_scale": "internal"
}
}

View File

@@ -1,6 +1,6 @@
"""Support for the definition of zones."""
import logging
from typing import Dict, Optional, cast
from typing import Any, Dict, Optional, cast
import voluptuous as vol
@@ -18,6 +18,7 @@ from homeassistant.const import (
CONF_RADIUS,
EVENT_CORE_CONFIG_UPDATE,
SERVICE_RELOAD,
STATE_UNAVAILABLE,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall, State, callback
from homeassistant.helpers import (
@@ -65,8 +66,20 @@ UPDATE_FIELDS = {
}
def empty_value(value: Any) -> Any:
"""Test if the user has the default config value from adding "zone:"."""
if isinstance(value, dict) and len(value) == 0:
return []
raise vol.Invalid("Not a default value")
CONFIG_SCHEMA = vol.Schema(
{vol.Optional(DOMAIN): vol.All(cv.ensure_list, [vol.Schema(CREATE_FIELDS)])},
{
vol.Optional(DOMAIN, default=[]): vol.Any(
vol.All(cv.ensure_list, [vol.Schema(CREATE_FIELDS)]), empty_value,
)
},
extra=vol.ALLOW_EXTRA,
)
@@ -93,7 +106,7 @@ def async_active_zone(
closest = None
for zone in zones:
if zone.attributes.get(ATTR_PASSIVE):
if zone.state == STATE_UNAVAILABLE or zone.attributes.get(ATTR_PASSIVE):
continue
zone_dist = distance(
@@ -126,6 +139,9 @@ def in_zone(zone: State, latitude: float, longitude: float, radius: float = 0) -
Async friendly.
"""
if zone.state == STATE_UNAVAILABLE:
return False
zone_dist = distance(
latitude,
longitude,
@@ -180,7 +196,7 @@ async def async_setup(hass: HomeAssistant, config: Dict) -> bool:
component, storage_collection, lambda conf: Zone(conf, True)
)
if DOMAIN in config:
if config[DOMAIN]:
await yaml_collection.async_load(config[DOMAIN])
await storage_collection.async_load()
@@ -206,7 +222,7 @@ async def async_setup(hass: HomeAssistant, config: Dict) -> bool:
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
return
await yaml_collection.async_load(conf.get(DOMAIN, []))
await yaml_collection.async_load(conf[DOMAIN])
service.async_register_admin_service(
hass,

View File

@@ -1,7 +1,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 107
PATCH_VERSION = "0b8"
PATCH_VERSION = "1"
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__ = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER = (3, 7, 0)

View File

@@ -12,7 +12,7 @@ cryptography==2.8
defusedxml==0.6.0
distro==1.4.0
hass-nabucasa==0.32.2
home-assistant-frontend==20200316.1
home-assistant-frontend==20200318.1
importlib-metadata==1.5.0
jinja2>=2.10.3
netdisco==2.6.0

View File

@@ -696,7 +696,7 @@ hole==0.5.0
holidays==0.10.1
# homeassistant.components.frontend
home-assistant-frontend==20200316.1
home-assistant-frontend==20200318.1
# homeassistant.components.zwave
homeassistant-pyozw==0.1.9

View File

@@ -263,7 +263,7 @@ hole==0.5.0
holidays==0.10.1
# homeassistant.components.frontend
home-assistant-frontend==20200316.1
home-assistant-frontend==20200318.1
# homeassistant.components.zwave
homeassistant-pyozw==0.1.9

View File

@@ -1,5 +1,5 @@
"""Initializer helpers for HomematicIP fake server."""
from asynctest import CoroutineMock, MagicMock, Mock
from asynctest import CoroutineMock, MagicMock, Mock, patch
from homematicip.aio.auth import AsyncAuth
from homematicip.aio.connection import AsyncConnection
from homematicip.aio.home import AsyncHome
@@ -106,9 +106,10 @@ async def mock_hap_with_service_fixture(
@pytest.fixture(name="simple_mock_home")
def simple_mock_home_fixture() -> AsyncHome:
"""Return a simple AsyncHome Mock."""
return Mock(
def simple_mock_home_fixture():
"""Return a simple mocked connection."""
mock_home = Mock(
spec=AsyncHome,
name="Demo",
devices=[],
@@ -120,6 +121,27 @@ def simple_mock_home_fixture() -> AsyncHome:
connected=True,
)
with patch(
"homeassistant.components.homematicip_cloud.hap.AsyncHome",
autospec=True,
return_value=mock_home,
):
yield
@pytest.fixture(name="mock_connection_init")
def mock_connection_init_fixture():
"""Return a simple mocked connection."""
with patch(
"homeassistant.components.homematicip_cloud.hap.AsyncHome.init",
return_value=None,
), patch(
"homeassistant.components.homematicip_cloud.hap.AsyncAuth.init",
return_value=None,
):
yield
@pytest.fixture(name="simple_mock_auth")
def simple_mock_auth_fixture() -> AsyncAuth:

View File

@@ -16,12 +16,15 @@ DEFAULT_CONFIG = {HMIPC_HAPID: "ABC123", HMIPC_PIN: "123", HMIPC_NAME: "hmip"}
IMPORT_CONFIG = {HMIPC_HAPID: "ABC123", HMIPC_AUTHTOKEN: "123", HMIPC_NAME: "hmip"}
async def test_flow_works(hass):
async def test_flow_works(hass, simple_mock_home):
"""Test config flow."""
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=False,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.get_auth",
return_value=True,
):
result = await hass.config_entries.flow.async_init(
HMIPC_DOMAIN, context={"source": "user"}, data=DEFAULT_CONFIG
@@ -137,7 +140,7 @@ async def test_init_already_configured(hass):
assert result["reason"] == "already_configured"
async def test_import_config(hass):
async def test_import_config(hass, simple_mock_home):
"""Test importing a host with an existing config file."""
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",

View File

@@ -125,14 +125,11 @@ async def test_hap_create(hass, hmip_config_entry, simple_mock_home):
hass.config.components.add(HMIPC_DOMAIN)
hap = HomematicipHAP(hass, hmip_config_entry)
assert hap
with patch(
"homeassistant.components.homematicip_cloud.hap.AsyncHome",
return_value=simple_mock_home,
), patch.object(hap, "async_connect"):
with patch.object(hap, "async_connect"):
assert await hap.async_setup()
async def test_hap_create_exception(hass, hmip_config_entry):
async def test_hap_create_exception(hass, hmip_config_entry, mock_connection_init):
"""Mock AsyncHome to execute get_hap."""
hass.config.components.add(HMIPC_DOMAIN)

View File

@@ -24,7 +24,9 @@ from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
async def test_config_with_accesspoint_passed_to_config_entry(hass):
async def test_config_with_accesspoint_passed_to_config_entry(
hass, mock_connection, simple_mock_home
):
"""Test that config for a accesspoint are loaded via config entry."""
entry_config = {
@@ -51,7 +53,9 @@ async def test_config_with_accesspoint_passed_to_config_entry(hass):
assert isinstance(hass.data[HMIPC_DOMAIN]["ABC123"], HomematicipHAP)
async def test_config_already_registered_not_passed_to_config_entry(hass):
async def test_config_already_registered_not_passed_to_config_entry(
hass, simple_mock_home
):
"""Test that an already registered accesspoint does not get imported."""
mock_config = {HMIPC_AUTHTOKEN: "123", HMIPC_HAPID: "ABC123", HMIPC_NAME: "name"}
@@ -87,7 +91,9 @@ async def test_config_already_registered_not_passed_to_config_entry(hass):
assert config_entries[0].unique_id == "ABC123"
async def test_load_entry_fails_due_to_connection_error(hass, hmip_config_entry):
async def test_load_entry_fails_due_to_connection_error(
hass, hmip_config_entry, mock_connection_init
):
"""Test load entry fails due to connection error."""
hmip_config_entry.add_to_hass(hass)
@@ -101,7 +107,9 @@ async def test_load_entry_fails_due_to_connection_error(hass, hmip_config_entry)
assert hmip_config_entry.state == ENTRY_STATE_SETUP_RETRY
async def test_load_entry_fails_due_to_generic_exception(hass, hmip_config_entry):
async def test_load_entry_fails_due_to_generic_exception(
hass, hmip_config_entry, simple_mock_home
):
"""Test load entry fails due to generic exception."""
hmip_config_entry.add_to_hass(hass)

View File

@@ -140,16 +140,7 @@ async def test_webhook_update_registration(webhook_client, authed_api_client):
async def test_webhook_handle_get_zones(hass, create_registrations, webhook_client):
"""Test that we can get zones properly."""
await async_setup_component(
hass,
ZONE_DOMAIN,
{
ZONE_DOMAIN: {
"name": "test",
"latitude": 32.880837,
"longitude": -117.237561,
"radius": 250,
}
},
hass, ZONE_DOMAIN, {ZONE_DOMAIN: {}},
)
resp = await webhook_client.post(
@@ -160,10 +151,9 @@ async def test_webhook_handle_get_zones(hass, create_registrations, webhook_clie
assert resp.status == 200
json = await resp.json()
assert len(json) == 2
assert len(json) == 1
zones = sorted(json, key=lambda entry: entry["entity_id"])
assert zones[0]["entity_id"] == "zone.home"
assert zones[1]["entity_id"] == "zone.test"
async def test_webhook_handle_get_config(hass, create_registrations, webhook_client):

View File

@@ -108,7 +108,7 @@ async def test_no_clients(hass):
"""Test the update_clients function when no clients are found."""
await setup_unifi_integration(hass)
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("device_tracker")) == 0
async def test_tracked_devices(hass):
@@ -123,7 +123,7 @@ async def test_tracked_devices(hass):
devices_response=[DEVICE_1, DEVICE_2],
known_wireless_clients=(CLIENT_4["mac"],),
)
assert len(hass.states.async_all()) == 6
assert len(hass.states.async_entity_ids("device_tracker")) == 5
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None
@@ -184,7 +184,7 @@ async def test_controller_state_change(hass):
controller = await setup_unifi_integration(
hass, clients_response=[CLIENT_1], devices_response=[DEVICE_1],
)
assert len(hass.states.async_all()) == 2
assert len(hass.states.async_entity_ids("device_tracker")) == 2
# Controller unavailable
controller.async_unifi_signalling_callback(
@@ -214,7 +214,7 @@ async def test_option_track_clients(hass):
controller = await setup_unifi_integration(
hass, clients_response=[CLIENT_1, CLIENT_2], devices_response=[DEVICE_1],
)
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids("device_tracker")) == 3
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None
@@ -259,7 +259,7 @@ async def test_option_track_wired_clients(hass):
controller = await setup_unifi_integration(
hass, clients_response=[CLIENT_1, CLIENT_2], devices_response=[DEVICE_1],
)
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids("device_tracker")) == 3
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None
@@ -304,7 +304,7 @@ async def test_option_track_devices(hass):
controller = await setup_unifi_integration(
hass, clients_response=[CLIENT_1, CLIENT_2], devices_response=[DEVICE_1],
)
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids("device_tracker")) == 3
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None
@@ -349,7 +349,7 @@ async def test_option_ssid_filter(hass):
controller = await setup_unifi_integration(
hass, options={CONF_SSID_FILTER: ["ssid"]}, clients_response=[CLIENT_3],
)
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("device_tracker")) == 0
# SSID filter active
client_3 = hass.states.get("device_tracker.client_3")
@@ -387,7 +387,7 @@ async def test_wireless_client_go_wired_issue(hass):
client_1_client["last_seen"] = dt_util.as_timestamp(dt_util.utcnow())
controller = await setup_unifi_integration(hass, clients_response=[client_1_client])
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("device_tracker")) == 1
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None
@@ -460,7 +460,7 @@ async def test_restoring_client(hass):
clients_response=[CLIENT_2],
clients_all_response=[CLIENT_1],
)
assert len(hass.states.async_all()) == 2
assert len(hass.states.async_entity_ids("device_tracker")) == 2
device_1 = hass.states.get("device_tracker.client_1")
assert device_1 is not None
@@ -474,7 +474,7 @@ async def test_dont_track_clients(hass):
clients_response=[CLIENT_1],
devices_response=[DEVICE_1],
)
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("device_tracker")) == 1
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is None
@@ -492,7 +492,7 @@ async def test_dont_track_devices(hass):
clients_response=[CLIENT_1],
devices_response=[DEVICE_1],
)
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("device_tracker")) == 1
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None
@@ -509,7 +509,7 @@ async def test_dont_track_wired_clients(hass):
options={unifi.controller.CONF_TRACK_WIRED_CLIENTS: False},
clients_response=[CLIENT_1, CLIENT_2],
)
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("device_tracker")) == 1
client_1 = hass.states.get("device_tracker.client_1")
assert client_1 is not None

View File

@@ -55,7 +55,7 @@ async def test_no_clients(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("sensor")) == 0
async def test_sensors(hass):
@@ -71,7 +71,7 @@ async def test_sensors(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 4
assert len(hass.states.async_entity_ids("sensor")) == 4
wired_client_rx = hass.states.get("sensor.wired_client_name_rx")
assert wired_client_rx.state == "1234.0"

View File

@@ -209,7 +209,7 @@ async def test_no_clients(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("switch")) == 0
async def test_controller_not_client(hass):
@@ -222,7 +222,7 @@ async def test_controller_not_client(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("switch")) == 0
cloudkey = hass.states.get("switch.cloud_key")
assert cloudkey is None
@@ -240,7 +240,7 @@ async def test_not_admin(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("switch")) == 0
async def test_switches(hass):
@@ -258,7 +258,7 @@ async def test_switches(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids("switch")) == 3
switch_1 = hass.states.get("switch.poe_client_1")
assert switch_1 is not None
@@ -312,7 +312,7 @@ async def test_new_client_discovered_on_block_control(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("switch")) == 0
blocked = hass.states.get("switch.block_client_1")
assert blocked is None
@@ -324,7 +324,7 @@ async def test_new_client_discovered_on_block_control(hass):
controller.api.session_handler("data")
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("switch")) == 1
blocked = hass.states.get("switch.block_client_1")
assert blocked is not None
@@ -336,7 +336,7 @@ async def test_option_block_clients(hass):
options={CONF_BLOCK_CLIENT: [BLOCKED["mac"]]},
clients_all_response=[BLOCKED, UNBLOCKED],
)
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("switch")) == 1
# Add a second switch
hass.config_entries.async_update_entry(
@@ -344,28 +344,28 @@ async def test_option_block_clients(hass):
options={CONF_BLOCK_CLIENT: [BLOCKED["mac"], UNBLOCKED["mac"]]},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 2
assert len(hass.states.async_entity_ids("switch")) == 2
# Remove the second switch again
hass.config_entries.async_update_entry(
controller.config_entry, options={CONF_BLOCK_CLIENT: [BLOCKED["mac"]]},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("switch")) == 1
# Enable one and remove another one
hass.config_entries.async_update_entry(
controller.config_entry, options={CONF_BLOCK_CLIENT: [UNBLOCKED["mac"]]},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("switch")) == 1
# Remove one
hass.config_entries.async_update_entry(
controller.config_entry, options={CONF_BLOCK_CLIENT: []},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
assert len(hass.states.async_entity_ids("switch")) == 0
async def test_new_client_discovered_on_poe_control(hass):
@@ -378,7 +378,7 @@ async def test_new_client_discovered_on_poe_control(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_entity_ids("switch")) == 1
controller.api.websocket._data = {
"meta": {"message": "sta:sync"},
@@ -391,7 +391,7 @@ async def test_new_client_discovered_on_poe_control(hass):
"switch", "turn_off", {"entity_id": "switch.poe_client_1"}, blocking=True
)
assert len(controller.mock_requests) == 5
assert len(hass.states.async_all()) == 2
assert len(hass.states.async_entity_ids("switch")) == 2
assert controller.mock_requests[4] == {
"json": {
"port_overrides": [{"port_idx": 1, "portconf_id": "1a1", "poe_mode": "off"}]
@@ -430,7 +430,7 @@ async def test_ignore_multiple_poe_clients_on_same_port(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 3
assert len(hass.states.async_entity_ids("device_tracker")) == 3
switch_1 = hass.states.get("switch.poe_client_1")
switch_2 = hass.states.get("switch.poe_client_2")
@@ -481,7 +481,7 @@ async def test_restoring_client(hass):
)
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 2
assert len(hass.states.async_entity_ids("switch")) == 2
device_1 = hass.states.get("switch.client_1")
assert device_1 is not None

View File

@@ -487,3 +487,18 @@ async def test_import_config_entry(hass):
assert state.attributes[zone.ATTR_RADIUS] == 3
assert state.attributes[zone.ATTR_PASSIVE] is False
assert state.attributes[ATTR_ICON] == "mdi:from-config-entry"
async def test_zone_empty_setup(hass):
"""Set up zone with empty config."""
assert await setup.async_setup_component(hass, DOMAIN, {"zone": {}})
async def test_unavailable_zone(hass):
"""Test active zone with unavailable zones."""
assert await setup.async_setup_component(hass, DOMAIN, {"zone": {}})
hass.states.async_set("zone.bla", "unavailable", {"restored": True})
assert zone.async_active_zone(hass, 0.0, 0.01) is None
assert zone.in_zone(hass.states.get("zone.bla"), 0, 0) is False