Exemplo n.º 1
0
    async def async_step_init(self, user_input=None):
        """Manage the options."""
        if user_input is not None:
            return self.async_create_entry(
                title=self.config_entry.data[CONF_USERNAME], data=user_input)

        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema({
                vol.Required(CONF_TRACK_ALARMS,
                             default=self.config_entry.options.get(
                                 CONF_TRACK_ALARMS, False)):
                bool,
                vol.Required(CONF_TRACK_DEVICES,
                             default=self.config_entry.options.get(
                                 CONF_TRACK_DEVICES, True)):
                bool,
                #vol.Required(CONF_TRACK_NEW_DEVICES, default=self.config_entry.options.get(CONF_TRACK_NEW_DEVICES, DEFAULT_TRACK_NEW)): bool,
                vol.Required(CONF_CONSIDER_HOME,
                             default=self.config_entry.options.get(
                                 CONF_CONSIDER_HOME,
                                 DEFAULT_CONSIDER_HOME.total_seconds())):
                int,
                vol.Required(
                    CONF_RSSI_THRESHOLD,
                    default=self.config_entry.options.get(
                        CONF_RSSI_THRESHOLD, DEFAULT_RSSI_THRESHOLD),
                ):
                int,
                #vol.Required(
                #    CONF_DEVICE_TYPES,
                #    default=self.config_entry.data.get(CONF_DEVICE_TYPES, DEFAULT_DEVICE_TYPES),
                #): [vol.In(DEFAULT_DEVICE_TYPES)],
            }),
        )
Exemplo n.º 2
0
async def async_get_scanner(hass: HomeAssistant, config: ConfigType) -> None:
    """Validate the configuration and return a Nmap scanner."""
    validated_config = config[DEVICE_TRACKER_DOMAIN]

    if CONF_SCAN_INTERVAL in validated_config:
        scan_interval = validated_config[CONF_SCAN_INTERVAL].total_seconds()
    else:
        scan_interval = TRACKER_SCAN_INTERVAL

    if CONF_CONSIDER_HOME in validated_config:
        consider_home = validated_config[CONF_CONSIDER_HOME].total_seconds()
    else:
        consider_home = DEFAULT_CONSIDER_HOME.total_seconds()

    import_config = {
        CONF_HOSTS: ",".join(validated_config[CONF_HOSTS]),
        CONF_HOME_INTERVAL: validated_config[CONF_HOME_INTERVAL],
        CONF_CONSIDER_HOME: consider_home,
        CONF_EXCLUDE: ",".join(validated_config[CONF_EXCLUDE]),
        CONF_OPTIONS: validated_config[CONF_OPTIONS],
        CONF_SCAN_INTERVAL: scan_interval,
    }

    hass.async_create_task(
        hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": SOURCE_IMPORT},
            data=import_config,
        )
    )

    _LOGGER.warning(
        "Your Nmap Tracker configuration has been imported into the UI, "
        "please remove it from configuration.yaml. "
    )
Exemplo n.º 3
0
    async def async_step_init(
        self, user_input: dict[str, Any] | None = None
    ) -> FlowResult:
        """Handle options flow."""

        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)

        data_schema = vol.Schema(
            {
                vol.Optional(
                    CONF_CONSIDER_HOME,
                    default=self.config_entry.options.get(
                        CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds()
                    ),
                ): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=900)),
                vol.Optional(
                    CONF_OLD_DISCOVERY,
                    default=self.config_entry.options.get(
                        CONF_OLD_DISCOVERY, DEFAULT_CONF_OLD_DISCOVERY
                    ),
                ): bool,
            }
        )
        return self.async_show_form(step_id="init", data_schema=data_schema)
Exemplo n.º 4
0
async def test_user(hass: HomeAssistant, fc_class_mock):
    """Test starting a flow by user."""
    with patch(
            "homeassistant.components.fritz.common.FritzConnection",
            side_effect=fc_class_mock,
    ), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
            "homeassistant.components.fritz.async_setup_entry"
    ) as mock_setup_entry:

        result = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER})
        assert result["type"] == RESULT_TYPE_FORM
        assert result["step_id"] == "user"

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"], user_input=MOCK_USER_DATA)
        assert result["type"] == RESULT_TYPE_CREATE_ENTRY
        assert result["data"][CONF_HOST] == "fake_host"
        assert result["data"][CONF_PASSWORD] == "fake_pass"
        assert result["data"][CONF_USERNAME] == "fake_user"
        assert (result["options"][CONF_CONSIDER_HOME] ==
                DEFAULT_CONSIDER_HOME.total_seconds())
        assert not result["result"].unique_id
        await hass.async_block_till_done()

    assert mock_setup_entry.called
