Официальный API UniFi

Полное руководство по работе с API UniFi для автоматизации управления сетевой инфраструктурой

Обзор API UniFi

UniFi предоставляет мощный API для автоматизации управления сетевой инфраструктурой. С помощью API можно получать информацию о устройствах, клиентах, статистике, а также выполнять различные операции программным способом.

Типы API

UniFi имеет несколько API-интерфейсов:

APIОписаниеПрименение
Local APIAPI локального контроллера UniFiУправление конкретным контроллером
Site Manager APIОблачный API через unifi.ui.comУправление несколькими сайтами
UniFi OS APIAPI операционной системы Dream MachineСистемные настройки и приложения
Примечание: API UniFi официально не документирован полностью. Информация в этой статье основана на обратном инжиниринге и опыте сообщества.

Аутентификация

Локальная аутентификация

Для работы с локальным API необходимо получить сессионный cookie:

# Авторизация на контроллере
curl -k -X POST https://CONTROLLER_IP:8443/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"your_password"}' \
  -c cookies.txt

# Использование cookie для запросов
curl -k -X GET https://CONTROLLER_IP:8443/api/s/default/stat/sta \
  -b cookies.txt

Аутентификация UniFi OS

Для Dream Machine и Cloud Gateway:

# Авторизация на UniFi OS
curl -k -X POST https://CONTROLLER_IP/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"your_password"}' \
  -c cookies.txt

# Запрос к Network Application
curl -k -X GET https://CONTROLLER_IP/proxy/network/api/s/default/stat/sta \
  -b cookies.txt
Безопасность: Никогда не храните пароли в скриптах в открытом виде. Используйте переменные окружения или секретные хранилища.

Основные эндпоинты

Информация о сайте

ЭндпоинтМетодОписание
/api/s/{site}/stat/sysinfoGETСистемная информация
/api/s/{site}/stat/healthGETСтатус здоровья сети
/api/s/{site}/selfGETИнформация о текущем пользователе

Устройства

ЭндпоинтМетодОписание
/api/s/{site}/stat/deviceGETСписок всех устройств UniFi
/api/s/{site}/stat/device-basicGETБазовая информация об устройствах
/api/s/{site}/cmd/devmgrPOSTУправление устройством (restart, adopt)

Клиенты

ЭндпоинтМетодОписание
/api/s/{site}/stat/staGETАктивные клиенты
/api/s/{site}/stat/alluserGETВсе известные клиенты
/api/s/{site}/rest/userGET/POSTУправление пользователями

Примеры использования

Получение списка клиентов (Python)

import requests
import urllib3

# Отключаем предупреждения о SSL
urllib3.disable_warnings()

class UniFiAPI:
    def __init__(self, host, username, password, site='default'):
        self.host = host
        self.site = site
        self.session = requests.Session()
        self.login(username, password)

    def login(self, username, password):
        url = f'{self.host}/api/login'
        data = {'username': username, 'password': password}
        response = self.session.post(url, json=data, verify=False)
        response.raise_for_status()

    def get_clients(self):
        url = f'{self.host}/api/s/{self.site}/stat/sta'
        response = self.session.get(url, verify=False)
        return response.json()['data']

    def get_devices(self):
        url = f'{self.host}/api/s/{self.site}/stat/device'
        response = self.session.get(url, verify=False)
        return response.json()['data']

# Использование
api = UniFiAPI('https://192.168.1.1:8443', 'admin', 'password')
clients = api.get_clients()
for client in clients:
    print(f"{client.get('hostname', 'Unknown')}: {client['ip']}")

Перезагрузка устройства

