GithubHelp home page GithubHelp logo

finish06 / pyunifi Goto Github PK

View Code? Open in Web Editor NEW

This project forked from calmh/unifi-api

223.0 16.0 99.0 201 KB

Home Page: https://unifi-sdn.ubnt.com/

License: MIT License

Python 100.00%
ubiquiti unifi python3 unifios

pyunifi's Introduction

PyPI version Build Status

PyUnifi


A rewrite of https://github.com/unifi-hackers/unifi-lab in cleaner Python. Forked from https://github.com/calmh/unifi-api due to unmaintained status and rewritten to use the Requests module.

Development & Pull Request

Perform all pull requests against the development branch. Pull requests against the master branch will not be merged, but closed.

Install

sudo pip install -U pyunifi

API Example

from pyunifi.controller import Controller
c = Controller('192.168.1.99', 'admin', 'p4ssw0rd')
for ap in c.get_aps():
	print('AP named %s with MAC %s' % (ap.get('name'), ap['mac']))

See also the scripts unifi-ls-clients and unifi-low-rssi-reconnect for more examples of how to use the API.

API

class Controller

Interact with a UniFi controller.

Uses the JSON interface on port 8443 (HTTPS) to communicate with a UniFi controller. Operations will raise unifi.controller.APIError on obvious problems (such as login failure), but many errors (such as disconnecting a nonexistant client) will go unreported.

__init__(self, host, username, password)

Create a Controller object.

  • host -- the address of the controller host; IP or name
  • username -- the username to log in with
  • password -- the password to log in with
  • port -- the port of the controller host
  • version -- the base version of the controller API [v4|v5|unifiOS|UDMP-unifiOS]
  • site_id -- the site ID to access
  • ssl_verify -- Verify the controllers SSL certificate, default=True, can also be False or "path/to/custom_cert.pem"

block_client(self, mac)

Add a client to the block list.

  • mac -- the MAC address of the client to block.

disconnect_client(self, mac)

Disconnects a client, forcing them to reassociate. Useful when the connection is of bad quality to force a rescan.

  • mac -- the MAC address of the client to disconnect.

get_alerts(self)

Return a list of Alerts.

get_alerts_unarchived(self)

Return a list of unarchived Alerts.

get_events(self)

Return a list of Events.

get_aps(self)

Return a list of all AP:s, with significant information about each.

get_clients(self)

Return a list of all active clients, with significant information about each.

get_statistics_last_24h(self)

Return statistical data of the last 24h

get_statistics_24h(self, endtime)

Return statistical data last 24h from endtime

  • endtime -- the last time of statistics.

get_users(self)

Return a list of all known clients, with significant information about each.

get_user_groups(self)

Return a list of user groups with its rate limiting settings.

update_user_group(self, group_id, down_kbps=-1, up_kbps=-1)

Update user group bandwidth settings.

  • group_id -- Group ID to modify.
  • down_kbps -- New bandwidth in KBPS for download.
  • up_kbps -- New bandwidth in KBPS for upload.

get_healthinfo(self)

Return high level health information on status of the setup

get_wlan_conf(self)

Return a list of configured WLANs with their configuration parameters.

restart_ap(self, mac)

Restart an access point (by MAC).

  • mac -- the MAC address of the AP to restart.

restart_ap_name(self, name)

Restart an access point (by name).

  • name -- the name address of the AP to restart.

unblock_client(self, mac)

Remove a client from the block list.

  • mac -- the MAC address of the client to unblock.

archive_all_alerts(self)

Archive all alerts of site.

create_backup(self)

Tells the controller to create a backup archive that can be downloaded with download_backup() and then be used to restore a controller on another machine.

Remember that this puts significant load on a controller for some time (depending on the amount of users and managed APs).

get_backup(self, targetfile)

Tells the controller to create a backup archive and downloads it to a file. It should have a .unf extension for later restore.

  • targetfile -- the target file name, you can also use a full path. Default creates unifi-backup.unf in the current directoy.

authorize_guest(self, guest_mac, minutes, up_bandwidth=None, down_bandwidth=None, byte_quota=None, ap_mac=None)

Authorize a guest based on his MAC address.

  • guest_mac -- the guest MAC address : aa:bb:cc:dd:ee:ff
  • minutes -- duration of the authorization in minutes
  • up_bandwith -- up speed allowed in kbps (optional)
  • down_bandwith -- down speed allowed in kbps (optional)
  • byte_quota -- quantity of bytes allowed in MB (optional)
  • ap_mac -- access point MAC address (UniFi >= 3.x) (optional)

unauthorize_guest(self, guest_mac)

Unauthorize a guest based on his MAC address.

  • guest_mac -- the guest MAC address : aa:bb:cc:dd:ee:ff

set_client_alias(self, mac, alias)

Set client alias. Use "" to reset to the default.

  • mac: The target MAC: aa:bb:cc:dd:ee:ff
  • alias: The alias to set

