diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..f233982 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore personal config file +examples/config.php \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000..b6dbf2a --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016, Art of WiFi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..5de2a6f --- /dev/null +++ b/README.md @@ -0,0 +1,149 @@ +## UniFi controller API client class + +This PHP class provides access to the **UniFi Controller API** and is based off the work of @domwo and @fbagnol and the API shell client as published by UBNT. + +Please refer to the code samples in the `examples` directory for a starting point for your own PHP code. + +### Donations +If you'd like to support further development of this PHP API client class, please use the donate button below. All donations go to the project maintainer. + +[![Donate](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=M7TVNVX3Z44VN) + +### Install + +Simply execute this command from your project directory: + +``` +composer require art-of-wifi/unifi-api-client +``` + +### Requirements +- a web server with PHP and cURL modules installed (tested on apache2 with PHP Version 5.6.1 and cURL 7.42.1) +- network connectivity between this web server and the server and port (normally port 8443) where the UniFi controller is running + +### Methods and functions supported + +This class currently supports the following functions/methods to get/set data through the UniFi controller API: +- login() +- logout() +- add_site() +- adopt_device() +- authorize_guest() +- unauthorize_guest() +- block_sta() +- unblock_sta() +- create_hotspotop() +- create_voucher() +- delete_site() +- disable_ap() +- led_override() +- list_admins() +- list_alarms() +- count_alarms() +- upgrade_device() +- upgrade_device_external() +- spectrum_scan() +- spectrum_scan_state() +- list_devices() +- list_aps() (deprecated but still available as alias) +- list_clients() +- list_dashboard() +- list_dynamicdns() +- list_events() +- list_extension() +- list_guests() +- list_health() +- list_hotspotop() +- list_networkconf() +- list_portconf() +- list_portforward_stats() +- list_portforwarding() +- list_radius_accounts() (supported on controller version 5.5.19 and higher) +- list_rogueaps() +- list_self() +- list_settings() +- list_sites() +- list_tags() (supported on controller version 5.5.19 and higher) +- list_usergroups() +- list_users() +- list_wlan_groups() +- list_wlanconf() +- list_current_channels() +- list_dpi_stats() +- reconnect_sta() +- rename_ap() +- restart_ap() +- revoke_voucher() +- extend_guest_validity() +- set_ap_radiosettings() +- set_guestlogin_settings() +- locate_ap() +- set_locate_ap() (deprecated but still available as alias) +- unset_locate_ap() (deprecated but still available as alias) +- set_sta_name() +- set_sta_note() +- set_usergroup() +- edit_usergroup() +- add_usergroup() +- delete_usergroup() +- edit_usergroup() +- add_usergroup() +- delete_usergroup() +- set_wlansettings() +- create_wlan() +- delete_wlan() +- site_leds() +- site_ledsoff() (deprecated but still available as alias) +- site_ledson() (deprecated but still available as alias) +- stat_allusers() +- stat_auths() +- stat_client() +- stat_daily_site() +- stat_daily_aps() +- stat_hourly_aps() +- stat_hourly_site() +- stat_payment() +- stat_sessions() +- stat_sites() +- stat_sta_sessions_latest() +- stat_sysinfo() +- stat_voucher() + +Internal functions: +- set_debug() +- get_last_results_raw() +- get_last_error_message() + +Please refer to the source code for more details on each function/method and it's parameters. + +### Example usage +A basic example how to use the class: + +```php + +... +/** + * initialize the Unifi API connection class, log in to the controller and request the alarms collection + * (this example assumes you have already assigned the correct values to the variables used) + */ +$unifi_connection = new UniFi_API\Client($controller_user, $controller_password, $controller_url, $site_id, $controller_version); +$login = $unifi_connection->login(); +$results = $unifi_connection->list_alarms(); // returns the alarms in a PHP array +... + +``` + +>**NOTE:** +> +>$site_id is the 8 character short site "name" which is visible in the URL when managing the site in the UniFi controller: +> +>``` +>https://:8443/manage/site/jl3z2shm/dashboard +>``` +> +>Here `jl3z2shm` is the value required for $site_id. + +Have a look at the files in the `examples` directory for more examples how to use this class. + +## Important Disclaimer +Many of these functions are not officially supported by UBNT and as such, may not be supported in future versions of the UniFi controller API. diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..cbc1550 --- /dev/null +++ b/composer.json @@ -0,0 +1,31 @@ +{ + "name": "art-of-wifi/unifi-api-client", + "type": "library", + "description": "API client class for use with Ubiquiti's UniFi controller", + "keywords": [ + "ubnt", + "ubiquiti", + "unifi", + "controller", + "api", + "client" + ], + "homepage": "https://github.com/Art-of-WiFi/UniFi-API-client", + "license": "MIT", + "authors": [ + { + "name": "Art of WiFi", + "email": "info@artofowifi.net", + "homepage": "http://artofwifi.net" + } + ], + "require": { + "php": ">=5.6.0", + "ext-curl": "*" + }, + "autoload": { + "psr-4": { + "UniFi-API\\": "src/" + } + } +} \ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100755 index 0000000..07eed1a --- /dev/null +++ b/examples/README.md @@ -0,0 +1,15 @@ +## API client class usage examples +This directory contains some PHP code examples which demonstrate usage of the PHP API client class and can be used as a good starting point for your own custom code. + +### Usage + +Copy the appropriate example file to your working directory together with a copy of the config.template.php file which should be renamed to config.php. +Then update the contents of your new config.php with your controller details and credentials and modify the example file as required to fit your needs. + +### Contribute + +If you would like to share your own example file(s), please open an issue and include your code there or else create a pull request. + +## Important Disclaimer + +Use these examples at your own risk! \ No newline at end of file diff --git a/examples/ap_scanning_state.php b/examples/ap_scanning_state.php new file mode 100755 index 0000000..d8bb06a --- /dev/null +++ b/examples/ap_scanning_state.php @@ -0,0 +1,33 @@ +'; +$ap_mac = ''; + +/** + * initialize the UniFi API connection class and log in to the controller and do our thing + * spectrum_scan_state() + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); +$data = $unifi_connection->spectrum_scan_state($ap_mac); + +/** + * provide feedback in json format + */ +echo json_encode($data, JSON_PRETTY_PRINT); \ No newline at end of file diff --git a/examples/auth_guest_basic.php b/examples/auth_guest_basic.php new file mode 100755 index 0000000..01d74f8 --- /dev/null +++ b/examples/auth_guest_basic.php @@ -0,0 +1,45 @@ +'; + +/** + * the duration to authorize the device for in minutes + */ +$duration = 2000; + +/** + * The site to authorize the device with + */ +$site_id = ''; + +/** + * initialize the UniFi API connection class and log in to the controller + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); + +/** + * then we authorize the device for the requested duration + */ +$auth_result = $unifi_connection->authorize_guest($mac, $duration); + +/** + * provide feedback in json format + */ +echo json_encode($auth_result, JSON_PRETTY_PRINT); \ No newline at end of file diff --git a/examples/auth_guest_with_note.php b/examples/auth_guest_with_note.php new file mode 100755 index 0000000..0fa36d6 --- /dev/null +++ b/examples/auth_guest_with_note.php @@ -0,0 +1,68 @@ +'; + +/** + * the duration to authorize the device for in minutes + */ +$duration = 2000; + +/** + * The site to authorize the device with + */ +$site_id = ''; + +/** + * the note to attach to the device + */ +$note = 'Note to attach to newly authorized device'; + +/** + * initialize the UniFi API connection class and log in to the controller + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); + +/** + * we authorize the device for the requested duration and attach the note to it's object + */ +$auth_result = $unifi_connection->authorize_guest($mac, $duration); +$getid_result = $unifi_connection->stat_client($mac); +$user_id = $getid_result[0]->_id; +$note_result = $unifi_connection->set_sta_note($user_id, $note); + +/** + * When using older Controller versions (< 5.5.x) to attach a note to a new (unconnected) device, we instead need to take the + * following steps before authorizing the device: + * - first block the device to get an entry in the user collection + * - get the device id from the user collection + * - attach note to the device + * - then unblock the device again **after the authorization has taken place** + */ +//$block_result = $unifi_connection->block_sta($mac); +//$getid_result = $unifi_connection->stat_client($mac); +//$user_id = $getid_result[0]->_id; +//$note_result = $unifi_connection->set_sta_note($user_id, $note); +//$unblock_result = $unifi_connection->unblock_sta($mac); +//$auth_result = $unifi_connection->authorize_guest($mac, $duration); + +/** + * provide feedback in json format + */ +echo json_encode($auth_result, JSON_PRETTY_PRINT); \ No newline at end of file diff --git a/examples/config.template.php b/examples/config.template.php new file mode 100755 index 0000000..938e21c --- /dev/null +++ b/examples/config.template.php @@ -0,0 +1,24 @@ +'; + +/** + * initialize the UniFi API connection class and log in to the controller + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); + +/** + * then we create the required number of vouchers for the requested duration + */ +$voucher_result = $unifi_connection->create_voucher($voucher_duration, $voucher_count); + +/** + * provide feedback (the newly created voucher code, without the dash) in json format + */ +echo json_encode($voucher_result, JSON_PRETTY_PRINT); diff --git a/examples/extend_guest_auth.php b/examples/extend_guest_auth.php new file mode 100755 index 0000000..46eae13 --- /dev/null +++ b/examples/extend_guest_auth.php @@ -0,0 +1,45 @@ +set_debug($debug); +$loginresults = $unifi_connection->login(); + +if ($loginresults === 400) { + print "UniFi controller login failure, please check your credentials in config.php.\n"; +} else { + $guestlist = $unifi_connection->list_guests(); + // print "
"; print_r ($guestlist); print "
"; + // loop thru all known guests + foreach ($guestlist as $guest) { + // print "
"; print_r ($guest); print "
"; + print "
" . $guest->_id . " (" . $guest->mac . "), valid until " . date (DATE_ATOM, $guest->end) . " (" . $guest->end . ")
"; + + // just a sample: only extend validity of guests which have end date after 2017-04-02 + if ($guest->end > 1491166482) { + // extend clients five times = five days + if (!$unifi_connection->extend_guest_validity ($guest->_id)) print "Extend failed for guest with id " . $guest->_id . "\n"; + if (!$unifi_connection->extend_guest_validity ($guest->_id)) print "Extend failed for guest with id " . $guest->_id . "\n"; + if (!$unifi_connection->extend_guest_validity ($guest->_id)) print "Extend failed for guest with id " . $guest->_id . "\n"; + if (!$unifi_connection->extend_guest_validity ($guest->_id)) print "Extend failed for guest with id " . $guest->_id . "\n"; + if (!$unifi_connection->extend_guest_validity ($guest->_id)) print "Extend failed for guest with id " . $guest->_id . "\n"; + } + } + + $logout_results = $unifi_connection->logout(); +} \ No newline at end of file diff --git a/examples/list_alarms.php b/examples/list_alarms.php new file mode 100755 index 0000000..1401f5f --- /dev/null +++ b/examples/list_alarms.php @@ -0,0 +1,31 @@ +'; + +/** + * initialize the UniFi API connection class and log in to the controller and do our thing + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); +$data = $unifi_connection->list_alarms(); + +/** + * provide feedback in json format + */ +echo json_encode($data, JSON_PRETTY_PRINT); \ No newline at end of file diff --git a/examples/list_ap_connected_users.php b/examples/list_ap_connected_users.php new file mode 100755 index 0000000..fa0e69c --- /dev/null +++ b/examples/list_ap_connected_users.php @@ -0,0 +1,37 @@ +'; + +/** + * initialize the UniFi API connection class and log in to the controller and pull the requested data + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); +$aps_array = $unifi_connection->list_aps(); + +/** + * output the results in HTML format + */ +header('Content-Type: text/html; charset=utf-8'); +foreach ($aps_array as $ap) { + if ($ap->type === 'uap') { + echo 'AP name:' . $ap->name . ' model:' . $ap->model . ' # connected clients:' . $ap->num_sta . '
'; + } +} \ No newline at end of file diff --git a/examples/list_site_health.php b/examples/list_site_health.php new file mode 100755 index 0000000..198c0f7 --- /dev/null +++ b/examples/list_site_health.php @@ -0,0 +1,34 @@ +'; + +/** + * initialize the UniFi API connection class and log in to the controller and pull the requested data + */ + +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); +$result = $unifi_connection->list_health(); + +/** + * output the results in correct json formatting + */ +header('Content-Type: application/json'); +echo (json_encode($result, JSON_PRETTY_PRINT)); \ No newline at end of file diff --git a/examples/list_social_auth_details.php b/examples/list_social_auth_details.php new file mode 100755 index 0000000..1313bed --- /dev/null +++ b/examples/list_social_auth_details.php @@ -0,0 +1,40 @@ +'; + +/** + * initialize the UniFi API connection class and log in to the controller and do our thing + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); +$data = $unifi_connection->stat_payment(); + +/** + * cycle through the results and print social auth details if set, + * at this stage you can choose to do with the payment objects whatever is needed + */ +echo 'Results from Facebook social auth:
'; +foreach ($data as $payment) { + if (isset($payment->gateway) && $payment->gateway == 'facebook') { + echo 'First name: ' . $payment->first_name . ' Last name: ' . $payment->last_name . ' E-mail address: ' . $payment->email . '
'; + } +} + +echo '