def restart_device(self, mac_address):
    url = f'{self.host}/api/s/{self.site}/cmd/devmgr'
    data = {
        'cmd': 'restart',
        'mac': mac_address
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()

Блокировка клиента

def block_client(self, mac_address):
    url = f'{self.host}/api/s/{self.site}/cmd/stamgr'
    data = {
        'cmd': 'block-sta',
        'mac': mac_address
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()

def unblock_client(self, mac_address):
    url = f'{self.host}/api/s/{self.site}/cmd/stamgr'
    data = {
        'cmd': 'unblock-sta',
        'mac': mac_address
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()

Работа с гостевым порталом

Авторизация гостя

def authorize_guest(self, mac, minutes=60):
    """Авторизовать гостя на указанное количество минут"""
    url = f'{self.host}/api/s/{self.site}/cmd/stamgr'
    data = {
        'cmd': 'authorize-guest',
        'mac': mac,
        'minutes': minutes
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()

def unauthorize_guest(self, mac):
    """Деавторизовать гостя"""
    url = f'{self.host}/api/s/{self.site}/cmd/stamgr'
    data = {
        'cmd': 'unauthorize-guest',
        'mac': mac
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()

Получение ваучеров

def get_vouchers(self):
    """Получить список ваучеров"""
    url = f'{self.host}/api/s/{self.site}/stat/voucher'
    response = self.session.get(url, verify=False)
    return response.json()['data']

def create_vouchers(self, count=1, quota=1, expire=1440, note=''):
    """Создать ваучеры

    Args:
        count: количество ваучеров
        quota: сколько раз можно использовать (0 = безлимит)
        expire: время действия в минутах (1440 = 1 день)
        note: заметка
    """
    url = f'{self.host}/api/s/{self.site}/cmd/hotspot'
    data = {
        'cmd': 'create-voucher',
        'n': count,
        'quota': quota,
        'expire': expire,
        'note': note
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()

Статистика и отчёты

Статистика трафика

def get_daily_stats(self, start_timestamp=None, end_timestamp=None):
    """Получить дневную статистику сайта"""
    import time

    if not end_timestamp:
        end_timestamp = int(time.time())
    if not start_timestamp:
        start_timestamp = end_timestamp - (30 * 24 * 60 * 60)  # 30 дней

    url = f'{self.host}/api/s/{self.site}/stat/report/daily.site'
    data = {
        'attrs': ['wlan-num_sta', 'wlan_bytes', 'wan-tx_bytes', 'wan-rx_bytes'],
        'start': start_timestamp * 1000,
        'end': end_timestamp * 1000
    }
    response = self.session.post(url, json=data, verify=False)
    return response.json()['data']

История событий

def get_events(self, limit=100):
    """Получить последние события"""
    url = f'{self.host}/api/s/{self.site}/stat/event'
    params = {'_limit': limit}
    response = self.session.get(url, params=params, verify=False)
    return response.json()['data']

def get_alarms(self):
    """Получить активные уведомления"""
    url = f'{self.host}/api/s/{self.site}/stat/alarm'
    response = self.session.get(url, verify=False)
    return response.json()['data']
Совет: Для мониторинга используйте webhooks или периодический polling. Не делайте запросы чаще, чем раз в 5-10 секунд, чтобы не перегружать контроллер.

Интеграции

Home Assistant

Для интеграции с Home Assistant используйте официальную интеграцию UniFi:

  1. Перейдите в Настройки → Устройства и службы
  2. Нажмите Добавить интеграцию
  3. Найдите UniFi Network
  4. Введите адрес контроллера и учётные данные

Prometheus и Grafana

Для мониторинга используйте unifi_exporter:

# docker-compose.yml
version: '3'
services:
  unifi-exporter:
    image: jessestuart/unifi_exporter:latest
    environment:
      - UNIFI_EXPORTER_CONTROLLER_URL=https://controller:8443
      - UNIFI_EXPORTER_CONTROLLER_USER=admin
      - UNIFI_EXPORTER_CONTROLLER_PASS=password
      - UNIFI_EXPORTER_CONTROLLER_SITE=default
    ports:
      - "9130:9130"

Telegram-бот для уведомлений

import requests
import time

TELEGRAM_BOT_TOKEN = 'your_bot_token'
TELEGRAM_CHAT_ID = 'your_chat_id'

def send_telegram(message):
    url = f'https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage'
    data = {'chat_id': TELEGRAM_CHAT_ID, 'text': message}
    requests.post(url, data=data)

def monitor_new_clients(api, known_clients):
    """Мониторинг новых клиентов"""
    current_clients = {c['mac'] for c in api.get_clients()}
    new_clients = current_clients - known_clients

    for mac in new_clients:
        client = next(c for c in api.get_clients() if c['mac'] == mac)
        hostname = client.get('hostname', 'Unknown')
        ip = client.get('ip', 'Unknown')
        send_telegram(f'🆕 Новый клиент в сети:\n{hostname}\nIP: {ip}\nMAC: {mac}')

    return current_clients

# Основной цикл мониторинга
known = set()
while True:
    known = monitor_new_clients(api, known)
    time.sleep(60)

Обработка ошибок

Типичные коды ответов

КодОписаниеРешение
200Успех
400Неверный запросПроверьте параметры
401Не авторизованПовторите login
403Доступ запрещёнПроверьте права пользователя
404Не найденоПроверьте имя сайта и эндпоинт

Обёртка с retry

import time
from functools import wraps

def retry_on_auth_error(max_retries=3):
    def decorator(func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(self, *args, **kwargs)
                except requests.exceptions.HTTPError as e:
                    if e.response.status_code == 401 and attempt < max_retries - 1:
                        self.login(self.username, self.password)
                        time.sleep(1)
                    else:
                        raise
            return None
        return wrapper
    return decorator

Best Practices

  • Используйте отдельного API-пользователя с минимальными правами
  • Храните учётные данные в переменных окружения или секретных хранилищах
  • Реализуйте retry-логику для обработки временных ошибок
  • Кэшируйте результаты запросов, где это возможно
  • Ограничивайте частоту запросов (rate limiting)
  • Логируйте все операции для отладки
  • Используйте HTTPS и проверяйте сертификаты в продакшене

Полезные ресурсы

Была ли эта статья полезной?

NetEvo
NetEvo Store Онлайн
👋

Привет!

Есть вопросы по оборудованию UniFi? Напишите нам, и мы поможем с выбором!

Представьтесь, чтобы начать диалог: