예제 #1
0
    async def async_step_init(self, user_input=None):
        """Handle options flow."""
        if self.config_entry.source == SOURCE_IMPORT:
            return await self.async_step_yaml(user_input)

        if user_input is not None:
            self.hk_options.update(user_input)
            return await self.async_step_include_exclude()

        self.hk_options = dict(self.config_entry.options)
        entity_filter = self.hk_options.get(CONF_FILTER, {})
        homekit_mode = self.hk_options.get(CONF_HOMEKIT_MODE, DEFAULT_HOMEKIT_MODE)
        domains = entity_filter.get(CONF_INCLUDE_DOMAINS, [])
        include_entities = entity_filter.get(CONF_INCLUDE_ENTITIES)
        if include_entities:
            domains.extend(_domains_set_from_entities(include_entities))

        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema(
                {
                    vol.Required(CONF_HOMEKIT_MODE, default=homekit_mode): vol.In(
                        HOMEKIT_MODES
                    ),
                    vol.Required(
                        CONF_DOMAINS,
                        default=domains,
                    ): cv.multi_select(SUPPORTED_DOMAINS),
                }
            ),
        )
예제 #2
0
    async def async_step_cameras(self, user_input=None):
        """Choose camera config."""
        if user_input is not None:
            entity_config = self.hk_options[CONF_ENTITY_CONFIG]
            for entity_id in self.included_cameras:
                if entity_id in user_input[CONF_CAMERA_COPY]:
                    entity_config.setdefault(entity_id, {})[
                        CONF_VIDEO_CODEC
                    ] = VIDEO_CODEC_COPY
                elif (
                    entity_id in entity_config
                    and CONF_VIDEO_CODEC in entity_config[entity_id]
                ):
                    del entity_config[entity_id][CONF_VIDEO_CODEC]
            return await self.async_step_advanced()

        cameras_with_copy = []
        entity_config = self.hk_options.setdefault(CONF_ENTITY_CONFIG, {})
        for entity in self.included_cameras:
            hk_entity_config = entity_config.get(entity, {})
            if hk_entity_config.get(CONF_VIDEO_CODEC) == VIDEO_CODEC_COPY:
                cameras_with_copy.append(entity)

        data_schema = vol.Schema(
            {
                vol.Optional(
                    CONF_CAMERA_COPY,
                    default=cameras_with_copy,
                ): cv.multi_select(self.included_cameras),
            }
        )
        return self.async_show_form(step_id="cameras", data_schema=data_schema)
예제 #3
0
    async def async_step_public_weather_areas(self, user_input=None):
        """Manage configuration of Netatmo public weather areas."""
        errors = {}

        if user_input is not None:
            new_client = user_input.pop(CONF_NEW_AREA, None)
            areas = user_input.pop(CONF_WEATHER_AREAS, None)
            user_input[CONF_WEATHER_AREAS] = {
                area: self.options[CONF_WEATHER_AREAS][area]
                for area in areas
            }
            self.options.update(user_input)
            if new_client:
                return await self.async_step_public_weather(
                    user_input={CONF_NEW_AREA: new_client})

            return self._create_options_entry()

        weather_areas = list(self.options[CONF_WEATHER_AREAS])

        data_schema = vol.Schema({
            vol.Optional(
                CONF_WEATHER_AREAS,
                default=weather_areas,
            ):
            cv.multi_select(weather_areas),
            vol.Optional(CONF_NEW_AREA):
            str,
        })
        return self.async_show_form(
            step_id="public_weather_areas",
            data_schema=data_schema,
            errors=errors,
        )
예제 #4
0
    async def async_step_client_control(self, user_input=None):
        """Manage configuration of network access controlled clients."""
        errors = {}

        if user_input is not None:
            self.options.update(user_input)
            return await self.async_step_statistics_sensors()

        clients_to_block = {}

        for client in self.controller.api.clients.values():
            clients_to_block[
                client.
                mac] = f"{client.name or client.hostname} ({client.mac})"

        return self.async_show_form(
            step_id="client_control",
            data_schema=vol.Schema({
                vol.Optional(CONF_BLOCK_CLIENT,
                             default=self.options[CONF_BLOCK_CLIENT]):
                cv.multi_select(clients_to_block),
                vol.Optional(
                    CONF_POE_CLIENTS,
                    default=self.options.get(CONF_POE_CLIENTS, DEFAULT_POE_CLIENTS),
                ):
                bool,
                vol.Optional(
                    CONF_DPI_RESTRICTIONS,
                    default=self.options.get(CONF_DPI_RESTRICTIONS, DEFAULT_DPI_RESTRICTIONS),
                ):
                bool,
            }),
            errors=errors,
            last_step=False,
        )
