Ubiquiti UniFi Video and Protect NVR Integration

Now supports Protect

I’ve released a basic integration via SmartApp and device handler for the Ubiquiti UniFi Video NVR. The SmartApp will connect to your NVR and discover the cameras for you. It creates camera devices that implements ST motion detection, (should the camera be configured for record on motion), connectivity and image capture. You can then use something like the “Notify Me When” SmartApp to get motion notifications and follow up with the Ubiquiti app.

I can see the device handler being expanded a bit, but can’t see it duplicating the features of the official Ubiquiti app since that is very feature rich.

Feature/Bugfix Releases:
12/27/2016 - Initial version, supports motion
12/29/2016 - Bugfix for multiple cameras
1/4/2017 - Add connection status indicator
1/14/2017 - Add Image Capture
1/15/2017 - Bugfix and add snapshot on motion
1/28/2017 - Use new image storage API, restores image capture
2/4/2017 - Fix for change in image storage API
4/21/2017 - Username/password login, 1st and 2nd gen cameras, polling watchdog
4/19/2020 - Add initial pass at Protect support
6/8/2020 - Protect will report motion even when set to always record

Enjoy!

16 Likes

WOW. That’s one heck of an introduction, first post and DTH!

Thank you very much!

Great Work! Congratulations. Hope someday we can watch video from ST App.

Thanks, Benji!

Thanks! I’ve thought about video but since the stream is only LAN accessible in my setup and the Ubiquiti mobile app is so good, I haven’t seen a real use for it yet. If their cloud access (I don’t have their cloud key to find out) can enable this, it might be worth investigating.

I have 4 unifi cameras, but somehow only 1 is being listed in “things”… any clue?

What kind of cameras are they? Can you provide logs from the SmartApp install?

3 x uvc bullet and 1 x UVC dome.
Sorry I wish I know how/where to get such “smartApp install logs”…

When you log into graph.api.smartthings.com, open the “Live Logging”. Remove the device (and the SmartApp if it doesn’t do that automatically) and then install the SmartApp again. You should see logs from the app that say things like “adding child: …”

Thanks for your instructions!. I just followed your steps and found these logs:
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug adding child: cam-frente, UVC Dome, d46d5e31-d329-3a16-9533-06ed1153c72c, 583ffe07e6eec93f9c02efc7
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug dni: 0418D6235EF0
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug bootstrapResponseHandler()
ef09b573-4ba4-4876-ada9-6a936f9195b3 12:26:42: debug motionOrContactHandler(cam-frente (UVC Dome) motion:inactive)
7821fc70-58fd-4bb9-a677-13a69449bfa9 12:26:42: debug state: [uuid:d46d5e31-d329-3a16-9533-06ed1153c72c, name:cam-frente, id:583ffe07e6eec93f9c02efc7, lastRecordingStartTime:null, motion:inactive, pollInterval:5]
3a24e311-61c3-4303-8c2c-c6a9c2ba6f60 12:26:42: trace getPhrases(), state.welcomeIssue = null
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:42: debug dni: 0418D6235EF0
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:42: debug bootstrapResponseHandler()
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug NVR API is located at 192.168.0.253:7080
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug initialize()
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug Updated with settings: [nvrAddress:192.168.0.253, nvrPort:7080, apiKey:iAiOa5bDIgqJizQz]
3a24e311-61c3-4303-8c2c-c6a9c2ba6f60 12:26:41: trace getPhrases(), state.welcomeIssue = null
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug NVR API is located at 192.168.0.253:7080
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug initialize()
f4bd608c-c861-4d8c-804e-1c731fd37582 12:26:41: debug Installed with settings: [nvrAddress:192.168.0.253, nvrPort:7080, apiKey:iAiOa5bDIgqJizQz]

Looks like it could only find the one device so it isn’t a problem with adding them. I don’t have multiple myself yet so its going to be hard to debug this one. I have more coming soon so I can take a look when I install the next one.

If you are feeling brave, edit the SmartApp and add the following lines in at line 87 and re-run the install

log.debug hubResponse.json.data.cameras[0]
log.debug hubResponse.json.data.cameras[1]
log.debug hubResponse.json.data.cameras[2]
log.debug hubResponse.json.data.cameras[3]

Done, this become much much verbose…