Exemplo n.º 5
0
    def scan_devices(self, now: datetime | None = None) -> None:
        """Scan for new devices and return a list of found device ids."""
        _LOGGER.debug("Checking devices for FRITZ!Box router %s", self.host)

        if self._options:
            consider_home = self._options.get(
                CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds())
        else:
            consider_home = DEFAULT_CONSIDER_HOME

        new_device = False
        for known_host in self._update_info():
            if not known_host.get("mac"):
                continue

            dev_mac = known_host["mac"]
            dev_name = known_host["name"]
            dev_ip = known_host["ip"]
            dev_home = known_host["status"]

            dev_info = Device(dev_mac, dev_ip, dev_name)

            if dev_mac in self._devices:
                self._devices[dev_mac].update(dev_info, dev_home,
                                              consider_home)
            else:
                device = FritzDevice(dev_mac, dev_name)
                device.update(dev_info, dev_home, consider_home)
                self._devices[dev_mac] = device
                new_device = True

        dispatcher_send(self.hass, self.signal_device_update)
        if new_device:
            dispatcher_send(self.hass, self.signal_device_new)
Exemplo n.º 6
0
async def _async_build_schema_with_user_input(
        hass: HomeAssistant, user_input: dict[str, Any],
        include_options: bool) -> vol.Schema:
    hosts = user_input.get(CONF_HOSTS, await async_get_network(hass))
    exclude = user_input.get(
        CONF_EXCLUDE, await network.async_get_source_ip(hass, MDNS_TARGET_IP))
    schema = {
        vol.Required(CONF_HOSTS, default=hosts):
        str,
        vol.Required(CONF_HOME_INTERVAL,
                     default=user_input.get(CONF_HOME_INTERVAL, 0)):
        int,
        vol.Optional(CONF_EXCLUDE, default=exclude):
        str,
        vol.Optional(CONF_OPTIONS,
                     default=user_input.get(CONF_OPTIONS, DEFAULT_OPTIONS)):
        str,
    }
    if include_options:
        schema.update({
            vol.Optional(
                CONF_SCAN_INTERVAL,
                default=user_input.get(CONF_SCAN_INTERVAL, TRACKER_SCAN_INTERVAL),
            ):
            vol.All(vol.Coerce(int), vol.Range(min=10, max=MAX_SCAN_INTERVAL)),
            vol.Optional(
                CONF_CONSIDER_HOME,
                default=user_input.get(CONF_CONSIDER_HOME) or DEFAULT_CONSIDER_HOME.total_seconds(
                ),
            ):
            vol.All(vol.Coerce(int), vol.Range(min=1, max=MAX_CONSIDER_HOME)),
        })
    return vol.Schema(schema)
Exemplo n.º 7
0
async def test_options_reload(hass: HomeAssistant, fc_class_mock,
                              fh_class_mock):
    """Test reload of Fritz!Tools, when options changed."""

    entry = MockConfigEntry(
        domain=DOMAIN,
        data=MOCK_USER_DATA,
        options={CONF_CONSIDER_HOME: DEFAULT_CONSIDER_HOME.total_seconds()},
    )
    entry.add_to_hass(hass)

    with patch(
            "homeassistant.config_entries.ConfigEntries.async_reload",
            return_value=None,
    ) as mock_reload:
        assert await async_setup_component(hass, DOMAIN, {})
        await hass.async_block_till_done()
        assert entry.state == ConfigEntryState.LOADED

        result = await hass.config_entries.options.async_init(entry.entry_id)
        await hass.async_block_till_done()
        await hass.config_entries.options.async_configure(
            result["flow_id"],
            user_input={CONF_CONSIDER_HOME: 60},
        )
        await hass.async_block_till_done()
        mock_reload.assert_called_once()
Exemplo n.º 8
0
 def _async_create_entry(self) -> FlowResult:
     """Async create flow handler entry."""
     return self.async_create_entry(
         title=self._name,
         data={
             CONF_HOST: self.fritz_tools.host,
             CONF_PASSWORD: self.fritz_tools.password,
             CONF_PORT: self.fritz_tools.port,
             CONF_USERNAME: self.fritz_tools.username,
         },
         options={
             CONF_CONSIDER_HOME: DEFAULT_CONSIDER_HOME.total_seconds(),
         },
     )
