Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ omit =
homeassistant/components/device_tracker/bt_home_hub_5.py
homeassistant/components/device_tracker/cisco_ios.py
homeassistant/components/device_tracker/ddwrt.py
homeassistant/components/device_tracker/freebox.py
homeassistant/components/device_tracker/fritz.py
homeassistant/components/device_tracker/google_maps.py
homeassistant/components/device_tracker/gpslogger.py
Expand Down
120 changes: 120 additions & 0 deletions homeassistant/components/device_tracker/freebox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""
Support for device tracking through Freebox routers.

This tracker keeps track of the devices connected to the configured Freebox.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the rest of the docstring from this line to the documentation. Replace this line with a link to the documentation. See other platforms for the correct link format.


For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.freebox/
"""
import asyncio
import copy
import logging
import socket
from collections import namedtuple
from datetime import timedelta

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.components.device_tracker import (
PLATFORM_SCHEMA, CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
from homeassistant.const import (
CONF_HOST, CONF_PORT)

REQUIREMENTS = ['aiofreepybox==0.0.3']

_LOGGER = logging.getLogger(__name__)

FREEBOX_CONFIG_FILE = 'freebox.conf'

PLATFORM_SCHEMA = vol.All(
PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PORT): cv.port
}))

MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)


async def async_setup_scanner(hass, config, async_see, discovery_info=None):
"""Set up the Freebox device tracker and start the polling."""
freebox_config = copy.deepcopy(config)
if discovery_info is not None:
freebox_config[CONF_HOST] = discovery_info['properties']['api_domain']
freebox_config[CONF_PORT] = discovery_info['properties']['https_port']
_LOGGER.info("Discovered Freebox server: %s:%s",
freebox_config[CONF_HOST], freebox_config[CONF_PORT])

scanner = FreeboxDeviceScanner(hass, freebox_config, async_see)
interval = freebox_config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
await scanner.async_start(hass, interval)
return True


Device = namedtuple('Device', ['id', 'name', 'ip'])


def _build_device(device_dict):
return Device(
device_dict['l2ident']['id'],
device_dict['primary_name'],
device_dict['l3connectivities'][0]['addr'])


class FreeboxDeviceScanner(object):
"""This class scans for devices connected to the Freebox."""

def __init__(self, hass, config, async_see):
"""Initialize the scanner."""
from aiofreepybox import Freepybox

self.host = config[CONF_HOST]
self.port = config[CONF_PORT]
self.token_file = hass.config.path(FREEBOX_CONFIG_FILE)
self.async_see = async_see

# Hardcode the app description to avoid invalidating the authentication
# file at each new version.
# The version can be changed if we want the user to re-authorize HASS
# on her Freebox.
app_desc = {
'app_id': 'hass',
'app_name': 'Home Assistant',
'app_version': '0.65',
'device_name': socket.gethostname()
}

api_version = 'v1' # Use the lowest working version.
self.fbx = Freepybox(
app_desc=app_desc,
token_file=self.token_file,
api_version=api_version)

async def async_start(self, hass, interval):
"""Perform a first update and start polling at the given interval."""
await self.async_update_info()
interval = max(interval, MIN_TIME_BETWEEN_SCANS)
async_track_time_interval(hass, self.async_update_info, interval)

async def async_update_info(self, now=None):
"""Check the Freebox for devices."""
from aiofreepybox.exceptions import HttpRequestError

_LOGGER.info('Scanning devices')

await self.fbx.open(self.host, self.port)
try:
hosts = await self.fbx.lan.get_hosts_list()
except HttpRequestError:
_LOGGER.exception('Failed to scan devices')
else:
active_devices = [_build_device(device)
for device in hosts
if device['active']]

if active_devices:
await asyncio.wait([self.async_see(mac=d.id, host_name=d.name)
for d in active_devices])

await self.fbx.close()
1 change: 1 addition & 0 deletions homeassistant/components/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
'kodi': ('media_player', 'kodi'),
'volumio': ('media_player', 'volumio'),
'nanoleaf_aurora': ('light', 'nanoleaf_aurora'),
'freebox': ('device_tracker', 'freebox'),
}

OPTIONAL_SERVICE_HANDLERS = {
Expand Down
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ aioautomatic==0.6.5
# homeassistant.components.sensor.dnsip
aiodns==1.1.1

# homeassistant.components.device_tracker.freebox
aiofreepybox==0.0.3

# homeassistant.components.emulated_hue
# homeassistant.components.http
aiohttp_cors==0.7.0
Expand Down