-
-
Save fake666/75c035c74b7be448dd9b3d1316ea6cfe to your computer and use it in GitHub Desktop.
| """ | |
| 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 | |
hi, the layout for custom components changed a bit a while back, insteaf of custom_components/switch it now has to be placed in
custom_components/fritzbox_calldeflection/switch.py
you may also need to create an empty __init__.py in the same directory.
Thank you for your help. I have done this but I get the same error message.
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.
Is this still working?
I got the following error:
Platform error switch.fritzbox_calldeflection - Integration 'fritzbox_calldeflection' not found.