Custom Component: Unifi Protect

Unifi-Protect
I just recently migrated from Unifi Video NVR to Unifi Protect NVR. I run Unifi Protect on a Unifi Cloud Key Gen2+ and I must say I really love the system. It is all local, so no cloud dependency and no sharing of my recordings with external parties.

Even though I can get the Camera feed in to Home Assistant using the Generic Camera component, and also some other stuff by installing MQTT on the Cloud Key, I would rather just have a Component that does all that, and without having to fiddle around outside Unifi Protect and Home Assistant.

So I decided to see if I could write my own Custom Component supporting the Unfi Protect platform. The problem I ran into immediately was that there is no official API released by Ubiquiti, but by searching the web I found a couple of people who had found some API commands that worked. So with this as a starting point and using Google Inspector I managed to pull enough together to write this and get support for what I wanted.

The component is supporting the following:

  • camera - It will automatically add a Camera entity of all Cameras found in your Unifi Protect NVR, and this supports all the basic Camera functions in HA.
  • binary_sensor - For each camera in Unifi Protect a binary sensor is created that shows if motion occurs on that camera. Note: This only works if the camera is armed.
  • sensor - Again, for all cameras a sensor is created that shows the current Recording State

Installation and Configuration

Please go to the Github Repository for installation and configuration instructions.

I am a “learn as you go” programmer, so please excuse me if the code is not optimal Python, but I have now had it running for a few days on 2 different HA installations and without receiving any errors, so it seems to me that it works as expected.

So I really look forward to hear from other people testing this.

Enjoy,
Bjarne

22 Likes

Great! Now it´s time to make the switch from UVC to Unifi Protect :slight_smile:

Works great, thank You

1 Like

This is awesome, thanks for creating it.
I can now remove my generic cameras and move to your component. :smiley:

image

Finally UniFI Protect motion detection in home Assistant!! Now to start automating…

1 Like

do the camera entities work with the stream integration, for preloading and streaming in the frontend/casting?

If I understand your question correctly, that should work. I can cast a view that displays the stream from from the cameras defined here to my Google Nest Hub. Is that what you are asking for?

Just remember there can be a small delay before motion is recorded. (1 to 2 seconds) :slight_smile:

Yes I think that answers it. I’ll try it out and let you know if not. thanks!

I have the CC running for two days now and works really nice. Thanks for creating!

Maybe as an addition to the installation instructions you could mention a warning to remove pre-existing manual camera configurations with the same name. I took me a while to figure out why the CC wasn’t creating the sensors. :wink:

Good point Robbo. I’ll do that.

Goooood Stuff Bjarne !

Thanks, works as expected Using a Cloud Key Gen2. I’m looking forward to see possible additions to functionality and HACS integration.

/Michael

Ps. Godt nytår i morgen !

Works great! Newb question, is there a way to see a live stream of video or is just an updated screenshot every 10 seconds?

Thanks again!

Hi Michael,
Glad you like it. Let me know what kind of additional functionality you would like to see and I will see if I can dig up the API calls to deliver it.
HACS is done as a Custom Integration, but as the Component seems to work for several people, I will now submit it as an official HACS Integration.

/B

Også et godt nytåt til dig :cocktail: :cocktail:

Hi Sean,
Yes you can see a live stream. If you did as instructed in the README file and activated the RTSP stream for each Camera, you just click on the image and a Window will pop up. The first time it might take a little while, but click the box in the top right corner Preload Stream and it should go faster the next time.

/B

I didn’t have

stream:

In the configuration.yaml

Thanks!

Getting it working slowly… Ran into an issue where I had a reset camera with no “last motion”. Generated an error when loading…