create_voucher(self, number, quota, expire, up_bandwidth=None, down_bandwidth=None, byte_quota=None, note=None)

Create voucher for guests. Return list of new vouchers.

  • number -- number of vouchers
  • quota -- maximal number of using; 0 = unlimited
  • expire -- expiration of vouchers in minutes
  • up_bandwidth -- up speed allowed in kbps (optional)
  • down_bandwidth -- down speed allowed in kbps (optional)
  • byte_quota -- quantity of bytes allowed in MB (optional)
  • note -- description of vouchers (optional)

list_vouchers(self, **filter)

Get list of vouchers.

  • filter -- Voucher filter (create_time, code, quota, used, note, status_expires, status, ...)
  c.list_vouchers(code='12345-67890')

delete_voucher(self, id)

Delete / revoke voucher.

  • id -- voucher id

get_device_stat(self, target_mac)

Gets the current state & configuration of the given device based on its MAC Address.

  • target_mac -- MAC address of the device

get_radius_users(self)

Returns a list of all RADIUS users, name, password, 24 digit user id, and 24 digit site id.

add_radius_user(self, name, password)

Add a new RADIUS user with this username and password.

  • name -- the new user's username
  • password -- the new user's password

update_radius_user(self, name, password, id)

Update a RADIUS user to this new username and password. Requires the user's 24 digit user id, which can be gotten from get_radius_users(self).

  • name -- the user's new username
  • password -- the user's new password
  • id -- the user's 24 digit user id.

delete_radius_user(self, id)

Delete a RADIUS user. Requires the user's 24 digit user id, which can be gotten from get_radius_users(self).

  • id -- the user's 24 digit user id.

get_switch_port_overrides(self, target_mac)

Gets a list of port overrides, in dictionary format, for the given target MAC address. The dictionary contains the port_idx, portconf_id, poe_mode, & name.

  • target_mac -- MAC address of the device

switch_port_power_off(self, target_mac, port_idx)

Powers Off the given port on the Switch identified by the given MAC Address.

  • target_mac -- MAC address of the device
  • port_idx -- Port ID to power off

switch_port_power_on(self, target_mac, port_idx)

Powers On the given port on the Switch identified by the given MAC Address.

  • target_mac -- MAC address of the device
  • port_idx -- Port ID to power on

Utilities

The following small utilities are bundled with the API:

unifi-ls-clients

Lists the currently active clients on the networks. Can take the following parameters:

Parameters Description Default
-c controller address unifi
-u controller username admin
-p controller password
-b controller port 8443
-v controller base version v5
-s site ID, UniFi >=3.x only default
-V ignore SSL certificates
-C verify with ssl certificate pem file
jb@unifi:~ % unifi-ls-clients -c localhost -u admin -p p4ssw0rd -v v3 -s default
NAME                             MAC  AP            CHAN  RSSI   RX   TX
client-kitchen     00:24:36:9a:0d:ab  Study          100    51  300  216
jborg-mbp          28:cf:da:d6:46:20  Study          100    45  300  300
jb-iphone          48:60:bc:44:36:a4  Living Room      1    45   65   65
jb-ipad            1c:ab:a7:af:05:65  Living Room      1    22   52   65

unifi-low-snr-reconnect

Periodically checks all clients for low SNR values, and disconnects those who fall below the limit. The point being that these clients will then try to reassociate, hopefully finding a closer AP. Take the same parameters as above, plus settings for intervals and SNR threshold. Use unifi-low-snr-reconnect -h for an option summary.

A good source of understanding for RSSI/SNR values is this article. According to that, an SNR of 15 dB seems like a good cutoff, and that's also the default value in the script. You can set a higher value for testing:

jb@unifi:~ % unifi-low-snr-reconnect -c localhost -u admin -p p4ssw0rd -v v3 -s default --minsnr 30
2012-11-15 11:23:01 INFO unifi-low-snr-reconnect: Disconnecting jb-ipad/1c:ab:a7:af:05:65@Study (SNR 22 dB < 30 dB)
2012-11-15 11:23:01 INFO unifi-low-snr-reconnect: Disconnecting Annas-Iphone/74:e2:f5:97:da:7e@Living Room (SNR 29 dB < 30 dB)

For production use, launching the script into the background is recommended...

unifi-save-statistics

Get a csv file with statistics

unifi-save-statistics -c localhost -u admin -p p4ssw0rd -v v3 -s default -f filename.csv

License

MIT

pyunifi's People

Contributors

aenea avatar agauvrit-tis avatar bachp avatar calmh avatar candlerb avatar chrismandich avatar cyr3xx avatar digitlength avatar elfixit avatar finish06 avatar gottsman avatar hamiltont avatar jamenlang avatar jchasey avatar jgarland79 avatar jsayles avatar kleo avatar luken avatar makuser avatar martey avatar matsimon avatar mtnocean avatar ryanaguilar avatar saroberts avatar sdague avatar the-loeki avatar timball avatar voltagex avatar xaviertorras avatar zakx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyunifi's Issues

use-case: dynamic IPv6 port forwarding

Here's what I'm trying to do: I'd like to be able to, on demand, expose port 443 on various network devices over IPv6. Each one has a globally routable address, after all, and so I should be able to do this. I already have automation on the DNS side of things; I just need to expose the network port.

  • I can't do it with static firewall configuration. Unifi doesn't support suffix masking so I can't mask out the prefix delegation and forward just the unchanging part of a machine's IP.
  • I can't do it with UPnP. I can't find any documentation on this, and whether it's a UPnP restriction or a Unifi configuration issue, but upnpc gets a "failed with code 606 (Action not authorized)" for port numbers less than 1024.
  • I can't do it with ULA addresses and NAT66, since that seems to just be totally unsupported.
  • I can't (currently) do it with pyunifi because it doesn't expose these objects via the API.

https://github.com/nickovs/unificontrol seems like it might expose some of the relevant APIs via list_networkconf and set_networksettings, but I can't experiment with those since I have a UDM pro and that library can't authenticate against a UDM Pro whereas this one can.

These APIs appear to be specified declaratively which might help copy them (and all the others, for that matter) into this library without too much additional work.

Change Password Function

Maybe something like this, probably add private 'put' function. Possibly call another function, as you can change anything with the put. Was in a rush, did this - much thanks much for your project.

    def set_wlan_pass(self, ssid, key):
        """Changes the password for a given
        ssid.  Daniel ToDo: Put method. """
        for wlan in self._api_read('list/wlanconf'):
            if wlan['name'] == ssid:
                wlan_id = wlan['_id']
                wlan_settings = {}
                wlan_settings["x_passphrase"] = key 
                params = json.dumps(wlan_settings)
                url = 'rest/wlanconf/' + wlan_id
                r = self.session.put(self._api_url() + url,
                        params)
                if r.status_code is not 200:
                    raise APIError("Login failed - status code: %i" %  
                            r.status_code)
        return 

RADIUS functions and utilities

Hi,
I've written some code for setting RADIUS usernames and passwords along with some demo Python code. Please tell me if you would like me to submit a pull request.
Paul

https://github.com/mtnocean/pyunifi/tree/radius

functions:

  • get_radius_users(self)
  • add_radius_user(self, name, password)
  • update_radius_user(self, name, password, id)
  • delete_radius_user(self, id)

support functions for delete_radius_user():

  • _delete(self, url, params=None)
  • _api_delete(self, url, params=None)

utilities:

  • unifi-ls-radius - lists all usernames/passwords
  • unifi-save-radius - saves all usernames/passwords to a .csv file
  • unifi-copy-radius - copies all usernames/passwords from one site to another

in progress:

  • unifi-upload-radius - uploads a .csv file of usernames/passwords to a site

ssl_verify attempt to suppress warnings is broken

This code does not work and also if the caller has already called urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) it prevents that from working either:

if ssl_verify is False:
    warnings.simplefilter("default", category=InsecureRequestWarning)

Removing that code from the Controller constructor allows disable_warnings() to do its job again and actually disable the warning.

requests.version
'2.21.0'
urllib3.version
'1.24.1'

pyunifi current git version as of today.

Controller Login Fails with "Remote end closed connection without response"

I have verified that I can login and have full use of the Unifi manager.

Whenever I try to initialize a Controller I would say I have a 1/6 chance of actually logging in. The other 5/6 times I simply have a trace-back that looks like the following:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 440, in send
    timeout=timeout
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 649, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/usr/local/lib/python3.6/site-packages/urllib3/util/retry.py", line 357, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "/usr/local/lib/python3.6/site-packages/urllib3/packages/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 600, in urlopen
    chunked=chunked)
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 386, in _make_request
    six.raise_from(e, None)
  File "<string>", line 2, in raise_from
  File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 382, in _make_request
    httplib_response = conn.getresponse()
  File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1331, in getresponse
    response.begin()
  File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 266, in _read_status
    raise RemoteDisconnected("Remote end closed connection without"
urllib3.exceptions.ProtocolError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))

I've been attempting to remedy this issue in some form which included me adding a couple of lines for a Requests adapter for max_retries, but this doesn't seem to actually help.

It could be related to psf/requests#2422 and psf/requests#2448

2FA Support

I have figured out what needs to be done for the 2FA changes that are coming into effect in July 22nd '24.

Here is the section of code I modified for the login to allow the passing of the 2FA token:

def _login(self):
        self.log.debug("login() as %s", self.username)
        self.session = requests.Session()
        self.session.verify = self.ssl_verify

        response = self.session.post(
            self.auth_url,
            data=json.dumps({"username": self.username, "password": self.password, "ubic_2fa_token": self.token}),
            headers=self.headers,
        )

        print(response.content)

        if response.headers.get("X-CSRF-Token"):
            self.headers = {"X-CSRF-Token": response.headers["X-CSRF-Token"]}
        if response.status_code == 400:
            raise APIError(
                "Login failed - status code: %i, msg: %s" % (response.status_code, response.json()["meta"]["msg"])
                )

        if response.status_code != 200:
            raise APIError(
                "Login failed - status code: %i, msg: %s" % (response.status_code, response.text)
                )

I pass this to the controller using this:

mfa_token = input("Enter your 2FA Token: ")

c = Controller('-Unifi Controller-', '-username-', '-password-', mfa_token)

You also need to add token=0 to the start of the init definition, I put this after the password entry, then you'll need to define the self variable down further using self.token = token

Passing json in the session.post command was not sending in the correct format for this. it needs to be sent as data, and decoded from JSON. I have checked that this still does work with accounts without the 2FA enabled on it, you can either just not pass the 2FA argument, or send any value you like - it will be ignored.

Hope this helps those looking for an answer for this!

List or query multiple sites

Hello,

As per the documentation, we need to give the site ID when connecting to the controller.
Is it possible to list the controller for sites and query multiple sites? E.g. search for a client across all sites or create a given setting for all existing sites on the controller?
Likewise, can one create a new site with this API client?

Thanks a lot.

ImportError: No module named parse

I'm not that familiar with python, so there might be an obvious answer to this; my apologies if that is the case.

I receive the following error while running unifi-ls-clients:

Traceback (most recent call last):
File "/usr/local/bin/unifi-ls-clients", line 5, in
from pyunifi.controller import Controller
File "/usr/local/lib/python2.7/dist-packages/pyunifi/controller.py", line 6, in
import urllib.parse
ImportError: No module named parse

I have urllib3 installed and parse

$ pip list --format=columns | grep -e 'urllib' -e 'parse'
parse 1.6.6
parsedatetime 1.4
urllib3 1.22

I worked around the issue by making the import statement in controller.py, line 6:
import urllib.parse -> import parse

It works like this, but I'm not sure why and I'm not sure if this work around is appropriate.

Allow to define request timeout

Currently this library doesn't seem to support setting a request timeout. In case the Unifi Controller is not responding, a script using this library is waiting infinitely.

In my case I'm using this library in a small local check for Check_MK to monitor my access points. If the Unifi Controller is not responding, every check will start an additional Python process waiting for the Unifi Controller to respond which will soon end in having hundreds of processes waiting for the Unifi Controller.

Could you please add the possibility to specify the timeout for the API requests?

Question

Excuse me Sir, currently i am having thesis about python scripting with UBNT and i'm quite new to UBNT because i just learn with Mikrotik. I want to asking some questions, can you help me?

  1. Can this script works on ubnt devices like rocket m2?
  2. Can rocket m2 use controller like any other device?

Thanks. Any answer will help me a lot

Grab USG Network

Hi!

Im trying to grab information from an USG-3P
image

like sent and recieved information.
any chance to help me out?

in network_table inside device_stat i get:
{ "_id":"xxxxxxxxxxxxxxx", "attr_hidden_id":"LAN", "attr_no_delete":true, "auto_scale_enabled":false, "dhcpd_enabled":true, "dhcpd_start":"192.168.1.6", "dhcpd_stop":"192.168.1.254", "dhcpdv6_enabled":false, "domain_name":"localdomain", "ip_subnet":"192.168.1.1/24", "ipv6_interface_type":"none", "ipv6_ra_enabled":false, "is_nat":true, "lte_lan_enabled":true, "mdns_enabled":true, "name":"Default", "networkgroup":"LAN", "purpose":"corporate", "setting_preference":"manual", "site_id":"xxxxxxxxx", "vlan_enabled":false, "is_guest":false, "ip":"192.168.1.1", "mac":"fc:ec:da:48:9e:07", "up":"true", "gateway_interface_name":"eth1", "num_sta":41, "rx_bytes":138500632107, "rx_packets":113999749, "tx_bytes":22781296050, "tx_packets":49695580 } ]

SSL: CERTIFICATE_VERIFY_FAILED

Traceback (most recent call last):
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\connectionpool.py", line 600, in urlopen
    chunked=chunked)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request
    self._validate_conn(conn)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\connectionpool.py", line 839, in _validate_conn
    conn.connect()
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\connection.py", line 344, in connect
    ssl_context=context)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\util\ssl_.py", line 357, in ssl_wrap_socket
    return context.wrap_socket(sock)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 817, in __init__
    self.do_handshake()
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 1077, in do_handshake
    self._sslobj.do_handshake()
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\adapters.py", line 449, in send
    timeout=timeout
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\connectionpool.py", line 638, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\urllib3\util\retry.py", line 398, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='192.168.66.6', port=8443): Max retries exceeded with url: /api/login (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)'),))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Administrator\Desktop\Checkunifi.py", line 2, in <module>
    c = Controller('192.168.66.6', 'nulee', 'shuidoubushi')
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\pyunifi\controller.py", line 89, in __init__
    self._login()
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\pyunifi\controller.py", line 137, in _login
    r = self.session.post(login_url, json=params)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\sessions.py", line 581, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\adapters.py", line 514, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='192.168.66.6', port=8443): Max retries exceeded with url: /api/login (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)'),))

