[PROJECT] Driver for Unifi Network Controllers

I have a UDM and would be willing to test. This is an awesome project.

1 Like

+1

@scottie.holden:
Well, thanks for the quick notice. I do not see any issue at all with the way that MAC is formatted. I will try to do some digging and see if I can find anything that indicates a difference. It would be a real pain if UDMs do have some slight differences in the API from UDMPs but should be workable.

@richard.shutes:
If you could try it with your UDM... we can see if it gets the same result or not. Thanks for offering to help!

This looks potentially interesting: GitHub - oznu/unifi-events: A Node.js module to listen for events from a UniFi Controller.

It seems that there are webhooks for connect/disconnect events as well as AP handoffs.

@tomw:
Hubitat is designed around a request/receive model for HTTP (you make a request and then receive the response) with the exception being the 39501 port. So it is generally difficult, if not impossible, for it to deal with "unsolicited" information.

@scottie.holden:
Can you try connecting to your UDM with the Controller Type set to "Other Unifi Controllers"? A lot of the stuff I am seeing keeps saying that the "different" URLs and port are for the UDMP. The do not mention the UDM... so I wonder if that is more meant to be like the others?

Hi @snell, thanks for the reply.

For webhooks like what this seems to provide, I have had good results with the Hubitat websocket interface for unsolicited traffic. I typically open the websocket connection in my initialize() function and just leave it open for the lifetime of the driver. For example, it works well in my Bose SoundTouch driver.

I typically take a pretty dumb approach since the data in the webhook message often differs from the typical HTTP APIs. If you have an active websocket and Hubitat receives a message on the socket, it gets passed to parse(). I do the bare minimum to make sure it's a webhook reply and not something else, and then I do data refreshes with the normal HTTP APIs. I see two benefits: I can space out the polled refresh interval; and I get snappier refreshes when something changes.

I cribbed the code that I linked to and was able to connect from Hubitat to the websocket server on my Unifi controller. The rest of my Unifi hardware got here today but is still in boxes, so I'll report back later on whether it actually behaves as expected.

Interesting. I was under the impression from past conversation with people that you could not do such things. Although I will admit to being pretty ignorant about websockets.

But if it works at all... I will have to look in more detail at that list to see what (if anything) might be useful to know on the Hubitat.

I made the suggested change with no effects. No child device created, "request timeout" in the logs.

Do the other features work or do they get errors also? The structure of the commands is different so it is interesting that you get the same error. It MIGHT imply that the UDM has a 3rd way of doing things...

Nice project! Is there a way to turn on/off the AP blue light other than from the controller?

Any luck with the USG-4 Pro and Cloud Key?

@Navat604: I do not see any commands to call it unfortunately... does not mean there is NOT a way, just that the references I have found do not seem to mention it and I have not seen much indication in the API yet. I have not decided whether there is value in making children for the Unifi devices yet either and without that it would make it more difficult to deal with the status of each one.

@Bago: Did you try the "Controller Type" preference with the "Other Unifi Controllers" settings? I have not seen anything to say that the USG-4 Pro would not work with that version of the API calls.

1 Like

Yes, I tried it. No, it doesn't work.

I thought one of the reasons UI was moving to docker containers for apps (controller, protect, etc.) under their UniFI OS, was to make things more standard and consistent.

I have a UDMP. I hate it. I'm sure the firmware is better now, than when I bailed on the beta/official hamster wheel of pain. The UDMP (from what I've read), still can't achieve close to the advertised throughput with threat management enabled (the USG can't handle that at all). Anyway, I boxed it. I am waiting for the UXG, but that seems to have slowed down a lot.

Below is some info.

State Variables

  • Cookie : csrf_token=1iOUtiHT5tXkck1V00S0DbRtwjKtGvB2;
  • Last Refresh : 2020-12-10T19:34:16+0000
  • Version : 0.1.1
  • Driver : UnifiAPI
  • Last Login : 2020-12-10T18:53:56+0000

