Last active
June 24, 2020 08:58
-
-
Save fake666/75c035c74b7be448dd9b3d1316ea6cfe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
A homeassistant switch component to enable or disable fritz! box call deflections / call forwarding | |
tr 064 needs to be enabled, and call deflections have to be pre-defined in the box's ui. | |
removing and adding calldeflections while homeassistant is running will break this ;-) | |
""" | |
import logging | |
import voluptuous as vol | |
from homeassistant.components.switch import (SwitchEntity, PLATFORM_SCHEMA) | |
from homeassistant.const import (CONF_HOST, CONF_PORT, CONF_PASSWORD, CONF_USERNAME) | |
import homeassistant.helpers.config_validation as cv | |
REQUIREMENTS = ['fritzconnection==1.3.0'] | |
_LOGGER = logging.getLogger(__name__) | |
DEFAULT_HOST = '169.254.1.1' # IP valid for all Fritz!Box routers | |
DEFAULT_PORT = 49000 | |
ATTR_TRIGGER_NUMBER = 'trigger_number' | |
ATTR_TARGET_NUMBER = 'target_number' | |
ATTR_UID = 'uid' | |
SERVICE = 'X_AVM-DE_OnTel' | |
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | |
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, | |
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, | |
vol.Required(CONF_PASSWORD): cv.string, | |
vol.Optional(CONF_USERNAME, default=''): cv.string, | |
}) | |
def setup_platform(hass, config, add_entities, discovery_info=None): | |
"""Set up Fritz!Box call deflection switch platform.""" | |
host = config.get(CONF_HOST) | |
port = config.get(CONF_PORT) | |
username = config.get(CONF_USERNAME) | |
password = config.get(CONF_PASSWORD) | |
from lxml import etree | |
import fritzconnection as fc | |
fritz_connection = None; | |
if username != '': | |
fritz_connection = fc.FritzConnection(address=host, password=password, user=username, port=port) | |
else: | |
fritz_connection = fc.FritzConnection(address=host, password=password, port=port) | |
raw_deflections = fritz_connection.call_action(SERVICE, "GetDeflections")["NewDeflectionList"]; | |
element_tree = etree.fromstring(raw_deflections); | |
switches = [] | |
for element in element_tree.findall('Item'): | |
uid = element.find('DeflectionId').text | |
enabled = int(element.find('Enable').text) | |
from_number = element.find('Number').text | |
to_number = element.find('DeflectionToNumber').text | |
# forwardings without to_number are blocked numbers | |
if to_number is None: | |
continue | |
switches.append(FritzCallDeflectSwitch(hass=hass, fritz_connection=fritz_connection, uid=uid, from_number=from_number, to_number=to_number, enabled=enabled)) | |
add_entities(switches); | |
class FritzCallDeflectSwitch(SwitchEntity): | |
"""Representation of a FRITZ! call deflection switch.""" | |
def __init__(self, hass, fritz_connection, uid, from_number, to_number, enabled): | |
"""Initialize the switch.""" | |
self._hass = hass; | |
self._fritz_connection = fritz_connection; | |
self._uid = uid; | |
self._from_number = from_number; | |
self._to_number = to_number; | |
self._enabled = enabled; | |
@property | |
def name(self): | |
"""Return the name of the FRITZ! call deflection (just the uid)""" | |
return "fritzdeflect_" + str(self._uid); | |
@property | |
def device_state_attributes(self): | |
"""Return the state attributes of the call deflection.""" | |
attrs = {} | |
attrs[ATTR_TRIGGER_NUMBER] = "{}".format(self._from_number) | |
attrs[ATTR_TARGET_NUMBER] = "{}".format(self._to_number) | |
attrs[ATTR_UID] = "{}".format(self._uid); | |
return attrs | |
@property | |
def is_on(self): | |
"""Return true if switch is on.""" | |
return self._enabled; | |
def turn_on(self, **kwargs): | |
"""Turn the switch on.""" | |
myargs = {'NewDeflectionId': self._uid, 'NewEnable': 1 } | |
self._fritz_connection.call_action(SERVICE, "SetDeflectionEnable", **myargs); | |
def turn_off(self, **kwargs): | |
"""Turn the switch off.""" | |
myargs = {'NewDeflectionId': self._uid, 'NewEnable': 0 } | |
self._fritz_connection.call_action(SERVICE, "SetDeflectionEnable", **myargs); | |
def update(self): | |
"""Get the latest data from the fritz box and update the state""" | |
kwargs = {'NewDeflectionId': self._uid } | |
try: | |
updated_dict = self._fritz_connection.call_action(SERVICE, "GetDeflection", **kwargs); | |
self._from_number = updated_dict['NewNumber']; | |
self._to_number = updated_dict['NewDeflectionToNumber']; | |
self._enabled = int(updated_dict['NewEnable']); | |
except TypeError: | |
pass | |
Ok. Now I am one step closer.
I renamed folder an file and changed the configuration.yaml entry
fritzbox_calldeflection:
host: 192.168.178.1 (optional)
username: myuser (optional)
password: !secret fb_pass
But now I get the following error:
Setup failed for fritzbox_calldeflection: No setup function defined.
here's my config:
switch:
- platform: fritzbox_calldeflection
host: 192.168.178.1
password: !secret fb_password
If I change my config like yours, home assistant don‘t start anymore.
Did you have other files in /custom_components/fritzbox_calldeflection?
no, just switch.py
and the empty __init__.py
.
do any other custom components work for you? does homeassistant have write permission on this directory?
Yes i have other custom components and they are working.
The permission of the folder and files are 777.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for your help. I have done this but I get the same error message.