Official Version

I know that the original project is on pypi as well, but perhaps this one could become the official one since it is now maintained. Maybe tell the original author to link to this project in his documentation ?

InsecureRequestWarning appearing while liburl3 is configured to mute them

Hey Pyunifi developers,

I have set the flag ssl_verify to False as x.509 certificate verification is not a concern in my environment. While this flag is disabled, I noticed that the script's output is spammed warnings of type InsecureRequestWarning. In the context of urllib3, this is a normal behavior, as stated in the official documentation. This may be disabled using the following code:

import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

Nonetheless, after implementing this code in my project, the warnings are still triggered. After diving into Pyunifi, I discovered that this issue was bound to the following instructions:

if ssl_verify is False:
warnings.simplefilter("default", category=InsecureRequestWarning)

Indeed, Pyunifi reactivates the warnings in case the flag ssl_verify is set to False.

From a developer perspective that consumes your library, I have the feeling the library forces me to trigger that warning in the underlying library urllib3 and mask the possibility to use the built-in feature of that underlying library to mute the warnings. In my opinion, this choice must be made by the consumer of the end application, rather than the library, to allow better extensibility.

I propose two solutions for improving that case:
c

  • removing these two lines and leaving the developers to apply the warning filter(s) as they pleased, or
  • adding another flag to control the execution of the call of warnings.simplefilter (a dedicated flag, instead of ssl_verify).

The latter solution keeps the library backward compatible in terms of behavior, but on the other hand, I think these two instructions don't add any values to Pyunifi.

If you are satisfied with one of these solutions, I can submit a pull request to perform those changes. If not so, I'm looking forward to discussing to find a better alternative to those unmaskable warnings.

Many thanks!
Cheers

Issues with create_backup()

I am using a Raspberry pi as my Unifi controller(version atag_6.0.45_14358), and I am trying to take backup of it.
I get the error message:
Exception has occurred: IndexError
list index out of range
File "C:\Users\mabor\OneDrive - IT Relation\Skrivebord\Python\Private\Unifi\UnifiAP.py", line 31, in
CreateBackup=c.create_backup()

This is basically my code(edited to remove unneeded things and passwords and so on):

from future import print_function

import argparse
import time
from collections import defaultdict

from pyunifi.controller import Controller

ControllerIP="192.168.254.111"
Username=""
Password=""
Port="8443" #Management port, default is 8443
Version="v5" #Default version is v5
Siteid="default" #Default siteID in Unifi

c = Controller(ControllerIP, Username, Password, Port, Version, Siteid ,ssl_verify = False)

CreateBackup=c.create_backup()
time.sleep(15)
print(CreateBackup)

Backup=c.get_backup(CreateBackup)

print(Backup)

I got it to work by editing the function create_backup().
Before I started:
def create_backup(self, days='0'):
"""Ask controller to create a backup archive file

    ..warning:
        This process puts significant load on the controller
        and may render it partially unresponsive for other requests.

    :param days: metrics of the last x days will be added to the backup.
        '-1' backup all metrics. '0' backup only the configuration.
    :return: URL path to backup file
    """
    res = self._run_command('backup', mgr='system', params={'days': days})
    return res[0]['url']

I changed mgr='system" to mgr='backup' and then it worked. This seems to be due to the fact that run_command uses the mgr in its API call.
I installed pyunifi using pip install pyunifi on my windows machine. I use pyunifi version
pyunifi==2.20.1

switch_port_power_off error

switch_port_power_off or switch_port_power_on will fail: TypeError: list indices must be integers or slices, not dict.

I fixed it with replacing for i in overrides: with for i in range(len(overrides)): in _switch_port_power().

Issues with login into a Cloud Key Gen2 plus

I tried to use pyunifi against a Cloud Key Gen2 plus, and I found a login issue to it.
I tried to use version="unifiOS" and then I got this error back:
raise APIError("Login failed - status code: %i" % r.status_code)
APIError: Login failed - status code: 401

I used F12 to login to the cloud key, and checked which URI it posted the login call to.
It is supposted to be towards: https://IP/api/auth/login.

In the script, the self.url is:
self.url = 'https://' + host + '/proxy/network/'

and the login function is using self.url like this:
login_url = self.url + 'api/login'

Which means it gets /proxy/network/ before api/login.

