UniFi config option SSID filter (#31842)

* Draft

* Use new multi_select config validation

* Bump dependency to v13

* Improve options flow

* Add title to config options

* Add config option descriptions

* Fix martins comment
This commit is contained in:
Robert Svensson 2020-02-18 23:24:21 +01:00 committed by GitHub
parent 60ae85564e
commit 774c892ee6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 84 additions and 62 deletions

View file

@ -25,18 +25,26 @@
},
"options": {
"step": {
"init": {
"data": {}
},
"device_tracker": {
"data": {
"detection_time": "Time in seconds from last seen until considered away",
"ssid_filter": "Select SSIDs to track wireless clients on",
"track_clients": "Track network clients",
"track_devices": "Track network devices (Ubiquiti devices)",
"track_wired_clients": "Include wired network clients"
}
},
"description": "Configure device tracking",
"title": "UniFi options"
},
"statistics_sensors": {
"data": {
"allow_bandwidth_sensors": "Create bandwidth usage sensors for network clients"
}
"allow_bandwidth_sensors": "Bandwidth usage sensors for network clients"
},
"description": "Configure statistics sensors",
"title": "UniFi options"
}
}
}

View file

@ -12,21 +12,18 @@ from homeassistant.const import (
CONF_VERIFY_SSL,
)
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from .const import (
CONF_ALLOW_BANDWIDTH_SENSORS,
CONF_CONTROLLER,
CONF_DETECTION_TIME,
CONF_SITE_ID,
CONF_SSID_FILTER,
CONF_TRACK_CLIENTS,
CONF_TRACK_DEVICES,
CONF_TRACK_WIRED_CLIENTS,
CONTROLLER_ID,
DEFAULT_ALLOW_BANDWIDTH_SENSORS,
DEFAULT_DETECTION_TIME,
DEFAULT_TRACK_CLIENTS,
DEFAULT_TRACK_DEVICES,
DEFAULT_TRACK_WIRED_CLIENTS,
DOMAIN,
LOGGER,
)
@ -185,33 +182,30 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
self.options.update(user_input)
return await self.async_step_statistics_sensors()
controller = get_controller_from_config_entry(self.hass, self.config_entry)
ssid_filter = {wlan: wlan for wlan in controller.api.wlans}
return self.async_show_form(
step_id="device_tracker",
data_schema=vol.Schema(
{
vol.Optional(
CONF_TRACK_CLIENTS,
default=self.config_entry.options.get(
CONF_TRACK_CLIENTS, DEFAULT_TRACK_CLIENTS
),
CONF_TRACK_CLIENTS, default=controller.option_track_clients,
): bool,
vol.Optional(
CONF_TRACK_WIRED_CLIENTS,
default=self.config_entry.options.get(
CONF_TRACK_WIRED_CLIENTS, DEFAULT_TRACK_WIRED_CLIENTS
),
default=controller.option_track_wired_clients,
): bool,
vol.Optional(
CONF_TRACK_DEVICES,
default=self.config_entry.options.get(
CONF_TRACK_DEVICES, DEFAULT_TRACK_DEVICES
),
CONF_TRACK_DEVICES, default=controller.option_track_devices,
): bool,
vol.Optional(
CONF_SSID_FILTER, default=controller.option_ssid_filter
): cv.multi_select(ssid_filter),
vol.Optional(
CONF_DETECTION_TIME,
default=self.config_entry.options.get(
CONF_DETECTION_TIME, DEFAULT_DETECTION_TIME
),
default=int(controller.option_detection_time.total_seconds()),
): int,
}
),
@ -223,16 +217,15 @@ class UnifiOptionsFlowHandler(config_entries.OptionsFlow):
self.options.update(user_input)
return await self._update_options()
controller = get_controller_from_config_entry(self.hass, self.config_entry)
return self.async_show_form(
step_id="statistics_sensors",
data_schema=vol.Schema(
{
vol.Optional(
CONF_ALLOW_BANDWIDTH_SENSORS,
default=self.config_entry.options.get(
CONF_ALLOW_BANDWIDTH_SENSORS,
DEFAULT_ALLOW_BANDWIDTH_SENSORS,
),
default=controller.option_allow_bandwidth_sensors,
): bool
}
),

View file

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

View file

@ -31,15 +31,20 @@
"device_tracker": {
"data": {
"detection_time": "Time in seconds from last seen until considered away",
"ssid_filter": "Select SSIDs to track wireless clients on",
"track_clients": "Track network clients",
"track_devices": "Track network devices (Ubiquiti devices)",
"track_wired_clients": "Include wired network clients"
}
},
"description": "Configure device tracking",
"title": "UniFi options"
},
"statistics_sensors": {
"data": {
"allow_bandwidth_sensors": "Create bandwidth usage sensors for network clients"
}
"allow_bandwidth_sensors": "Bandwidth usage sensors for network clients"
},
"description": "Configure statistics sensors",
"title": "UniFi options"
}
}
}