예제 #5
0
    async def async_step_options_2(self, user_input=None):
        """Manage the options 2."""
        if user_input is not None:
            self.options.update(user_input)
            return await self._update_options()

        return self.async_show_form(
            step_id="options_2",
            data_schema=vol.Schema({
                vol.Optional(
                    CONF_STRING,
                    default=self.config_entry.options.get(
                        CONF_STRING,
                        "Default",
                    ),
                ):
                str,
                vol.Optional(
                    CONF_SELECT,
                    default=self.config_entry.options.get(
                        CONF_SELECT, "default"),
                ):
                vol.In(["default", "other"]),
                vol.Optional(
                    CONF_MULTISELECT,
                    default=self.config_entry.options.get(
                        CONF_MULTISELECT, ["default"]),
                ):
                cv.multi_select({
                    "default": "Default",
                    "other": "Other"
                }),
            }),
        )
예제 #6
0
    async def async_step_simple_options(self, user_input=None):
        """For users without advanced settings enabled."""
        if user_input is not None:
            self.options.update(user_input)
            return await self._update_options()

        clients_to_block = {}

        for client in self.controller.api.clients.values():
            clients_to_block[
                client.
                mac] = f"{client.name or client.hostname} ({client.mac})"

        return self.async_show_form(
            step_id="simple_options",
            data_schema=vol.Schema({
                vol.Optional(
                    CONF_TRACK_CLIENTS,
                    default=self.controller.option_track_clients,
                ):
                bool,
                vol.Optional(
                    CONF_TRACK_DEVICES,
                    default=self.controller.option_track_devices,
                ):
                bool,
                vol.Optional(CONF_BLOCK_CLIENT,
                             default=self.options[CONF_BLOCK_CLIENT]):
                cv.multi_select(clients_to_block),
            }),
            last_step=True,
        )
예제 #7
0
def test_multi_select_in_serializer():
    """Test multi_select with custom_serializer."""
    assert cv.custom_serializer(cv.multi_select({"paulus": "Paulus"})) == {
        "type": "multi_select",
        "options": {
            "paulus": "Paulus"
        },
    }
예제 #8
0
    async def async_step_init(self, user_input=None):
        """Handle options flow."""

        if self.config_entry.state is not config_entries.ConfigEntryState.LOADED:
            _LOGGER.error("Tuya integration not yet loaded")
            return self.async_abort(reason=RESULT_CONN_ERROR)

        if user_input is not None:
            dev_ids = user_input.get(CONF_LIST_DEVICES)
            if dev_ids:
                return await self.async_step_device(None, dev_ids)

            user_input.pop(CONF_LIST_DEVICES, [])
            return self._save_config(data=user_input)

        data_schema = vol.Schema(
            {
                vol.Optional(
                    CONF_DISCOVERY_INTERVAL,
                    default=self.config_entry.options.get(
                        CONF_DISCOVERY_INTERVAL, DEFAULT_DISCOVERY_INTERVAL
                    ),
                ): vol.All(vol.Coerce(int), vol.Clamp(min=30, max=900)),
            }
        )

        query_devices = self._get_tuya_devices_filtered(
            TUYA_TYPE_NOT_QUERY, True, False
        )
        if query_devices:
            devices = {ENTITY_MATCH_NONE: "Default"}
            devices.update(query_devices)
            def_val = self.config_entry.options.get(CONF_QUERY_DEVICE)
            if not def_val or not query_devices.get(def_val):
                def_val = ENTITY_MATCH_NONE
            data_schema = data_schema.extend(
                {
                    vol.Optional(
                        CONF_QUERY_INTERVAL,
                        default=self.config_entry.options.get(
                            CONF_QUERY_INTERVAL, DEFAULT_QUERY_INTERVAL
                        ),
                    ): vol.All(vol.Coerce(int), vol.Clamp(min=30, max=240)),
                    vol.Optional(CONF_QUERY_DEVICE, default=def_val): vol.In(devices),
                }
            )

        config_devices = self._get_tuya_devices_filtered(TUYA_TYPE_CONFIG, False, True)
        if config_devices:
            data_schema = data_schema.extend(
                {vol.Optional(CONF_LIST_DEVICES): cv.multi_select(config_devices)}
            )

        return self.async_show_form(
            step_id="init",
            data_schema=data_schema,
            errors=self._get_form_error(),
        )
