[PROJECT] Driver for Unifi Protect Controllers

There's another issue. You're never posting event data to the camera because the device id doesn't match in a modelKey:event message. The beginning of parse should look something like this:

def parse( String description ){
    def Data = DecodeWebSocket( description )
    if( Data != null ){
        Logging( "WebSocket Data = ${ Data }", 4 )
		def Device
        def id = Data.actionPacket.actionPayload.id
        def dashPos = id.indexOf('-')
        if (dashPos > -1) {
            id = id.substring(dashPos + 1)
        }
        getChildDevices().each{
			if( id == getChildDevice( it.deviceNetworkId ).ReturnState( "ID" ) ){
				Device = it.deviceNetworkId
			}
		}

This at least gets smart detection events down to the camera device. I'm experimenting with some other changes as well. It appears that modelKey:event always has two part ids, the first part being the event id and the second part, the device id. But modelKey:event can occur in an add or an update.

I think "add" adds something new, generally an event but perhaps also a device when a one is adopted (or maybe a new schedule, etc.), and "update" updates something whether it's the state of a device or the state of a previously created event.

I think that just storing the last "add" id isn't right. In a system with multiple cameras there likely will be overlapping events and if you're only storing the last id then an update on a different event id will not be handled and that camera's state won't be updated.

Maybe the way to deal with this is to store events (where modelKey == event && action == add) in a list and then when a subsequent update (modelKey == event && action == update) occurs, look in the array for the event, update the appropriate camera and then remove the event from the list. Does that make sense? In the case of events, there's one add and one update and then that event id is never referenced again. Or perhaps dataPayload:null indicates that the event is over and can be discarded.

I'm going to try something like that and see how it works. Probably won't get it finished tonight though.

... Or maybe the event itself should just be passed down to the device and the device keeps track of all its own events. Probably different types of device have different events, so it might be better to handle them in the device rather than the API driver.

I REALLY do not want the devices trying to handle the events. It gets bad enough with so many children just trying to handle when they have their own commands (although my method of passing it back to the parent seems to work well for the Network API).

That was a mistake on my part about the ID. I am correcting it now. I was worried about the multiple cameras aspect... but I just wanted to get the basics working first before I started worrying about the "layers" of it. My thought was not to make it list overall but to include it in a state for the child devices. Then check the device for a related previous ID.

Updated Version(s):

  • UnifiProtectAPI.groovy = 0.2.17
  • UnifiProtectChild.groovy = 0.1.7
  • UnifiProtectChild-Camera.groovy = 0.1.6
  • UnifiProtectChild-Doorbell.groovy = 0.1.5
  • UnifiProtectChild-Light.groovy = 0.1.4

Change(s):

  • Simple one out of the way first, child device drivers received a new attribute for "Last Motion" since that was being sent to them as an event.
  • Changes to the WebSocket handling. Based on the feedback from @dcaton1220 I tried to break up the ID method a bit depending on if it was an event or otherwise as well as handle it by child. It is still fairly messy and there are things I need to figure out but it is better than what it was. It should handle last WSS per child... but I will need to make more changes so it can handle multiple TYPES of WSS per child. For example, my G3 Instant was reporting the Dark state and Motion. If the last WSS it pushes was Motion BEFORE it closed out a Dark state (I do not know if this can happen, I did not see it... but MAYBE it could) then it would not necessarily work properly. Part of the problem determining it is how my 2 devices (G3 Instant and a Floodlight) keep pushing normal WSS with their motion and other states but not as part of events. Plus the G3 will often push an event WITHOUT a 2 part ID for it. Fun times. In any case, this should be better for WSS activity than it was before... so I wanted to make sure it was available to everyone.

Updated to the latest version and still only seeing one of two WAPs. Is this an issue?

I do not do any specific AP detection, just what the API provides back as bridge devices. If you can send me a Trace log (as a message, not posted on the thread) when you perform a GetProtectInfo, I can check if all are being provided as bridges.

All the APs that my Protect says are bridges are displayed on mine, but that is NOT all of my APs. I am not sure why Protect does not have the In Wall AP... But Protect itself does not have it so... I am not really sure what the requirements are to be a bridge. I am also not sure whether there is value in my including them in the driver.

I sent a Trace Log but probably should resolve these errors first?

Appears I've seen this error before and a reboot of my UDM-Pro (temporarily) resolved the issue but my UDM-Pro appears to be operating as expected at the moment.

Login errors are a weird problem and tough to track. I would recommend trying a manual login, then GetProtectInfo. If it still gets errors, then a reboot. If it is still getting errors after that... It becomes a bigger question mark... Do you have MFA enabled? Are you using a local user credential with admin rights?

I am actually working with Ubiquiti's support on my own login issue with MFA but using a local user credential... (that cropped up without warning even though it was working fine for some time). It is now being bumped up their escalation path... But that still does not solve why it has happened. The most consistent fix has been to disable MFA. That is not a good option though.

Thanks for sending the Trace logging. I will have to look it over. I will reply to the message there.

image

No events are getting processed because indicies are backwards. 0 is the event id, 1 is the device id.

Added this:


otherwise smartDetectType retains its last value and a subsequent detection of the same type cannot be detected by a change in the attribute value.

Also changed this:


You were passing it.value (an array) to smartDetectType (a string) so if nothing was detected it ended up with the string "[]" and if something was detected it ended up as "[person]", I don't know if an attribute can be an array type, if that's really what you want to pass.

With these changes, my cameras correctly detect people and vehicles and can be used in a rule such as:

Not sure why smartDetectTypes is sent as an array. I suppose it's possible that the camera could detect a person and a vehicle at the same time, in which case smartDetectTypes: [person, vehicle] might be received (or vice versa). I've yet to see that happen but who knows... Perhaps the camera attributes should be 'personDetected' and 'vehicleDetected' instead. That's the only two smart detect types supported at present in the Ubiquity UI.

Sorry about the indexes being wrong, I will correct that ASAP, although editing code on my phone is a pain.

Yes, I intentionally made it as a string as I am playing with the type a bit because of it being passed as an array. I did not want to pre-break anything in case it does send two (as you wondered). Since it is being posted as a string it is still obvious as a person or vehicle. I MAY edit that in the future to make it say "person", "vehicle", "person & vehicle"... I am also wondering if they are going to add MORE types. So it will likely become a .each loop to "build" the actual string displayed.

Edit:
I have the changes made but I cannot copy/paste properly from my mobile device to the webserver file editor at the moment. Including trying to handle multiple types. I will get it posted as soon as I can.

No rush on my part, I've already fixed it on my end. Thank you for all you've done to create this driver in the first place.

Hard to imagine what else they would add (animals?) although for the doorbell maybe package detection? If I can ever get my hands on one of their doorbells I'll let you know, but they're perpetually out of stock.

I suppose just passing the array as a string is good enough, can always use a "contains" test in a rule for whatever you're interested in.

I would guess package but maybe animals possibly with more specifics like dog, cat, bird... It all depends on how they expand the algorithms. They might start doing car or truck. Maybe drone... Who knows.

They did add package detection to doorbells. It works on the normal G4 doorbell (sort of...mine mostly just thinks the Christmas inflatables are packages). The G4 Pro doorbell has a specific down-facing package camera.

In my integration, I just fire an event for each of the entries in the smartDetectTypes array. That way any automation that is triggered from any type will execute.

Sounds like the way to go, it should be future proof.

Yep, my Hubitat logs told me first when the package detection was added. It started working on my system before Ubiquiti mentioned it in release notes.

Since my website file editor appears not to work on my phone and I am traveling until the weekend, here is the code I have added with the impacted lines:
Replace lines 186 & 187:

            EventID = TempID[ 0 ]
            TempID = TempID[ 1 ]

Insert after line 254:

                                PostEventToChild( Device, "smartDetectType", "none" )

L
Replace lines 262 to 267:

                          if( it.value.size() > 1 ){
                                def TempString
                                def Count = 0
                                it.value.each{
                                    TempString = "${ it.value[ Count ] }"
                                    Count = ( Count + 1 )
                                    if( ( Count + 1 ) < it.value.size() ){
                                        TempString = TempString + ", "
                                    } else if( ( Count + 1 ) == it.value.size() ){
                                        TempString = TempString + " & "
                                    }
                                }
                                PostEventToChild( Device, "smartDetectType", TempString )
                            } else if( it.value.size() == 1 ){
                                PostEventToChild( Device, "smartDetectType", "${ it.value[ 0 ] }" )
                            } else {
                                PostEventToChild( Device, "smartDetectType", "none" )
                            }

I tried to copy things over from the editor for posting... But apologies if it does not turn out right. Google has been trying to help with the code editor and is causing me massive problems now.

But if it fires an even for each item, wouldn't you get multiple Hubitat events for the same overall event?

The other option I wonder about the array is if they will subdivide it. Using facial ID for example:

Person - Bob...

Edit: Sorry all, near today's destination so I will not be available for some time. Let me know how you all want these events published. Since I do not have anything that can trigger them, I have to rely on your opinions for it.

Really, it's not all that important in the grand scheme of things. Enjoy your trip, life is more important than any of this.

This is a published update of the changes included above. It also includes changes that were part of an unpublished 0.2.18.

Updated Version(s):

  • UnifiProtectAPI.groovy = 0.2.19

Change(s):

  • Rework of the indices and smartDetect portion as @dcaton1220 brought up.
  • Attempt at handling multiple items for the smartDetectType and making a single string out of them.
  • Unpublished 0.2.18 changes include login error handling to for MFA-related items (hopefully) as well as a change to Uptime handling if the device adds 000 on the end of it (mine started doing this after it was reset, so despite being up less than a week it was reporting YEARS of uptime).

Note(s):

  • Not directly related to this update (although the MFA error handling was something I added in my attempts to diagnose the issue) there is a "known" (now) problem within the Unifi OS related to MFA and local user credentials that CAN (it is not constant and does not happen all the time/right when enabled) prevent the API from working and cause login errors to be displayed. Ubiquiti confirmed they found "something" and would have a fix in a future release, although they did not provide more detail than that. If they provide me with more detail (like a release version) I will try to remember to mention it.

I have a UAP-AC-M-Pro which refuses to accept the Child-AP as the driver.
Here are the state variables for that device.
Any other info you need to debug, let me know.

I also wondered if you had considered a USG specific device? You have the newer routers as devices, but not the older USG and USGPro4 devices.