diff --git a/homeassistant/components/fritz/common.py b/homeassistant/components/fritz/common.py index 2cd6616f134..667d94695d3 100644 --- a/homeassistant/components/fritz/common.py +++ b/homeassistant/components/fritz/common.py @@ -18,6 +18,7 @@ from fritzconnection.core.exceptions import ( ) from fritzconnection.lib.fritzhosts import FritzHosts from fritzconnection.lib.fritzstatus import FritzStatus +from fritzconnection.lib.fritzwlan import DEFAULT_PASSWORD_LENGTH, FritzGuestWLAN from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN from homeassistant.components.device_tracker.const import ( @@ -47,6 +48,7 @@ from .const import ( SERVICE_CLEANUP, SERVICE_REBOOT, SERVICE_RECONNECT, + SERVICE_SET_GUEST_WIFI_PW, MeshRoles, ) @@ -150,6 +152,7 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator): self._options: MappingProxyType[str, Any] | None = None self._unique_id: str | None = None self.connection: FritzConnection = None + self.fritz_guest_wifi: FritzGuestWLAN = None self.fritz_hosts: FritzHosts = None self.fritz_status: FritzStatus = None self.hass = hass @@ -193,6 +196,7 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator): ) self.fritz_hosts = FritzHosts(fc=self.connection) + self.fritz_guest_wifi = FritzGuestWLAN(fc=self.connection) self.fritz_status = FritzStatus(fc=self.connection) info = self.connection.call_action("DeviceInfo:1", "GetInfo") @@ -421,6 +425,14 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator): """Trigger device reconnect.""" await self.hass.async_add_executor_job(self.connection.reconnect) + async def async_trigger_set_guest_password( + self, password: str | None, length: int + ) -> None: + """Trigger service to set a new guest wifi password.""" + await self.hass.async_add_executor_job( + self.fritz_guest_wifi.set_password, password, length + ) + async def async_trigger_cleanup( self, config_entry: ConfigEntry | None = None ) -> None: @@ -520,6 +532,13 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator): await self.async_trigger_cleanup(config_entry) return + if service_call.service == SERVICE_SET_GUEST_WIFI_PW: + await self.async_trigger_set_guest_password( + service_call.data.get("password"), + service_call.data.get("length", DEFAULT_PASSWORD_LENGTH), + ) + return + except (FritzServiceError, FritzActionError) as ex: raise HomeAssistantError("Service or parameter unknown") from ex except FritzConnectionException as ex: diff --git a/homeassistant/components/fritz/const.py b/homeassistant/components/fritz/const.py index 59200e07c78..0a4e9fd6cd8 100644 --- a/homeassistant/components/fritz/const.py +++ b/homeassistant/components/fritz/const.py @@ -49,6 +49,7 @@ FRITZ_SERVICES = "fritz_services" SERVICE_REBOOT = "reboot" SERVICE_RECONNECT = "reconnect" SERVICE_CLEANUP = "cleanup" +SERVICE_SET_GUEST_WIFI_PW = "set_guest_wifi_password" SWITCH_TYPE_DEFLECTION = "CallDeflection" SWITCH_TYPE_PORTFORWARD = "PortForward" diff --git a/homeassistant/components/fritz/services.py b/homeassistant/components/fritz/services.py index e32f4c7ffd7..c4e7de8df5e 100644 --- a/homeassistant/components/fritz/services.py +++ b/homeassistant/components/fritz/services.py @@ -1,6 +1,10 @@ """Services for Fritz integration.""" +from __future__ import annotations + import logging +import voluptuous as vol + from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.exceptions import HomeAssistantError @@ -13,18 +17,31 @@ from .const import ( SERVICE_CLEANUP, SERVICE_REBOOT, SERVICE_RECONNECT, + SERVICE_SET_GUEST_WIFI_PW, ) _LOGGER = logging.getLogger(__name__) +SERVICE_SCHEMA_SET_GUEST_WIFI_PW = vol.Schema( + { + vol.Required("device_id"): str, + vol.Optional("password"): vol.Length(min=8, max=63), + vol.Optional("length"): vol.Range(min=8, max=63), + } +) -SERVICE_LIST = [SERVICE_CLEANUP, SERVICE_REBOOT, SERVICE_RECONNECT] +SERVICE_LIST: list[tuple[str, vol.Schema | None]] = [ + (SERVICE_CLEANUP, None), + (SERVICE_REBOOT, None), + (SERVICE_RECONNECT, None), + (SERVICE_SET_GUEST_WIFI_PW, SERVICE_SCHEMA_SET_GUEST_WIFI_PW), +] async def async_setup_services(hass: HomeAssistant) -> None: """Set up services for Fritz integration.""" - for service in SERVICE_LIST: + for service, _ in SERVICE_LIST: if hass.services.has_service(DOMAIN, service): return @@ -51,8 +68,8 @@ async def async_setup_services(hass: HomeAssistant) -> None: service_call.service, ) - for service in SERVICE_LIST: - hass.services.async_register(DOMAIN, service, async_call_fritz_service) + for service, schema in SERVICE_LIST: + hass.services.async_register(DOMAIN, service, async_call_fritz_service, schema) async def _async_get_configured_avm_device( @@ -80,5 +97,5 @@ async def async_unload_services(hass: HomeAssistant) -> None: hass.data[FRITZ_SERVICES] = False - for service in SERVICE_LIST: + for service, _ in SERVICE_LIST: hass.services.async_remove(DOMAIN, service) diff --git a/homeassistant/components/fritz/services.yaml b/homeassistant/components/fritz/services.yaml index 2375aa71f57..3c7ed643841 100644 --- a/homeassistant/components/fritz/services.yaml +++ b/homeassistant/components/fritz/services.yaml @@ -35,3 +35,30 @@ cleanup: integration: fritz entity: device_class: connectivity +set_guest_wifi_password: + name: Set guest wifi password + description: Set a new password for the guest wifi. The password must be between 8 and 63 characters long. If no additional parameter is set, the password will be auto-generated with a length of 12 characters. + fields: + device_id: + name: Fritz!Box Device + description: Select the Fritz!Box to check + required: true + selector: + device: + integration: fritz + entity: + device_class: connectivity + password: + name: Password + description: New password for the guest wifi + required: false + selector: + text: + length: + name: Password length + description: Length of the new password. The password will be auto-generated, if no password is set. + required: false + selector: + number: + min: 8 + max: 63