Exemplo n.º 9
0
    def scan_devices(self, now: datetime | None = None) -> None:
        """Scan for new devices and return a list of found device ids."""
        _LOGGER.debug("Checking devices for FRITZ!Box router %s", self.host)

        _default_consider_home = DEFAULT_CONSIDER_HOME.total_seconds()
        if self._options:
            consider_home = self._options.get(CONF_CONSIDER_HOME,
                                              _default_consider_home)
        else:
            consider_home = _default_consider_home

        new_device = False
        for known_host in self._update_hosts_info():
            if not known_host.get("mac"):
                continue

            dev_mac = known_host["mac"]
            dev_name = known_host["name"]
            dev_ip = known_host["ip"]
            dev_home = known_host["status"]
            dev_wan_access = True
            if dev_ip:
                wan_access = self.connection.call_action(
                    "X_AVM-DE_HostFilter:1",
                    "GetWANAccessByIP",
                    NewIPv4Address=dev_ip,
                )
                if wan_access:
                    dev_wan_access = not wan_access.get("NewDisallow")

            dev_info = Device(dev_mac, dev_ip, dev_name, dev_wan_access)

            if dev_mac in self._devices:
                self._devices[dev_mac].update(dev_info, dev_home,
                                              consider_home)
            else:
                device = FritzDevice(dev_mac, dev_name)
                device.update(dev_info, dev_home, consider_home)
                self._devices[dev_mac] = device
                new_device = True

        dispatcher_send(self.hass, self.signal_device_update)
        if new_device:
            dispatcher_send(self.hass, self.signal_device_new)

        _LOGGER.debug("Checking host info for FRITZ!Box router %s", self.host)
        self._update_available, self._latest_firmware = self._update_device_info(
        )
Exemplo n.º 10
0
    async def async_step_init(
        self, user_input: dict[str, Any] | None = None
    ) -> FlowResult:
        """Handle options flow."""
        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)

        data_schema = vol.Schema(
            {
                vol.Optional(
                    CONF_CONSIDER_HOME,
                    default=self.config_entry.options.get(
                        CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds()
                    ),
                ): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=900)),
                vol.Optional(
                    CONF_TRACK_UNKNOWN,
                    default=self.config_entry.options.get(
                        CONF_TRACK_UNKNOWN, DEFAULT_TRACK_UNKNOWN
                    ),
                ): bool,
                vol.Required(
                    CONF_INTERFACE,
                    default=self.config_entry.options.get(
                        CONF_INTERFACE, DEFAULT_INTERFACE
                    ),
                ): str,
                vol.Required(
                    CONF_DNSMASQ,
                    default=self.config_entry.options.get(
                        CONF_DNSMASQ, DEFAULT_DNSMASQ
                    ),
                ): str,
            }
        )

        if self.config_entry.data[CONF_MODE] == MODE_AP:
            data_schema = data_schema.extend(
                {
                    vol.Optional(
                        CONF_REQUIRE_IP,
                        default=self.config_entry.options.get(CONF_REQUIRE_IP, True),
                    ): bool,
                }
            )

        return self.async_show_form(step_id="init", data_schema=data_schema)
Exemplo n.º 11
0
    async def update_devices(self) -> None:
        """Update AsusWrt devices tracker."""
        new_device = False
        _LOGGER.debug("Checking devices for ASUS router %s", self._host)
        try:
            api_devices = await self._api.async_get_connected_devices()
        except OSError as exc:
            if not self._connect_error:
                self._connect_error = True
                _LOGGER.error(
                    "Error connecting to ASUS router %s for device update: %s",
                    self._host,
                    exc,
                )
            return

        if self._connect_error:
            self._connect_error = False
            _LOGGER.info("Reconnected to ASUS router %s", self._host)

        self._connected_devices = len(api_devices)
        consider_home = self._options.get(
            CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds())
        track_unknown = self._options.get(CONF_TRACK_UNKNOWN,
                                          DEFAULT_TRACK_UNKNOWN)

        wrt_devices = {
            format_mac(mac): dev
            for mac, dev in api_devices.items()
        }
        for device_mac, device in self._devices.items():
            dev_info = wrt_devices.pop(device_mac, None)
            device.update(dev_info, consider_home)

        for device_mac, dev_info in wrt_devices.items():
            if not track_unknown and not dev_info.name:
                continue
            new_device = True
            device = AsusWrtDevInfo(device_mac)
            device.update(dev_info)
            self._devices[device_mac] = device

        async_dispatcher_send(self.hass, self.signal_device_update)
        if new_device:
            async_dispatcher_send(self.hass, self.signal_device_new)
        await self._update_unpolled_sensors()
