Custom Component: Unifi Protect

ok - got it - you wait until the sensor clears, then grab the new updated state time.

Yeah. It sends out two notifications. One as soon as the event happens with just the thumbnail. And a second, which will replace the first, with the video after the event ends. If you clear the notification before it sends out the video one, it will not send out the video one.

1 Like

so I use a script to send notifications out via MQTT (that way they go to a whole pile of other platforms and logs and things, and a platform that sends out iOS notifications back via HA - but ignore that as it’s sort of irrelevant).

And I didn’t really want the interaction on the iOS notifications in the blueprint. So I have distilled the logic down to this - you can replace the script call to MQTT with a notify script easily enough:

alias: Security Camera Triggered
description: Send notifications when a security camera detects something
trigger:
  - type: turned_on
    platform: device
    device_id: ffcac901c50a0b33c66b18eb8c6957ce
    entity_id: binary_sensor.garagecam_front_person_detected
    domain: binary_sensor
    id: Person
  - type: turned_on
    platform: device
    device_id: ffcac901c50a0b33c66b18eb8c6957ce
    entity_id: binary_sensor.garagecam_front_vehicle_detected
    domain: binary_sensor
    id: Vehicle
condition: []
action:
  - variables:
      parent_entity_id: >-
        {{ (device_entities(device_id(trigger.entity_id)) |
        select('match','camera') | list) | last }}
      event_id: "{{ state_attr(trigger.entity_id, 'event_id') }}"
      image_url: >-
        /api/unifiprotect/thumbnail/{{ config_entry_id(trigger.entity_id) }}/{{
        event_id }}
      video_start: "{{ states[trigger.entity_id].last_changed.isoformat() }}"
      friendly_name: "{{ state_attr(parent_entity_id, 'friendly_name') }}"
  - service: script.send_mqtt_announcement
    data:
      message: "{{ friendly_name }} camera has recorded an image, tap and hold to view."
      title: Automation
      subtitle: >-
        {% if trigger.id == "Person" %}Person{% elif trigger.id == "Motion"
        %}Motion{% else %}Vehicle{% endif %} detected
      channels: HA_NOTIFY
      image: "{{ image_url }}"
      view: /default-mobile/cameras
      thread: security
      level: info
      tag: "{{ event_id }}"
  - wait_template: "{{ states(trigger.entity_id) == 'off' }}"
    continue_on_timeout: false
  - variables:
      video_url: >-
        /api/unifiprotect/video/{{ config_entry_id(trigger.entity_id) }}/{{
        trigger.entity_id }}/{{ video_start }}/{{
        states[trigger.entity_id].last_changed.isoformat() }}
  - service: script.send_mqtt_announcement
    data:
      message: >-
        {{ friendly_name }} camera has recorded some video, tap and hold to
        view.
      title: Automation
      subtitle: >-
        {% if trigger.id == "Person" %}Person{% elif trigger.id == "Motion"
        %}Motion{% else %}Vehicle{% endif %} detected
      channels: HA_NOTIFY
      video: "{{ video_url }}"
      view: /default-mobile/cameras
      thread: security
      level: info
      tag: "{{ event_id }}"
mode: restart

I tried reading all 985 posts, but my mind kept wandering. Is there an “easy” way to get the door bell video to display on an Echo Show and a TV when door bell is pushed? I have it announcing to certain dots, but I would like the video to display on an Echo show and a Roku TV (I can change it to be an Apple TV if it is easier). It seems like people are using scrypted or monocle cam with some luck.

UNVR
G4 Doorbell

My doorbell cam shows on my Apple TV whenever there’s a person detected and doorbell press.
(Homekit YAML)
Haven’t seen if this is configurable via UI yet.

entity_config:
  camera.front_door_camera_video:
    linked_doorbell_sensor: binary_sensor.doorbell_front_door
    linked_motion_sensor: binary_sensor.front_door_person_detected 

Edit: Updated for the new person detected entity. I used to have my own from a template.

2 Likes

Hey all, I had to reinstall the Unifi Protect component, after adding correct server, username and password, the component has the status “Failed to set up” and looking at the log I see the final error as “ValueError: ‘homekit’ is not a valid VideoMode”

I cannot find any one else with this issue so I’d appreciate the help!