The logs show this, no matter how many times I log in.

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:30:45.124 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:29:45.142 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:29:16.131 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:28:45.150 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:27:45.135 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:26:45.136 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:25:45.139 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:24:45.104 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

[dev:1623](http://192.168.10.15/logs/past#dev1623)2020-12-10 01:24:16.149 pm [error](http://192.168.10.15/device/edit/1623)UniFi - Unauthorized, login again

The wrong Cookie got stored. There are two Set-Cookie header entries in the login response. I'm not sure what controls the order (maybe just luck?)

You need something like this to make sure you get the right one. There's probably a more elegant way, but this works for me. You know you got the right one if the Cookie value starts with unifises (or apparently TOKEN for the UDMP).

def cookie
    resp.getHeaders().each
    {
        if((it.value.split('=')[0].toString() == "unifises") || (it.value.split('=')[0].toString() == "TOKEN"))
        {
            cookie = it.value.split(';')[0]
        }
    }
1 Like

Thanks for that information & sample @tomw, I have tried to build it in.

@Bago, if you can give version 0.1.2 a try... Too bad about the UDMP originally. I read a lot of complaints about it early on but heard it had settled in a bit. It seems to do everything I need of it but I think I am probably underutilizing it.

Updated Version(s):

  • UnifiAPI.groovy = 0.1.2

Change(s):

  • Change to how login responses are handled to try to get the correct cookie regardless of controller.
2 Likes
[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:25.419 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Event: Last Login = Thu Dec 10 18:23:25 CST 2020

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:25.412 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Login header data [X-Frame-Options:DENY, Keep-Alive:timeout=60, Access-Control-Expose-Headers:Access-Control-Allow-Origin,Access-Control-Allow-Credentials, vary:Origin, Access-Control-Allow-Credentials:true, Connection:keep-alive, Set-Cookie:csrf_token=g6vIOp4alaJE4f59JzO2PuTrZI5PdSWm; Path=/; Secure, Content-Length:30, Date:Fri, 11 Dec 2020 00:23:24 GMT, Content-Type:application/json;charset=UTF-8]

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:25.410 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Login response data {"meta":{"rc":"ok"},"data":[]}

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:20.275 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Event: Last Login = Thu Dec 10 18:23:20 CST 2020

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:20.272 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Login header data [X-Frame-Options:DENY, Keep-Alive:timeout=60, Access-Control-Expose-Headers:Access-Control-Allow-Origin,Access-Control-Allow-Credentials, vary:Origin, Access-Control-Allow-Credentials:true, Connection:keep-alive, Set-Cookie:csrf_token=ZtqLHT41Hy089ZTftaxRMTGhcwuPh4We; Path=/; Secure, Content-Length:30, Date:Fri, 11 Dec 2020 00:23:19 GMT, Content-Type:application/json;charset=UTF-8]

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:20.270 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Login response data {"meta":{"rc":"ok"},"data":[]}

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:20.202 pm[debug](http://192.168.10.15/device/edit/1629)UniFi - Driver version up to date

[dev:1629](http://192.168.10.15/logs/past#dev1629)2020-12-10 06:23:19.449 pm[trace](http://192.168.10.15/device/edit/1629)UniFi - Event: Last Refresh = Thu Dec 10 18:23:19 CST 2020

Um... I do not know off the top of my head to be honest. It looks like it responds with an http 200 status (normally an all good, here is your data) but with no response and then the header has that DENY in it plus it lacks a cookie.

So it does not work for the login... but recognized it as a login...

Can you remind me, which controller specifically are you attempting to connect to and include what version of firmware it has? I think it is possible to look up some API stuff from Ubiquiti if you know the version.

1 Like

Controller is running on a cloud Key. Version is 6.0.41

Thanks for the quick response. I doubt I will get it worked out tonight but I will try to take a look and should definitely have more info by tomorrow night.

1 Like

No hurry. Thank you for your hard work.