Exemplo n.º 12
0
async def async_migrate_entry(hass: HomeAssistant,
                              config_entry: ConfigEntry) -> bool:
    """Migrate config entry."""
    _LOGGER.debug("Migrating from version %s", config_entry.version)

    if config_entry.version == 1:
        config_entry.version = 2
        hass.config_entries.async_update_entry(
            config_entry,
            options={
                CONF_CONSIDER_HOME: DEFAULT_CONSIDER_HOME.total_seconds()
            },
        )

    _LOGGER.info("Migration to version %s successful", config_entry.version)

    return True
Exemplo n.º 13
0
 def __init__(self, hass, client, config, device):
     """Initialize the scanner."""
     super().__init__(
         hass,
         timedelta(seconds=config.options.get(CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME.total_seconds())),
         #config.options.get(CONF_TRACK_NEW_DEVICES, DEFAULT_TRACK_NEW),
         True, # TODO migrate to the new device tracker api
         {}, list(),
     )
     self.hass = hass
     self.rssi = config.options.get(CONF_RSSI_THRESHOLD, DEFAULT_RSSI_THRESHOLD)
     self.device_types = config.options.get(CONF_DEVICE_TYPES, DEFAULT_DEVICE_TYPES)
     self.host = device.host
     self.uuid = device.uuid
     self.name = device.friendly_name
     self.client = client
     self.config_entry = config
     self.removal = None
     self.active = True
Exemplo n.º 14
0
async def test_user(hass: HomeAssistant, fc_class_mock, mock_get_source_ip):
    """Test starting a flow by user."""
    with patch(
        "homeassistant.components.fritz.common.FritzConnection",
        side_effect=fc_class_mock,
    ), patch("homeassistant.components.fritz.common.FritzStatus"), patch(
        "homeassistant.components.fritz.common.FritzBoxTools._update_device_info",
        return_value=MOCK_FIRMWARE_INFO,
    ), patch(
        "homeassistant.components.fritz.async_setup_entry"
    ) as mock_setup_entry, patch(
        "requests.get"
    ) as mock_request_get, patch(
        "requests.post"
    ) as mock_request_post:

        mock_request_get.return_value.status_code = 200
        mock_request_get.return_value.content = MOCK_REQUEST
        mock_request_post.return_value.status_code = 200
        mock_request_post.return_value.text = MOCK_REQUEST

        result = await hass.config_entries.flow.async_init(
            DOMAIN, context={"source": SOURCE_USER}
        )
        assert result["type"] == RESULT_TYPE_FORM
        assert result["step_id"] == "user"

        result = await hass.config_entries.flow.async_configure(
            result["flow_id"], user_input=MOCK_USER_DATA
        )
        assert result["type"] == RESULT_TYPE_CREATE_ENTRY
        assert result["data"][CONF_HOST] == "fake_host"
        assert result["data"][CONF_PASSWORD] == "fake_pass"
        assert result["data"][CONF_USERNAME] == "fake_user"
        assert (
            result["options"][CONF_CONSIDER_HOME]
            == DEFAULT_CONSIDER_HOME.total_seconds()
        )
        assert not result["result"].unique_id
        await hass.async_block_till_done()

    assert mock_setup_entry.called
Exemplo n.º 15
0
"""Constants used in the Keenetic NDMS2 components."""

from homeassistant.components.device_tracker.const import (
    DEFAULT_CONSIDER_HOME as _DEFAULT_CONSIDER_HOME, )

DOMAIN = "keenetic_ndms2"
ROUTER = "router"
UNDO_UPDATE_LISTENER = "undo_update_listener"
DEFAULT_TELNET_PORT = 23
DEFAULT_SCAN_INTERVAL = 120
DEFAULT_CONSIDER_HOME = _DEFAULT_CONSIDER_HOME.total_seconds()
DEFAULT_INTERFACE = "Home"

CONF_CONSIDER_HOME = "consider_home"
CONF_INTERFACES = "interfaces"
CONF_TRY_HOTSPOT = "try_hotspot"
CONF_INCLUDE_ARP = "include_arp"
CONF_INCLUDE_ASSOCIATED = "include_associated"