View file

@ -199,7 +199,7 @@ aiopylgtv==0.3.3
aioswitcher==2019.4.26
# homeassistant.components.unifi
aiounifi==12
aiounifi==13
# homeassistant.components.wwlln
aiowwlln==2.0.2

View file

@ -78,7 +78,7 @@ aiopylgtv==0.3.3
aioswitcher==2019.4.26
# homeassistant.components.unifi
aiounifi==12
aiounifi==13
# homeassistant.components.wwlln
aiowwlln==2.0.2

View file

@ -2,6 +2,7 @@
import aiounifi
from asynctest import patch
from homeassistant import data_entry_flow
from homeassistant.components import unifi
from homeassistant.components.unifi import config_flow
from homeassistant.components.unifi.const import CONF_CONTROLLER, CONF_SITE_ID
@ -13,8 +14,12 @@ from homeassistant.const import (
CONF_VERIFY_SSL,
)
from .test_controller import setup_unifi_integration
from tests.common import MockConfigEntry
WLANS = [{"name": "SSID 1"}, {"name": "SSID 2"}]
async def test_flow_works(hass, aioclient_mock, mock_discovery):
"""Test config flow."""
@ -236,36 +241,39 @@ async def test_flow_fails_unknown_problem(hass, aioclient_mock):
async def test_option_flow(hass):
"""Test config flow options."""
entry = MockConfigEntry(domain=config_flow.DOMAIN, data={}, options=None)
hass.config_entries._entries.append(entry)
controller = await setup_unifi_integration(hass, wlans_response=WLANS)
flow = await hass.config_entries.options.async_create_flow(
entry.entry_id, context={"source": "test"}, data=None
result = await hass.config_entries.options.async_init(
controller.config_entry.entry_id
)
result = await flow.async_step_init()
assert result["type"] == "form"
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "device_tracker"
result = await flow.async_step_device_tracker(
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
config_flow.CONF_TRACK_CLIENTS: False,
config_flow.CONF_TRACK_WIRED_CLIENTS: False,
config_flow.CONF_TRACK_DEVICES: False,
config_flow.CONF_SSID_FILTER: ["SSID 1"],
config_flow.CONF_DETECTION_TIME: 100,
}
},
)
assert result["type"] == "form"
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "statistics_sensors"
result = await flow.async_step_statistics_sensors(
user_input={config_flow.CONF_ALLOW_BANDWIDTH_SENSORS: True}
result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input={config_flow.CONF_ALLOW_BANDWIDTH_SENSORS: True}
)
assert result["type"] == "create_entry"
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["data"] == {
config_flow.CONF_TRACK_CLIENTS: False,
config_flow.CONF_TRACK_WIRED_CLIENTS: False,
config_flow.CONF_TRACK_DEVICES: False,
config_flow.CONF_DETECTION_TIME: 100,
config_flow.CONF_SSID_FILTER: ["SSID 1"],
config_flow.CONF_ALLOW_BANDWIDTH_SENSORS: True,
}

View file