17:27:46: trace getPhrases(), state.welcomeIssue = null
3a24e311-61c3-4303-8c2c-c6a9c2ba6f60 17:27:45: trace getPhrases(), state.welcomeIssue = null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug adding child: cam-frente, UVC Dome, d46d5e31-d329-3a16-9533-06ed1153c72c, 583ffe07e6eec93f9c02efc7
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug dni: 0418D6235EF0
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug [[enableSpeaker:true, deviceSettings:[persists:false, timezone:GMT-3, name:cam-frente], lastSeen:1482858244774, scheduleId:null, model:UVC Dome, enableStatusLed:true, provisioned:true, state:CONNECTED, analyticsSettings:[minimumMotionSecs:0, enableSoundAlert:false, soundAlertVolume:100, endMotionAfterSecs:null], mac:0418D6235EF0, hasDefaultCredentials:false, firmwareBuild:5d0239d, username:ubnt, _id:583ffe07e6eec93f9c02efc7, enableSuggestedVideoSettings:true, name:cam-frente, firmwareVersion:v3.5.2, micVolume:100, internalHost:192.168.0.101, platform:GEN2, lastRecordingId:58642049e6ee7971778db907, host:192.168.0.101, lastRecordingStartTime:1482956870635, status:[scheduledAction:null, remotePort:7443, remoteHost:192.168.0.253, recordingStatus:[2:[fullTimeRecordingEnabled:false, motionRecordingEnabled:false], 1:[fullTimeRecordingEnabled:false, motionRecordingEnabled:false], 0:[fullTimeRecordingEnabled:false, motionRecordingEnabled:true]]], networkStatus:[signalLevel:0, connectionState:2, linkSpeedMbps:100, essid:null, quality:0, frequency:0, connectionStateDescription:CONNECTED, ipAddress:192.168.0.101, qualityMax:0], uptime:1482761835209, channels:[[enabled:true, width:1280, fps:15, rtspAlias:null, maxBitrate:3000000, minBitrate:32000, idrInterval:1, isRtspEnabled:false, id:0, fpsValues:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30], height:720, name:video1, bitrate:1516000], [enabled:true, width:720, fps:15, rtspAlias:null, maxBitrate:1500000, minBitrate:32000, idrInterval:1, isRtspEnabled:false, id:1, fpsValues:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30], height:400, name:video2, bitrate:766000], [enabled:true, width:640, fps:15, rtspAlias:null, maxBitrate:750000, minBitrate:32000, idrInterval:1, isRtspEnabled:false, id:2, fpsValues:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30], height:360, name:video3, bitrate:391000]], zones:[[_id:583fff6ee6eec93f9c02efd6, bitmap:null, sensitivity:20, name:cam-frente, coordinates:[[y:0.0, x:0.0], [y:1.0, x:0.0], [y:1.0, x:1.0], [y:…[TRUNCATED]
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug bootstrapResponseHandler()
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug dni: 0418D6235EF0
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug [[enableSpeaker:true, deviceSettings:[persists:false, timezone:GMT-3, name:cam-frente], lastSeen:1482858244774, scheduleId:null, model:UVC Dome, enableStatusLed:true, provisioned:true, state:CONNECTED, analyticsSettings:[minimumMotionSecs:0, enableSoundAlert:false, soundAlertVolume:100, endMotionAfterSecs:null], mac:0418D6235EF0, hasDefaultCredentials:false, firmwareBuild:5d0239d, username:ubnt, _id:583ffe07e6eec93f9c02efc7, enableSuggestedVideoSettings:true, name:cam-frente, firmwareVersion:v3.5.2, micVolume:100, internalHost:192.168.0.101, platform:GEN2, lastRecordingId:58642049e6ee7971778db907, host:192.168.0.101, lastRecordingStartTime:1482956870635, status:[scheduledAction:null, remotePort:7443, remoteHost:192.168.0.253, recordingStatus:[2:[fullTimeRecordingEnabled:false, motionRecordingEnabled:false], 1:[fullTimeRecordingEnabled:false, motionRecordingEnabled:false], 0:[fullTimeRecordingEnabled:false, motionRecordingEnabled:true]]], networkStatus:[signalLevel:0, connectionState:2, linkSpeedMbps:100, essid:null, quality:0, frequency:0, connectionStateDescription:CONNECTED, ipAddress:192.168.0.101, qualityMax:0], uptime:1482761835209, channels:[[enabled:true, width:1280, fps:15, rtspAlias:null, maxBitrate:3000000, minBitrate:32000, idrInterval:1, isRtspEnabled:false, id:0, fpsValues:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30], height:720, name:video1, bitrate:1516000], [enabled:true, width:720, fps:15, rtspAlias:null, maxBitrate:1500000, minBitrate:32000, idrInterval:1, isRtspEnabled:false, id:1, fpsValues:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30], height:400, name:video2, bitrate:766000], [enabled:true, width:640, fps:15, rtspAlias:null, maxBitrate:750000, minBitrate:32000, idrInterval:1, isRtspEnabled:false, id:2, fpsValues:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30], height:360, name:video3, bitrate:391000]], zones:[[_id:583fff6ee6eec93f9c02efd6, bitmap:null, sensitivity:20, name:cam-frente, coordinates:[[y:0.0, x:0.0], [y:1.0, x:0.0], [y:1.0, x:1.0], [y:…[TRUNCATED]
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug bootstrapResponseHandler()
ef09b573-4ba4-4876-ada9-6a936f9195b3 17:27:45: debug motionOrContactHandler(cam-frente (UVC Dome) motion:inactive)
5bf2744a-39f4-46fe-b2bd-2fbcf95fd014 17:27:45: debug state: [uuid:d46d5e31-d329-3a16-9533-06ed1153c72c, name:cam-frente, id:583ffe07e6eec93f9c02efc7, lastRecordingStartTime:null, motion:inactive, pollInterval:5]
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug NVR API is located at 192.168.0.253:7080
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug initialize()
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:45: debug Updated with settings: [nvrAddress:192.168.0.253, nvrPort:7080, apiKey:iAiOa5bDIgqJizQz]
3a24e311-61c3-4303-8c2c-c6a9c2ba6f60 17:27:44: trace getPhrases(), state.welcomeIssue = null
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:44: debug NVR API is located at 192.168.0.253:7080
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:44: debug initialize()
47f9ee3e-2b41-4b93-bd06-6ec509beb3f0 17:27:44: debug Installed with settings: [nvrAddress:192.168.0.253, nvrPort:7080, apiKey:iAiOa5bDIgqJizQz]

Great start on this. I was using IFTTT to use my cameras as motion sensors but this will be a much more elegant solution. Unfortunately, like @Jcarostegui, I’m only able to see one camera. In my case, it’s the one that is not setup to record motion. It does sense motion but does not record.

Can’t wait to see this progress.

Looks like either the parsing is wrong or the NVR isn’t giving the data. My other camera shows up tomorrow so I’ll be able to do more digging in the next few days to find out whats going wrong.

I’m not a programmer but I know enough to be dangerous. I can tell my NVR is sending the data in the JSON response if I put http://[SERVER_IP:7080/api/2.0/bootstrap?apiKey=[APIKEY] in browser window.

Your code only finds one of three cameras but if I change
log.info "nvr_bootstrapPollCallback: found ${data.cameras.size
to
log.info "nvr_bootstrapPollCallback: found ${data.cameras.name

I see my three cameras in the log.

b34fd07a-5bc2-472d-b368-1017480808b8 7:24:27 PM: debug nvr_bootstrapPollCallback: found [[UVC-Micro, UVC-Garage, UVC G3]] camera(s)

This validates that the SmartThings is reading my JSON correctly.

If I replace
def dni = "${camera.mac[0]}"
with
def dni = “${camera.mac[1]}” and continue to replace all array [0] references with [1], my second camera is added to the app.

So, based on what I see, there is some issue with the array. If I knew how to program the array correctly, I think I could resolve this. Hopefully, this will help you resolve the issue.

Thats awesome, thanks! I’ll take a look. I’ve been a C programmer for 20 years…this Groovy stuff is weird and I’m probably assuming too much C/C++ behavior. When I add the second cam tomorrow I’ll release an update.

@thesohoguy @Jcarostegui I have fixed the multiple camera issue. Please remove the devices, update the files and install the SmartApp. Thanks for both of your help.

Let me try new version, really appreciate your hard work!

@cvincent Thanks for the update. The new version found all of my cameras easily.

I’ll play with the motion detection more tomorrow.

The only suggestion I have would be if the camera state is disconnected to show that versus No Motion in the app UI. Of course I don’t how easy that would be to do an it’s not a show stopper. I’m just saying that as I have a test camera that I don’t have online all the time.

Thanks again for the quick update.

You sir, are awesome. Was hoping my UniFi cameras would eventually be integrated into ST, and you’ve just made it a reality. Especially useful considering Ubiquiti’s push notifications have seemingly never worked.

Thanks a bunch!