[PROJECT] Driver for Unifi Network Controllers

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.

The X-Frame-Options:DENY is most likely a red herring, though it certainly caught my eye too.

I had a deja vu moment, and I wonder if you're running into this issue due to using asynchronous POST for the login: asynchttpPost header issue

Here's a dump of all of the headers from my successful synchronous POST login, in case it helps:

1 Like

Are you using the code available in GitHub? I have yet to see the second token - unifises.

No, I happened to be writing my own thing when I noticed this project. So, I'm learning as @snell goes and also sharing things that I discover. I'll PM you my version just to see if you're able to get a login to work, in case that helps for further debugging.

1 Like

@snell, a synchronous HTTP POST for login worked for @Bago. Do you want to give that a try in your driver in case other users have the same issue?

@tomw:
I actually made a new version earlier that includes a sync post and a bunch of other changes... But did not post it yet (I ran out of time at lunch and had to get back to work).

That said, happy to take a look at it and see if I will need to make changes to what I already made.

2 Likes