Несмотря на то, что у HA есть штатная интеграция для сетевых устройств Keenetic, она предоставляет только возможность отслеживать присутствие устройств в сети (presence detection). Но, как обычно это бывает, со временем появляется необходимость в получении дополнительных данных или управлении интернет-центром.
Маршрутизаторы Keenetic предоставляют несколько вариантов управления – это классический веб-интерфейс, доступ к консоли по telnet или ssh, а так же RESTful API. Несмотря на такой богатый выбор, интегрировать эти устройства без дополнительных телодвижений не получится. Использование telnet зачастую невозможно, так как этот пакет попросту отсутствует в докер контейнере HA, ssh сервер Кинетиков не поддерживает авторизацию пользователей по ключам (только логин\пароль), а REST интерфейс использует собственный механизм авторизации, с которым компоненты HA работать не умеют.
Так как использовать telnet и ssh в самом популярном варианте инсталляции HA без дополнительных прослоек в виде контейнеров, серверов, и т.д. проблематично, стоит сконцентрировать внимание на REST API.
Описание механизма аутентификации можно найти здесь. Так же в свое время техническая поддержка Кинетиков, присылала мне пакет для Node.js реализующий авторизацию на интернет-центрах.
JS-код текстом
const axios = require('axios'); const md5 = require('js-md5'); const jsSHA = require('jssha'); const KEENETIC_IP = '192.168.1.1'; const LOGIN = 'admin'; const PASSWORD = '1'; const AUTH_URL = `http://${KEENETIC_IP}/auth`; const RCI_URL_PREFIX = `http://${KEENETIC_IP}/rci`; const getSha256Hash = (text) => { const shaObj = new jsSHA('SHA-256', 'TEXT'); shaObj.update(text); return shaObj.getHash('HEX'); }; const getMd5HashArg = (login, realm, password) => `${login}:${realm}:${password}`; const getCryptedPass = (login, password, token, realm) => { const md5Arg = getMd5HashArg(login, realm, password); const md5Hash = md5(md5Arg); return getSha256Hash(token + md5Hash); } const authPromise = new Promise((resolve, reject) => { axios.get(AUTH_URL) .then((res) => { console.log('NO PASSWORD'); resolve(); }) .catch((err) => { const headers = err.response.headers; const token = headers['x-ndm-challenge']; const realm = headers['x-ndm-realm']; // DEBUG OUTPUT console.log(`TOKEN=<${token}>`); console.log(`REALM=<${realm}>`); console.log(headers); const cookies = headers['set-cookie'][0].split(';'); // DEBUG OUTPUT console.log(`COOKIES=<${cookies}`); axios({ method: 'post', url: AUTH_URL, headers: { Cookie: cookies[0] }, data: { login: LOGIN, password: getCryptedPass(LOGIN, PASSWORD, token, realm) } }) .then((res) => { console.log('AUTHORIZED!'); resolve(cookies[0]); }) .catch((err) => { console.log('ERROR', err); reject(); }); }); }); authPromise.then((cookie) => { let headers = {}; if (cookie) { headers.Cookie = cookie; } axios({ method: 'get', url: `${RCI_URL_PREFIX}/show/ip/hotspot`, headers: headers }) .then(requestObj => { console.log(requestObj.data); }); })
К сожалению, этот вариант не подходит для стандартной интеграции REST, так как она поддерживает только basic или digest аутентификацию.
Вопрос можно было бы решить написанием кастомного компонента, но, это не ко мне =).
Тем не менее, все же существует возможность общения с Кинетиками по REST без авторизации. Это достаточно “грязный” хак, крайне небезопасный по умолчанию и поэтому требующий в обязательном порядке дополнительных мер – настройки фаервола и\или использования VLAN, благо все это Кинетик умеет.
Дело в том, что “внутри” Keenetic OS во многом используется тот же REST API, только без авторизации. Доступен он по адресу http://127.0.0.1:79
и все что нам остается это создать правило трансляции портов, направляющее трафик из локальной сети на “внутренний” порт 79/tcp
.
Сделать это можно создав следующее правило переадресации портов:
Или через telnet\ssh:
ip static tcp 192.168.0.0 255.255.255.0 81 127.0.0.1 79 !RCI for HA
Где 192.168.0.0
и 255.255.255.0
подсеть, откуда будут обращения к REST’у, а 81
– порт, на который вы будете обращаться.
После создания такого правила, по адресу http://192.168.0.1:81/rci
будет доступен REST API позволяющий управлять практически всеми функциями интернет-центра без авторизации. И повторюсь еще раз – это опасно!
Позаботьтесь как минимум о настройке фаервола, ограничив доступ к 81 порту всем, кроме избранных адресов.
Теперь можно приступить к изучению API.
Некоторую информацию можно почерпнуть из англоязычной документации на интернет-центры, например здесь (Appendix B, HTTP API). Как ни странно, но в русской версии документации этой информации нет. Зато в любой версии документации есть достаточно подробное описание консольных команд, которые пригодятся для формирования нужных запросов к API.
Также полезным может быть использование Developer Tools браузеров, настраивая интернет-центр через веб-интерфейс можно увидеть все выполненные запросы к API:
Для отладки запросов\ответов удобно использовать веб-интерфейс по адресу http://192.168.0.1/a
(вкладка REST):
Далее я приведу несколько примеров использования REST платформы HA для управления Кинетиками.
(вместо 192.168.0.1
нужно указать IP-адрес вашего интернет-центра)
Сенсор IP адреса выданного провайдером (имя интерфейса по умолчанию ISP):
sensor: - platform: rest name: Keenetic MGTS IP unique_id: 2aa13ade-9d53-48a6-8183-f238b13804a4 resource: http://192.168.0.1:81/rci/show/interface?name=ISP scan_interval: 300 value_template: "{{ value_json.address }}" json_attributes: - mask - mac
Сенсоры загрузки CPU и RAM:
sensor: - platform: rest name: Keenetic CPU Usage unique_id: ded628f3-2510-4894-953a-247ad62de663 unit_of_measurement: '%' resource: http://192.168.0.1:81/rci/show/system value_template: "{{ value_json.cpuload }}" - platform: rest name: Keenetic RAM Usage unique_id: 3a225571-d10f-4405-8e0a-b3015a4273b4 unit_of_measurement: '%' resource: http://192.168.0.1:81/rci/show/system value_template: > {%- set mem = value_json.memory-%} {%- set memfree = mem.split('/')[0]|int(0)-%} {%- set memtotal = mem.split('/')[1]|int(1)-%} {{ (memfree*100/memtotal)| round(2) }}
Скорость интерфейса (GigabitEthernet1):
sensor: - platform: rest name: Keenetic MGTS Speed TX unique_id: f454be65-7854-4e28-86cb-3300dd200468 resource: http://192.168.0.1:81/rci/show/interface/stat?name=GigabitEthernet1 scan_interval: 30 value_template: "{{ (value_json.txspeed / 1250000) | round(2) }}" unit_of_measurement: 'Mbit/s' json_attributes: - txbytes - txerrors - txspeed - platform: rest resource: http://192.168.0.1:81/rci/show/interface/stat?name=GigabitEthernet1 name: Keenetic MGTS Speed RX unique_id: 0e5c3581-1e57-42c7-b60f-38141d76165e scan_interval: 30 value_template: "{{ (value_json.rxspeed / 1250000) | round(2) }}" unit_of_measurement: 'Mbit/s' json_attributes: - rxbytes - rxerrors - rxspeed
Статус VPN подключения (интерфейс Wireguard0):
sensor: - platform: rest name: Keenetic Wireguard0 unique_id: 84fcece4-cc5b-43b9-a57a-3ef39c367d9b resource: http://192.168.0.1:81/rci/show/interface/Wireguard0 value_template: "{{ value_json.state }}" json_attributes: - address - link - uptime
Switch для управления гостевой WiFi сетью (таким образом можно включать\выключать любой интерфейс):
switch: - platform: rest name: keenetic_guest_wifi unique_id: fe415708-fafa-4008-9656-96599ba1ba13 resource: "http://192.168.0.1:81/rci/interface/GuestWiFi" body_on: '{"up":"true"}' body_off: '{"down":"true"}' is_on_template: "{{ value_json.up is defined }}"
Включение или отключение интернета для конкретного устройства (mac-адрес нужно заменить на ваш):
switch: - platform: rest name: keenetic_inet_xbox_01 unique_id: 2c5447b0-bcda-478f-bd72-167f56fd0821 resource: "http://192.168.0.1:81/rci/ip/hotspot/host" body_on: '{"mac":"a4:50:46:d4:9b:d0", "access":"permit"}' body_off: '{"mac":"a4:50:46:d4:9b:d0", "access":"deny" }' is_on_template: "{{ 'permit' in value_json | selectattr('mac', 'match', 'a4:50:46:d4:9b:d0') | join }}"
Включение или отключение VPN для устройства:
(Policy4 – предварительно созданная политика доступа в интернет с подключением через VPN, mac заменить на свой)
switch: - platform: rest name: keenetic_vpn_mi8 unique_id: 888c7caa-4352-446a-8b4b-415a4676fa5a resource: "http://192.168.0.1:81/rci/ip/hotspot/host" body_on: '{"mac":"a4:50:46:d4:9b:d0", "policy":"Policy4"}' body_off: '{"mac":"a4:50:46:d4:9b:d0", "policy": false }' is_on_template: "{{ 'Policy4' in value_json | selectattr('mac', 'match', 'a4:50:46:d4:9b:d0') | join }}"
В целом, используя REST API можно управлять практически всеми функциями интернет-центров, а с Home Assistant возможности становятся практически безграничными.
– Алиса, включи VPN для телефона!