forked from home-assistant/core
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b147bcbf7 | |||
| ca81c6e684 | |||
| e62ba49979 | |||
| 6ea20090a4 | |||
| c43b7d10d8 | |||
| 430fa24acd | |||
| d51b2ad675 | |||
| b8fbe758d8 | |||
| 61476f4f2c | |||
| cab60bcd0c | |||
| c0394232f3 | |||
| a5d9e89d08 | |||
| f43b26f250 | |||
| 58b32bbeff | |||
| 6d0a465390 | |||
| a5d334bbf7 | |||
| a77fd4892e | |||
| 2d68b37dd5 | |||
| 4de3871a78 | |||
| 9c755d8fd4 | |||
| 1e5f0a5136 | |||
| 897433ecba | |||
| 89625010e5 |
@@ -37,7 +37,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
gateway.option_allow_clip_sensor
|
||||
or not sensor.type.startswith("CLIP")
|
||||
)
|
||||
and sensor.deconz_id not in gateway.deconz_ids.values()
|
||||
):
|
||||
entities.append(DeconzBinarySensor(sensor, gateway))
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
gateway.option_allow_clip_sensor
|
||||
or not sensor.type.startswith("CLIP")
|
||||
)
|
||||
and sensor.deconz_id not in gateway.deconz_ids.values()
|
||||
):
|
||||
entities.append(DeconzThermostat(sensor, gateway))
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
entities = []
|
||||
|
||||
for group in groups:
|
||||
if group.lights and group.deconz_id not in gateway.deconz_ids.values():
|
||||
if group.lights:
|
||||
entities.append(DeconzGroup(group, gateway))
|
||||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
@@ -68,7 +68,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
gateway.option_allow_clip_sensor
|
||||
or not sensor.type.startswith("CLIP")
|
||||
)
|
||||
and sensor.deconz_id not in gateway.deconz_ids.values()
|
||||
):
|
||||
entities.append(DeconzSensor(sensor, gateway))
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
||||
# Protocol version specific obis
|
||||
if dsmr_version in ("4", "5"):
|
||||
gas_obis = obis_ref.HOURLY_GAS_METER_READING
|
||||
elif dsmr_version in ("5B"):
|
||||
elif dsmr_version in ("5B",):
|
||||
gas_obis = obis_ref.BELGIUM_HOURLY_GAS_METER_READING
|
||||
else:
|
||||
gas_obis = obis_ref.GAS_METER_READING
|
||||
@@ -238,7 +238,7 @@ class DSMREntity(Entity):
|
||||
"""Convert 2/1 to normal/low depending on DSMR version."""
|
||||
# DSMR V5B: Note: In Belgium values are swapped:
|
||||
# Rate code 2 is used for low rate and rate code 1 is used for normal rate.
|
||||
if dsmr_version in ("5B"):
|
||||
if dsmr_version in ("5B",):
|
||||
if value == "0001":
|
||||
value = "0002"
|
||||
elif value == "0002":
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Home Assistant Frontend",
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"requirements": [
|
||||
"home-assistant-frontend==20200220.3"
|
||||
"home-assistant-frontend==20200220.5"
|
||||
],
|
||||
"dependencies": [
|
||||
"api",
|
||||
|
||||
@@ -46,13 +46,7 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_BRIDGES): vol.All(
|
||||
cv.ensure_list,
|
||||
[
|
||||
vol.All(
|
||||
cv.deprecated("filename", invalidation_version="0.106.0"),
|
||||
BRIDGE_CONFIG_SCHEMA,
|
||||
),
|
||||
],
|
||||
cv.ensure_list, [BRIDGE_CONFIG_SCHEMA],
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Code to handle a Hue bridge."""
|
||||
import asyncio
|
||||
from functools import partial
|
||||
import logging
|
||||
|
||||
from aiohttp import client_exceptions
|
||||
import aiohue
|
||||
@@ -24,7 +25,8 @@ SCENE_SCHEMA = vol.Schema(
|
||||
{vol.Required(ATTR_GROUP_NAME): cv.string, vol.Required(ATTR_SCENE_NAME): cv.string}
|
||||
)
|
||||
# How long should we sleep if the hub is busy
|
||||
HUB_BUSY_SLEEP = 0.01
|
||||
HUB_BUSY_SLEEP = 0.5
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HueBridge:
|
||||
@@ -123,9 +125,14 @@ class HueBridge:
|
||||
except (
|
||||
client_exceptions.ClientOSError,
|
||||
client_exceptions.ClientResponseError,
|
||||
client_exceptions.ServerDisconnectedError,
|
||||
) as err:
|
||||
if tries == 3 or (
|
||||
# We only retry if it's a server error. So raise on all 4XX errors.
|
||||
if tries == 3:
|
||||
_LOGGER.error("Request failed %s times, giving up.", tries)
|
||||
raise
|
||||
|
||||
# We only retry if it's a server error. So raise on all 4XX errors.
|
||||
if (
|
||||
isinstance(err, client_exceptions.ClientResponseError)
|
||||
and err.status < 500
|
||||
):
|
||||
|
||||
@@ -5,6 +5,7 @@ from functools import partial
|
||||
import logging
|
||||
import random
|
||||
|
||||
from aiohttp import client_exceptions
|
||||
import aiohue
|
||||
import async_timeout
|
||||
|
||||
@@ -172,7 +173,11 @@ async def async_safe_fetch(bridge, fetch_method):
|
||||
except aiohue.Unauthorized:
|
||||
await bridge.handle_unauthorized_error()
|
||||
raise UpdateFailed
|
||||
except (asyncio.TimeoutError, aiohue.AiohueException):
|
||||
except (
|
||||
asyncio.TimeoutError,
|
||||
aiohue.AiohueException,
|
||||
client_exceptions.ClientError,
|
||||
):
|
||||
raise UpdateFailed
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import asyncio
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from aiohttp import client_exceptions
|
||||
from aiohue import AiohueException, Unauthorized
|
||||
from aiohue.sensors import TYPE_ZLL_PRESENCE
|
||||
import async_timeout
|
||||
@@ -60,7 +61,7 @@ class SensorManager:
|
||||
except Unauthorized:
|
||||
await self.bridge.handle_unauthorized_error()
|
||||
raise UpdateFailed
|
||||
except (asyncio.TimeoutError, AiohueException):
|
||||
except (asyncio.TimeoutError, AiohueException, client_exceptions.ClientError):
|
||||
raise UpdateFailed
|
||||
|
||||
async def async_register_component(self, binary, async_add_entities):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Instituto Português do Mar e Atmosfera (IPMA)",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/ipma",
|
||||
"requirements": ["pyipma==2.0.3"],
|
||||
"requirements": ["pyipma==2.0.4"],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@dgomes", "@abmantis"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"device_automation": {
|
||||
"action_type": {
|
||||
"brightness_decrease": "Decrease {entity_name} brightness",
|
||||
"brightness_increase": "Increase {entity_name} brightness",
|
||||
"toggle": "Toggle {entity_name}",
|
||||
"turn_on": "Turn on {entity_name}",
|
||||
"turn_off": "Turn off {entity_name}"
|
||||
|
||||
@@ -104,6 +104,9 @@ class LovelaceStorage:
|
||||
|
||||
async def async_save(self, config):
|
||||
"""Save config."""
|
||||
if self._hass.config.safe_mode:
|
||||
raise HomeAssistantError("Deleting not supported in safe mode")
|
||||
|
||||
if self._data is None:
|
||||
await self._load()
|
||||
self._data["config"] = config
|
||||
@@ -112,6 +115,9 @@ class LovelaceStorage:
|
||||
|
||||
async def async_delete(self):
|
||||
"""Delete config."""
|
||||
if self._hass.config.safe_mode:
|
||||
raise HomeAssistantError("Deleting not supported in safe mode")
|
||||
|
||||
await self.async_save(None)
|
||||
|
||||
async def _load(self):
|
||||
|
||||
@@ -202,17 +202,19 @@ class RestSensor(Entity):
|
||||
self.rest.update()
|
||||
value = self.rest.data
|
||||
_LOGGER.debug("Data fetched from resource: %s", value)
|
||||
content_type = self.rest.headers.get("content-type")
|
||||
if self.rest.headers is not None:
|
||||
# If the http request failed, headers will be None
|
||||
content_type = self.rest.headers.get("content-type")
|
||||
|
||||
if content_type and content_type.startswith("text/xml"):
|
||||
try:
|
||||
value = json.dumps(xmltodict.parse(value))
|
||||
_LOGGER.debug("JSON converted from XML: %s", value)
|
||||
except ExpatError:
|
||||
_LOGGER.warning(
|
||||
"REST xml result could not be parsed and converted to JSON."
|
||||
)
|
||||
_LOGGER.debug("Erroneous XML: %s", value)
|
||||
if content_type and content_type.startswith("text/xml"):
|
||||
try:
|
||||
value = json.dumps(xmltodict.parse(value))
|
||||
_LOGGER.debug("JSON converted from XML: %s", value)
|
||||
except ExpatError:
|
||||
_LOGGER.warning(
|
||||
"REST xml result could not be parsed and converted to JSON."
|
||||
)
|
||||
_LOGGER.debug("Erroneous XML: %s", value)
|
||||
|
||||
if self._json_attrs:
|
||||
self._attributes = {}
|
||||
|
||||
@@ -154,6 +154,7 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
|
||||
@callback
|
||||
def _async_save_refresh_token(hass, config_entry, token):
|
||||
"""Save a refresh token to the config entry."""
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry, data={**config_entry.data, CONF_TOKEN: token}
|
||||
)
|
||||
@@ -520,41 +521,34 @@ class SimpliSafe:
|
||||
|
||||
tasks = [update_system(system) for system in self.systems.values()]
|
||||
|
||||
def cancel_tasks():
|
||||
"""Cancel tasks and ensure their cancellation is processed."""
|
||||
for task in tasks:
|
||||
task.cancel()
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
for result in results:
|
||||
if isinstance(result, InvalidCredentialsError):
|
||||
if self._emergency_refresh_token_used:
|
||||
_LOGGER.error(
|
||||
"SimpliSafe authentication disconnected. Please restart HASS."
|
||||
)
|
||||
remove_listener = self._hass.data[DOMAIN][DATA_LISTENER].pop(
|
||||
self._config_entry.entry_id
|
||||
)
|
||||
remove_listener()
|
||||
return
|
||||
|
||||
try:
|
||||
await asyncio.gather(*tasks)
|
||||
except InvalidCredentialsError:
|
||||
cancel_tasks()
|
||||
_LOGGER.warning("SimpliSafe cloud error; trying stored refresh token")
|
||||
self._emergency_refresh_token_used = True
|
||||
return await self._api.refresh_access_token(
|
||||
self._config_entry.data[CONF_TOKEN]
|
||||
)
|
||||
|
||||
if self._emergency_refresh_token_used:
|
||||
_LOGGER.error(
|
||||
"SimpliSafe authentication disconnected. Please restart HASS."
|
||||
)
|
||||
remove_listener = self._hass.data[DOMAIN][DATA_LISTENER].pop(
|
||||
self._config_entry.entry_id
|
||||
)
|
||||
remove_listener()
|
||||
if isinstance(result, SimplipyError):
|
||||
_LOGGER.error("SimpliSafe error while updating: %s", result)
|
||||
return
|
||||
|
||||
_LOGGER.warning("SimpliSafe cloud error; trying stored refresh token")
|
||||
self._emergency_refresh_token_used = True
|
||||
return await self._api.refresh_access_token(
|
||||
self._config_entry.data[CONF_TOKEN]
|
||||
)
|
||||
except SimplipyError as err:
|
||||
cancel_tasks()
|
||||
_LOGGER.error("SimpliSafe error while updating: %s", err)
|
||||
return
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
cancel_tasks()
|
||||
_LOGGER.error("Unknown error while updating: %s", err)
|
||||
return
|
||||
if isinstance(result, SimplipyError):
|
||||
_LOGGER.error("Unknown error while updating: %s", result)
|
||||
return
|
||||
|
||||
if self._api.refresh_token_dirty:
|
||||
if self._api.refresh_token != self._config_entry.data[CONF_TOKEN]:
|
||||
_async_save_refresh_token(
|
||||
self._hass, self._config_entry, self._api.refresh_token
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "SimpliSafe",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
||||
"requirements": ["simplisafe-python==8.1.1"],
|
||||
"requirements": ["simplisafe-python==9.0.2"],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@bachya"]
|
||||
}
|
||||
|
||||
@@ -200,6 +200,11 @@ class UniFiClientTracker(UniFiClient, ScannerEntity):
|
||||
|
||||
else:
|
||||
self.wired_bug = None
|
||||
|
||||
# A client that has never been seen cannot be connected.
|
||||
if self.client.last_seen is None:
|
||||
return False
|
||||
|
||||
since_last_seen = dt_util.utcnow() - dt_util.utc_from_timestamp(
|
||||
float(self.client.last_seen)
|
||||
)
|
||||
@@ -333,4 +338,4 @@ class UniFiDeviceTracker(ScannerEntity):
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -62,4 +62,4 @@ class UniFiClient(Entity):
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""No polling needed."""
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 106
|
||||
PATCH_VERSION = "0b5"
|
||||
PATCH_VERSION = "2"
|
||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER = (3, 7, 0)
|
||||
|
||||
@@ -11,7 +11,7 @@ cryptography==2.8
|
||||
defusedxml==0.6.0
|
||||
distro==1.4.0
|
||||
hass-nabucasa==0.31
|
||||
home-assistant-frontend==20200220.3
|
||||
home-assistant-frontend==20200220.5
|
||||
importlib-metadata==1.5.0
|
||||
jinja2>=2.10.3
|
||||
netdisco==2.6.0
|
||||
|
||||
@@ -683,7 +683,7 @@ hole==0.5.0
|
||||
holidays==0.10.1
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20200220.3
|
||||
home-assistant-frontend==20200220.5
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.8
|
||||
@@ -1305,7 +1305,7 @@ pyicloud==0.9.2
|
||||
pyintesishome==1.6
|
||||
|
||||
# homeassistant.components.ipma
|
||||
pyipma==2.0.3
|
||||
pyipma==2.0.4
|
||||
|
||||
# homeassistant.components.iqvia
|
||||
pyiqvia==0.2.1
|
||||
@@ -1827,7 +1827,7 @@ simplehound==0.3
|
||||
simplepush==1.1.4
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==8.1.1
|
||||
simplisafe-python==9.0.2
|
||||
|
||||
# homeassistant.components.sisyphus
|
||||
sisyphus-control==2.2.1
|
||||
|
||||
@@ -254,7 +254,7 @@ hole==0.5.0
|
||||
holidays==0.10.1
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20200220.3
|
||||
home-assistant-frontend==20200220.5
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.8
|
||||
@@ -477,7 +477,7 @@ pyhomematic==0.1.64
|
||||
pyicloud==0.9.2
|
||||
|
||||
# homeassistant.components.ipma
|
||||
pyipma==2.0.3
|
||||
pyipma==2.0.4
|
||||
|
||||
# homeassistant.components.iqvia
|
||||
pyiqvia==0.2.1
|
||||
@@ -626,7 +626,7 @@ sentry-sdk==0.13.5
|
||||
simplehound==0.3
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==8.1.1
|
||||
simplisafe-python==9.0.2
|
||||
|
||||
# homeassistant.components.sleepiq
|
||||
sleepyq==0.7
|
||||
|
||||
@@ -187,6 +187,50 @@ async def test_v4_meter(hass, mock_connection_factory):
|
||||
assert gas_consumption.attributes.get("unit_of_measurement") == "m3"
|
||||
|
||||
|
||||
async def test_v5_meter(hass, mock_connection_factory):
|
||||
"""Test if v5 meter is correctly parsed."""
|
||||
(connection_factory, transport, protocol) = mock_connection_factory
|
||||
|
||||
from dsmr_parser.obis_references import (
|
||||
HOURLY_GAS_METER_READING,
|
||||
ELECTRICITY_ACTIVE_TARIFF,
|
||||
)
|
||||
from dsmr_parser.objects import CosemObject, MBusObject
|
||||
|
||||
config = {"platform": "dsmr", "dsmr_version": "5"}
|
||||
|
||||
telegram = {
|
||||
HOURLY_GAS_METER_READING: MBusObject(
|
||||
[
|
||||
{"value": datetime.datetime.fromtimestamp(1551642213)},
|
||||
{"value": Decimal(745.695), "unit": "m³"},
|
||||
]
|
||||
),
|
||||
ELECTRICITY_ACTIVE_TARIFF: CosemObject([{"value": "0001", "unit": ""}]),
|
||||
}
|
||||
|
||||
with assert_setup_component(1):
|
||||
await async_setup_component(hass, "sensor", {"sensor": config})
|
||||
|
||||
telegram_callback = connection_factory.call_args_list[0][0][2]
|
||||
|
||||
# simulate a telegram pushed from the smartmeter and parsed by dsmr_parser
|
||||
telegram_callback(telegram)
|
||||
|
||||
# after receiving telegram entities need to have the chance to update
|
||||
await asyncio.sleep(0)
|
||||
|
||||
# tariff should be translated in human readable and have no unit
|
||||
power_tariff = hass.states.get("sensor.power_tariff")
|
||||
assert power_tariff.state == "low"
|
||||
assert power_tariff.attributes.get("unit_of_measurement") == ""
|
||||
|
||||
# check if gas consumption is parsed correctly
|
||||
gas_consumption = hass.states.get("sensor.gas_consumption")
|
||||
assert gas_consumption.state == "745.695"
|
||||
assert gas_consumption.attributes.get("unit_of_measurement") == "m³"
|
||||
|
||||
|
||||
async def test_belgian_meter(hass, mock_connection_factory):
|
||||
"""Test if Belgian meter is correctly parsed."""
|
||||
(connection_factory, transport, protocol) = mock_connection_factory
|
||||
|
||||
@@ -37,7 +37,7 @@ async def test_setup_defined_hosts_known_auth(hass):
|
||||
hue.CONF_ALLOW_HUE_GROUPS: False,
|
||||
hue.CONF_ALLOW_UNREACHABLE: True,
|
||||
},
|
||||
{hue.CONF_HOST: "1.1.1.1", "filename": "bla"},
|
||||
{hue.CONF_HOST: "1.1.1.1"},
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -59,7 +59,6 @@ async def test_setup_defined_hosts_known_auth(hass):
|
||||
hue.CONF_HOST: "1.1.1.1",
|
||||
hue.CONF_ALLOW_HUE_GROUPS: True,
|
||||
hue.CONF_ALLOW_UNREACHABLE: False,
|
||||
"filename": "bla",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,16 @@ async def test_lovelace_from_storage(hass, hass_ws_client, hass_storage):
|
||||
assert not response["success"]
|
||||
assert response["error"]["code"] == "config_not_found"
|
||||
|
||||
await client.send_json(
|
||||
{"id": 9, "type": "lovelace/config/save", "config": {"yo": "hello"}}
|
||||
)
|
||||
response = await client.receive_json()
|
||||
assert not response["success"]
|
||||
|
||||
await client.send_json({"id": 10, "type": "lovelace/config/delete"})
|
||||
response = await client.receive_json()
|
||||
assert not response["success"]
|
||||
|
||||
|
||||
async def test_lovelace_from_storage_save_before_load(
|
||||
hass, hass_ws_client, hass_storage
|
||||
|
||||
@@ -589,6 +589,35 @@ class TestRestSensor(unittest.TestCase):
|
||||
assert mock_logger.warning.called
|
||||
assert mock_logger.debug.called
|
||||
|
||||
@patch("homeassistant.components.rest.sensor._LOGGER")
|
||||
def test_update_with_failed_get(self, mock_logger):
|
||||
"""Test attributes get extracted from a XML result with bad xml."""
|
||||
value_template = template("{{ value_json.toplevel.master_value }}")
|
||||
value_template.hass = self.hass
|
||||
|
||||
self.rest.update = Mock(
|
||||
"rest.RestData.update", side_effect=self.update_side_effect(None, None),
|
||||
)
|
||||
self.sensor = rest.RestSensor(
|
||||
self.hass,
|
||||
self.rest,
|
||||
self.name,
|
||||
self.unit_of_measurement,
|
||||
self.device_class,
|
||||
value_template,
|
||||
["key"],
|
||||
self.force_update,
|
||||
self.resource_template,
|
||||
self.json_attrs_path,
|
||||
)
|
||||
|
||||
self.sensor.update()
|
||||
assert {} == self.sensor.device_state_attributes
|
||||
assert mock_logger.warning.called
|
||||
assert mock_logger.debug.called
|
||||
assert self.sensor.state is None
|
||||
assert self.sensor.available is False
|
||||
|
||||
|
||||
class TestRestData(unittest.TestCase):
|
||||
"""Tests for RestData."""
|
||||
|
||||
@@ -54,6 +54,14 @@ CLIENT_4 = {
|
||||
"last_seen": 1562600145,
|
||||
"mac": "00:00:00:00:00:04",
|
||||
}
|
||||
CLIENT_5 = {
|
||||
"essid": "ssid",
|
||||
"hostname": "client_5",
|
||||
"ip": "10.0.0.5",
|
||||
"is_wired": True,
|
||||
"last_seen": None,
|
||||
"mac": "00:00:00:00:00:05",
|
||||
}
|
||||
|
||||
DEVICE_1 = {
|
||||
"board_rev": 3,
|
||||
@@ -111,11 +119,11 @@ async def test_tracked_devices(hass):
|
||||
controller = await setup_unifi_integration(
|
||||
hass,
|
||||
options={CONF_SSID_FILTER: ["ssid"]},
|
||||
clients_response=[CLIENT_1, CLIENT_2, CLIENT_3, client_4_copy],
|
||||
clients_response=[CLIENT_1, CLIENT_2, CLIENT_3, CLIENT_5, client_4_copy],
|
||||
devices_response=[DEVICE_1, DEVICE_2],
|
||||
known_wireless_clients=(CLIENT_4["mac"],),
|
||||
)
|
||||
assert len(hass.states.async_all()) == 6
|
||||
assert len(hass.states.async_all()) == 7
|
||||
|
||||
client_1 = hass.states.get("device_tracker.client_1")
|
||||
assert client_1 is not None
|
||||
@@ -134,6 +142,11 @@ async def test_tracked_devices(hass):
|
||||
assert client_4 is not None
|
||||
assert client_4.state == "not_home"
|
||||
|
||||
# A client that has never been seen should be marked away.
|
||||
client_5 = hass.states.get("device_tracker.client_5")
|
||||
assert client_5 is not None
|
||||
assert client_5.state == "not_home"
|
||||
|
||||
device_1 = hass.states.get("device_tracker.device_1")
|
||||
assert device_1 is not None
|
||||
assert device_1.state == "not_home"
|
||||
|
||||
Reference in New Issue
Block a user