I hope this post will help a lot of people with 429 Resource has been exhausted
and 503 Service Unavailable
. There is nothing you can do to prevent these errors unless you are a corporate entity paying hundreds of thousands of dollars per day to use the service.
Free account users get what few computing cycles that are left over after the corporate accounts are serviced. I switched over to a paid account, and it doesn’t appear to make any difference on the 429 errors, but at least I don’t have to worry about getting my account locked for too many queries in succession. For what it’s worth, my last month’s bill was $0.04.
Now, for the part that will help. I have finally been able to handle errors from the generative AI call and have the script finish and at least send the image and notification. Even though there is no AI description, and it might be a false positive without any actual motion, I still get the alert message.
I’ve been testing this for the last few days and it appears to work.
That day of testing, I received three 429 errors, and I also received three MMS text messages with the caption “Google AI Error”. Very promising.
I previously posted that I changed the automation and script to handle multiple cameras with just a single automation and a single script. That is the code that I’ll be posting below. If you are using Adam’s original code, you’ll have to break out the error handling routines and add them to his code.
Here’s the calling automation. It is configured to queue up to 4 motion calls in case multiple cameras trigger close to each other.
alias: Unifi Cameras Motion AI SMS Snapshot
description: ""
triggers:
- trigger: state
entity_id:
- binary_sensor.ai_pro_driveway_motion
- binary_sensor.ai_pro_backyard_motion
- binary_sensor.ai_pro_frontyard_motion
from: "off"
to: "on"
conditions: []
actions:
- action: script.camera_snapshot_ai_notification
metadata: {}
data:
camera_id: "{{ device_id(trigger.entity_id) }}"
camera_name: "{{ device_attr(trigger.entity_id, 'name') }}"
mode: queued
max: 4
And this is the script that handles the snapshot creation. This runs in single mode so there is no chance that the snapshots we create will be stomped on by a second automation call before this finishes handling the current one.
alias: Camera - Snapshot AI & Notification
sequence:
- metadata: {}
data:
filename: ./www/snapshots/{{ camera_name }}_snapshot1.jpg
target:
device_id: "{{ camera_id }}"
enabled: true
action: camera.snapshot
- delay:
hours: 0
minutes: 0
seconds: 0
milliseconds: 500
enabled: true
- metadata: {}
data:
filename: ./www/snapshots/{{ camera_name }}_snapshot2.jpg
target:
device_id: "{{ camera_id }}"
enabled: true
action: camera.snapshot
- delay:
hours: 0
minutes: 0
seconds: 0
milliseconds: 500
enabled: true
- metadata: {}
data:
filename: ./www/snapshots/{{ camera_name }}_snapshot3.jpg
target:
device_id: "{{ camera_id }}"
enabled: true
action: camera.snapshot
- metadata: {}
data:
prompt: >-
Motion has been detected, compare and very briefly describe what you see
in the following sequence of images from my {{ camera_name }} camera.
What do you think caused the motion alarm? If a moving person or moving
car is present, describe them in detail. Do not describe stationary
objects or buildings. If motion was caused by snow or rain reply with
"No Obvious Motion Detected". If you see no significant motion, or no
obvious causes of motion, reply with "No Obvious Motion Detected". Your
message needs to be short enough to fit in a phone notification.
image_filename:
- ./www/snapshots/{{ camera_name }}_snapshot1.jpg
- ./www/snapshots/{{ camera_name }}_snapshot2.jpg
- ./www/snapshots/{{ camera_name }}_snapshot3.jpg
response_variable: generated_content
continue_on_error: true
action: google_generative_ai_conversation.generate_content
- variables:
filtered_content: >-
{{ 'Google AI Error' if generated_content == empty else
generated_content.text }}
- if:
- condition: template
value_template: "{{ 'no obvious motion detected' in filtered_content | lower}}"
then:
- stop: ""
else:
- action: shell_command.fixup_jpeg
data:
image_file: ./www/snapshots/{{ camera_name }}_snapshot2.jpg
- delay:
hours: 0
minutes: 0
seconds: 0
milliseconds: 500
- metadata: {}
data:
title: "{{ camera_name }} Motion Detected"
message: "{{filtered_content}}"
data:
images:
- /config/www/snapshots/{{ camera_name }}_snapshot2.jpg
action: notify.family_sms
mode: single
description: ""
The important parts are the continue_on_error: true
line before the generative ai call, and the variables
block after the call. The filtered_content
variable will contain “google AI Error” if the generative AI call failed, or the response text if it succeeded.
The check to see if no motion occured, and the actual notification message now need to use the new filtered_content
variable and not the previous generated_content.text
.
That’s all you need to do to at least get a notification that something occurred on your cameras even if Google fails. Good luck.
If you are still reading at this point, I also noticed something curious during my testing and I’m looking into it further. During my testing I was also trying out various prompts for Gemini (trying to get it to recognize that raindrops are not “motion”), and I noticed that when I was using a short prompt, I received fewer 429 Resource has been exhausted
errors. I don’t know at this point if there really is a cause and effect relationship, or if it was just coincidence. I’m testing further and I’ll let you know.
Cheers!
EDIT - it was pointed out in another thread that my used of == empty
only works by accident. The proper test should be is not defined
.