예제 #9
0
    async def async_step_device_tracker(self, user_input=None):
        """Manage the device tracker options."""
        if user_input is not None:
            self.options.update(user_input)
            return await self.async_step_client_control()

        ssids = (set(self.controller.api.wlans)
                 | {
                     f"{wlan.name}{wlan.name_combine_suffix}"
                     for wlan in self.controller.api.wlans.values()
                     if not wlan.name_combine_enabled
                 }
                 | {
                     wlan["name"]
                     for ap in self.controller.api.devices.values()
                     for wlan in ap.wlan_overrides if "name" in wlan
                 })
        ssid_filter = {ssid: ssid for ssid in sorted(ssids)}

        return self.async_show_form(
            step_id="device_tracker",
            data_schema=vol.Schema({
                vol.Optional(
                    CONF_TRACK_CLIENTS,
                    default=self.controller.option_track_clients,
                ):
                bool,
                vol.Optional(
                    CONF_TRACK_WIRED_CLIENTS,
                    default=self.controller.option_track_wired_clients,
                ):
                bool,
                vol.Optional(
                    CONF_TRACK_DEVICES,
                    default=self.controller.option_track_devices,
                ):
                bool,
                vol.Optional(CONF_SSID_FILTER,
                             default=self.controller.option_ssid_filter):
                cv.multi_select(ssid_filter),
                vol.Optional(
                    CONF_DETECTION_TIME,
                    default=int(self.controller.option_detection_time.total_seconds(
                    )),
                ):
                int,
                vol.Optional(
                    CONF_IGNORE_WIRED_BUG,
                    default=self.controller.option_ignore_wired_bug,
                ):
                bool,
            }),
            last_step=False,
        )
예제 #10
0
    async def async_step_user(self, user_input=None):
        """Handle a flow initialized by the user."""
        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)

        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema({
                vol.Optional(CONF_IGNORED_SOURCES,
                             default=self.ignored_sources):
                cv.multi_select(self.source_list)
            }),
        )
예제 #11
0
    async def async_step_user(self,
                              user_input: ConfigType | None = None
                              ) -> FlowResult:
        """Manage the device tracker options."""
        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)

        options = vol.Schema(
            {
                vol.Required(
                    CONF_SCAN_INTERVAL,
                    default=self.config_entry.options.get(
                        CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL),
                ):
                int,
                vol.Required(
                    CONF_CONSIDER_HOME,
                    default=self.config_entry.options.get(
                        CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME),
                ):
                int,
                vol.Required(
                    CONF_INTERFACES,
                    default=self.config_entry.options.get(
                        CONF_INTERFACES, [DEFAULT_INTERFACE]),
                ):
                cv.multi_select(self._interface_options),
                vol.Optional(
                    CONF_TRY_HOTSPOT,
                    default=self.config_entry.options.get(
                        CONF_TRY_HOTSPOT, True),
                ):
                bool,
                vol.Optional(
                    CONF_INCLUDE_ARP,
                    default=self.config_entry.options.get(
                        CONF_INCLUDE_ARP, True),
                ):
                bool,
                vol.Optional(
                    CONF_INCLUDE_ASSOCIATED,
                    default=self.config_entry.options.get(
                        CONF_INCLUDE_ASSOCIATED, True),
                ):
                bool,
            })

        return self.async_show_form(step_id="user", data_schema=options)