Logger: homeassistant.config_entries
Source: custom_components/unifiprotect/data.py:93
Integration: UniFi Protect (documentation, issues)
First occurred: 18:21:50 (5 occurrences)
Last logged: 18:45:57
Error setting up entry UNVR_PKSN for unifiprotect

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 382, in async_setup
    result = await component.async_setup_entry(hass, self)
  File "/config/custom_components/unifiprotect/__init__.py", line 193, in async_setup_entry
    await data_service.async_setup()
  File "/config/custom_components/unifiprotect/data.py", line 73, in async_setup
    await self.async_refresh()
  File "/config/custom_components/unifiprotect/data.py", line 93, in async_refresh
    updates = await self.api.update(force=force)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/api.py", line 506, in update
    self._bootstrap = await self.get_bootstrap()
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/api.py", line 675, in get_bootstrap
    return Bootstrap.from_unifi_dict(**data, api=self)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 104, in from_unifi_dict
    data = cls.unifi_dict_to_dict(data)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/bootstrap.py", line 152, in unifi_dict_to_dict
    return super().unifi_dict_to_dict(data)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 336, in unifi_dict_to_dict
    data[key] = cls._clean_protect_obj_dict(data[key], unifi_dicts[key], api)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 281, in _clean_protect_obj_dict
    items[key] = cls._clean_protect_obj(value, klass, api)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 265, in _clean_protect_obj
    return klass.unifi_dict_to_dict(data=data)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/devices.py", line 697, in unifi_dict_to_dict
    return super().unifi_dict_to_dict(data)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 607, in unifi_dict_to_dict
    return super().unifi_dict_to_dict(data)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 326, in unifi_dict_to_dict
    data[key] = cls._clean_protect_obj(data[key], unifi_objs[key], api)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 265, in _clean_protect_obj
    return klass.unifi_dict_to_dict(data=data)
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/data/base.py", line 319, in unifi_dict_to_dict
    data[key] = convert_unifi_data(data[key], cls.__fields__[key])
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/utils.py", line 160, in convert_unifi_data
    value = [convert_unifi_data(v, field) for v in value]
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/utils.py", line 160, in <listcomp>
    value = [convert_unifi_data(v, field) for v in value]
  File "/usr/local/lib/python3.10/site-packages/pyunifiprotect/utils.py", line 176, in convert_unifi_data
    value = field.type_(value)
  File "/usr/local/lib/python3.10/enum.py", line 385, in __call__
    return cls.__new__(cls, value)
  File "/usr/local/lib/python3.10/enum.py", line 710, in __new__
    raise ve_exc
ValueError: 'homekit' is not a valid VideoMode


I think this is a feature request - or at least a design question.

Why does setting privacy mode change the recording state? The way it used to work was perfect - set the mask, or remove the mask. Now turning privacy mode on sets recording mode to ‘never’ and turning privacy mode back off does not restore the previous state. Seems like turning privacy on then off shouldn’t change any other state.

Great integration and support, thank you!

Thank you Sir! I have updated my Camera rules to pull the image directly from Protect and everything is working great.

Just tried the blueprint for sending notifications on motion. Discovered that the notification contains a short video clip of the motion instead of a static image (shown in the notification). Didn’t know that was possible on Android.

Since I don’t understand how I can customize the blueprint and I want to use my current automation for sending notifications I wonder if I can get access to that clip in my own automation? Where do I find it?

Second question is if/how I can access the type of movement (person/vehicle) so that I can print this out in my notification?

alias: KAMERA - Ny test
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.framsidan_person_detected
      - binary_sensor.framsidan_vehicle_detected
      - binary_sensor.garageuppfarten_person_detected
      - binary_sensor.garageuppfarten_vehicle_detected
    to: "on"
action:
  - service: notify.ls_mobil
    data:
      message: >-
        Test 
      title: Rörelse pÄ framsidan
      data:
        priority: high
        clickAction: app://com.ubnt.unifi.protect
        ttl: 0
        group: framsidan
        image: >-
          /api/unifiprotect/thumbnail/{{ config_entry_id(trigger.entity_id)
          }}/{{ state_attr(trigger.entity_id, 'event_id') }}
mode: queued
max: 10

I see the new “signed paths” way of accessing images works “magically” with the notify component, but I can’t seem to figure out if there’s a way to access the images directly via URL, either locally from a script or remotely.

Developer docs don’t show a way to sign a path from a script/automation:

Any way to get something as simple as a local download to work?

automation:

- id: unifi_protect_event
  alias: "UniFi Protect: Motion Event"
  mode: parallel
  
  trigger:
  - platform: state
	entity_id: binary_sensor.back_yard_motion
	to: "on"
	
  variables:
	camera_name: "{{ device_attr(trigger.entity_id, 'name') }}"
	nvr_id: "{{ config_entry_id(trigger.entity_id) }}"
	event_id: "{{ state_attr(trigger.entity_id, 'event_id') }}"
#         base_url: "http://127.0.0.1:8123"
#         base_url: "http://homeassistant.local:8123"
	base_url: "https://<redacted>.ui.nabu.casa"
	image_path: "/api/unifiprotect/thumbnail/{{ nvr_id }}/{{ event_id }}"

  action:		
	- service: downloader.download_file
	  data:
		url: "{{ base_url }}{{ image_path }}"
		filename: "{{ camera_name }}/{{ now().strftime('%Y-%m-%d_%H.%M.%S') }}.jpg"
		subdir: "media/events"

