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 @@ -201,6 +201,7 @@ omit =
homeassistant/components/device_tracker/icloud.py
homeassistant/components/device_tracker/linksys_ap.py
homeassistant/components/device_tracker/luci.py
homeassistant/components/device_tracker/mikrotik.py
homeassistant/components/device_tracker/netgear.py
homeassistant/components/device_tracker/nmap_tracker.py
homeassistant/components/device_tracker/ping.py
Expand Down
131 changes: 131 additions & 0 deletions homeassistant/components/device_tracker/mikrotik.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
Support for Mikrotik routers as device tracker.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.mikrotik/
"""
import logging
import threading
from datetime import timedelta

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.components.device_tracker import (
DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
from homeassistant.const import (CONF_HOST,
CONF_PASSWORD,
CONF_USERNAME,
CONF_PORT)
from homeassistant.util import Throttle

REQUIREMENTS = ['librouteros==1.0.2']

# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)

MTK_DEFAULT_API_PORT = '8728'

_LOGGER = logging.getLogger(__name__)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_PORT, default=MTK_DEFAULT_API_PORT): cv.port
})


def get_scanner(hass, config):
"""Validate the configuration and return MTikScanner."""
scanner = MikrotikScanner(config[DOMAIN])
return scanner if scanner.success_init else None


class MikrotikScanner(DeviceScanner):
"""This class queries a Mikrotik router."""

def __init__(self, config):
"""Initialize the scanner."""
self.last_results = {}

self.host = config[CONF_HOST]
self.port = config[CONF_PORT]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]

self.lock = threading.Lock()

self.connected = False
self.success_init = False
self.client = None

self.success_init = self.connect_to_device()

if self.success_init:
_LOGGER.info('Start polling Mikrotik router...')
self._update_info()
else:
_LOGGER.error('Connection to Mikrotik failed.')

def connect_to_device(self):
"""Connect to Mikrotik method."""
# pylint: disable=import-error
import librouteros
try:
self.client = librouteros.connect(
self.host,
self.username,
self.password,
port=int(self.port)
)

routerboard_info = self.client(cmd='/system/routerboard/getall')

if routerboard_info:
_LOGGER.info('Connected to Mikrotik %s with ip %s.',
routerboard_info[0].get('model', 'Router'),
self.host)
self.connected = True

except (librouteros.exceptions.TrapError,
librouteros.exceptions.ConnectionError) as api_error:
_LOGGER.error('Connection error: %s', api_error)

return self.connected

def scan_devices(self):
"""Scan for new devices and return a list with found device MACs."""
self._update_info()
return [device for device in self.last_results]

def get_device_name(self, mac):
"""Return the name of the given device or None if we don't know."""
with self.lock:
return self.last_results.get(mac)

@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""Retrieve latest information from the Mikrotik box."""
with self.lock:
_LOGGER.info('Loading wireless device from Mikrotik...')

wireless_clients = self.client(
cmd='/interface/wireless/registration-table/getall'
)
device_names = self.client(cmd='/ip/dhcp-server/lease/getall')

if device_names is None or wireless_clients is None:
return False

mac_names = {device.get('mac-address'): device.get('host-name')
for device in device_names
if device.get('mac-address')}

self.last_results = {
device.get('mac-address'):
mac_names.get(device.get('mac-address'))
for device in wireless_clients
}

return True
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ knxip==0.3.3
# homeassistant.components.device_tracker.owntracks
libnacl==1.5.0

# homeassistant.components.device_tracker.mikrotik
librouteros==1.0.2

# homeassistant.components.media_player.soundtouch
libsoundtouch==0.3.0

Expand Down