Официальный API UniFi
Полное руководство по работе с API UniFi для автоматизации управления сетевой инфраструктурой
Обзор API UniFi
UniFi предоставляет мощный API для автоматизации управления сетевой инфраструктурой. С помощью API можно получать информацию о устройствах, клиентах, статистике, а также выполнять различные операции программным способом.
Типы API
UniFi имеет несколько API-интерфейсов:
| API | Описание | Применение |
|---|---|---|
| Local API | API локального контроллера UniFi | Управление конкретным контроллером |
| Site Manager API | Облачный API через unifi.ui.com | Управление несколькими сайтами |
| UniFi OS API | API операционной системы 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/sysinfo | GET | Системная информация |
/api/s/{site}/stat/health | GET | Статус здоровья сети |
/api/s/{site}/self | GET | Информация о текущем пользователе |
Устройства
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/s/{site}/stat/device | GET | Список всех устройств UniFi |
/api/s/{site}/stat/device-basic | GET | Базовая информация об устройствах |
/api/s/{site}/cmd/devmgr | POST | Управление устройством (restart, adopt) |
Клиенты
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/s/{site}/stat/sta | GET | Активные клиенты |
/api/s/{site}/stat/alluser | GET | Все известные клиенты |
/api/s/{site}/rest/user | GET/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:
- Перейдите в Настройки → Устройства и службы
- Нажмите Добавить интеграцию
- Найдите UniFi Network
- Введите адрес контроллера и учётные данные
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 decoratorBest Practices
- Используйте отдельного API-пользователя с минимальными правами
- Храните учётные данные в переменных окружения или секретных хранилищах
- Реализуйте retry-логику для обработки временных ошибок
- Кэшируйте результаты запросов, где это возможно
- Ограничивайте частоту запросов (rate limiting)
- Логируйте все операции для отладки
- Используйте HTTPS и проверяйте сертификаты в продакшене