Unifi Protect: G4 Pro- Choose Image

I’d like to request the ability to select media to display on the Unifi G4 Pro Doorbell Camera other than messages. You can upload GIFs to display on the front of the doorbell, but currently through HA, you can only select or set text. I’d like to be able to have my doorbell update the image on the front when the baby is asleep encouraging people not to knock (and freak the dog out).

I tried to request it at the Github page, but it was closed immediately.

I hope they will ever implement this feature…

Me too, I have a really awesome animated GIF that tells people that the baby is sleeping, don’t ring the doorbell. I’ve noticed most people ring the doorbell, then read the no soliciting sign on it. When I have an animated GIF, people stop and read it first.

1 Like

Was this ever posted as a feature request rather than reported as a bug? I’d also really like to see this feature added.

this is possible through ubiquiti’s rest api now (documentation: unifi.ui.com protect->settings->control plane->integrations->documentation). while this isn’t ideal it’s a reasonable stop gap until this is added to home assistant. You can create an api key also on unifi.ui.com protect->settings->control plane->integrations->create api key

under camera information and management:

https://YOUR_CONSOLE_IP/proxy/protect/integration/v1/cameras/{id}

it’ll return something like this:

{
  "id": "66d025b301ebc903e80003ea",
  "modelKey": "camera",
  "state": "CONNECTED",
  "name": "string",
  "isMicEnabled": true,
  "osdSettings": {
    "isNameEnabled": true,
    "isDateEnabled": true,
    "isLogoEnabled": true,
    "isDebugEnabled": true
  },
  "ledSettings": {
    "isEnabled": true
  },
  "lcdMessage": {
    "type": "LEAVE_PACKAGE_AT_DOOR",
    "resetAt": 0,
    "text": "string"
  },
  "micVolume": 100,
  "activePatrolSlot": 0,
  "videoMode": "default",
  "hdrType": "auto",
  "featureFlags": {
    "supportFullHdSnapshot": true,
    "hasHdr": true,
    "smartDetectTypes": [
      "person"
    ],
    "smartDetectAudioTypes": [
      "alrmSmoke"
    ],
    "videoModes": [
      "default"
    ],
    "hasMic": true,
    "hasLedStatus": true,
    "hasSpeaker": true
  },
  "smartDetectSettings": {
    "objectTypes": [
      "person"
    ],
    "audioTypes": [
      "alrmSmoke"
    ]
  }
}

you can directly set a custom message (instead of what is required in home assistant which is to add a new message and then select it) by using the patch camera settings. eg:

the camera id is just that string of letters and numbers at the end of the URL when you navigate to a given camera in the protect tab of unifi.ui.com:

https://unifi.ui.com/consoles/<CONSOLE_ID>/protect/devices/<CAMERA_ID>

 curl -k -X PATCH "https://<YOUR_CONSOLE_IP>/proxy/protect/integration/v1/cameras/<CAMERA_ID>" \
     -H "Content-Type: application/json" \
     -H "X-API-KEY: <api key>" \
     -d '{
       "lcdMessage": {
         "type": "CUSTOM_MESSAGE",
         "resetAt": 1747334450917,
         "text": "This is my custom message"
       }
     }'

you can even select an existing animation to display (although you do have to know the animation guid eg:

 curl -k -X PATCH "https://<YOUR_CONSOLE_IP>/proxy/protect/integration/v1/cameras/<CAMERA_ID>" \
     -H "Content-Type: application/json" \
     -H "X-API-KEY:  <API_KEY>" \
     -d '{
       "lcdMessage": {
         "type": "IMAGE",
         "resetAt": null,
         "text": "<IMAGE_GUID>.png"
       }
     }'

i write the following python functions that im using in one of my appdaemons

    async def set_g4_doorbell_message(self, camera_id: str, message: str, expires_in: int = None):
        """
        Sets a custom message on the G4 Doorbell using an async HTTP PATCH request.

        Args:
            message (str): The custom message to set on the doorbell.
        """
        # Define the API endpoint and headers
        url = f"https://{self.nvr_host}/proxy/protect/integration/v1/cameras/{camera_id}"
        headers = {
            "Content-Type": "application/json",
            "X-API-KEY": self.nvr_api_key
        }

        # Define the payload
        payload = {
            "lcdMessage": {
            "type": "CUSTOM_MESSAGE",
            "resetAt": None if expires_in is None else int(time.time() * 1000) + (expires_in * 1000),
            "text": message
            }
        }

        # Make the async HTTP PATCH request
        async with aiohttp.ClientSession() as session:
            try:
                async with session.patch(url, headers=headers, json=payload, ssl=False) as response:
                    if response.status == 200:
                        self.log(f"Successfully set G4 Doorbell message: {message}")
                    else:
                        self.log(f"Failed to set G4 Doorbell message. Status: {response.status}, Response: {await response.text()}", level="ERROR")
            except Exception as e:
                self.log(f"Error setting G4 Doorbell message: {e}", level="ERROR")
    async def set_g4_doorbell_image(self, camera_id: str, image_guid: str, expires_in: int = None):
        """
        Sets an image on the G4 Doorbell using an async HTTP PATCH request.

        Args:
            image_guid (str): The GUID of the image to display on the doorbell.
            expires_in (int, optional): The number of seconds before the image expires. Defaults to None (no expiration).
        """
        # Define the API endpoint and headers
        url = f"https://{self.nvr_host}/proxy/protect/integration/v1/cameras/{camera_id}"
        headers = {
            "Content-Type": "application/json",
            "X-API-KEY": self.nvr_api_key
        }

        # Define the payload
        payload = {
            "lcdMessage": {
                "type": "IMAGE",
                "resetAt": None if expires_in is None else int(time.time() * 1000) + (expires_in * 1000),
                "text": f"{image_guid}.png"
            }
        }

        # Make the async HTTP PATCH request
        async with aiohttp.ClientSession() as session:
            try:
                async with session.patch(url, headers=headers, json=payload, ssl=False) as response:
                    if response.status == 200:
                        self.log(f"Successfully set G4 Doorbell image: {image_guid}")
                    else:
                        self.log(f"Failed to set G4 Doorbell image. Status: {response.status}, Response: {await response.text()}", level="ERROR")
            except Exception as e:
                self.log(f"Error setting G4 Doorbell image: {e}", level="ERROR")

Hope this helps folks

1 Like

Thanks for this! I got it working via a Node Red HTTP Request node thanks to your post.

@teek541 Searching around for this, any chance you can post your nodered as I was working to do the same as well, but running into issues. Thx!

Actually never mind… figure it out. I wasn’t ignoring the unifi cert.

that’s interesting, can you share a bit more about this ?