예제 #12
0
    async def async_step_init(
        self, user_input: dict[str, Any] | None = None
    ) -> FlowResult:
        """Manage the options."""

        effects = {source: source for source in const.KEY_COMPONENTID_EXTERNAL_SOURCES}
        async with self._create_client() as hyperion_client:
            if not hyperion_client:
                return self.async_abort(reason="cannot_connect")
            for effect in hyperion_client.effects or []:
                if const.KEY_NAME in effect:
                    effects[effect[const.KEY_NAME]] = effect[const.KEY_NAME]

        # If a new effect is added to Hyperion, we always want it to show by default. So
        # rather than store a 'show list' in the config entry, we store a 'hide list'.
        # However, it's more intuitive to ask the user to select which effects to show,
        # so we inverse the meaning prior to storage.

        if user_input is not None:
            effect_show_list = user_input.pop(CONF_EFFECT_SHOW_LIST)
            user_input[CONF_EFFECT_HIDE_LIST] = sorted(
                set(effects) - set(effect_show_list)
            )
            return self.async_create_entry(title="", data=user_input)

        default_effect_show_list = list(
            set(effects)
            - set(self._config_entry.options.get(CONF_EFFECT_HIDE_LIST, []))
        )

        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema(
                {
                    vol.Optional(
                        CONF_PRIORITY,
                        default=self._config_entry.options.get(
                            CONF_PRIORITY, DEFAULT_PRIORITY
                        ),
                    ): vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
                    vol.Optional(
                        CONF_EFFECT_SHOW_LIST,
                        default=default_effect_show_list,
                    ): cv.multi_select(effects),
                }
            ),
        )
예제 #13
0
def test_multi_select():
    """Test multi select validation.

    Expected behavior:
        - Will not accept any input but a list
        - Will not accept selections outside of configured scope
    """
    schema = vol.Schema(
        cv.multi_select({
            "paulus": "Paulus",
            "robban": "Robban"
        }))

    with pytest.raises(vol.Invalid):
        schema("robban")
        schema(["paulus", "martinhj"])

    schema(["robban", "paulus"])
예제 #14
0
def _resource_schema_base(available_resources, selected_resources):
    """Resource selection schema."""

    known_available_resources = {
        sensor_id: sensor[SENSOR_NAME]
        for sensor_id, sensor in SENSOR_TYPES.items()
        if sensor_id in available_resources
    }

    if KEY_STATUS in known_available_resources:
        known_available_resources[KEY_STATUS_DISPLAY] = SENSOR_TYPES[
            KEY_STATUS_DISPLAY
        ][SENSOR_NAME]

    return {
        vol.Required(CONF_RESOURCES, default=selected_resources): cv.multi_select(
            known_available_resources
        )
    }
예제 #15
0
    async def async_step_user(self, user_input=None):
        """Choose specific domains in bridge mode."""
        if user_input is not None:
            entity_filter = _EMPTY_ENTITY_FILTER.copy()
            entity_filter[CONF_INCLUDE_DOMAINS] = user_input[CONF_INCLUDE_DOMAINS]
            self.hk_data[CONF_FILTER] = entity_filter
            return await self.async_step_pairing()

        self.hk_data[CONF_HOMEKIT_MODE] = HOMEKIT_MODE_BRIDGE
        default_domains = [] if self._async_current_names() else DEFAULT_DOMAINS
        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema(
                {
                    vol.Required(
                        CONF_INCLUDE_DOMAINS, default=default_domains
                    ): cv.multi_select(SUPPORTED_DOMAINS),
                }
            ),
        )
예제 #16
0
    async def async_step_init(self, user_input=None):
        """Manage the options."""
        errors = {}
        if not self.departure_filters:

            departure_list = {}
            self.hub = self.opp.data[DOMAIN][self.config_entry.entry_id]

            try:
                departure_list = await self.hub.gti.departureList(
                    {
                        "station": self.config_entry.data[CONF_STATION],
                        "time": {"date": "heute", "time": "jetzt"},
                        "maxList": 5,
                        "maxTimeOffset": 200,
                        "useRealtime": True,
                        "returnFilters": True,
                    }
                )
            except CannotConnect:
                errors["base"] = "cannot_connect"
            except InvalidAuth:
                errors["base"] = "invalid_auth"

            if not errors:
                self.departure_filters = {
                    str(i): departure_filter
                    for i, departure_filter in enumerate(departure_list.get("filter"))
                }

        if user_input is not None and not errors:

            options = {
                CONF_FILTER: [
                    self.departure_filters[x] for x in user_input[CONF_FILTER]
                ],
                CONF_OFFSET: user_input[CONF_OFFSET],
                CONF_REAL_TIME: user_input[CONF_REAL_TIME],
            }

            return self.async_create_entry(title="", data=options)

        if CONF_FILTER in self.config_entry.options:
            old_filter = [
                i
                for (i, f) in self.departure_filters.items()
                if f in self.config_entry.options.get(CONF_FILTER)
            ]
        else:
            old_filter = []

        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema(
                {
                    vol.Optional(CONF_FILTER, default=old_filter): cv.multi_select(
                        {
                            key: f"{departure_filter['serviceName']}, {departure_filter['label']}"
                            for key, departure_filter in self.departure_filters.items()
                        }
                    ),
                    vol.Required(
                        CONF_OFFSET,
                        default=self.config_entry.options.get(CONF_OFFSET, 0),
                    ): cv.positive_int,
                    vol.Optional(
                        CONF_REAL_TIME,
                        default=self.config_entry.options.get(CONF_REAL_TIME, True),
                    ): bool,
                }
            ),
            errors=errors,
        )