@ -63,6 +63,7 @@ async def setup_unifi_integration(
clients_response=None,
devices_response=None,
clients_all_response=None,
wlans_response=None,
known_wireless_clients=None,
controllers=None,
):
@ -98,6 +99,10 @@ async def setup_unifi_integration(
if clients_all_response:
mock_client_all_responses.append(clients_all_response)
mock_wlans_responses = deque()
if wlans_response:
mock_wlans_responses.append(wlans_response)
mock_requests = []
async def mock_request(self, method, path, json=None):
@ -109,6 +114,8 @@ async def setup_unifi_integration(
return mock_device_responses.popleft()
if path == "s/{site}/rest/user" and mock_client_all_responses:
return mock_client_all_responses.popleft()
if path == "s/{site}/rest/wlanconf" and mock_wlans_responses:
return mock_wlans_responses.popleft()
return {}
# "aiounifi.Controller.start_websocket", return_value=True
@ -128,6 +135,7 @@ async def setup_unifi_integration(
controller.mock_client_responses = mock_client_responses
controller.mock_device_responses = mock_device_responses
controller.mock_client_all_responses = mock_client_all_responses
controller.mock_wlans_responses = mock_wlans_responses
controller.mock_requests = mock_requests
return controller

View file

@ -54,7 +54,7 @@ async def test_no_clients(hass):
hass, options={unifi.const.CONF_ALLOW_BANDWIDTH_SENSORS: True},
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 1
@ -70,7 +70,7 @@ async def test_sensors(hass):
clients_response=CLIENTS,
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 5
wired_client_rx = hass.states.get("sensor.wired_client_name_rx")

View file

@ -207,7 +207,7 @@ async def test_no_clients(hass):
},
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 1
@ -223,7 +223,7 @@ async def test_controller_not_client(hass):
devices_response=[DEVICE_1],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 1
cloudkey = hass.states.get("switch.cloud_key")
assert cloudkey is None
@ -244,7 +244,7 @@ async def test_not_admin(hass):
devices_response=[DEVICE_1],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 1
@ -262,7 +262,7 @@ async def test_switches(hass):
clients_all_response=[BLOCKED, UNBLOCKED, CLIENT_1],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 4
switch_1 = hass.states.get("switch.poe_client_1")
@ -297,7 +297,7 @@ async def test_new_client_discovered_on_block_control(hass):
clients_all_response=[BLOCKED],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 2
controller.api.websocket._data = {
@ -310,9 +310,9 @@ async def test_new_client_discovered_on_block_control(hass):
await hass.services.async_call(
"switch", "turn_off", {"entity_id": "switch.block_client_1"}, blocking=True
)
assert len(controller.mock_requests) == 4
assert len(controller.mock_requests) == 5
assert len(hass.states.async_all()) == 2
assert controller.mock_requests[3] == {
assert controller.mock_requests[4] == {
"json": {"mac": "00:00:00:00:01:01", "cmd": "block-sta"},
"method": "post",
"path": "s/{site}/cmd/stamgr/",
@ -321,8 +321,8 @@ async def test_new_client_discovered_on_block_control(hass):
await hass.services.async_call(
"switch", "turn_on", {"entity_id": "switch.block_client_1"}, blocking=True
)
assert len(controller.mock_requests) == 5
assert controller.mock_requests[4] == {
assert len(controller.mock_requests) == 6
assert controller.mock_requests[5] == {
"json": {"mac": "00:00:00:00:01:01", "cmd": "unblock-sta"},
"method": "post",
"path": "s/{site}/cmd/stamgr/",
@ -341,7 +341,7 @@ async def test_new_client_discovered_on_poe_control(hass):
devices_response=[DEVICE_1],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 2
controller.api.websocket._data = {
@ -354,9 +354,9 @@ async def test_new_client_discovered_on_poe_control(hass):
await hass.services.async_call(
"switch", "turn_off", {"entity_id": "switch.poe_client_1"}, blocking=True
)
assert len(controller.mock_requests) == 4
assert len(controller.mock_requests) == 5
assert len(hass.states.async_all()) == 3
assert controller.mock_requests[3] == {
assert controller.mock_requests[4] == {
"json": {
"port_overrides": [{"port_idx": 1, "portconf_id": "1a1", "poe_mode": "off"}]
},
@ -367,8 +367,8 @@ async def test_new_client_discovered_on_poe_control(hass):
await hass.services.async_call(
"switch", "turn_on", {"entity_id": "switch.poe_client_1"}, blocking=True
)
assert len(controller.mock_requests) == 5
assert controller.mock_requests[3] == {
assert len(controller.mock_requests) == 6
assert controller.mock_requests[4] == {
"json": {
"port_overrides": [
{"port_idx": 1, "portconf_id": "1a1", "poe_mode": "auto"}
@ -393,7 +393,7 @@ async def test_ignore_multiple_poe_clients_on_same_port(hass):
hass, clients_response=POE_SWITCH_CLIENTS, devices_response=[DEVICE_1],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 4
switch_1 = hass.states.get("switch.poe_client_1")
@ -444,7 +444,7 @@ async def test_restoring_client(hass):
clients_all_response=[CLIENT_1],
)
assert len(controller.mock_requests) == 3
assert len(controller.mock_requests) == 4
assert len(hass.states.async_all()) == 3
device_1 = hass.states.get("switch.client_1")