So I changed the init from:
if version == "unifiOS":
self.host = host
self.username = username
self.password = password
self.site_id = site_id
self.ssl_verify = ssl_verify
self.url = 'https://' + host + '/proxy/network/'

to:
if version == "unifiOS":
self.host = host
self.username = username
self.password = password
self.site_id = site_id
self.ssl_verify = ssl_verify
self.url = 'https://' + host + '/proxy/network/'
self.urllogin= 'https://' + host + '/'
self.version=version

And the login function I changed from this:
def _login(self):
log.debug('login() as %s', self.username)

    # XXX Why doesn't passing in the dict work?
    params = {'username': self.username, 'password': self.password}
    login_url = self.url + 'api/login'

To:
def _login(self):
log.debug('login() as %s', self.username)

    # XXX Why doesn't passing in the dict work?
    params = {'username': self.username, 'password': self.password}
    if self.version=="v5":
        login_url = self.url + 'api/login'
    elif self.version=="unifiOS":
        login_url = self.urllogin + 'api/auth/login'

And then I could login to the Cloud key and pull everything I needed.

Just wanted to inform you about this issue, awesome job with the library!

switch_port_power_on/off issues

executing switch_port_power_on or switch_port_power_off will modify the port overrides such that the assigned network is set to "default". the port configuration gets into a jacked up state where the only way to fix it is to reset the port overrides and then reassign the network. not sure why this is happening because the json payload only contains the poe setting. i'm using a udmpro with the current firmware. i suspect that the pyunifi usage of these apis is not what is expected by the udmpro.

i really didn't need power off & power on but really wanted the power cycle api. so i implemented the devmgr/power-cycle for my purposes.

Support Unifi's insistence on ancient TLSv1

Connecting (at least with Python 3.7) gives the error:

requests.exceptions.SSLError: HTTPSConnectionPool(host='xxx', port=8443): Max retries exceeded with url: /api/login (Caused by SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:1056)')))

Caused by the Unifi controller supporting only TLS v1.

This can be resolved by manually adjusting your controller to support TLSv1.2, however given that Ubiquiti have deemed the default to be only TLSv1 support, this API probably should support it.

Unable to login on Controller v5.10

In [11]: ctrl = Controller(host, username, password, port, version='v4', site_id=site_id, ssl_verify=False)                    
/home/homeassistant/.virtualenvs/hass/lib64/python3.6/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
---------------------------------------------------------------------------
APIError                                  Traceback (most recent call last)
<ipython-input-11-f04d4ea99bd7> in <module>
----> 1 ctrl = Controller(host, username, password, port, version='v4', site_id=site_id, ssl_verify=False)

~/.virtualenvs/hass/lib64/python3.6/site-packages/pyunifi/controller.py in __init__(self, host, username, password, port, version, site_id, ssl_verify)
     87 
     88         log.debug('Controller for %s', self.url)
---> 89         self._login(version)
     90 
     91     def _jsondec(self, data):

~/.virtualenvs/hass/lib64/python3.6/site-packages/pyunifi/controller.py in _login(self, version)
    149 
    150         if r.status_code is not 200:
--> 151             raise APIError("Login failed - status code: %i" % r.status_code)
    152 
    153     def _logout(self):

APIError: Login failed - status code: 400

Same for v5:

In [13]: ctrl = Controller(host, username, password, port, version='v5', site_id=site_id, ssl_verify=False)                    
/home/homeassistant/.virtualenvs/hass/lib64/python3.6/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
---------------------------------------------------------------------------
APIError                                  Traceback (most recent call last)
<ipython-input-13-b48ed86d0681> in <module>
----> 1 ctrl = Controller(host, username, password, port, version='v5', site_id=site_id, ssl_verify=False)

~/.virtualenvs/hass/lib64/python3.6/site-packages/pyunifi/controller.py in __init__(self, host, username, password, port, version, site_id, ssl_verify)
     87 
     88         log.debug('Controller for %s', self.url)
---> 89         self._login(version)
     90 
     91     def _jsondec(self, data):

~/.virtualenvs/hass/lib64/python3.6/site-packages/pyunifi/controller.py in _login(self, version)
    149 
    150         if r.status_code is not 200:
--> 151             raise APIError("Login failed - status code: %i" % r.status_code)
    152 
    153     def _logout(self):

APIError: Login failed - status code: 400

CC: @finish06

Unable to login to Controller v5.9

Logging in always returns "Login failed - status code: 400".

Trace:

>>> from pyunifi.controller import Controller, APIError
>>> c = Controller('myhostname.tld', 'username', 'password', 8443, version='v5', site_id='site')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/pyunifi/controller.py", line 89, in __init__
    self._login(version)
  File "/usr/local/lib/python3.6/site-packages/pyunifi/controller.py", line 151, in _login
    raise APIError("Login failed - status code: %i" % r.status_code)