예제 #17
0
    async def async_step_prompt_options(self, user_input=None):
        """Prompt for options."""
        errors = {}

        if user_input is not None:
            self._global_options = {
                CONF_AUTOMATIC_ADD: user_input[CONF_AUTOMATIC_ADD],
            }
            if CONF_DEVICE in user_input:
                entry_id = user_input[CONF_DEVICE]
                device_data = self._get_device_data(entry_id)
                self._selected_device_entry_id = entry_id
                event_code = device_data[CONF_EVENT_CODE]
                self._selected_device_event_code = event_code
                self._selected_device = self._config_entry.data[CONF_DEVICES][
                    event_code]
                self._selected_device_object = get_rfx_object(event_code)
                return await self.async_step_set_device_options()
            if CONF_REMOVE_DEVICE in user_input:
                remove_devices = user_input[CONF_REMOVE_DEVICE]
                devices = {}
                for entry_id in remove_devices:
                    device_data = self._get_device_data(entry_id)

                    event_code = device_data[CONF_EVENT_CODE]
                    device_id = device_data[CONF_DEVICE_ID]
                    self.opp.helpers.dispatcher.async_dispatcher_send(
                        f"{DOMAIN}_{CONF_REMOVE_DEVICE}_{device_id}")
                    self._device_registry.async_remove_device(entry_id)
                    if event_code is not None:
                        devices[event_code] = None

                self.update_config_data(global_options=self._global_options,
                                        devices=devices)

                return self.async_create_entry(title="", data={})
            if CONF_EVENT_CODE in user_input:
                self._selected_device_event_code = user_input[CONF_EVENT_CODE]
                self._selected_device = {}
                selected_device_object = get_rfx_object(
                    self._selected_device_event_code)
                if selected_device_object is None:
                    errors[CONF_EVENT_CODE] = "invalid_event_code"
                elif not self._can_add_device(selected_device_object):
                    errors[CONF_EVENT_CODE] = "already_configured_device"
                else:
                    self._selected_device_object = selected_device_object
                    return await self.async_step_set_device_options()

            if not errors:
                self.update_config_data(global_options=self._global_options)

                return self.async_create_entry(title="", data={})

        device_registry = await async_get_device_registry(self.opp)
        device_entries = async_entries_for_config_entry(
            device_registry, self._config_entry.entry_id)
        self._device_registry = device_registry
        self._device_entries = device_entries

        remove_devices = {
            entry.id: entry.name_by_user if entry.name_by_user else entry.name
            for entry in device_entries
        }

        configure_devices = {
            entry.id: entry.name_by_user if entry.name_by_user else entry.name
            for entry in device_entries
            if self._get_device_event_code(entry.id) is not None
        }

        options = {
            vol.Optional(
                CONF_AUTOMATIC_ADD,
                default=self._config_entry.data[CONF_AUTOMATIC_ADD],
            ):
            bool,
            vol.Optional(CONF_EVENT_CODE):
            str,
            vol.Optional(CONF_DEVICE):
            vol.In(configure_devices),
            vol.Optional(CONF_REMOVE_DEVICE):
            cv.multi_select(remove_devices),
        }

        return self.async_show_form(step_id="prompt_options",
                                    data_schema=vol.Schema(options),
                                    errors=errors)