def __init__(self, config): """Initialize the scanner.""" self.last_results = [] self.host = config[CONF_HOST] self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] self.success_init = True # Establish a connection to the FRITZ!Box. try: self.fritz_box = FritzHosts(address=self.host, user=self.username, password=self.password) except (ValueError, TypeError): self.fritz_box = None # At this point it is difficult to tell if a connection is established. # So just check for null objects. if self.fritz_box is None or not self.fritz_box.modelname: self.success_init = False if self.success_init: _LOGGER.info("Successfully connected to %s", self.fritz_box.modelname) self._update_info() else: _LOGGER.error( "Failed to establish connection to FRITZ!Box with IP: %s", self.host)
async def _async_update_data(self) -> None: """Update FritzboxTools data.""" try: self.fritz_hosts = FritzHosts(fc=self.connection) await self.async_scan_devices() except (FritzSecurityError, FritzConnectionException) as ex: raise update_coordinator.UpdateFailed from ex
def setup(self) -> None: """Set up FritzboxTools class.""" self.connection = FritzConnection( address=self.host, port=self.port, user=self.username, password=self.password, timeout=60.0, pool_maxsize=30, ) if not self.connection: _LOGGER.error("Unable to establish a connection with %s", self.host) return self.fritz_hosts = FritzHosts(fc=self.connection) self.fritz_status = FritzStatus(fc=self.connection) info = self.connection.call_action("DeviceInfo:1", "GetInfo") if not self._unique_id: self._unique_id = info["NewSerialNumber"] self._model = info.get("NewModelName") self._current_firmware = info.get("NewSoftwareVersion") self._update_available, self._latest_firmware = self._update_device_info() self.device_is_router = "WANIPConn1" in self.connection.services
async def async_start(self, options): """Start FritzHosts connection.""" self.fritz_hosts = FritzHosts(fc=self.connection) self._options = options await self.opp.async_add_executor_job(self.scan_devices) self._cancel_scan = async_track_time_interval( self.opp, self.scan_devices, timedelta(seconds=TRACKER_SCAN_INTERVAL) )
async def async_start(self, options: MappingProxyType[str, Any]) -> None: """Start FritzHosts connection.""" self.fritz_hosts = FritzHosts(fc=self.connection) self._options = options await self.hass.async_add_executor_job(self.scan_devices) self._cancel_scan = async_track_time_interval( self.hass, self.scan_devices, timedelta(seconds=TRACKER_SCAN_INTERVAL))
def hosts(): active_hosts = [] fh = FritzHosts(address=ADDRESS, password=PASSWORD) hosts = fh.get_hosts_info() for index, host in enumerate(hosts, start=1): # print(f"{host['name']:<28} {host['status']}") if host['status']: if host['name'] in SCAN_HOSTS: active_hosts.append(host['name']) return active_hosts
def getHOSTStatus(): fh = FritzHosts(fc) hosts = fh.get_hosts_info() activehosts = fh.get_active_hosts() print("**********************************\n") print("Overview known hosts:") print("Following %s hosts are known!\n" % (len(hosts))) print("Following %s hosts are active in your network:" % (len(activehosts))) print("IP-Address Name Status") print("---------------------------------------------------") for i in range(0, len(hosts) - 1): if hosts[i]["status"] == True: ipaddress = hosts[i]["ip"] hostname = hosts[i]["name"] hoststatus = hosts[i]["status"] print(f"{ipaddress:18} {hostname:25} - {hoststatus}")
def _poll_loop(self): self._current_data = FritzBoxData() last_hosts: Optional[datetime] = None while self._running: try: self._current_data.status = FritzStatus(address=self._address, password=self._password) if not last_hosts or (datetime.now() - last_hosts) / timedelta(seconds=10) >= 1: self.current_data.hosts = FritzHosts(address=self._address, password=self._password) self.current_data.wlan = FritzWLAN(address=self._address, password=self._password) last_hosts = datetime.now() except IOError as e: log.warning(f"Failed to get FritzBox data: {e}") self._notify_listeners() self._queue.get()
def check_hosts(status): home = False hosts = FritzHosts(fritz).get_active_hosts() # Read data from Fritz!Box with fritzconnection # check if given MAC addresses stored in .env are online # This could be a bit more readable though... for host in hosts: mac = host.get('mac') if mac in maclist: if status != "PAUSE": logger.info("Found {} - {}".format(mac, host.get('name'))) home = True return home
class FritzBoxTools(update_coordinator.DataUpdateCoordinator): """FrtizBoxTools class.""" def __init__( self, hass: HomeAssistant, password: str, username: str = DEFAULT_USERNAME, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT, ) -> None: """Initialize FritzboxTools class.""" super().__init__( hass=hass, logger=_LOGGER, name=f"{DOMAIN}-{host}-coordinator", update_interval=timedelta(seconds=30), ) self._devices: dict[str, FritzDevice] = {} self._options: MappingProxyType[str, Any] | None = None self._unique_id: str | None = None self.connection: FritzConnection = None self.fritz_hosts: FritzHosts = None self.fritz_status: FritzStatus = None self.hass = hass self.host = host self.password = password self.port = port self.username = username self._mac: str | None = None self._model: str | None = None self._current_firmware: str | None = None self._latest_firmware: str | None = None self._update_available: bool = False async def async_setup(self, options: MappingProxyType[str, Any] | None = None ) -> None: """Wrap up FritzboxTools class setup.""" self._options = options await self.hass.async_add_executor_job(self.setup) def setup(self) -> None: """Set up FritzboxTools class.""" self.connection = FritzConnection( address=self.host, port=self.port, user=self.username, password=self.password, timeout=60.0, pool_maxsize=30, ) if not self.connection: _LOGGER.error("Unable to establish a connection with %s", self.host) return self.fritz_status = FritzStatus(fc=self.connection) info = self.connection.call_action("DeviceInfo:1", "GetInfo") if not self._unique_id: self._unique_id = info["NewSerialNumber"] self._model = info.get("NewModelName") self._current_firmware = info.get("NewSoftwareVersion") self._update_available, self._latest_firmware = self._update_device_info( ) @callback async def _async_update_data(self) -> None: """Update FritzboxTools data.""" try: self.fritz_hosts = FritzHosts(fc=self.connection) await self.async_scan_devices() except (FritzSecurityError, FritzConnectionException) as ex: raise update_coordinator.UpdateFailed from ex @property def unique_id(self) -> str: """Return unique id.""" if not self._unique_id: raise ClassSetupMissing() return self._unique_id @property def model(self) -> str: """Return device model.""" if not self._model: raise ClassSetupMissing() return self._model @property def current_firmware(self) -> str: """Return current SW version.""" if not self._current_firmware: raise ClassSetupMissing() return self._current_firmware @property def latest_firmware(self) -> str | None: """Return latest SW version.""" return self._latest_firmware @property def update_available(self) -> bool: """Return if new SW version is available.""" return self._update_available @property def mac(self) -> str: """Return device Mac address.""" if not self._unique_id: raise ClassSetupMissing() return self._unique_id @property def devices(self) -> dict[str, FritzDevice]: """Return devices.""" return self._devices @property def signal_device_new(self) -> str: """Event specific per FRITZ!Box entry to signal new device.""" return f"{DOMAIN}-device-new-{self._unique_id}" @property def signal_device_update(self) -> str: """Event specific per FRITZ!Box entry to signal updates in devices.""" return f"{DOMAIN}-device-update-{self._unique_id}" def _update_hosts_info(self) -> list[HostInfo]: """Retrieve latest hosts information from the FRITZ!Box.""" try: return self.fritz_hosts.get_hosts_info( ) # type: ignore [no-any-return] except Exception as ex: # pylint: disable=[broad-except] if not self.hass.is_stopping: raise HomeAssistantError("Error refreshing hosts info") from ex return [] def _update_device_info(self) -> tuple[bool, str | None]: """Retrieve latest device information from the FRITZ!Box.""" version = self.connection.call_action( "UserInterface1", "GetInfo").get("NewX_AVM-DE_Version") return bool(version), version async def async_scan_devices(self, now: datetime | None = None) -> None: """Wrap up FritzboxTools class scan.""" await self.hass.async_add_executor_job(self.scan_devices, now) 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( ) async def async_trigger_firmware_update(self) -> bool: """Trigger firmware update.""" results = await self.hass.async_add_executor_job( self.connection.call_action, "UserInterface:1", "X_AVM-DE_DoUpdate") return cast(bool, results["NewX_AVM-DE_UpdateState"]) async def async_trigger_reboot(self) -> None: """Trigger device reboot.""" await self.hass.async_add_executor_job(self.connection.call_action, "DeviceConfig1", "Reboot") async def async_trigger_reconnect(self) -> None: """Trigger device reconnect.""" await self.hass.async_add_executor_job(self.connection.call_action, "WANIPConn1", "ForceTermination") async def service_fritzbox(self, service_call: ServiceCall, config_entry: ConfigEntry) -> None: """Define FRITZ!Box services.""" _LOGGER.debug("FRITZ!Box router: %s", service_call.service) if not self.connection: raise HomeAssistantError("Unable to establish a connection") try: if service_call.service == SERVICE_REBOOT: _LOGGER.warning( 'Service "fritz.reboot" is deprecated, please use the corresponding button entity instead' ) await self.hass.async_add_executor_job( self.connection.call_action, "DeviceConfig1", "Reboot") return if service_call.service == SERVICE_RECONNECT: _LOGGER.warning( 'Service "fritz.reconnect" is deprecated, please use the corresponding button entity instead' ) await self.hass.async_add_executor_job( self.connection.call_action, "WANIPConn1", "ForceTermination", ) return if service_call.service == SERVICE_CLEANUP: device_hosts_list: list = await self.hass.async_add_executor_job( self.fritz_hosts.get_hosts_info) except (FritzServiceError, FritzActionError) as ex: raise HomeAssistantError("Service or parameter unknown") from ex except FritzConnectionException as ex: raise HomeAssistantError("Service not supported") from ex entity_reg: EntityRegistry = ( await self.hass.helpers.entity_registry.async_get_registry()) ha_entity_reg_list: list[ RegistryEntry] = self.hass.helpers.entity_registry.async_entries_for_config_entry( entity_reg, config_entry.entry_id) entities_removed: bool = False device_hosts_macs = {device["mac"] for device in device_hosts_list} for entry in ha_entity_reg_list: if (not _cleanup_entity_filter(entry) or entry.unique_id.split("_")[0] in device_hosts_macs): continue _LOGGER.info("Removing entity: %s", entry.name or entry.original_name) entity_reg.async_remove(entry.entity_id) entities_removed = True if entities_removed: self._async_remove_empty_devices(entity_reg, config_entry) @callback def _async_remove_empty_devices(self, entity_reg: EntityRegistry, config_entry: ConfigEntry) -> None: """Remove devices with no entities.""" device_reg = async_get(self.hass) device_list = async_entries_for_config_entry(device_reg, config_entry.entry_id) for device_entry in device_list: if not async_entries_for_device( entity_reg, device_entry.id, include_disabled_entities=True, ): _LOGGER.info("Removing device: %s", device_entry.name) device_reg.async_remove_device(device_entry.id)
class FritzBoxTools: """FrtizBoxTools class.""" def __init__( self, hass, password, username=DEFAULT_USERNAME, host=DEFAULT_HOST, port=DEFAULT_PORT, ): """Initialize FritzboxTools class.""" self._cancel_scan = None self._device_info = None self._devices: dict[str, Any] = {} self._unique_id = None self.connection = None self.fritzhosts = None self.fritzstatus = None self.hass = hass self.host = host self.password = password self.port = port self.username = username async def async_setup(self): """Wrap up FritzboxTools class setup.""" return await self.hass.async_add_executor_job(self.setup) def setup(self): """Set up FritzboxTools class.""" self.connection = FritzConnection( address=self.host, port=self.port, user=self.username, password=self.password, timeout=60.0, ) self.fritzstatus = FritzStatus(fc=self.connection) if self._unique_id is None: self._unique_id = self.connection.call_action( "DeviceInfo:1", "GetInfo")["NewSerialNumber"] self._device_info = self._fetch_device_info() async def async_start(self): """Start FritzHosts connection.""" self.fritzhosts = FritzHosts(fc=self.connection) await self.hass.async_add_executor_job(self.scan_devices) self._cancel_scan = async_track_time_interval( self.hass, self.scan_devices, timedelta(seconds=TRACKER_SCAN_INTERVAL)) @callback def async_unload(self): """Unload FritzboxTools class.""" _LOGGER.debug("Unloading FRITZ!Box router integration") if self._cancel_scan is not None: self._cancel_scan() self._cancel_scan = None @property def unique_id(self): """Return unique id.""" return self._unique_id @property def fritzbox_model(self): """Return model.""" return self._device_info["model"].replace("FRITZ!Box ", "") @property def device_info(self): """Return device info.""" return self._device_info @property def devices(self) -> dict[str, Any]: """Return devices.""" return self._devices @property def signal_device_new(self) -> str: """Event specific per FRITZ!Box entry to signal new device.""" return f"{DOMAIN}-device-new-{self._unique_id}" @property def signal_device_update(self) -> str: """Event specific per FRITZ!Box entry to signal updates in devices.""" return f"{DOMAIN}-device-update-{self._unique_id}" def _update_info(self): """Retrieve latest information from the FRITZ!Box.""" return self.fritzhosts.get_hosts_info() 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) 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) else: device = FritzDevice(dev_mac) device.update(dev_info, dev_home) self._devices[dev_mac] = device new_device = True async_dispatcher_send(self.hass, self.signal_device_update) if new_device: async_dispatcher_send(self.hass, self.signal_device_new) def _fetch_device_info(self): """Fetch device info.""" info = self.connection.call_action("DeviceInfo:1", "GetInfo") dev_info = {} dev_info["identifiers"] = { # Serial numbers are unique identifiers within a specific domain (DOMAIN, self.unique_id) } dev_info["manufacturer"] = "AVM" if dev_name := info.get("NewName"): dev_info["name"] = dev_name if dev_model := info.get("NewModelName"): dev_info["model"] = dev_model
class FritzBoxTools: """FrtizBoxTools class.""" def __init__( self, hass: HomeAssistant, password: str, username: str = DEFAULT_USERNAME, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT, ) -> None: """Initialize FritzboxTools class.""" self._cancel_scan: CALLBACK_TYPE | None = None self._devices: dict[str, Any] = {} self._options: MappingProxyType[str, Any] | None = None self._unique_id: str | None = None self.connection: FritzConnection = None self.fritz_hosts: FritzHosts = None self.fritz_profiles: dict[str, FritzProfileSwitch] = {} self.fritz_status: FritzStatus = None self.hass = hass self.host = host self.password = password self.port = port self.username = username self._mac: str | None = None self._model: str | None = None self._sw_version: str | None = None async def async_setup(self) -> None: """Wrap up FritzboxTools class setup.""" await self.hass.async_add_executor_job(self.setup) def setup(self) -> None: """Set up FritzboxTools class.""" self.connection = FritzConnection( address=self.host, port=self.port, user=self.username, password=self.password, timeout=60.0, ) self.fritz_status = FritzStatus(fc=self.connection) info = self.connection.call_action("DeviceInfo:1", "GetInfo") if not self._unique_id: self._unique_id = info["NewSerialNumber"] self._model = info.get("NewModelName") self._sw_version = info.get("NewSoftwareVersion") self.fritz_profiles = { profile: FritzProfileSwitch("http://" + self.host, self.username, self.password, profile) for profile in get_all_profiles(self.host, self.username, self.password) } async def async_start(self, options: MappingProxyType[str, Any]) -> None: """Start FritzHosts connection.""" self.fritz_hosts = FritzHosts(fc=self.connection) self._options = options await self.hass.async_add_executor_job(self.scan_devices) self._cancel_scan = async_track_time_interval( self.hass, self.scan_devices, timedelta(seconds=TRACKER_SCAN_INTERVAL)) @callback def async_unload(self) -> None: """Unload FritzboxTools class.""" _LOGGER.debug("Unloading FRITZ!Box router integration") if self._cancel_scan is not None: self._cancel_scan() self._cancel_scan = None @property def unique_id(self) -> str: """Return unique id.""" if not self._unique_id: raise ClassSetupMissing() return self._unique_id @property def model(self) -> str: """Return device model.""" if not self._model: raise ClassSetupMissing() return self._model @property def sw_version(self) -> str: """Return SW version.""" if not self._sw_version: raise ClassSetupMissing() return self._sw_version @property def mac(self) -> str: """Return device Mac address.""" if not self._unique_id: raise ClassSetupMissing() return self._unique_id @property def devices(self) -> dict[str, Any]: """Return devices.""" return self._devices @property def signal_device_new(self) -> str: """Event specific per FRITZ!Box entry to signal new device.""" return f"{DOMAIN}-device-new-{self._unique_id}" @property def signal_device_update(self) -> str: """Event specific per FRITZ!Box entry to signal updates in devices.""" return f"{DOMAIN}-device-update-{self._unique_id}" def _update_info(self) -> list[HostInfo]: """Retrieve latest information from the FRITZ!Box.""" return self.fritz_hosts.get_hosts_info() 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) async def service_fritzbox(self, service: str) -> None: """Define FRITZ!Box services.""" _LOGGER.debug("FRITZ!Box router: %s", service) if not self.connection: raise HomeAssistantError("Unable to establish a connection") try: if service == SERVICE_REBOOT: await self.hass.async_add_executor_job( self.connection.call_action, "DeviceConfig1", "Reboot") elif service == SERVICE_RECONNECT: await self.hass.async_add_executor_job( self.connection.call_action, "WANIPConn1", "ForceTermination", ) except (FritzServiceError, FritzActionError) as ex: raise HomeAssistantError("Service or parameter unknown") from ex except FritzConnectionException as ex: raise HomeAssistantError("Service not supported") from ex
def report_hosts(): fh = FritzHosts(address=args.ip, password=args.password) hosts = fh.get_active_hosts() return sorted((host["name"] for host in hosts), key=str.lower)
#!/usr/bin/env python3 # faster to just check status of phone than all hosts from fritzconnection.lib.fritzhosts import FritzHosts import config fh = FritzHosts(password=config.fritz_pwd) he = fh.get_specific_host_entry(config.phone_mac) print(he['NewActive'])
class FritzBoxTools(update_coordinator.DataUpdateCoordinator): """FritzBoxTools class.""" def __init__( self, hass: HomeAssistant, password: str, username: str = DEFAULT_USERNAME, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT, ) -> None: """Initialize FritzboxTools class.""" super().__init__( hass=hass, logger=_LOGGER, name=f"{DOMAIN}-{host}-coordinator", update_interval=timedelta(seconds=30), ) self._devices: dict[str, FritzDevice] = {} self._options: MappingProxyType[str, Any] | None = None self._unique_id: str | None = None self.connection: FritzConnection = None self.fritz_hosts: FritzHosts = None self.fritz_status: FritzStatus = None self.hass = hass self.host = host self.mesh_role = MeshRoles.NONE self.device_is_router: bool = True self.password = password self.port = port self.username = username self._model: str | None = None self._current_firmware: str | None = None self._latest_firmware: str | None = None self._update_available: bool = False async def async_setup( self, options: MappingProxyType[str, Any] | None = None ) -> None: """Wrap up FritzboxTools class setup.""" self._options = options await self.hass.async_add_executor_job(self.setup) def setup(self) -> None: """Set up FritzboxTools class.""" self.connection = FritzConnection( address=self.host, port=self.port, user=self.username, password=self.password, timeout=60.0, pool_maxsize=30, ) if not self.connection: _LOGGER.error("Unable to establish a connection with %s", self.host) return self.fritz_hosts = FritzHosts(fc=self.connection) self.fritz_status = FritzStatus(fc=self.connection) info = self.connection.call_action("DeviceInfo:1", "GetInfo") if not self._unique_id: self._unique_id = info["NewSerialNumber"] self._model = info.get("NewModelName") self._current_firmware = info.get("NewSoftwareVersion") self._update_available, self._latest_firmware = self._update_device_info() self.device_is_router = "WANIPConn1" in self.connection.services @callback async def _async_update_data(self) -> None: """Update FritzboxTools data.""" try: await self.async_scan_devices() except (FritzSecurityError, FritzConnectionException) as ex: raise update_coordinator.UpdateFailed from ex @property def unique_id(self) -> str: """Return unique id.""" if not self._unique_id: raise ClassSetupMissing() return self._unique_id @property def model(self) -> str: """Return device model.""" if not self._model: raise ClassSetupMissing() return self._model @property def current_firmware(self) -> str: """Return current SW version.""" if not self._current_firmware: raise ClassSetupMissing() return self._current_firmware @property def latest_firmware(self) -> str | None: """Return latest SW version.""" return self._latest_firmware @property def update_available(self) -> bool: """Return if new SW version is available.""" return self._update_available @property def mac(self) -> str: """Return device Mac address.""" if not self._unique_id: raise ClassSetupMissing() return dr.format_mac(self._unique_id) @property def devices(self) -> dict[str, FritzDevice]: """Return devices.""" return self._devices @property def signal_device_new(self) -> str: """Event specific per FRITZ!Box entry to signal new device.""" return f"{DOMAIN}-device-new-{self._unique_id}" @property def signal_device_update(self) -> str: """Event specific per FRITZ!Box entry to signal updates in devices.""" return f"{DOMAIN}-device-update-{self._unique_id}" def _update_hosts_info(self) -> list[HostInfo]: """Retrieve latest hosts information from the FRITZ!Box.""" try: return self.fritz_hosts.get_hosts_info() # type: ignore [no-any-return] except Exception as ex: # pylint: disable=[broad-except] if not self.hass.is_stopping: raise HomeAssistantError("Error refreshing hosts info") from ex return [] def _update_device_info(self) -> tuple[bool, str | None]: """Retrieve latest device information from the FRITZ!Box.""" version = self.connection.call_action("UserInterface1", "GetInfo").get( "NewX_AVM-DE_Version" ) return bool(version), version async def async_scan_devices(self, now: datetime | None = None) -> None: """Wrap up FritzboxTools class scan.""" await self.hass.async_add_executor_job(self.scan_devices, now) 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 device %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 device %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 dr.format_mac(int_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) async def async_trigger_firmware_update(self) -> bool: """Trigger firmware update.""" results = await self.hass.async_add_executor_job( self.connection.call_action, "UserInterface:1", "X_AVM-DE_DoUpdate" ) return cast(bool, results["NewX_AVM-DE_UpdateState"]) async def async_trigger_reboot(self) -> None: """Trigger device reboot.""" await self.hass.async_add_executor_job(self.connection.reboot) async def async_trigger_reconnect(self) -> None: """Trigger device reconnect.""" await self.hass.async_add_executor_job(self.connection.reconnect) async def async_trigger_cleanup( self, config_entry: ConfigEntry | None = None ) -> None: """Trigger device trackers cleanup.""" device_hosts_list = await self.hass.async_add_executor_job( self.fritz_hosts.get_hosts_info ) entity_reg: er.EntityRegistry = er.async_get(self.hass) if config_entry is None: if self.config_entry is None: return config_entry = self.config_entry ha_entity_reg_list: list[er.RegistryEntry] = er.async_entries_for_config_entry( entity_reg, config_entry.entry_id ) entities_removed: bool = False device_hosts_macs = set() device_hosts_names = set() for device in device_hosts_list: device_hosts_macs.add(device["mac"]) device_hosts_names.add(device["name"]) for entry in ha_entity_reg_list: if entry.original_name is None: continue entry_name = entry.name or entry.original_name entry_host = entry_name.split(" ")[0] entry_mac = entry.unique_id.split("_")[0] if not _cleanup_entity_filter(entry) or ( entry_mac in device_hosts_macs and entry_host in device_hosts_names ): _LOGGER.debug( "Skipping entity %s [mac=%s, host=%s]", entry_name, entry_mac, entry_host, ) continue _LOGGER.info("Removing entity: %s", entry_name) entity_reg.async_remove(entry.entity_id) entities_removed = True if entities_removed: self._async_remove_empty_devices(entity_reg, config_entry) @callback def _async_remove_empty_devices( self, entity_reg: er.EntityRegistry, config_entry: ConfigEntry ) -> None: """Remove devices with no entities.""" device_reg = dr.async_get(self.hass) device_list = dr.async_entries_for_config_entry( device_reg, config_entry.entry_id ) for device_entry in device_list: if not er.async_entries_for_device( entity_reg, device_entry.id, include_disabled_entities=True, ): _LOGGER.info("Removing device: %s", device_entry.name) device_reg.async_remove_device(device_entry.id) async def service_fritzbox( self, service_call: ServiceCall, config_entry: ConfigEntry ) -> None: """Define FRITZ!Box services.""" _LOGGER.debug("FRITZ!Box service: %s", service_call.service) if not self.connection: raise HomeAssistantError("Unable to establish a connection") try: if service_call.service == SERVICE_REBOOT: _LOGGER.warning( 'Service "fritz.reboot" is deprecated, please use the corresponding button entity instead' ) await self.async_trigger_reboot() return if service_call.service == SERVICE_RECONNECT: _LOGGER.warning( 'Service "fritz.reconnect" is deprecated, please use the corresponding button entity instead' ) await self.async_trigger_reconnect() return if service_call.service == SERVICE_CLEANUP: _LOGGER.warning( 'Service "fritz.cleanup" is deprecated, please use the corresponding button entity instead' ) await self.async_trigger_cleanup(config_entry) return except (FritzServiceError, FritzActionError) as ex: raise HomeAssistantError("Service or parameter unknown") from ex except FritzConnectionException as ex: raise HomeAssistantError("Service not supported") from ex
class FritzBoxScanner(DeviceScanner): """This class queries a FRITZ!Box router.""" def __init__(self, config): """Initialize the scanner.""" self.last_results = [] self.host = config[CONF_HOST] self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] self.success_init = True # Establish a connection to the FRITZ!Box. try: self.fritz_box = FritzHosts(address=self.host, user=self.username, password=self.password) except (ValueError, TypeError): self.fritz_box = None # At this point it is difficult to tell if a connection is established. # So just check for null objects. if self.fritz_box is None or not self.fritz_box.modelname: self.success_init = False if self.success_init: _LOGGER.info("Successfully connected to %s", self.fritz_box.modelname) self._update_info() else: _LOGGER.error( "Failed to establish connection to FRITZ!Box with IP: %s", self.host) def scan_devices(self): """Scan for new devices and return a list of found device ids.""" self._update_info() active_hosts = [] for known_host in self.last_results: if known_host["status"] and known_host.get("mac"): active_hosts.append(known_host["mac"]) return active_hosts def get_device_name(self, device): """Return the name of the given device or None if is not known.""" ret = self.fritz_box.get_specific_host_entry(device).get("NewHostName") if ret == {}: return None return ret def get_extra_attributes(self, device): """Return the attributes (ip, mac) of the given device or None if is not known.""" ip_device = self.fritz_box.get_specific_host_entry(device).get( "NewIPAddress") if not ip_device: return {} return {"ip": ip_device, "mac": device} def _update_info(self): """Retrieve latest information from the FRITZ!Box.""" if not self.success_init: return False _LOGGER.debug("Scanning") self.last_results = self.fritz_box.get_hosts_info() return True
def get_arguments(): parser = argparse.ArgumentParser(description="Get Devices from the WLAN") parser.add_argument('-i', '--ip', help='The IP of the FritzBox', required=True) parser.add_argument('-p', '--password', help='The Password of FritzBox', required=True) arguments = parser.parse_args() return arguments def get_known_devices(f_h): result = '' hosts = f_h.get_hosts_info() for index, host in enumerate(hosts, start=1): ip = host['ip'] if host['ip'] else '-' name = host['name'] mac = host['mac'] if host['mac'] else '-' status = 'online' if host['status'] else 'offline' result += name + ',' + ip + ',' + mac + ',' + status + "\n" result = result.rstrip("\n") return result if __name__ == '__main__': args = get_arguments() fh = FritzHosts(address=args.ip, password=args.password) output = "" print(get_known_devices(fh))
# installation # pip3 install fritzconnection from InfluxUploader import InfluxUploader from fritzconnection.lib.fritzhosts import FritzHosts from fritzconnection import FritzConnection influx = InfluxUploader(verbose=False) my_measurement = 'FritzHosts' # fc = FritzConnection(address='192.168.178.1') # print(fc) # print router model informations fh = FritzHosts(address='192.168.178.1', user='******', password='******') # d = fh.get_specific_host_entry_by_ip('192.168.178.112') # for key, value in d.items(): # print(f"{key} = {value}") l_mac_blacklist = [] l_mac_blacklist.append('E0:C7:67:D9:AE:C4') # FR l_mac_blacklist.append('24:1B:7A:AE:DD:84') # FR # l_mac_blacklist.append('B8:27:EB:05:7C:7E') # raspi3 hosts = fh.get_hosts_info() for index, host in enumerate(hosts, start=1): status = 'active' if host['status'] else '-' ip = host['ip'] if host['ip'] else '-'
with open("conf", "r") as config: key = config.readline().split(":", 1)[-1].strip() allowed_users = [ int(x) for x in config.readline().split(':', 1)[-1].strip().split(',') if len(x) > 0 ] router_ip = config.readline().split(':', 1)[-1].strip() router_pw = config.readline().split(':', 1)[-1].strip() db_vals = config.readline().split(':', 1)[-1].strip() user, user_pw, location, port, database = db_vals.split(',') port = int(port) router_connection = FritzConnection(address=router_ip, password=router_pw) router_wlan = FritzWLAN(router_connection) router_host = FritzHosts(router_connection) router_status = FritzStatus(router_connection) router_model = router_status.modelname metadata = MetaData() db_engine = create_engine( f'mysql+pymysql://{user}:{user_pw}@{location}:{port}/{database}') metadata.reflect(db_engine, only=['stats']) Base = automap_base(metadata=metadata) Base.prepare() db_statistics_class = Base.classes.stats Session = sessionmaker(bind=db_engine) db_session = Session()