pyunifi.controller.APIError: Login failed - status code: 400
>>> try:
...     c = Controller('myhostname.tld', 'username', 'password', 8443, version='v5', site_id='site')
... except APIError as e:
...     print(e)
... 
Login failed - status code: 400
>>> 

InsecureRequestWarning spams log

Hello!
Maybe dumb question but is following necessary?:

if ssl_verify is False:
warnings.simplefilter("default", category=requests.packages.
urllib3.exceptions.
InsecureRequestWarning)

My Home Assistant core log is getting spammed by these warnings.

Using pyunifi on an IP without SSL cert

Hi there,

our UniFi controller is running on a server (software-install, v5.12.35) which is only accessable via an IP (which is not public). Therefore this IP is not SSL certified, but I see that the controller.py always creates an URL with https://

So I set the ssl_verify to false.

Is this an issue?

update docs and possibly improve login

I had a very hard time getting this working.

At first I got an SSL _CERTIFICATE verification error, so apparently you need to add ssl_verify = False to the controller command line. This generates a warning when you run the script, but that apparently is a KNOWN 'feature'.

Next it would not connect and login. I got 404 no matter what I tried. Turns out that the port and version parameters ARE NOT OPTIONAL, and the library does not try to figure them out. so for the UDM Pro you also need to add port=443, version='UDMP-unifiOS'

Finally, the username and password worked with the values used for primary login to the device/cloud at ubiquity, in my case my username was my email address. using the "SSH" password DOES NOT work. that returns 403.

I RECOMMEND that the parameters be considered NOT OPTIONAL and that a note be added to that effect in the documentation. when parameters are "optional" the user expects that the library will figure out a reasonable value to use, unless you REALLY want something different.

NameError: global name 'urllib' is not defined

I'm receiving the following errors when I run a simple get_alerts_unarchived() call. All other API calls and sample scripts work perfectly. This seems to be the only call that references urllib. Tested in 2.X and 3.X. It seems the format for urllib changed in 3 so that may be related.

File "/usr/lib/python2.7/site-packages/pyunifi/controller.py", line 166, in get_alerts_unarchived
params = urllib.urlencode({'json': js})
NameError: global name 'urllib' is not defined

File "/usr/lib/python3.6/site-packages/pyunifi/controller.py", line 166, in get_alerts_unarchived
params = urllib.urlencode({'json': js})
NameError: name 'urllib' is not defined

ssl_verify issues

Hi,

Trying to modify an old script.

I have an argument set as:

parser.add_argument('-s', '--sslCert', help = "SSL CertPath True or False", default = "False")

and parse the argument as below:

if args.sslcert is not None:
    sslCert = args.sslcert
else:
    sslCert = os.getenv("SSL_CERT_VAR")
    if sslCert is None:
        sslCert = raw_input('SSL_Var: ')

And use the argument here:

c = Controller(controllerIP, userName, password, "8443", "v4", "default", sslCert)
clients = c.get_clients()
list = {}

I'm getting the error:

Traceback (most recent call last):
  File "/home/pi/client-mapping.py", line 58, in <module>
    c = Controller(controllerIP, userName, password, "8443", "v4", "default", sslCert)
  File "/usr/local/lib/python2.7/dist-packages/pyunifi/controller.py", line 113, in __init__
    self._login()
  File "/usr/local/lib/python2.7/dist-packages/pyunifi/controller.py", line 161, in _login
    r = self.session.post(login_url, json=params)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 578, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 416, in send
    self.cert_verify(conn, request.url, verify, cert)
  File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 228, in cert_verify
    "invalid path: {}".format(cert_loc))
IOError: Could not find a suitable TLS CA certificate bundle, invalid path: False

So it seems it sees "False", but it's not seeing it as an input for "ssl_verify"

Any ideas? As you can tell, I'm still learning.

Thanks,
Shane.

Authentication issue with unifi controller 5.5.9

I'm using the unify home assistant component which depends on this library at version 2.0.0.

After updating my unifi controller to the latest beta (5.5.9), I noticed that my home-assistant unify integration stopped working.

Here's the debug output:

17-04-19 22:04:23 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "uvloop/future.pyx", line 374, in uvloop.loop.BaseTask._fast_step (uvloop/loop.c:112704)
  File "/usr/src/app/homeassistant/components/device_tracker/__init__.py", line 698, in async_device_tracker_scan
    found_devices = yield from scanner.async_scan_devices()
  File "uvloop/future.pyx", line 230, in __iter__ (uvloop/loop.c:110600)
  File "uvloop/future.pyx", line 432, in uvloop.loop.BaseTask._fast_wakeup (uvloop/loop.c:113980)
  File "uvloop/future.pyx", line 101, in uvloop.loop.BaseFuture._result_impl (uvloop/loop.c:108900)
  File "/usr/local/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/src/app/homeassistant/components/device_tracker/unifi.py", line 88, in scan_devices
    self._update()
  File "/usr/src/app/homeassistant/components/device_tracker/unifi.py", line 79, in _update
    clients = self._controller.get_clients()
  File "/usr/local/lib/python3.5/site-packages/pyunifi/controller.py", line 183, in get_clients
    return self._read(self.api_url + 'stat/sta')
  File "/usr/local/lib/python3.5/site-packages/pyunifi/controller.py", line 82, in _read
    return self._jsondec(r.text)
  File "/usr/local/lib/python3.5/site-packages/pyunifi/controller.py", line 75, in _jsondec
    raise APIError(obj['meta']['msg'])