I use the telegram service for notifications and want to send the snapshot/thumbnail as an attachment. This works using the snapshot approach, but the snapshot is low resolution and of course a bit delayed compared to the detection event. Is there a way to either get the snapshot at full resolution or retrieve the unifi thumbnail to a JPG file similar to the snapshot service?

My current automation:

alias: Person ved indgangen
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.g4_indgang_person_detected
    to: "on"
condition: []
action:
  - service: camera.snapshot
    data:
      filename: /config/www/snapshots/snapshot_indgang.jpg
    target:
      entity_id: camera.g4_indgang_high
  - service: notify.jaybebot
    data:
      message: Person detected
      data:
        photo:
          - file: /config/www/snapshots/snapshot_indgang.jpg
            caption: "Person detected!"
mode: single

Yes, notification services are able to sign media URLs. What I’m looking for is how to pull the image bytes from the media URL in an automation.

@AngellusMortis stated: “There needs to be another generic way to expose media for an entity without access to the Python code for automations, add-ons (Node Red) etc. The recent work and optimization to the recorder has made that really easy: expose them as attributes and then exclude them from recorder. That allows us to combine the way the camera platform exposes entity_picture with the new async_sign_path to add media an attribute.”

I was hoping/expecting to be able to pull the signed path from the trigger entity, but I’m not seeing that implemented.

Got a very strange issue yesterday that maybe someone have an idea about?

I changed the DNS of my phone to my Home Assistant NUC where i have AdGuard running. Immediately when I did so one of my 5 Unifi cameras disconnected with the message “Lost power”. Changing back DNS solved the issue. All other cameras kept working fine.

Camera kept recording but was unaccessible from other devices too.

I just can’t see how this can be related?

Per the thread and installation process first configuration should be easy but I can;t even login.
I met all prerequisites, I have UCKP with production OS 3.0.17.
In Local portal, admins section (now users are created there) I created non remote user.
I can login with local user account but configuring that in HA does not work. I have response wrong authentication. Any thoughts?

Update: Motion disable and Person/Vehicle working as expected.

With that said, I answered my own questions.


Quick question to answer I probably already now.

With Smart Detection now having its own identity, can Motion Detection be turned off within Unifi Protect?

I have UNVR and used to have UDMP. It seemed I had better luck catching the object using snapshot with UDMP than UNVR so I am not sure if this is the case for everyone. However, I have recently come to realize that the snapshots are created every 5 second or so. I tested this buy repeatedly calling the snapshot service and realized the timestamp on the snapshot is not updated.

My conclusion is that when you call the snapshot service, it is not taken in real time but whatever snapshot created most recently is sent to HA. If you have a detection that happens after the snapshot was created but before the next one was taken, you are going to end up with a picture without any object in it.

The proper way to get the actual snapshot is documented under the View section in UniFi Protect - Home Assistant. I automate using NodeRed so I was able to see the event id but not the unvr id. Even though the documentation says it’s the same as in config entry, it does not work when i simply type the name in (for me was unvr) but it turned out to be a 32 character long id. If you look at the post just above your from z11, it gives you an idea how to generate the link to get snapshot sent based on event, not the snapshot created every 5 seconds.

as such, for the photo path, it has to be in the form of “/api/unifiprotect/thumbnail/{{ nvr_id }}/{{ event_id }}” It still does not solve the resolution issue, but I think at least it will be the actual event detection snapshot.

Thanks. I would like to get the thumbnail as an image file so I can attach it to telegram and not need to expose access to the unifi api to the internet. Does anyone have a working automation similar to the one I shared above using the snapshot service?

I see. In my case when the snap shot does not contain the detected object it’s generally taken in an earlier time. This gives an impression that the snap shot was delayed. I think you should pass along a time stamp in notification and figure out if the snapshot is taken before or after the time stamp (comparing to the unifi time stamp).

Within the current constraints of the system, perhaps passing two snapshots 5 seconds apart or add a slight delay before snapshot is fired to increase the chance that snapshot occur after detection. For mine I noticed it happens every 1 and 6 second, so maybe able to add some time condition too.

I am wondering what about passing an rtsp stream to create a camera entity in home assistant and take snapshot of the rtsp stream instead. That way you could bypass the unifi api and just use home assistant?

I am just curious whether this non real time snap shot is a constraint of unifi or home assistant.

My automation above uses the “normal” snapshot service from the stream and does not get the thumbnail from the unifi event - I would like to get that, though, as it should be taken at the exact point in time where the unifi event triggers. Anyway - it kind of works, so I haven’t spent too much time on improving


I do not understand why my snapshots are low resolution though!

Hi Team
Anyone else seeing " set_doorbell_message is Deprecated" when running unifiprotect/dynamic_doorbell.yaml at master · briis/unifiprotect (github.com)? I have removed this blueprint, just wondering if others have encountered and plans to enhance with text.set_value service.
Thanks