homeassistant | 2019-12-31 17:26:36 ERROR (MainThread) [homeassistant.components.sensor] Error while setting up platform unifiprotect
homeassistant | Traceback (most recent call last):
homeassistant | File “/usr/src/homeassistant/homeassistant/helpers/entity_platform.py”, line 150, in _async_setup_platform
homeassistant | await asyncio.wait_for(asyncio.shield(task), SLOW_SETUP_MAX_WAIT)
homeassistant | File “/usr/local/lib/python3.7/asyncio/tasks.py”, line 442, in wait_for
homeassistant | return fut.result()
homeassistant | File “/config/custom_components/unifiprotect/sensor.py”, line 38, in async_setup_platform
homeassistant | for camera in cameradata.cameras:
homeassistant | File “/config/custom_components/unifiprotect/protectnvr.py”, line 43, in cameras
homeassistant | self._api_camera_list = self._get_camera_list()
homeassistant | File “/config/custom_components/unifiprotect/protectnvr.py”, line 116, in _get_camera_list
homeassistant | lastmotion = datetime.datetime.fromtimestamp(int(camera[‘lastMotion’])/1000).strftime(’%Y-%m-%d %H:%M:%S’)
homeassistant | TypeError: int() argument must be a string, a bytes-like object or a number, not ‘NoneType’

I will look in to capturing this error more gracefully.

Version 0.0.6

I have posted a new release to Github and the HACS store, with the following content:
hacs_badge

  • Added Integration to the Default HACS store. So it can now be installed directly from there. Search for unifiprotect
  • binary_sensor_:
    • Changed default SCAN_INTERVAL to 3 seconds to optimize Motion Detection
  • camera:
    • Added new service camera.unifiprotect_save_thumbnail. When calling this services the Thumbnail of the last recorded motion will be saved to disk, and could then be used in an automation, to send to a phone via the notify platform. Requires entity_id and filename as attributes.
      The thumbnail image is the same image you see when you open the activity page in the Unifi Protect App.
  • sensor:
    • Added new attribute camera_type to the sensor. Showing what type of Unfi Camera is attached to this sensor
  • Core Module
    • changed size of the thumbnail image when being created.
    • fixed error when no Last Motion record exist
    • cleaned up the code, removing obsolete parts.
4 Likes

Many thanks @briis for working on this. I’m pretty sure many people are greatful for this, myself included.

Apolgies for the possibly newbie question, I have lot to learn in HASS itself, yet alone when it comes to custom components. I’m facing with the following error message:

Sat Jan 04 2020 16:29:08 GMT+0100 (Central European Standard Time)
Error while setting up platform unifiprotect
Traceback (most recent call last):
  File "/config/custom_components/unifiprotect/camera.py", line 27, in async_setup_platform
    cameras = nvrobject.cameras
  File "/config/custom_components/unifiprotect/protectnvr.py", line 43, in cameras
    self._api_camera_list = self._get_camera_list()
  File "/config/custom_components/unifiprotect/protectnvr.py", line 127, in _get_camera_list
    upsince = datetime.datetime.fromtimestamp(int(camera['upSince'])/1000).strftime('%Y-%m-%d %H:%M:%S')
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 150, in _async_setup_platform
    await asyncio.wait_for(asyncio.shield(task), SLOW_SETUP_MAX_WAIT)
  File "/usr/local/lib/python3.7/asyncio/tasks.py", line 442, in wait_for
    return fut.result()
  File "/config/custom_components/unifiprotect/camera.py", line 33, in async_setup_platform
    except nvr.NotAuthorized:
NameError: name 'nvr' is not defined

I’m using the latest version you published recently. Installed it with HACS. Created a local user in Protect and verified that it works fine. Added the needful to the configration.yaml.

Worth noting that I have one camera offline. Could it that one cause the uptime to be NoneType? If so, maybe this is an edge case which the component could handle gracefully in a future release?

Alternatively, if you think I’m doing something wrong please let me know

Thanks

Don’t apologise, there are no bad questions :ok_hand:
You might be right. I need to do some error handling when reading that field, so that it does not crash when a camera is offline. I will make a fix available shortly.

1 Like