'; \ No newline at end of file diff --git a/examples/toggle_led.php b/examples/toggle_led.php new file mode 100755 index 0000000..bed36c6 --- /dev/null +++ b/examples/toggle_led.php @@ -0,0 +1,51 @@ +'; + +/** + * other specific variables to be used + */ +$mac = ''; + +/** + * initialize the UniFi API connection class and log in to the controller to do our thing + */ +$unifi_connection = new UniFi_API\Client($controlleruser, $controllerpassword, $controllerurl, $site_id, $controllerversion); // initialize the class instance +$set_debug_mode = $unifi_connection->set_debug($debug); +$loginresults = $unifi_connection->login(); + +/** + * using the new method/function + */ +$data = $unifi_connection->locate_ap($mac, true); // uncomment to switch locating on +//$data = $unifi_connection->locate_ap($mac, false); // uncomment to switch locating off (choose either of these two lines!) + +if ($data) { + /** + * provide feedback in json format + */ + echo json_encode($data, JSON_PRETTY_PRINT); +} else { + /** + * method returned false so we display the raw results in json format + */ + echo '
';
+    print_r($unifi_connection->get_last_results_raw(true));
+    echo '
'; +} \ No newline at end of file diff --git a/src/Client.php b/src/Client.php new file mode 100755 index 0000000..54d2990 --- /dev/null +++ b/src/Client.php @@ -0,0 +1,1725 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this package in the file LICENSE.md + * + */ +namespace UniFi_API; + +class Client +{ + /** + * public properties + */ + public $user = ''; + public $password = ''; + public $site = 'default'; + public $baseurl = 'https://127.0.0.1:8443'; + public $version = '5.4.16'; + + /** + * private properties + */ + private $debug = false; + private $is_loggedin = false; + private $cookies = ''; + private $request_type = 'POST'; + private $last_results_raw; + private $last_error_message; + + function __construct($user = '', $password = '', $baseurl = '', $site = '', $version = '') + { + if (!empty($user)) $this->user = trim($user); + if (!empty($password)) $this->password = trim($password); + if (!empty($baseurl)) $this->baseurl = trim($baseurl); + if (!empty($site)) $this->site = trim($site); + if (!empty($version)) $this->version = trim($version); + if (isset($_SESSION['unificookie'])) { + $this->cookies = $_SESSION['unificookie']; + } + } + + function __destruct() + { + /** + * if user has $_SESSION['unificookie'] set, do not logout here + */ + if (isset($_SESSION['unificookie'])) return; + + /** + * logout, if needed + */ + if ($this->is_loggedin) { + $this->logout(); + } + } + + /** + * Login to UniFi Controller + */ + public function login() + { + /** + * if user has $_SESSION['unificookie'] set, skip the login ;) + */ + if (isset($_SESSION['unificookie'])) { + $this->is_loggedin = true; + return $this->is_loggedin; + } + + $ch = $this->get_curl_obj(); + + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_REFERER, $this->baseurl.'/login'); + curl_setopt($ch, CURLOPT_URL, $this->baseurl.'/api/login'); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['username' => $this->user, 'password' => $this->password])); + + if (($content = curl_exec($ch)) === false) { + trigger_error('cURL error: '.curl_error($ch)); + } + + if ($this->debug) { + curl_setopt($ch, CURLOPT_VERBOSE, true); + + print '
';
+            print PHP_EOL.'-----------LOGIN-------------'.PHP_EOL;
+            print_r (curl_getinfo($ch));
+            print PHP_EOL.'----------RESPONSE-----------'.PHP_EOL;
+            print $content;
+            print PHP_EOL.'-----------------------------'.PHP_EOL;
+            print '
'; + } + + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $body = trim(substr($content, $header_size)); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + curl_close ($ch); + + preg_match_all('|Set-Cookie: (.*);|U', substr($content, 0, $header_size), $results); + if (isset($results[1])) { + $this->cookies = implode(';', $results[1]); + if (!empty($body)) { + if (($code >= 200) && ($code < 400)) { + if (strpos($this->cookies, 'unifises') !== false) { + $this->is_loggedin = true; + } + } + + if ($code === 400) { + trigger_error('We have received an HTTP response status: 400. Probably a controller login failure'); + return $code; + } + } + } + + return $this->is_loggedin; + } + + /** + * Logout from UniFi Controller + */ + public function logout() + { + if (!$this->is_loggedin) return false; + $this->exec_curl($this->baseurl.'/logout'); + $this->is_loggedin = false; + $this->cookies = ''; + return true; + } + + /**************************************************************** + * setter/getter functions from here: + ****************************************************************/ + + /** + * Set debug mode + * -------------- + * sets debug mode to true or false, returns false if a non-boolean parameter was passed + * required parameter = boolean; true will enable debug mode, false will disable it + */ + public function set_debug($enable) + { + if ($enable) { + $this->debug = true; + } elseif ($enable === false) { + $this->debug = false; + } + + return false; + } + + /** + * Get last raw results + * -------------------- + * returns the raw results of the last method called in PHP stdClass Object format by default, returns false if not set + * optional parameter = boolean; true will return the results in "pretty printed" json format + * + * NOTE: + * this method can be used to get the full error as returned by the controller + */ + public function get_last_results_raw($return_json = false) + { + if ($this->last_results_raw != null) { + if ($return_json) { + return json_encode($this->last_results_raw, JSON_PRETTY_PRINT); + } + + return $this->last_results_raw; + } + + return false; + } + + /** + * Get last error message + * ---------------------- + * returns the error message of the last method called in PHP stdClass Object format, returns false if not set + */ + public function get_last_error_message() + { + if (isset($this->last_error_message)) { + return $this->last_error_message; + } + + return false; + } + + /** + * Get Cookie from UniFi Controller + * -------------------------------- + * returns the UniFi controller cookie + */ + public function getcookie() + { + if (!$this->is_loggedin) return false; + return $this->cookies; + } + + /**************************************************************** + * Functions to access UniFi controller API routes from here: + ****************************************************************/ + + /** + * Authorize a client device + * ------------------------- + * return true on success + * required parameter = client MAC address + * required parameter = minutes (from now) until authorization expires + * optional parameter = upload speed limit in kbps + * optional parameter = download speed limit in kbps + * optional parameter = data transfer limit in MB + * optional parameter = AP MAC address to which client is connected, should result in faster authorization + */ + public function authorize_guest($mac, $minutes, $up = null, $down = null, $MBytes = null, $ap_mac = null) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = ['cmd' => 'authorize-guest', 'mac' => $mac, 'minutes' => $minutes]; + + /** + * if we have received values for up/down/MBytes we append them to the payload array to be submitted + */ + if (isset($up)) $json['up'] = $up; + if (isset($down)) $json['down'] = $down; + if (isset($MBytes)) $json['bytes'] = $MBytes; + if (isset($ap_mac)) $json['ap_mac'] = $ap_mac; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/stamgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Unauthorize a client device + * --------------------------- + * return true on success + * required parameter = client MAC address + */ + public function unauthorize_guest($mac) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = json_encode(['cmd' => 'unauthorize-guest', 'mac' => $mac]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/stamgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Reconnect a client device + * ------------------------- + * return true on success + * required parameter = client MAC address + */ + public function reconnect_sta($mac) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = json_encode(['cmd' => 'kick-sta', 'mac' => $mac]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/stamgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Block a client device + * --------------------- + * return true on success + * required parameter = client MAC address + */ + public function block_sta($mac) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = json_encode(['cmd' => 'block-sta', 'mac' => $mac]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/stamgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Unblock a client device + * ----------------------- + * return true on success + * required parameter = client MAC address + */ + public function unblock_sta($mac) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = json_encode(['cmd' => 'unblock-sta', 'mac' => $mac]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/stamgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Add/modify a client device note + * ------------------------------- + * return true on success + * required parameter = id of the user device to be modified + * optional parameter = note to be applied to the user device + * + * NOTES: + * - when note is empty or not set, the existing note for the user will be removed and "noted" attribute set to false + */ + public function set_sta_note($user_id, $note = null) + { + if (!$this->is_loggedin) return false; + $noted = (is_null($note)) || (empty($note)) ? false : true; + $json = json_encode(['note' => $note, 'noted' => $noted]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/user/'.trim($user_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Add/modify a client device name + * ------------------------------- + * return true on success + * required parameter = id of the user device to be modified + * optional parameter = name to be applied to the user device + * + * NOTES: + * - when name is empty or not set, the existing name for the user will be removed + */ + public function set_sta_name($user_id, $name = null) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['name' => $name]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/user/'.trim($user_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Daily site stats method + * ------------------------ + * returns an array of daily stats objects for the current site + * optional parameter = Unix timestamp in seconds + * optional parameter = Unix timestamp in seconds + * + * NOTES: + * - defaults to the past 52*7*24 hours + * - bytes" are no longer returned with controller version 4.9.1 and later + */ + public function stat_daily_site($start = null, $end = null) + { + if (!$this->is_loggedin) return false; + $end = is_null($end) ? ((time()-(time() % 3600))*1000) : $end; + $start = is_null($start) ? $end-(52*7*24*3600*1000) : $start; + $attributes = ['bytes', 'wan-tx_bytes', 'wan-rx_bytes', 'wlan_bytes', 'num_sta', 'lan-num_sta', 'wlan-num_sta', 'time']; + $json = json_encode(['attrs' => $attributes, 'start' => $start, 'end' => $end]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/report/daily.site', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Hourly site stats method + * ------------------------ + * returns an array of hourly stats objects for the current site + * optional parameter = Unix timestamp in seconds + * optional parameter = Unix timestamp in seconds + * + * NOTES: + * - defaults to the past 7*24 hours + * - "bytes" are no longer returned with controller version 4.9.1 and later + */ + public function stat_hourly_site($start = null, $end = null) + { + if (!$this->is_loggedin) return false; + $end = is_null($end) ? ((time())*1000) : $end; + $start = is_null($start) ? $end-(7*24*3600*1000) : $start; + $attributes = ['bytes', 'wan-tx_bytes', 'wan-rx_bytes', 'wlan_bytes', 'num_sta', 'lan-num_sta', 'wlan-num_sta', 'time']; + $json = json_encode(['attrs' => $attributes, 'start' => $start, 'end' => $end]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/report/hourly.site', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Hourly stats method for a single access point or all access points + * ------------------------------------------------------------------ + * returns an array of hourly stats objects + * optional parameter = Unix timestamp in seconds + * optional parameter = Unix timestamp in seconds + * optional parameter = 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 + */ + public function stat_hourly_aps($start = null, $end = null, $mac = null) + { + if (!$this->is_loggedin) return false; + $end = is_null($end) ? ((time())*1000) : $end; + $start = is_null($start) ? $end-(7*24*3600*1000) : $start; + $json = ['attrs' => ['bytes', 'num_sta', 'time'], 'start' => $start, 'end' => $end]; + if (!is_null($mac)) $json['mac'] = $mac; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/report/hourly.ap', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Daily stats method for a single access point or all access points + * ----------------------------------------------------------------- + * returns an array of daily stats objects + * optional parameter = Unix timestamp in seconds + * optional parameter = Unix timestamp in seconds + * optional parameter = 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 + */ + public function stat_daily_aps($start = null, $end = null, $mac = null) + { + if (!$this->is_loggedin) return false; + $end = is_null($end) ? ((time())*1000) : $end; + $start = is_null($start) ? $end-(7*24*3600*1000) : $start; + $json = ['attrs' => ['bytes', 'num_sta', 'time'], 'start' => $start, 'end' => $end]; + if (!is_null($mac)) $json['mac'] = $mac; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/report/daily.ap', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Show all login sessions + * ----------------------- + * returns an array of login session objects for all devices + * optional parameter = Unix timestamp in seconds + * optional parameter = Unix timestamp in seconds + * optional parameter = client MAC address to return sessions for (can only be used when start and end are also provided) + * + * NOTES: + * - defaults to the past 7*24 hours + */ + public function stat_sessions($start = null, $end = null, $mac = null) + { + if (!$this->is_loggedin) return false; + $end = is_null($end) ? time() : $end; + $start = is_null($start) ? $end-(7*24*3600) : $start; + $json = ['type'=> 'all', 'start' => $start, 'end' => $end]; + if (!is_null($mac)) $json['mac'] = $mac; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/session', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Show latest 'n' login sessions for a single client device + * --------------------------------------------------------- + * returns an array of latest login session objects for given client device + * required parameter = client MAC address + * optional parameter = maximum number of sessions to get (default value is 5) + */ + public function stat_sta_sessions_latest($mac, $limit = null) + { + if (!$this->is_loggedin) return false; + $limit = is_null($limit) ? 5 : $limit; + $json = json_encode(['mac' => $mac, '_limit' => $limit, '_sort'=> '-assoc_time']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/session', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Show all authorizations + * ----------------------- + * returns an array of authorization objects + * optional parameter = Unix timestamp in seconds + * optional parameter = Unix timestamp in seconds + * + * NOTES: + * - defaults to the past 7*24 hours + */ + public function stat_auths($start = null, $end = null) + { + if (!$this->is_loggedin) return false; + $end = is_null($end) ? time() : $end; + $start = is_null($start) ? $end-(7*24*3600) : $start; + $json = json_encode(['start' => $start, 'end' => $end]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/authorization', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List all client devices ever connected to the site + * -------------------------------------------------- + * returns an array of client device objects + * optional parameter = hours to go back (default is 8760 hours or 1 year) + * + * NOTES: + * - 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 + */ + public function stat_allusers($historyhours = 8760) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['type' => 'all', 'conn' => 'all', 'within' => $historyhours]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/alluser', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List guest devices + * ------------------ + * returns an array of guest device objects with valid access + * optional parameter = time frame in hours to go back to list guests with valid access (default = 24*365 hours) + */ + public function list_guests($within = 8760) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['within' => $within]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/guest', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List online client device(s) + * ---------------------------- + * returns an array of online client device objects, or in case of a single device request, returns a single client device object + * optional parameter = the MAC address of a single online client device for which the call must be made + */ + public function list_clients($client_mac = null) + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/sta/'.trim($client_mac))); + return $this->process_response($content_decoded); + } + + /** + * Get details for a single client device + * -------------------------------------- + * returns an object with the client device information + * required parameter = client device MAC address + */ + public function stat_client($client_mac) + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/user/'.trim($client_mac))); + return $this->process_response($content_decoded); + } + + /** + * List user groups + * ---------------- + * returns an array of user group objects + */ + public function list_usergroups() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/usergroup')); + return $this->process_response($content_decoded); + } + + /** + * Assign user device to another group + * ----------------------------------- + * return true on success + * required parameter = id of the user device to be modified + * required parameter = id of the user group to assign user to + */ + public function set_usergroup($user_id, $group_id) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['usergroup_id' => $group_id]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/user/'.trim($user_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Edit user group + * --------------- + * returns an array containing a single object with attributes of the updated usergroup on success + * required parameter = id of the user group + * required parameter = id of the site + * required parameter = name of the user group + * optional parameter = limit download bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) + * optional parameter = limit upload bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) + * + */ + public function edit_usergroup($group_id, $site_id, $group_name, $group_dn = -1, $group_up = -1) + { + if (!$this->is_loggedin) return false; + $this->request_type = 'PUT'; + $json = json_encode(['_id' => $group_id, 'name' => $group_name, 'qos_rate_max_down' => $group_dn, 'qos_rate_max_up' => $group_up, 'site_id' => $site_id]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/usergroup/'.trim($group_id), $json)); + return $this->process_response($content_decoded); + } + + /** + * Add user group + * -------------- + * 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 = name of the user group + * optional parameter = limit download bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) + * optional parameter = limit upload bandwidth in Kbps (default = -1, which sets bandwidth to unlimited) + */ + public function add_usergroup($group_name, $group_dn = -1, $group_up = -1) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['name' => $group_name, 'qos_rate_max_down' => $group_dn, 'qos_rate_max_up' => $group_up]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/usergroup', $json)); + return $this->process_response($content_decoded); + } + + /** + * Delete user group + * ----------------- + * returns true on success + * required parameter = id of the user group + */ + public function delete_usergroup($group_id) + { + if (!$this->is_loggedin) return false; + $this->request_type = 'DELETE'; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/usergroup/'.trim($group_id))); + return $this->process_response_boolean($content_decoded); + } + + /** + * List health metrics + * ------------------- + * returns an array of health metric objects + */ + public function list_health() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/health')); + return $this->process_response($content_decoded); + } + + /** + * List dashboard metrics + * ---------------------- + * returns an array of dashboard metric objects (available since controller version 4.9.1.alpha) + */ + public function list_dashboard() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/dashboard')); + return $this->process_response($content_decoded); + } + + /** + * List user devices + * ----------------- + * returns an array of known user device objects + */ + public function list_users() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/user')); + return $this->process_response($content_decoded); + } + + /** + * List access points and other devices under management of the controller (USW and/or USG devices) + * ------------------------------------------------------------------------------------------------ + * returns an array of known device objects (or a single device when using the parameter) + * optional parameter = the MAC address of a single device for which the call must be made + */ + public function list_devices($device_mac = null) + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/device/'.$device_mac)); + return $this->process_response($content_decoded); + } + + /** + * List (device) tags + * ------------------ + * returns an array of known device tag objects + * + * NOTES: this endpoint was introduced with controller versions 5.5.X + */ + public function list_tags() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/tag')); + return $this->process_response($content_decoded); + } + + /** + * List rogue access points + * ------------------------ + * returns an array of known rogue access point objects + * optional parameter = hours to go back to list discovered "rogue" access points (default = 24 hours) + */ + public function list_rogueaps($within = '24') + { + if (!$this->is_loggedin) return false; + $json = json_encode(['within' => $within]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/rogueap', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List sites + * ---------- + * returns a list sites hosted on this controller with some details + */ + public function list_sites() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/self/sites')); + return $this->process_response($content_decoded); + } + + /** + * List sites stats + * ---------------- + * returns statistics for all sites hosted on this controller + * + * NOTES: this endpoint was introduced with controller version 5.2.9 + */ + public function stat_sites() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/stat/sites')); + return $this->process_response($content_decoded); + } + + /** + * Add a site + * ---------- + * returns an array containing a single object with attributes of the new site ("_id", "desc", "name") on success + * required parameter = the long name for the new site + * + * NOTES: immediately after being added, the new site will be available in the output of the "list_sites" function + */ + public function add_site($description) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['desc' => $description, 'cmd' => 'add-site']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/sitemgr', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Delete a site + * ------------- + * return true on success + * required parameter = 24 char string; _id of the site to delete + */ + public function delete_site($site_id) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['site' => $site_id, 'cmd' => 'delete-site']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/sitemgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * List admins + * ----------- + * returns an array containing administrator objects for selected site + */ + public function list_admins() + { + if (!$this->is_loggedin) return false; + $json = json_encode(['cmd' => 'get-admins']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/sitemgr', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List wlan_groups + * ---------------- + * returns an array containing known wlan_groups + */ + public function list_wlan_groups() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/wlangroup')); + return $this->process_response($content_decoded); + } + + /** + * List sysinfo + * ------------ + * returns an array of known sysinfo data + */ + public function stat_sysinfo() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/sysinfo')); + return $this->process_response($content_decoded); + } + + /** + * List self + * --------- + * returns an array of information about the logged in user + */ + public function list_self() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/self')); + return $this->process_response($content_decoded); + } + + /** + * List networkconf + * ---------------- + * returns an array of network configuration data + */ + public function list_networkconf() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/networkconf')); + return $this->process_response($content_decoded); + } + + /** + * List vouchers + * ------------- + * returns an array of hotspot voucher objects + * optional parameter = Unix timestamp in seconds + */ + public function stat_voucher($create_time = null) + { + if (!$this->is_loggedin) return false; + $json = json_encode([]); + if (trim($create_time) != null) { + $json = json_encode(['create_time' => $create_time]); + } + + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/voucher', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List payments + * ------------- + * returns an array of hotspot payments + * optional parameter = number of hours to go back to fetch payments + */ + public function stat_payment($within = null) + { + if (!$this->is_loggedin) return false; + $url_suffix = ''; + if ($within != null) { + $url_suffix = '?within='.$within; + } + + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/payment'.$url_suffix)); + return $this->process_response($content_decoded); + } + + /** + * Create hotspot operator + * ----------------------- + * return true upon success + * required parameter = name for the hotspot operator + * required parameter = clear text password for the hotspot operator + * optional parameter = note to attach to the hotspot operator + */ + public function create_hotspotop($name, $x_password, $note = null) + { + if (!$this->is_loggedin) return false; + $json = ['name' => $name, 'x_password' => $x_password]; + + /** + * if we have received a value for note, we append it to the payload array to be submitted + */ + if (isset($note)) $json['note'] = trim($note); + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/hotspotop', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * List hotspot operators + * ---------------------- + * returns an array of hotspot operators + */ + public function list_hotspotop() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/hotspotop')); + return $this->process_response($content_decoded); + } + + /** + * Create voucher(s) + * ----------------- + * returns an array of voucher codes (without the dash "-" in the middle) by calling the stat_voucher method + * required parameter = minutes the voucher is valid after activation (expiration time) + * optional parameter = number of vouchers to create, default value is 1 + * optional parameter = single-use or multi-use vouchers, string value '0' is for multi-use, '1' is for single-use, + * "n" is for multi-use n times + * optional parameter = note text to add to voucher when printing + * optional parameter = upload speed limit in kbps + * optional parameter = download speed limit in kbps + * optional parameter = data transfer limit in MB + */ + public function create_voucher($minutes, $count = 1, $quota = '0', $note = null, $up = null, $down = null, $MBytes = null) + { + if (!$this->is_loggedin) return false; + $json = ['cmd' => 'create-voucher', 'expire' => $minutes, 'n' => $count, 'quota' => $quota]; + + /** + * if we have received values for note/up/down/MBytes we append them to the payload array to be submitted + */ + if (isset($note)) $json['note'] = trim($note); + if (isset($up)) $json['up'] = $up; + if (isset($down)) $json['down'] = $down; + if (isset($MBytes)) $json['bytes'] = $MBytes; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/hotspot', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * Revoke voucher + * -------------- + * return true on success + * required parameter = 24 char string; _id of the voucher to revoke + */ + public function revoke_voucher($voucher_id) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['_id' => $voucher_id, 'cmd' => 'delete-voucher']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/hotspot', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Extend guest validity + * --------------------- + * return true on success + * required parameter = 24 char string; _id of the guest to extend validity + */ + public function extend_guest_validity($guest_id) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['_id' => $guest_id, 'cmd' => 'extend']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/hotspot', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * List port forwarding stats + * -------------------------- + * returns an array of port forwarding stats + */ + public function list_portforward_stats() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/portforward')); + return $this->process_response($content_decoded); + } + + /** + * List DPI stats + * -------------- + * returns an array of DPI stats + */ + public function list_dpi_stats() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/dpi')); + return $this->process_response($content_decoded); + } + + /** + * List current channels + * --------------------- + * returns an array of currently allowed channels + */ + public function list_current_channels() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/current-channel')); + return $this->process_response($content_decoded); + } + + /** + * List port forwarding settings + * ----------------------------- + * returns an array of port forwarding settings + */ + public function list_portforwarding() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/portforward')); + return $this->process_response($content_decoded); + } + + /** + * List dynamic DNS settings + * ------------------------- + * returns an array of dynamic DNS settings + */ + public function list_dynamicdns() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/dynamicdns')); + return $this->process_response($content_decoded); + } + + /** + * List port configuration + * ----------------------- + * returns an array of port configurations + */ + public function list_portconf() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/portconf')); + return $this->process_response($content_decoded); + } + + /** + * List VoIP extensions + * -------------------- + * returns an array of VoIP extensions + */ + public function list_extension() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/extension')); + return $this->process_response($content_decoded); + } + + /** + * List site settings + * ------------------ + * returns an array of site configuration settings + */ + public function list_settings() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/get/setting')); + return $this->process_response($content_decoded); + } + + /** + * Adopt a device to the selected site + * ----------------------------------- + * return true on success + * required parameter = device MAC address + */ + public function adopt_device($mac) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = json_encode(['mac' => $mac, 'cmd' => 'adopt']); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/devmgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Reboot an access point + * ---------------------- + * return true on success + * required parameter = device MAC address + */ + public function restart_ap($mac) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $json = json_encode(['cmd' => 'restart', 'mac' => $mac]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/devmgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Disable/enable an access point + * ------------------------------ + * return true on success + * required parameter = 24 char string; value of _id for the access point which can be obtained from the device list + * required parameter = boolean; true will disable the device, false will enable the device + * + * NOTES: + * - a disabled device will be excluded from the dashboard status and device count and its LED and WLAN will be turned off + * - appears to only be supported for access points + * - available since controller versions 5.2.X + */ + public function disable_ap($ap_id, $disable) + { + if (!$this->is_loggedin) return false; + $this->request_type = 'PUT'; + $json = json_encode(['disabled' => (bool)$disable]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/device/'.trim($ap_id), $json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Override LED mode for a device + * ------------------------------ + * return true on success + * required parameter = 24 char string; value of _id for the device which can be obtained from the device list + * required parameter = string, off/on/default; "off" will disable the LED of the device, + * "on" will enable the LED of the device, + * "default" will apply the site-wide setting for device LEDs + * + * NOTES: + * - available since controller versions 5.2.X + */ + public function led_override($device_id, $override_mode) + { + if (!$this->is_loggedin) return false; + $this->request_type = 'PUT'; + $override_mode_options = ['off', 'on', 'default']; + if (in_array($override_mode, $override_mode_options)) { + $json = json_encode(['led_override' => $override_mode]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/device/'.trim($device_id), $json)); + return $this->process_response_boolean($content_decoded); + } + + return false; + } + + /** + * Toggle flashing LED of an access point for locating purposes + * ------------------------------------------------------------ + * return true on success + * required parameter = device MAC address + * required parameter = boolean; true will enable flashing LED, false will disable + * + * NOTES: + * replaces the old set_locate_ap() and unset_locate_ap() methods/functions + */ + public function locate_ap($mac, $enable) + { + if (!$this->is_loggedin) return false; + $mac = strtolower($mac); + $cmd = (($enable) ? 'set-locate' : 'unset-locate'); + $json = json_encode(['cmd' => $cmd, 'mac' => $mac]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/devmgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Toggle LEDs of all the access points ON or OFF + * ---------------------------------------------- + * return true on success + * required parameter = boolean; true will switch LEDs of all the access points ON, false will switch them OFF + */ + public function site_leds($enable) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['led_enabled' => (bool)$enable]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/set/setting/mgmt', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Set access point radio settings + * ------------------------------- + * return true on success + * required parameter + * required parameter (default=ng) + * required parameter + * required parameter (default=20) + * required parameter + * required parameter (default=0) + */ + public function set_ap_radiosettings($ap_id, $radio, $channel, $ht, $tx_power_mode, $tx_power) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['radio_table' => ['radio' => $radio, 'channel' => $channel, 'ht' => $ht, 'tx_power_mode' => $tx_power_mode, 'tx_power' =>$tx_power]]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/device/'.trim($ap_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Set guest login settings + * ------------------------ + * return true on success + * required parameter + * required parameter + * required parameter + * required parameter + * required parameter + * required parameter + * required parameter + * required parameter + * + * NOTES: + * - both portal parameters are set to the same value! + */ + public function set_guestlogin_settings( + $portal_enabled, + $portal_customized, + $redirect_enabled, + $redirect_url, + $x_password, + $expire_number, + $expire_unit, + $site_id + ) { + if (!$this->is_loggedin) return false; + $json = [ + 'portal_enabled' => $portal_enabled, + 'portal_customized' => $portal_customized, + 'redirect_enabled' => $redirect_enabled, + 'redirect_url' => $redirect_url, + 'x_password' => $x_password, + 'expire_number' => $expire_number, + 'expire_unit' => $expire_unit, + 'site_id' => $site_id + ]; + $json = json_encode($json, JSON_UNESCAPED_SLASHES); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/set/setting/guest_access', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Rename access point + * ------------------- + * return true on success + * required parameter + * required parameter + */ + public function rename_ap($ap_id, $apname) + { + if (!$this->is_loggedin) return false; + $json = json_encode(['name' => $apname]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/device/'.trim($ap_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Add a wlan + * ---------- + * return true on success + * required parameter = string; SSID + * required parameter = string; new pre-shared key, minimal length is 8 characters, maximum length is 63 + * required parameter = string; user group id that can be found using the list_usergroups() function + * required parameter = string; wlan group id that can be found using the list_wlan_groups() function + * optional parameter = boolean; enable/disable wlan + * optional parameter = boolean; hide/unhide wlan SSID + * optional parameter = boolean; apply guest policies or not + * optional parameter = string; security type + * optional parameter = string; wpa mode (wpa, wpa2, ..) + * optional parameter = string; encryption (auto, ccmp) + * optional parameter = boolean; enable/disable vlan for this wlan + * optional parameter = string; vlan id + * optional parameter = boolean; enable/disable Unscheduled Automatic Power Save Delivery + * optional parameter = boolean; enable/disable wlan schedule + * optional parameter = string; schedule rules + * ----------------- + * TODO: Check parameter values + */ + public function create_wlan( + $name, + $x_passphrase, + $usergroup_id, + $wlangroup_id, + $enabled = true, + $hide_ssid = false, + $is_guest = false, + $security = 'open', + $wpa_mode = 'wpa2', + $wpa_enc = 'ccmp', + $vlan_enabled = false, + $vlan = null, + $uapsd_enabled = false, + $schedule_enabled = false, + $schedule = [] + ) { + if (!$this->is_loggedin) return false; + $json = [ + 'name' => $name, + 'x_passphrase' => $x_passphrase, + 'usergroup_id' => $usergroup_id, + 'wlangroup_id' => $wlangroup_id, + 'enabled' => $enabled, + 'hide_ssid' => $hide_ssid, + 'is_guest' => $is_guest, + 'security' => $security, + 'wpa_mode' => $wpa_mode, + 'wpa_enc' => $wpa_enc, + 'vlan_enabled' => $vlan_enabled, + 'uapsd_enabled' => $uapsd_enabled, + 'schedule_enabled' => $schedule_enabled, + 'schedule' => $schedule, + ]; + if (!is_null($vlan) && $vlan_enabled) $json['vlan'] = $vlan; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/add/wlanconf', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Delete a wlan + * ------------- + * return true on success + * required parameter = 24 char string; _id of the wlan that can be found with the list_wlanconf() function + */ + public function delete_wlan($wlan_id) + { + if (!$this->is_loggedin) return false; + $json = json_encode([]); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/del/wlanconf/'.trim($wlan_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Set wlan settings + * ----------------- + * return true on success + * required parameter + * required parameter = new pre-shared key, minimal length is 8 characters, maximum length is 63, + * will be ignored if set to null + * optional parameter + */ + public function set_wlansettings($wlan_id, $x_passphrase, $name = null) + { + if (!$this->is_loggedin) return false; + $json = []; + if (!is_null($x_passphrase)) $json['x_passphrase'] = trim($x_passphrase); + if (!is_null($name)) $json['name'] = trim($name); + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/wlanconf/'.trim($wlan_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Disable/Enable wlan + * ------------------- + * return true on success + * required parameter + * required parameter = boolean; true disables the wlan, false enables it + */ + public function disable_wlan($wlan_id, $disable) + { + if (!$this->is_loggedin) return false; + $action = ($disable) ? false : true; + $json = ['enabled' => (bool)$action]; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/upd/wlanconf/'.trim($wlan_id), 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * List events + * ----------- + * returns an array of known events + * optional parameter = hours to go back, default value is 720 hours + * optional parameter = which event number to start with (useful for paging of results), default value is 0 + * optional parameter = number of events to return, default value is 3000 + */ + public function list_events($historyhours = 720, $start = 0, $limit = 3000) + { + if (!$this->is_loggedin) return false; + $json = ['_sort' => '-time', 'within' => $historyhours, 'type' => null, '_start' => $start, '_limit' => $limit]; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/event', 'json='.$json)); + return $this->process_response($content_decoded); + } + + /** + * List wireless settings + * ---------------------- + * returns an array of wireless networks and settings + */ + public function list_wlanconf() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/wlanconf')); + return $this->process_response($content_decoded); + } + + /** + * List alarms + * ----------- + * returns an array of known alarms + */ + public function list_alarms() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/list/alarm')); + return $this->process_response($content_decoded); + } + + /** + * Count alarms + * ------------ + * returns an array containing the alarm count + * optional parameter = boolean; if true all alarms will be counted, if false only non-archived (active) alarms will be counted + */ + public function count_alarms($archived = null) + { + if (!$this->is_loggedin) return false; + $url_suffix = ($archived === false) ? '?archived=false' : null; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cnt/alarm'.$url_suffix)); + return $this->process_response($content_decoded); + } + + /** + * Upgrade a device to the latest firmware + * --------------------------------------- + * return true on success + * required parameter = MAC address of the device to upgrade + * + * NOTES: + * - updates the device to the latest firmware known to the controller + */ + public function upgrade_device($device_mac) + { + if (!$this->is_loggedin) return false; + $json = ['mac' => $device_mac]; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/devmgr/upgrade', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Upgrade a device to a specific firmware file + * -------------------------------------------- + * return true on success + * required parameter = URL for the firmware file to upgrade the device to + * required parameter = MAC address of the device to upgrade + * + * NOTES: + * - updates the device to the firmware file at the given URL + * - please take great care to select a valid firmware file for the device! + */ + public function upgrade_device_external($firmware_url, $device_mac) + { + if (!$this->is_loggedin) return false; + $json = ['url' => $firmware_url, 'mac' => $device_mac]; + $json = json_encode($json, JSON_UNESCAPED_SLASHES); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/devmgr/upgrade-external', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Trigger an RF scan by an AP + * --------------------------- + * return true on success + * required parameter = MAC address of the AP + */ + public function spectrum_scan($ap_mac) + { + if (!$this->is_loggedin) return false; + $json = ['cmd' => 'spectrum-scan', 'mac' => $ap_mac]; + $json = json_encode($json); + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/cmd/devmgr', 'json='.$json)); + return $this->process_response_boolean($content_decoded); + } + + /** + * Check the RF scanning state of an AP + * ------------------------------------ + * returns an object with relevant information (results if available) regarding the RF scanning state of the AP + * required parameter = MAC address of the AP + */ + public function spectrum_scan_state($ap_mac) + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/stat/spectrum-scan/'.trim($ap_mac))); + return $this->process_response($content_decoded); + } + + /** + * List Radius user accounts + * ------------------------- + * returns an array of objects containing all Radius accounts for the current site + * + * NOTES: + * - this function/method is only supported on controller versions 5.5.19 and later + */ + public function list_radius_accounts() + { + if (!$this->is_loggedin) return false; + $content_decoded = json_decode($this->exec_curl($this->baseurl.'/api/s/'.$this->site.'/rest/account')); + return $this->process_response($content_decoded); + } + + /**************************************************************** + * "Aliases" for deprecated functions from here, to support + * backward compatibility: + ****************************************************************/ + + /** + * List access points and other devices under management of the controller (USW and/or USG devices) + * ------------------------------------------------------------------------------------------------ + * returns an array of known device objects (or a single device when using the parameter) + * optional parameter = the MAC address of a single device for which the call must be made + * + * NOTE: + * changed function/method name to fit it's purpose + */ + public function list_aps($device_mac = null) + { + return $this->list_devices($device_mac); + } + + /** + * Start flashing LED of an access point for locating purposes + * ----------------------------------------------------------- + * return true on success + * required parameter = device MAC address + */ + public function set_locate_ap($mac) + { + trigger_error( + 'Function set_locate_ap() has been deprecated, use locate_ap() instead.', + E_USER_DEPRECATED + ); + return $this->locate_ap($mac, true); + } + + /** + * Stop flashing LED of an access point for locating purposes + * ---------------------------------------------------------- + * return true on success + * required parameter = device MAC address + */ + public function unset_locate_ap($mac) + { + trigger_error( + 'Function unset_locate_ap() has been deprecated, use locate_ap() instead.', + E_USER_DEPRECATED + ); + return $this->locate_ap($mac, false); + } + + /** + * Switch LEDs of all the access points ON + * --------------------------------------- + * return true on success + */ + public function site_ledson() + { + trigger_error( + 'Function site_ledson() has been deprecated, use site_leds() instead.', + E_USER_DEPRECATED + ); + return $this->site_leds(true); + } + + /** + * Switch LEDs of all the access points OFF + * ---------------------------------------- + * return true on success + */ + public function site_ledsoff() + { + trigger_error( + 'Function site_ledsoff() has been deprecated, use site_leds() instead.', + E_USER_DEPRECATED + ); + return $this->site_leds(false); + } + + /**************************************************************** + * Internal (private) functions from here: + ****************************************************************/ + + /** + * Process regular responses where output is the content of the data array + */ + private function process_response($response) + { + $this->last_results_raw = $response; + if (isset($response->meta->rc)) { + if ($response->meta->rc === 'ok') { + $this->last_error_message = null; + if (is_array($response->data)) { + return $response->data; + } + + return true; + } elseif ($response->meta->rc === 'error') { + /** + * we have an error: + * set $this->set last_error_message if the returned error message is available + */ + if (isset($response->meta->msg)) { + $this->last_error_message = $response->meta->msg; + } + + if ($this->debug) { + trigger_error('Last error message: ' . $this->last_error_message); + } + } + } + + return false; + } + + /** + * Process responses where output should be boolean (true/false) + */ + private function process_response_boolean($response) + { + $this->last_results_raw = $response; + if (isset($response->meta->rc)) { + if ($response->meta->rc === 'ok') { + $this->last_error_message = null; + return true; + } elseif ($response->meta->rc === 'error') { + /** + * we have an error: + * set $this->last_error_message if the returned error message is available + */ + if (isset($response->meta->msg)) { + $this->last_error_message = $response->meta->msg; + } + + if ($this->debug) { + trigger_error('Last error message: ' . $this->last_error_message); + } + } + } + + return false; + } + + /** + * Execute the cURL request + */ + private function exec_curl($url, $data = '') + { + $ch = $this->get_curl_obj(); + curl_setopt($ch, CURLOPT_URL, $url); + + if (trim($data) != '') { + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + if ($this->request_type === 'PUT') { + curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json','Content-Length: '.strlen($data)]); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); + } else { + curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); + } + + } else { + curl_setopt($ch, CURLOPT_POST, false); + if ($this->request_type === 'DELETE') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); + } + } + + if (($content = curl_exec($ch)) === false) { + trigger_error('cURL error: '.curl_error($ch)); + } + + /** + * has the session timed out? + */ + $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $strerr = '{ "data" : [ ] , "meta" : { "msg" : "api.err.LoginRequired" , "rc" : "error"}}'; + + if ($httpcode == 401 && strcmp($content, $strerr) == 0) { + error_log('cURL: Needed reconnect to UniFi Controller'); + + /** + * explicit unset the old cookie now + */ + if (isset($_SESSION['unificookie'])) { + unset($_SESSION['unificookie']); + $have_cookie_in_use = 1; + } + + $this->login(); + + /** + * when login was okay, exec the same command again + */ + if ($this->is_loggedin) { + curl_close ($ch); + + /** + * setup the cookie for the user within $_SESSION + */ + if (isset($have_cookie_in_use) && session_status() != PHP_SESSION_DISABLED) { + $_SESSION['unificookie'] = $this->cookies; + unset($have_cookie_in_use); + } + + return $this->exec_curl($url, $data); + } + } + + if ($this->debug) { + print '
';
+            print PHP_EOL.'---------cURL INFO-----------'.PHP_EOL;
+            print_r (curl_getinfo($ch));
+            print PHP_EOL.'-------URL & PAYLOAD---------'.PHP_EOL;
+            print $url.PHP_EOL;
+            print $data;
+            print PHP_EOL.'----------RESPONSE-----------'.PHP_EOL;
+            print $content;
+            print PHP_EOL.'-----------------------------'.PHP_EOL;
+            print '
'; + } + + curl_close ($ch); + return $content; + } + + /** + * get the cURL object + */ + private function get_curl_obj() + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + if ($this->debug) { + curl_setopt($ch, CURLOPT_VERBOSE, true); + } + + if ($this->cookies != '') { + curl_setopt($ch, CURLOPT_COOKIESESSION, true); + curl_setopt($ch, CURLOPT_COOKIE, $this->cookies); + } + + return $ch; + } +}