CONF_LEGACY_INTERFACE = "interface"
Exemplo n.º 16
0
    CONF_HOME_INTERVAL,
    CONF_OPTIONS,
    DEFAULT_OPTIONS,
    DOMAIN,
    TRACKER_SCAN_INTERVAL,
)

_LOGGER = logging.getLogger(__name__)


PLATFORM_SCHEMA = DEVICE_TRACKER_PLATFORM_SCHEMA.extend(
    {
        vol.Required(CONF_HOSTS): cv.ensure_list,
        vol.Required(CONF_HOME_INTERVAL, default=0): cv.positive_int,
        vol.Required(
            CONF_CONSIDER_HOME, default=DEFAULT_CONSIDER_HOME.total_seconds()
        ): cv.time_period,
        vol.Optional(CONF_EXCLUDE, default=[]): vol.All(cv.ensure_list, [cv.string]),
        vol.Optional(CONF_OPTIONS, default=DEFAULT_OPTIONS): cv.string,
    }
)


async def async_get_scanner(hass: HomeAssistant, config: ConfigType) -> None:
    """Validate the configuration and return a Nmap scanner."""
    validated_config = config[DEVICE_TRACKER_DOMAIN]

    if CONF_SCAN_INTERVAL in validated_config:
        scan_interval = validated_config[CONF_SCAN_INTERVAL].total_seconds()
    else:
        scan_interval = TRACKER_SCAN_INTERVAL
Exemplo n.º 17
0
    def scan_devices(self, now: datetime | None = None) -> None:
        """Scan for new devices and return a list of found device ids."""

        _LOGGER.debug("Checking host info for FRITZ!Box router %s", self.host)
        self._update_available, self._latest_firmware = self._update_device_info(
        )

        try:
            topology = self.fritz_hosts.get_mesh_topology()
        except FritzActionError:
            self.mesh_role = MeshRoles.SLAVE
            return

        _LOGGER.debug("Checking devices for FRITZ!Box router %s", self.host)
        _default_consider_home = DEFAULT_CONSIDER_HOME.total_seconds()
        if self._options:
            consider_home = self._options.get(CONF_CONSIDER_HOME,
                                              _default_consider_home)
        else:
            consider_home = _default_consider_home

        new_device = False
        hosts = {}
        for host in self._update_hosts_info():
            if not host.get("mac"):
                continue

            hosts[host["mac"]] = Device(
                name=host["name"],
                connected=host["status"],
                connected_to="",
                connection_type="",
                ip_address=host["ip"],
                ssid=None,
                wan_access=False,
            )

        mesh_intf = {}
        # first get all meshed devices
        for node in topology["nodes"]:
            if not node["is_meshed"]:
                continue

            for interf in node["node_interfaces"]:
                int_mac = interf["mac_address"]
                mesh_intf[interf["uid"]] = Interface(
                    device=node["device_name"],
                    mac=int_mac,
                    op_mode=interf.get("op_mode", ""),
                    ssid=interf.get("ssid", ""),
                    type=interf["type"],
                )
                if format_mac(int_mac) == format_mac(self.mac):
                    self.mesh_role = MeshRoles(node["mesh_role"])

        # second get all client devices
        for node in topology["nodes"]:
            if node["is_meshed"]:
                continue

            for interf in node["node_interfaces"]:
                dev_mac = interf["mac_address"]
                for link in interf["node_links"]:
                    intf = mesh_intf.get(link["node_interface_1_uid"])
                    if (intf is not None and link["state"] == "CONNECTED"
                            and dev_mac in hosts):
                        dev_info: Device = hosts[dev_mac]
                        if intf["op_mode"] != "AP_GUEST":
                            dev_info.wan_access = not self.connection.call_action(
                                "X_AVM-DE_HostFilter:1",
                                "GetWANAccessByIP",
                                NewIPv4Address=dev_info.ip_address,
                            ).get("NewDisallow")

                        dev_info.connected_to = intf["device"]
                        dev_info.connection_type = intf["type"]
                        dev_info.ssid = intf.get("ssid")

                        if dev_mac in self._devices:
                            self._devices[dev_mac].update(
                                dev_info, consider_home)
                        else:
                            device = FritzDevice(dev_mac, dev_info.name)
                            device.update(dev_info, consider_home)
                            self._devices[dev_mac] = device
                            new_device = True

        dispatcher_send(self.hass, self.signal_device_update)
        if new_device:
            dispatcher_send(self.hass, self.signal_device_new)