pyunifi.controller.APIError: api.err.LoginRequired

Any idea on what the issue may be?

Scripts use dos line endings

Brand new install on linux will break as the scripts are using dos line endings. I worked around by manually editing the (pip installed) scripts. I'm not sure what the proper "fix" is - perhaps to have setuptools generate the scripts for the project, which would then generate OS-correct scripts?

Steps to reproduce:

m ~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.2 LTS
Release:	18.04
Codename:	bionic
m ~$ uname -an
Linux media 4.15.0-51-generic #55-Ubuntu SMP Wed May 15 14:27:21 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
~$ sudo pip install -U pyunifi
/usr/local/lib/python2.7/dist-packages/pip/_vendor/requests/__init__.py:83: RequestsDependencyWarning: Old version of cryptography ([1, 2, 1]) may cause slowdown.
  warnings.warn(warning, RequestsDependencyWarning)
The directory '/home/hamiltont/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/hamiltont/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting pyunifi
  Downloading https://files.pythonhosted.org/packages/aa/6e/e4e524081f8e795b8e60e1e46fb30f30fe88f651da65fd77b24ce3032176/pyunifi-2.16.tar.gz
Requirement already satisfied, skipping upgrade: requests in /usr/lib/python2.7/dist-packages (from pyunifi) (2.18.4)
Installing collected packages: pyunifi
  Running setup.py install for pyunifi ... done
Successfully installed pyunifi-2.16
m ~$ unifi-ls-clients
/usr/bin/env: ‘python\r’: No such file or directory

Note: See https://stackoverflow.com/questions/19425857/env-python-r-no-such-file-or-directory for multiple methods to manually fix the issue

create_voucher fail

Er kann sich einloggen aber einen voucher, kann er nicht setzen

c = Controller(host=myconf["unifi"]["ip"], version = myconf["unifi"]["version"],username=myconf["unifi"]["user"], password=myconf["unifi"]["pw"], ssl_verify=False) c.create_voucher(number="7777755555",quota="70",expire="60")

Fehler Meldung

/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/urllib3/connectionpool.py:1103: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.100.35'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
warnings.warn(
Failed to perform <function Controller._write at 0x7f073fcf7420> due to api.err.InvalidArgs
Traceback (most recent call last):
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 31, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 151, in _write
return self._jsondec(response.text)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 120, in _jsondec
raise APIError(obj["meta"]["msg"])
pyunifi.controller.APIError: api.err.InvalidArgs

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 36, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 151, in _write
return self._jsondec(response.text)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 120, in _jsondec
raise APIError(obj["meta"]["msg"])
pyunifi.controller.APIError: api.err.InvalidArgs

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/user/PycharmProjects/qrcode_unifi/main.py", line 99, in
c.create_voucher(number="7777755555",quota="70",expire="60")
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 832, in create_voucher
res = self._run_command(cmd, mgr="hotspot", params=params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 306, in _run_command
return self._api_write("cmd/" + mgr, params=params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 154, in _api_write
return self._write(self._api_url() + url, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/PycharmProjects/qrcode_unifi/venv/lib/python3.11/site-packages/pyunifi/controller.py", line 38, in wrapper
raise APIError(err)
pyunifi.controller.APIError: api.err.InvalidArgs

Process finished with exit code 1

SSL Error

Any idea why I'm getting an error related to SSL?

from pyunifi.controller import Controller

c = Controller('192.168.2.126', 'JeffHerr', 'XXXXXX')
for ap in c.get_aps():
print('AP named %s with MAC %s', ap.get('name'), ap['mac'])

requests.exceptions.SSLError: HTTPSConnectionPool(host='192.168.2.126', port=8443): Max retries exceeded with url: /api/login (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))

I'm using a self-signed cert, I suppose, as I don't have a formal cert assigned.

pyunifi.controller.APIError: Login failed - status code: 404 after FW upgrade

Hi @finish06 ,

Today i updated FW on my Cloud Key Gen2 and now I’m receiving and error pyunifi.controller.APIError: Login failed - status code: 404

Here is my Client initialisation

c = Controller('host', 'login', 'pass, ssl_verify=False, site_id="default")

Python version - 3.7.3
pyunifi version - 2.21
Cloud Key version - 2.1.11
Cloud Network version - 6.4.54

Can you please help me to solve this issue ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.