Skip to content

Commit

Permalink
Add Fritz services (home-assistant#50056)
Browse files Browse the repository at this point in the history
  • Loading branch information
chemelli74 authored May 11, 2021
1 parent 214fd41 commit d877c0c
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 1 deletion.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ omit =
homeassistant/components/fritz/const.py
homeassistant/components/fritz/device_tracker.py
homeassistant/components/fritz/sensor.py
homeassistant/components/fritz/services.py
homeassistant/components/fritzbox_callmonitor/__init__.py
homeassistant/components/fritzbox_callmonitor/const.py
homeassistant/components/fritzbox_callmonitor/base.py
Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/fritz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from .common import FritzBoxTools, FritzData
from .const import DATA_FRITZ, DOMAIN, PLATFORMS
from .services import async_setup_services, async_unload_services

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -55,6 +56,8 @@ def _async_unload(event):
# Load the other platforms like switch
hass.config_entries.async_setup_platforms(entry, PLATFORMS)

await async_setup_services(hass)

return True


Expand All @@ -73,4 +76,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)

await async_unload_services(hass)

return unload_ok
27 changes: 27 additions & 0 deletions homeassistant/components/fritz/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@

# pylint: disable=import-error
from fritzconnection import FritzConnection
from fritzconnection.core.exceptions import (
FritzActionError,
FritzConnectionException,
FritzServiceError,
)
from fritzconnection.lib.fritzhosts import FritzHosts
from fritzconnection.lib.fritzstatus import FritzStatus

from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
Expand All @@ -22,6 +28,8 @@
DEFAULT_PORT,
DEFAULT_USERNAME,
DOMAIN,
SERVICE_REBOOT,
SERVICE_RECONNECT,
TRACKER_SCAN_INTERVAL,
)

Expand Down Expand Up @@ -157,6 +165,25 @@ def scan_devices(self, now: datetime | None = None) -> None:
if new_device:
async_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)
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


class FritzData:
"""Storage class for platform global data."""
Expand Down
5 changes: 4 additions & 1 deletion homeassistant/components/fritz/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
DEFAULT_PORT = 49000
DEFAULT_USERNAME = ""


ERROR_AUTH_INVALID = "invalid_auth"
ERROR_CONNECTION_ERROR = "connection_error"
ERROR_UNKNOWN = "unknown_error"

FRITZ_SERVICES = "fritz_services"
SERVICE_REBOOT = "reboot"
SERVICE_RECONNECT = "reconnect"

TRACKER_SCAN_INTERVAL = 30

UPTIME_DEVIATION = 5
62 changes: 62 additions & 0 deletions homeassistant/components/fritz/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Services for Fritz integration."""
import logging

from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.service import async_extract_config_entry_ids

from .const import DOMAIN, FRITZ_SERVICES, SERVICE_REBOOT, SERVICE_RECONNECT

_LOGGER = logging.getLogger(__name__)


async def async_setup_services(hass: HomeAssistant):
"""Set up services for Fritz integration."""
if hass.data.get(FRITZ_SERVICES, False):
return

hass.data[FRITZ_SERVICES] = True

async def async_call_fritz_service(service_call):
"""Call correct Fritz service."""

if not (
fritzbox_entry_ids := await _async_get_configured_fritz_tools(
hass, service_call
)
):
raise HomeAssistantError(
f"Failed to call service '{service_call.service}'. Config entry for target not found"
)

for entry in fritzbox_entry_ids:
_LOGGER.debug("Executing service %s", service_call.service)
fritz_tools = hass.data[DOMAIN].get(entry)
await fritz_tools.service_fritzbox(service_call.service)

for service in [SERVICE_REBOOT, SERVICE_RECONNECT]:
hass.services.async_register(DOMAIN, service, async_call_fritz_service)


async def _async_get_configured_fritz_tools(
hass: HomeAssistant, service_call: ServiceCall
):
"""Get FritzBoxTools class from config entry."""

return [
entry_id
for entry_id in await async_extract_config_entry_ids(hass, service_call)
if hass.config_entries.async_get_entry(entry_id).domain == DOMAIN
]


async def async_unload_services(hass: HomeAssistant):
"""Unload services for Fritz integration."""

if not hass.data.get(FRITZ_SERVICES):
return

hass.data[FRITZ_SERVICES] = False

hass.services.async_remove(DOMAIN, SERVICE_REBOOT)
hass.services.async_remove(DOMAIN, SERVICE_RECONNECT)
13 changes: 13 additions & 0 deletions homeassistant/components/fritz/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
reconnect:
description: Reconnects your FRITZ!Box internet connection
target:
entity:
integration: fritz
domain: binary_sensor

reboot:
description: Reboots your FRITZ!Box
target:
entity:
integration: fritz
domain: binary_sensor

0 comments on commit d877c0c

Please sign in to comment.