UNPKG

node-unifi

Version:

NodeJS class for querying UniFi-Controller (www.ubnt.com)

1,526 lines (1,334 loc) 110 kB
/* eslint-disable max-params, camelcase */ /** * * UniFi controller class (NodeJS) * * This nodejs class provides functionality to query a UniFi controller (www.ubnt.com) through * its Web-API. The functionality implemented here had been gathered through different * souces, namely: * * UniFi-API-client: https://github.com/Art-of-WiFi/UniFi-API-client/blob/master/src/Client.php * UniFi-API sh: https://dl.ui.com/unifi/5.12.35/unifi_sh_api * domwo: http://community.ubnt.com/t5/UniFi-Wireless/little-php-class-for-unifi-api/m-p/603051 * fbagnol: https://github.com/fbagnol/class.unifi.php * * The majority of the functions in here are actually based on the PHP UniFi-API-client class * which defines compatibility to UniFi-Controller versions v4 and v5+ * * Based/Compatible to UniFi-API-client class: v1.1.80 * * Copyright (c) 2017-2023 Jens Maus <mail@jens-maus.de> * * The source code is distributed under the MIT license * */ 'use strict'; const EventEmitter = require('eventemitter2').EventEmitter2; const WebSocket = require('ws'); const axios = require('axios'); const {CookieJar} = require('tough-cookie'); const {HttpCookieAgent, HttpsCookieAgent} = require('http-cookie-agent/http'); /// /////////////////////////////////////////////////////////// // PUBLIC CLASS class Controller extends EventEmitter { /** CONSTRUCTOR */ constructor(options) { super({ wildcard: true }); // Parse opts this.opts = options || {}; this.opts.host = (typeof (this.opts.host) === 'undefined' ? 'unifi' : this.opts.host); this.opts.port = (typeof (this.opts.port) === 'undefined' ? 8443 : this.opts.port); this.opts.username = (typeof (this.opts.username) === 'undefined' ? 'admin' : this.opts.username); this.opts.password = (typeof (this.opts.password) === 'undefined' ? 'ubnt' : this.opts.password); this.opts.token2FA = (typeof (this.opts.token2FA) === 'undefined' ? null : this.opts.token2FA); this.opts.site = (typeof (this.opts.site) === 'undefined' ? 'default' : this.opts.site); this.opts.sslverify = (typeof (this.opts.sslverify) === 'undefined' ? true : this.opts.sslverify); this.opts.timeout = (typeof (this.opts.timeout) === 'undefined' ? 5000 : this.opts.timeout); this.opts.rememberMe = (typeof (this.opts.rememberMe) === 'undefined' ? true : this.opts.rememberMe); this._baseurl = new URL(`https://${options.host}:${options.port}`); this._cookieJar = new CookieJar(); this._unifios = false; this._isClosed = true; this._autoReconnectInterval = 5 * 1000; // Ms this._pingPongInterval = 3 * 1000; // Ms this._isInit = false; } /** PUBLIC METHODS */ /** * Login to the UniFi controller - login() * * returns true upon success */ async login(username = null, password = null, token2FA = null) { // Allows to override username+password if (username !== null) { this.opts.username = username; } if (password !== null) { this.opts.password = password; } if (token2FA !== null) { this.opts.token2FA = token2FA; } // Make sure init() was called const result = await this._init(); // If init() was already called // resolve immediately if (result === 2) { return true; } let endpointUrl = `${this._baseurl.href}api/login`; if (this._unifios) { endpointUrl = `${this._baseurl.href}api/auth/login`; } // Prepare payload data const data = { username: this.opts.username, password: this.opts.password, rememberMe: this.opts.rememberMe }; // Add 2FA token to payload if (this.opts.token2FA) { // On UniFiOS 2FA is in 'token' field, else in 'ubic_2fa_token' data[this._unifios ? 'token' : 'ubic_2fa_token'] = this.opts.token2FA; } // Perform the login to the Unifi controller const response = await this._instance.post(endpointUrl, data, { timeout: this.opts.timeout }); // Catch x-csrf-token if supplied in response if (response.headers['x-csrf-token']) { this._xcsrftoken = response.headers['x-csrf-token']; this._instance.defaults.headers.common['x-csrf-token'] = this._xcsrftoken; } return true; } /** * Logout from the UniFi controller - logout() * * returns true upon success */ async logout() { if (this._unifios === true) { return this._request('/api/auth/logout', null, 'POST'); } return this._request('/logout'); } /** * Authorize a client device - authorize_guest() * * required parameter <mac> = client MAC address * optional parameter <minutes> = minutes (from now) until authorization expires * optional parameter <up> = upload speed limit in kbps * optional parameter <down> = download speed limit in kbps * optional parameter <megabytes>= data transfer limit in MB * optional parameter <ap_mac> = AP MAC address to which client is connected, should result in faster authorization */ authorizeGuest(mac, minutes = null, up = null, down = null, megabytes = null, ap_mac = null) { const payload = {cmd: 'authorize-guest', mac: mac.toLowerCase()}; if (minutes !== null) { payload.minutes = minutes; } if (up !== null) { payload.up = up; } if (down !== null) { payload.down = down; } if (megabytes !== null) { payload.bytes = megabytes; } if (ap_mac !== null) { payload.ap_mac = ap_mac.toLowerCase(); } return this._request('/api/s/<SITE>/cmd/stamgr', payload); } /** * Unauthorize a client device - unauthorize_guest() * * required parameter <mac> = client MAC address */ unauthorizeGuest(mac) { return this._request('/api/s/<SITE>/cmd/stamgr', {cmd: 'unauthorize-guest', mac: mac.toLowerCase()}); } /** * Reconnect a client device - reconnect_sta() * * required parameter <mac> = client MAC address */ reconnectClient(mac) { return this._request('/api/s/<SITE>/cmd/stamgr', {cmd: 'kick-sta', mac: mac.toLowerCase()}); } /** * Block a client device - block_sta() * * required parameter <mac> = client MAC address */ blockClient(mac) { return this._request('/api/s/<SITE>/cmd/stamgr', {cmd: 'block-sta', mac: mac.toLowerCase()}); } /** * Unblock a client device - unblock_sta() * * required parameter <mac> = client MAC address */ unblockClient(mac) { return this._request('/api/s/<SITE>/cmd/stamgr', {cmd: 'unblock-sta', mac: mac.toLowerCase()}); } /** * Forget one or more client devices - forget_sta() * * return true on success * required parameter <macs> = array of client MAC addresses * * NOTE: * only supported with controller versions 5.9.X and higher, can be * slow (up to 5 minutes) on larger controllers */ forgetClient(macs) { return this._request('/api/s/<SITE>/cmd/stamgr', {cmd: 'forget-sta', macs}); } /** * Create a new user/client-device - create_user() * * return an array with a single object containing details of the new user/client-device on success, else return false * required parameter <mac> = client MAC address * required parameter <user_group_id> = _id value for the user group the new user/client-device should belong to which * can be obtained from the output of list_usergroups() * optional parameter <name> = name to be given to the new user/client-device * optional parameter <note> = note to be applied to the new user/client-device * optional parameter <is_guest> = boolean; defines whether the new user/client-device is a guest or not * optional parameter <is_wired> = boolean; defines whether the new user/client-device is wi red or not */ createUser(mac, user_group_id, name = null, note = null, is_guest = null, is_wired = null) { const new_user = {mac: mac.toLowerCase(), user_group_id }; if (name !== null) { new_user.name = name; } if (note !== null) { new_user.note = note; } if (is_guest !== null) { new_user.is_guest = is_guest; } if (is_wired !== null) { new_user.is_wired = is_wired; } return this._request('/api/s/<SITE>/group/user', {objects: [{data: new_user}]}); } /** * Add/modify/remove a client device note - set_sta_note() * * required parameter <user_id> = id of the client-device to be modified * optional parameter <note> = note to be applied to the client-device * * NOTES: * - when note is empty or not set, the existing note for the client-device is removed and "noted" attribute set to false */ setClientNote(user_id, note = '') { return this._request('/api/s/<SITE>/upd/user/' + user_id.trim(), {note}); } /** * Add/modify/remove a client device name - set_sta_name() * * required parameter <user_id> = id of the client device to be modified * optional parameter <name> = name to be applied to the client device * * NOTES: * - when name is empty or not set, the existing name for the client device is removed */ setClientName(user_id, name = '') { return this._request('/api/s/<SITE>/upd/user/' + user_id.trim(), {name}); } /** * Fetch 5 minutes site stats method - stat_5minutes_site() * * returns an array of 5-minute stats objects for the current site * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * * NOTES: * - defaults to the past 12 hours * - this function/method is only supported on controller versions 5.5.* and later * - make sure that the retention policy for 5 minutes stats is set to the correct value in * the controller settings */ get5minSiteStats(start = null, end = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (12 * 3600 * 1000); } const payload = {attrs: ['bytes', 'wan-tx_bytes', 'wan-rx_bytes', 'wan2-tx_bytes', 'wan2-rx_bytes', 'wlan_bytes', 'num_sta', 'lan-num_sta', 'wlan-num_sta', 'time'], start, end}; return this._request('/api/s/<SITE>/stat/report/5minutes.site', payload); } /** * Fetch Hourly site stats method - stat_hourly_site() * * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * * NOTES: * - defaults to the past 7*24 hours * - "bytes" are no longer returned with controller version 4.9.1 and later */ getHourlySiteStats(start = null, end = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (7 * 24 * 3600 * 1000); } const payload = {attrs: ['bytes', 'wan-tx_bytes', 'wan-rx_bytes', 'wan2-tx_bytes', 'wan2-rx_bytes', 'wlan_bytes', 'num_sta', 'lan-num_sta', 'wlan-num_sta', 'time'], start, end}; return this._request('/api/s/<SITE>/stat/report/hourly.site', payload); } /** * Fetch Daily site stats method - stat_daily_site() * * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * * NOTES: * - defaults to the past 52*7*24 hours * - "bytes" are no longer returned with controller version 4.9.1 and later */ getDailySiteStats(start = null, end = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (52 * 7 * 24 * 3600 * 1000); } const payload = {attrs: ['bytes', 'wan-tx_bytes', 'wan-rx_bytes', 'wan2-tx_bytes', 'wan2-rx_bytes', 'wlan_bytes', 'num_sta', 'lan-num_sta', 'wlan-num_sta', 'time'], start, end}; return this._request('/api/s/<SITE>/stat/report/daily.site', payload); } /** * Fetch monthly site stats - stat_monthly_site() * * @param int $start optional, Unix timestamp in milliseconds * @param int $end optional, Unix timestamp in milliseconds * @return array returns an array of monthly stats objects for the current site * * NOTES: * - defaults to the past 52 weeks (52*7*24 hours) * - "bytes" are no longer returned with controller version 4.9.1 and later */ getMonthlySiteStats(start = null, end = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (52 * 7 * 24 * 3600 * 1000); } const payload = {attrs: ['bytes', 'wan-tx_bytes', 'wan-rx_bytes', 'wan2-tx_bytes', 'wan2-rx_bytes', 'wlan_bytes', 'num_sta', 'lan-num_sta', 'wlan-num_sta', 'time'], start, end}; return this._request('/api/s/<SITE>/stat/report/monthly.site', payload); } /** * Fetch 5 minutes stats method for a single access point or all access points - stat_5minutes_aps() * * returns an array of 5-minute stats objects * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <mac> = AP MAC address to return stats for * * NOTES: * - defaults to the past 12 hours * - this function/method is only supported on controller versions 5.5.* and later * - make sure that the retention policy for 5 minutes stats is set to the correct value in * the controller settings */ get5minApStats(start = null, end = null, mac = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (12 * 3600 * 1000); } const payload = {attrs: ['bytes', 'num_sta', 'time'], start, end}; if (mac !== null) { payload.mac = mac.toLowerCase(); } return this._request('/api/s/<SITE>/stat/report/5minutes.ap', payload); } /** * Fetch Hourly stats method for a single access point or all access points - stat_hourly_aps() * * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <mac> = AP MAC address to return stats for * * NOTES: * - defaults to the past 7*24 hours * - UniFi controller does not keep these stats longer than 5 hours with versions < 4.6.6 */ getHourlyApStats(start = null, end = null, mac = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (7 * 24 * 3600 * 1000); } const payload = {attrs: ['bytes', 'num_sta', 'time'], start, end}; if (mac !== null) { payload.mac = mac.toLowerCase(); } return this._request('/api/s/<SITE>/stat/report/hourly.ap', payload); } /** * Fetch Daily stats method for a single access point or all access points - stat_daily_aps() * * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <mac> = AP MAC address to return stats for * * NOTES: * - defaults to the past 7*24 hours * - UniFi controller does not keep these stats longer than 5 hours with versions < 4.6.6 */ getDailyApStats(start = null, end = null, mac = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (7 * 24 * 3600 * 1000); } const payload = {attrs: ['bytes', 'num_sta', 'time'], start, end}; if (mac !== null) { payload.mac = mac.toLowerCase(); } return this._request('/api/s/<SITE>/stat/report/daily.ap', payload); } /** * Fetch monthly stats for a single access point or all access points - stat_monthly_aps() * * NOTES: * - defaults to the past 52 weeks (52*7*24 hours) * - make sure that the retention policy for hourly stats is set to the correct value in * the controller settings * * @param int $start optional, Unix timestamp in milliseconds * @param int $end optional, Unix timestamp in milliseconds * @param string $mac optional, AP MAC address to return stats for, when empty, * stats for all APs are returned * @return array returns an array of monthly stats objects */ getMonthlyApStats(start = null, end = null, mac = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (52 * 7 * 24 * 3600 * 1000); } const payload = {attrs: ['bytes', 'num_sta', 'time'], start, end}; if (mac !== null) { payload.mac = mac.toLowerCase(); } return this._request('/api/s/<SITE>/stat/report/monthly.ap', payload); } /** * Fetch 5 minutes stats method for a single user/client device - stat_5minutes_user() * * returns an array of 5-minute stats objects * required parameter <mac> = MAC address of user/client device to return stats for * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <attribs> = array containing attributes (strings) to be returned, valid values are: * rx_bytes, tx_bytes, signal, rx_rate, tx_rate, rx_retries, tx_retries, rx_packets, tx_packets * default is ['rx_bytes', 'tx_bytes'] * * NOTES: * - defaults to the past 12 hours * - only supported with UniFi controller versions 5.8.X and higher * - make sure that the retention policy for 5 minutes stats is set to the correct value in * the controller settings * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance section */ get5minUserStats(mac, start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (12 * 3600 * 1000); } attribs = attribs === null ? ['time', 'rx_bytes', 'tx_bytes'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end, mac: mac.toLowerCase()}; return this._request('/api/s/<SITE>/stat/report/5minutes.user', payload); } /** * Fetch Hourly stats method for a a single user/client device - stat_hourly_user() * * returns an array of hourly stats objects * required parameter <mac> = MAC address of user/client device to return stats for * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <attribs> = array containing attributes (strings) to be returned, valid values are: * rx_bytes, tx_bytes, signal, rx_rate, tx_rate, rx_retries, tx_retries, rx_packets, tx_packets * default is ['rx_bytes', 'tx_bytes'] * * NOTES: * - defaults to the past 7*24 hours * - only supported with UniFi controller versions 5.8.X and higher * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance section */ getHourlyUserStats(mac, start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (7 * 24 * 3600 * 1000); } attribs = attribs === null ? ['time', 'rx_bytes', 'tx_bytes'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end, mac: mac.toLowerCase()}; return this._request('/api/s/<SITE>/stat/report/hourly.user', payload); } /** * Fetch Daily stats method for a single user/client device - stat_daily_user() * * returns an array of daily stats objects * required parameter <mac> = MAC address of user/client device to return stats for * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <attribs> = array containing attributes (strings) to be returned, valid values are: * rx_bytes, tx_bytes, signal, rx_rate, tx_rate, rx_retries, tx_retries, rx_packets, tx_packets * default is ['rx_bytes', 'tx_bytes'] * * NOTES: * - defaults to the past 7*24 hours * - only supported with UniFi controller versions 5.8.X and higher * - make sure that the retention policy for daily stats is set to the correct value in * the controller settings * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance section */ getDailyUserStats(mac, start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (7 * 24 * 3600 * 1000); } attribs = attribs === null ? ['time', 'rx_bytes', 'tx_bytes'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end, mac: mac.toLowerCase()}; return this._request('/api/s/<SITE>/stat/report/daily.user', payload); } /** * Fetch monthly stats for a single user/client device - stat_monthly_user() * * NOTES: * - defaults to the past 13 weeks (52*7*24 hours) * - only supported with UniFi controller versions 5.8.X and higher * - make sure that the retention policy for monthly stats is set to the correct value in * the controller settings * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance section * * @param string $mac MAC address of user/client device to return stats for * @param int $start optional, Unix timestamp in milliseconds * @param int $end optional, Unix timestamp in milliseconds * @param array $attribs array containing attributes (strings) to be returned, valid values are: * rx_bytes, tx_bytes, signal, rx_rate, tx_rate, rx_retries, tx_retries, rx_packets, tx_packets * default is ['rx_bytes', 'tx_bytes'] * @return array returns an array of monthly stats objects */ getMonthlyUserStats(mac, start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (13 * 7 * 24 * 3600 * 1000); } attribs = attribs === null ? ['time', 'rx_bytes', 'tx_bytes'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end, mac: mac.toLowerCase()}; return this._request('/api/s/<SITE>/stat/report/monthly.user', payload); } /** * Fetch 5 minutes gateway stats method - stat_5minutes_gateway() * * returns an array of 5-minute stats objects for the gateway belonging to the current site * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <attribs> = array containing attributes (strings) to be returned, valid val ues are: * mem, cpu, loadavg_5, lan-rx_errors, lan-tx_errors, lan-rx_bytes , * lan-tx_bytes, lan-rx_packets, lan-tx_packets, lan-rx_dropped, l an-tx_dropped * default is ['time', 'mem', 'cpu', 'loadavg_5'] * * NOTES: * - defaults to the past 12 hours * - this function/method is only supported on controller versions 5.5.* and later * - make sure that the retention policy for 5 minutes stats is set to the correct value in * the controller settings * - requires a USG */ get5minGatewayStats(start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (12 * 3600 * 1000); } attribs = attribs === null ? ['time', 'mem', 'cpu', 'loadavg_5'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end}; return this._request('/api/s/<SITE>/stat/report/5minutes.gw', payload); } /** * Fetch Hourly gateway stats method - stat_hourly_gateway() * * returns an array of hourly stats objects for the gateway belonging to the current site * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <attribs> = array containing attributes (strings) to be returned, valid val ues are: * mem, cpu, loadavg_5, lan-rx_errors, lan-tx_errors, lan-rx_bytes , * lan-tx_bytes, lan-rx_packets, lan-tx_packets, lan-rx_dropped, l an-tx_dropped * default is ['time', 'mem', 'cpu', 'loadavg_5'] * * NOTES: * - defaults to the past 7*24 hours * - requires a USG */ getHourlyGatewayStats(start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (7 * 24 * 3600 * 1000); } attribs = attribs === null ? ['time', 'mem', 'cpu', 'loadavg_5'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end}; return this._request('/api/s/<SITE>/stat/report/hourly.gw', payload); } /** * Fetch Daily gateway stats method - stat_daily_gateway() * * returns an array of daily stats objects for the gateway belonging to the current site * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <attribs> = array containing attributes (strings) to be returned, valid val ues are: * mem, cpu, loadavg_5, lan-rx_errors, lan-tx_errors, lan-rx_bytes , * lan-tx_bytes, lan-rx_packets, lan-tx_packets, lan-rx_dropped, l an-tx_dropped * default is ['time', 'mem', 'cpu', 'loadavg_5'] * * NOTES: * - defaults to the past 52 weeks (52*7*24 hours) * - requires a USG */ getDailyGatewayStats(start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (52 * 7 * 24 * 3600 * 1000); } attribs = attribs === null ? ['time', 'mem', 'cpu', 'loadavg_5'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end}; return this._request('/api/s/<SITE>/stat/report/daily.gw', payload); } /** * Fetch monthly gateway stats - stat_monthly_gateway() * * NOTES: * - defaults to the past 52 weeks (52*7*24 hours) * - requires a USG * * @param int $start optional, Unix timestamp in milliseconds * @param int $end optional, Unix timestamp in milliseconds * @param array $attribs array containing attributes (strings) to be returned, valid values are: * mem, cpu, loadavg_5, lan-rx_errors, lan-tx_errors, lan-rx_bytes, * lan-tx_bytes, lan-rx_packets, lan-tx_packets, lan-rx_dropped, lan-tx_dropped * default is ['time', 'mem', 'cpu', 'loadavg_5'] * @return array returns an array of monthly stats objects for the gateway belonging to the current site */ getMonthlyGatewayStats(start = null, end = null, attribs = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (52 * 7 * 24 * 3600 * 1000); } attribs = attribs === null ? ['time', 'mem', 'cpu', 'loadavg_5'] : ['time', ...attribs]; const payload = {attrs: attribs, start, end}; return this._request('/api/s/<SITE>/stat/report/monthly.gw', payload); } /** * Fetch speed test results method - stat_speedtest_results() * * returns an array of speed test result objects * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * * NOTES: * - defaults to the past 24 hours * - requires a USG */ getSpeedTestResults(start = null, end = null) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (24 * 3600 * 1000); } const payload = { attrs: ['xput_download', 'xput_upload', 'latency', 'time'], start, end}; return this._request('/api/s/<SITE>/stat/report/archive.speedtest', payload); } /** * Fetch IPS/IDS events methods - stat_ips_events * * returns an array of IPS/IDS event objects * optional parameter <start> = Unix timestamp in milliseconds * optional parameter <end> = Unix timestamp in milliseconds * optional parameter <limit> = Maximum number of events to return, defaults to 10000 * * NOTES: * - defaults to the past 24 hours * - requires a USG * - supported in UniFi controller versions 5.9.X and higher */ getIPSEvents(start = null, end = null, limit = 10_000) { if (end === null) { end = Date.now(); } if (start === null) { start = end - (24 * 3600 * 1000); } const payload = {start, end, _limit: limit}; return this._request('/api/s/<SITE>/stat/ips/event', payload); } /** * Fetch login sessions - stat_sessions() * * returns an array of login session objects for all devices or a single device * optional parameter <start> = Unix timestamp in seconds * optional parameter <end> = Unix timestamp in seconds * optional parameter <mac> = client MAC address to return sessions for (can only be used when start and end are also provided) * optional parameter <type> = client type to return sessions for, can be 'all', 'guest' or 'user'; default value is 'all' * * NOTES: * - defaults to the past 7*24 hours */ getSessions(start = null, end = null, mac = null, type = 'all') { if (end === null) { end = Math.floor(Date.now() / 1000); } if (start === null) { start = end - (7 * 24 * 3600); } const payload = {type, start, end}; if (mac !== null) { payload.mac = mac.toLowerCase(); } return this._request('/api/s/<SITE>/stat/session', payload); } /** * Fetch latest 'n' login sessions for a single client device - stat_sta_sessions_latest() * * required parameter <mac> = client MAC address * optional parameter <limit> = maximum number of sessions to get (defaults to 5) * */ getLatestSessions(mac, limit = 5) { const payload = {mac: mac.toLowerCase(), _limit: limit, _sort: '-assoc_time'}; return this._request('/api/s/<SITE>/stat/session', payload); } /** * Fetch authorizations - stat_auths() * * optional parameter <start> = Unix timestamp in seconds * optional parameter <end> = Unix timestamp in seconds * * NOTES: * - defaults to the past 7*24 hours */ getAllAuthorizations(start = null, end = null) { if (end === null) { end = Math.floor(Date.now() / 1000); } if (start === null) { start = end - (7 * 24 * 3600); } return this._request('/api/s/<SITE>/stat/authorization', {start, end}); } /** * Fetch client devices that connected to the site within given timeframe - stat_allusers() * * optional parameter <historyhours> = hours to go back (default is 8760 hours or 1 year) * * NOTES: * - <historyhours> is only used to select clients that were online within that period, * the returned stats per client are all-time totals, irrespective of the value of <historyhours> */ getAllUsers(within = 8760) { const payload = {type: 'all', conn: 'all', within}; return this._request('/api/s/<SITE>/stat/alluser', payload); } /** * List all blocked client devices ever connected to the site * * optional parameter <historyhours> = hours to go back (default is 8760 hours or 1 year) * * NOTES: * - <historyhours> is only used to select clients that were online within that period, * the returned stats per client are all-time totals, irrespective of the value of <historyhours> */ getBlockedUsers(within = 8760) { const payload = {type: 'blocked', conn: 'all', within}; return this._request('/api/s/<SITE>/stat/alluser', payload); } /** * Fetch guest devices - list_guests() * * optional parameter <within> = time frame in hours to go back to list guests with valid access (default = 24*365 hours) * * NOTES: * - defaults to the past 7*24 hours * */ getGuests(within = 8760) { return this._request('/api/s/<SITE>/stat/guest', {within}); } /** * Fetch online client device(s) - list_clients() * * returns an array of online client device objects, or in case of a single device request, returns a single client device object * * optional parameter <client_mac> = the MAC address of a single online client device for which the call must be made */ getClientDevices(client_mac = '') { return this._request('/api/s/<SITE>/stat/sta/' + client_mac.trim().toLowerCase()); } /** * Fetch details for a single client device - stat_client() * * optional parameter <client_mac> = the MAC address of a single online client device for which the call must be made */ getClientDevice(client_mac = '') { return this._request('/api/s/<SITE>/stat/user/' + client_mac.trim().toLowerCase()); } /** * Assign client device to another group - set_usergroup() * * @param string $client_id _id value of the client device to be modified * @param string $group_id _id value of the user group to assign client device to * @return bool returns true upon success */ setUserGroup(client_id, group_id) { return this._request('/api/s/<SITE>/upd/user/' + client_id.trim(), {usergroup_id: group_id}); } /** * Update client fixedip (using REST) - edit_client_fixedip() * * returns an array containing a single object with attributes of the updated client on success * required parameter <client_id> = _id of the client * required parameter <use_fixedip> = boolean defining whether if use_fixedip is true or false * optional parameter <network_id> = _id value for the network where the ip belongs to * optional parameter <fixed_ip> = value of client's fixed_ip field * */ editClientFixedIP(client_id, use_fixedip, network_id = null, fixed_ip = null) { const payload = {_id: client_id, use_fixedip}; if (use_fixedip === true) { if (network_id !== null) { payload.network_id = network_id; } if (fixed_ip !== null) { payload.fixed_ip = fixed_ip; } } return this._request('/api/s/<SITE>/rest/user/' + client_id.trim(), payload, 'PUT'); } /** * Update client name (using REST) - edit_client_name() * * @param string $client_id _id value for the client * @param bool $name of the client * @return array|false returns an array containing a single object with attributes of the updated client on success */ editClientName(client_id, name) { const payload = {_id: client_id, name}; return this._request('/api/s/<SITE>/rest/user/' + client_id.trim(), payload, 'PUT'); } /** * Fetch user groups - list_usergroups() * */ getUserGroups() { return this._request('/api/s/<SITE>/list/usergroup'); } /** * Create user group (using REST) - create_usergroup() * * returns an array containing a single object with attributes of the new usergroup ("_id", "name", "qos_rate_max_down", "qos_rate_max_up", "site_id") on success * * required parameter <group_name> = name of the user group * optional parameter <group_dn> = limit download bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) * optional parameter <group_up> = limit upload bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) * */ createUserGroup(group_name, group_dn = -1, group_up = -1) { const payload = {name: group_name, qos_rate_max_down: group_dn, qos_rate_max_up: group_up}; return this._request('/api/s/<SITE>/rest/usergroup', payload); } /** * Modify user group (using REST) - edit_usergroup() * * returns an array containing a single object with attributes of the updated usergroup on success * * required parameter <group_id> = _id of the user group * required parameter <site_id> = _id of the site * required parameter <group_name> = name of the user group * optional parameter <group_dn> = limit download bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) * optional parameter <group_up> = limit upload bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) * */ editUserGroup(group_id, site_id, group_name, group_dn = -1, group_up = -1) { const payload = {_id: group_id, site_id, name: group_name, qos_rate_max_down: group_dn, qos_rate_max_up: group_up}; return this._request('/api/s/<SITE>/rest/usergroup/' + group_id.trim(), payload, 'PUT'); } /** * Delete user group (using REST) - delete_usergroup() * * returns true on success * * required parameter <group_id> = _id value of the user group to delete * */ deleteUserGroup(group_id) { return this._request('/api/s/<SITE>/rest/usergroup/' + group_id.trim(), null, 'DELETE'); } /** * Fetch AP groups - list_apgroups() * * @return array containing the current AP groups on success */ getAPGroups() { return this._request('/v2/api/site/<SITE>/apgroups'); } /** * Create AP group - create_apgroup() * * @param string $group_name name to assign to the AP group * @param array $device_macs optional, array containing the MAC addresses (strings) of the APs to add to the new group * @return object returns a single object with attributes of the new AP group on success * */ createAPGroup(group_name, device_macs = []) { const payload = {device_macs, name: group_name }; return this._request('/v2/api/site/<SITE>/apgroups', payload); } /** * Modify AP group - edit_apgroup() * * @param string $group_id _id value of the AP group to modify * @param string $group_name name to assign to the AP group * @param array $device_macs array containing the members of the AP group which overwrites the existing * group_members (passing an empty array clears the AP member list) * @return object returns a single object with attributes of the updated AP group on success * */ editAPGroup(group_id, group_name, device_macs) { const payload = {_id: group_id, attr_no_delete: false, name: group_name, device_macs}; return this._request('/v2/api/site/<SITE>/apgroups/' + group_id.trim(), payload, 'PUT'); } /** * Delete AP group - delete_apgroup() * * @param string $group_id _id value of the AP group to delete * @return bool returns true on success * */ deleteAPGroup(group_id) { return this._request('/v2/api/site/<SITE>/apgroups/' + group_id.trim(), null, 'DELETE'); } /** * List firewall groups (using REST) - list_firewallgroups() * * returns an array containing the current firewall groups or the selected firewall group on success * optional parameter <group_id> = _id value of the single firewall group to list */ getFirewallGroups(group_id = '') { return this._request('/api/s/<SITE>/rest/firewallgroup/' + group_id.trim()); } /** * Create firewall group (using REST) - create_firewallgroup() * * returns an array containing a single object with attributes of the new firewall group on succe ss * required parameter <group_name> = name to assign to the firewall group * required parameter <group_type> = firewall group type; valid values are address-group, ipv6 -address-group, port-group * optional parameter <group_members> = array containing the members of the new group (IPv4 addre sses, IPv6 addresses or port numbers) * (default is an empty array) */ createFirewallGroup(group_name, group_type, group_members = []) { const payload = {name: group_name, group_type, group_members}; return this._request('/api/s/<SITE>/rest/firewallgroup', payload); } /** * Modify firewall group (using REST) - edit_firewallgroup * * returns an array containing a single object with attributes of the updated firewall group on s uccess * required parameter <group_id> = _id value of the firewall group to modify * required parameter <site_id> = site_id value of the firewall group to modify * required parameter <group_name> = name of the firewall group * required parameter <group_type> = firewall group type; valid values are address-group, ipv6 -address-group, port-group, * group_type cannot be changed for an existing firewall gro up! * optional parameter <group_members> = array containing the members of the group (IPv4 addresses , IPv6 addresses or port numbers) * which overwrites the existing group_members (default is an empty array) * * */ editFirewallGroup(group_id, site_id, group_name, group_type, group_members = []) { const payload = {_id: group_id, name: group_name, group_type, group_members, site_id}; return this._request('/api/s/<SITE>/rest/firewallgroup/' + group_id.trim(), payload, 'PUT'); } /** * Delete firewall group (using REST) - delete_firewallgroup() * * returns true on success * required parameter <group_id> = _id value of the firewall group to delete */ deleteFirewallGroup(group_id) { return this._request('/api/s/<SITE>/rest/firewallgroup/' + group_id.trim(), null, 'DELETE'); } /** * List firewall rules (using REST) - list_firewallrules() * * returns an array containing the current firewall rules on success */ getFirewallRules() { return this._request('/api/s/<SITE>/rest/firewallrule'); } /** * List static routing settings (using REST) - list_routing() * * returns an array of static routes and their settings * optional parameter <route_id> = string; _id value of the static route to get settings for */ getRouting(route_id = '') { return this._request('/api/s/<SITE>/rest/routing/' + route_id.trim()); } /** * List health metrics - list_health() * */ getHealth() { return this._request('/api/s/<SITE>/stat/health'); } /** * List dashboard metrics - list_dashboard() * * returns an array of dashboard metric objects (available since controller version 4.9.1.alpha) * optional parameter <five_minutes> = boolean; if true, return stats based on 5 minute intervals, * returns hourly stats by default (supported on controller versions 5.5.* and higher) */ getDashboard(five_minutes = false) { const path_suffix = five_minutes === true ? '?scale=5minutes' : ''; return this._request('/api/s/<SITE>/stat/dashboard' + path_suffix); } /** * List client devices - list_users() * * returns an array of known client device objects */ getUsers() { return this._request('/api/s/<SITE>/list/user'); } /** * List of site devices with a basic subset of fields (e.g., mac, state, adopted, disabled, type, model, name) - list_devices_basic() * * returns an array containing known UniFi device objects) */ getAccessDevicesBasic() { return this._request('/api/s/<SITE>/stat/device-basic'); } /** * List access points and other devices under management of the controller (USW and/or USG devices) - list_devices() * * optional paramater <device_mac> = the MAC address of a single device for which the call must be made */ getAccessDevices(device_mac = '') { return this._request('/api/s/<SITE>/stat/device/' + device_mac.trim().toLowerCase()); } /** * List (device) tags (using REST) - list_tags() * * returns an array of known device tag objects * * NOTES: this endpoint was introduced with controller versions 5.5.X */ listTags() { return this._request('/api/s/<SITE>/rest/tag'); } /** * List rogue/neighboring access points - list_rogueaps() * * returns an array of rogue/neighboring access point objects * optional parameter <within> = hours to go back to list discovered "rogue" access points (default = 24 hours) * */ getRogueAccessPoints(within = 24) { return this._request('/api/s/<SITE>/stat/rogueap', {within}); } /** * List known rogue access points - list_known_rogueaps() * * returns an array of known rogue access point objects */ getKnownRogueAccessPoints() { return this._request('/api/s/<SITE>/rest/rogueknown'); } /** * Generate a backup - generate_backup() * * returns a URL from where the backup file can be downloaded once generated * * NOTES: this is an experimental function, please do not use unless you know * exactly what you're doing */ generateBackup() { return this._request('/api/s/<SITE>/cmd/backup', {cmd: 'backup'}); } /** * List auto backups - list_backups() * * return an array containing objects with backup details on success */ getBackups() { return this._request('/api/s/<SITE>/cmd/backup', {cmd: 'list-backups'}); } /** * Generate a backup/export of the current site - generate_backup_site() * * NOTES: this is an experimental function, please do not use unless you know * exactly what you're doing */ generateBackupSite() { return this._request('/api/s/<SITE>/cmd/backup', {cmd: 'export-site'}); } /** * Delete a backup file * * return true on success * required parameter <filename> = string; filename of backup to delete */ deleteBackup(filename) { return this._request('/api/s/<SITE>/cmd/backup', {cmd: 'delete-backup', filename}); } /** * List sites * * calls callback function(err, result) with an array of the sites * registered to the UniFi controller */ getSites() { return this._request('/api/self/sites'); } /** * List sites stats * * calls callback function(err, result) with an array of sysinfo information * for all sites registered to the UniFi controller * * NOTES: endpoint was introduced with controller version 5.2.9 */ getSitesStats() { return this._request('/api/stat/sites'); } /** * Create a site - create_site() * * required parameter <description> = the long name for the new site * * NOTES: immediately after being added, the new site is available in the output of the "list_sites" function */ createSite(description) { const payload = {desc: description, cmd: 'add-site'}; return this._request('/api/s/<SITE>/cmd/sitemgr', payload); } /** * Delete a site - delete_site() * * return true on success * required parameter <site_id> = 24 char string; _id value of the site to delete * */ deleteSite(site_id) { const payload = {site: site_id, cmd: 'delete-site'}; return this._request('/api/s/<SITE>/cmd/sitemgr', payload); } /** * Change the current site's name - set_site_name() * * return true on success * required parameter <site_name> = string; the new long name for the current site * * NOTES: immediately after being changed, the site is available in the output of the list_sites() function */ setSiteName(site_name) { const payload = {desc: site_name, cmd: 'update-site'}; return this._request('/api/s/<SITE>/cmd/sitemgr', payload); } /** * Set site country - set_site_country() * * required parameter <payload> = stdClass object or associative array containing the configuration to apply to the network, must be a (partial) * object structured in the same manner as is returned by list_settings() for the "country" key. * Valid country codes can be obtained using the list_country_codes() function/method. * Do not include the _id property, it is assigned by the controller and returned upon success. * return true on success */ setSiteCountry(country_id, payload) { return this._request('/api/s/<SITE>/rest/setting/country/' + country_id.trim(), payload, 'PUT'); } /** * Set site locale - set_site_locale() * * required parameter <payload> = stdClass object or associative array containing the configuration to apply to the network, must be a (partial) * object structured in the same manner as is returned by list_settings() for the "locale" key. * Do not include the _id property, it is assigned by the controller and returned upon success. * return true on success */ setSiteLocale(locale_id, payload) { return this._request('/api/s/<SITE>/rest/setting/locale/' + locale_id.trim(), payload, 'PUT'); } /** * Set site snmp - set_site_snmp() * * required parameter <payload> = stdClass object or associative array containing the configuration to apply to the network,