Encourage FUNIX

The consultation of the site is completely free and without advertisements. Donations are nevertheless appreciated to pay for hosting and encourage its author


CCTV systems - Frigate overview

CCTV systems

Presentation of Frigate and Frigate+

January 31, 2026


Presentation

This section aims to introduce you to various tools for setting up a Linux-based video surveillance system using independent surveillance cameras (IP or Wi-Fi), analog, digital, or simple webcams, also known as CCTV. ZoneMinder and Frigate are presented here. They all allow you to integrate a wide range of cameras, perform automatic motion detection, and create events. They are also web-based, allowing you to configure them, view the cameras in real time, and manage events via a browser, whether on a desktop or mobile device. ZoneMinder and Frigate are advanced tools with  machine learning and object recognition capabilities. ZoneMinder can also be considered more complex than Frigate, which integrates with Home Assistant.
This section is divided into several pages:

Docker and Frigate Installation

Frigate relies on Docker , which I installed simply by typing on my Mageia.

urpmi docker docker-compose

Next, we launch Docker by typing

systemctl start docker

that is its status

systemctl status docker

and the result

docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; preset: disabled)
     Active: active (running) since Fri 2025-09-26 17:02:55 CEST; 6s ago
       Docs: http://docs.docker.com
    Process: 210883 ExecStartPre=/usr/sbin/docker-network-cleanup (code=exited, status=0/SUCCESS)
   Main PID: 210886 (dockerd)
      Tasks: 17
     Memory: 41.1M
        CPU: 369ms
     CGroup: /system.slice/docker.service
             ├─210886 /usr/sbin/dockerd --data-root /var/cache/docker -H unix:///var/run/docker.sock -H tcp://127.0.0.1:2375
             └─210899 containerd --config /var/run/docker/containerd/containerd.toml

sept. 26 17:02:52 ultra.kervao.fr dockerd[210899]: time="2025-09-26T17:02:52.687489959+02:00" level=info msg=serving... address=/var/run/docker/containerd/containerd.sock
sept. 26 17:02:52 ultra.kervao.fr dockerd[210899]: time="2025-09-26T17:02:52.687576078+02:00" level=info msg="containerd successfully booted in 0.201550s"
sept. 26 17:02:54 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:54.283134739+02:00" level=info msg="Loading containers: start."
sept. 26 17:02:55 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:55.007460149+02:00" level=info msg="Loading containers: done."
sept. 26 17:02:55 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:55.281188368+02:00" level=warning msg="WARNING: API is accessible on http://127.0.0.1:2375 without encryption>
sept. 26 17:02:55 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:55.281244407+02:00" level=info msg="Docker daemon" commit=library-import containerd-snapshotter=false storage>
sept. 26 17:02:55 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:55.281378785+02:00" level=info msg="Daemon has completed initialization"
sept. 26 17:02:55 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:55.804448712+02:00" level=info msg="API listen on /var/run/docker.sock"
sept. 26 17:02:55 ultra.kervao.fr systemd[1]: Started docker.service.
sept. 26 17:02:55 ultra.kervao.fr dockerd[210886]: time="2025-09-26T17:02:55.804558097+02:00" level=info msg="API listen on 127.0.0.1:2375"

to see if Docker is working correctly, we will type

Docker Run Hello World

Here is the result

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete
Digest: sha256:54e66cc1dd1fcb1c3c58bd8017914dbed8701e2d8c74d9262e26bd9cc1642d31
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

To have Docker launch on every reboot, type

systemctl enable docker

We will create the /etc/frigate and /etc/frigate/config directories ; the records will be stored in the /media/frigate directory. We return to /etc/frigate/config where I created the docker-compose.yml file which will contain

services:
  frigate:
    container_name: frigate
    privileged: true # this may not be necessary for all setups
    network_mode: host # j'ai dû rajouter cette ligne pour accéder à ma caméra restreamée avec mediamtx
    restart: unless-stopped

    stop_grace_period: 30s # allow enough time to shut down the various services
    image: ghcr.io/blakeblackshear/frigate:stable
    shm_size: "512mb" # update for your cameras based on calculation above
    devices:
    
- /dev/bus/usb:/dev/bus/usb # ligne pour l'accélérateur USB Google Coral, à commenter sinon
     - /dev/dri/renderD128:/dev/dri/renderD128 # For intel hwaccel, needs to be updated for your hardware

    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /etc/frigate/config:/config
      - /media/frigate:/media/frigate
      - type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear
        target: /tmp/cache
        tmpfs:
          size: 1000000000
    ports: #section inutile avec le mode réseau host
      - "8971:8971" # port de l'interface navigateur
      #- "8554:8554" # RTSP feeds, j'ai mis en commentaire car conflit avec mediamtx, utile pour renvoyer le flux vidéo vers homeassistant
      - "8555:8555/tcp" # WebRTC over tcp
      - "8555:8555/udp" # WebRTC over udp

[ back to top of page ]

and config.yaml in which we will define the cameras and objects to detect (list here https://docs.frigate.video/configuration/objects )

mqtt:
  enabled: false
cameras:
  Camera-sud:
    ffmpeg:
      inputs:
        - path: rtsp://frigate:passwd@192.168.2.110
          roles:
            - detect
            - record
      hwaccel_args: preset-vaapi
    objects:
      track:
        - person
        - dog
        - cat
        - bird
 
       - bicycle
        - car
        - motorcycle
    detect:
      width: 1280
      height: 720
    record:
      enabled: true
      retain:
        days: 7
        mode: all
  Camera-entree:
    ffmpeg:
      inputs:
        - path: rtsp://frigate:passwd@192.168.2.112
          roles:
            - detect
            - record
      hwaccel_args: preset-vaapi
    objects:
      track:
        - person
        - dog
        - cat
        - bird
 
       - bicycle
        - car
        - motorcycle
    detect:
      width: 1280
      height: 720
    record:
      enabled: true
      retain:
        days: 7
        mode: all
  Camera-piscine:
    ffmpeg:
      inputs:
        - path: rtsp://frigate:passwd@192.168.2.200:554/ch0_1.264
          roles:
            - detect
            - record
    objects:
      track:
        - person
        - dog
        - cat
        - bird

    detect:
      width: 800
      height: 448
    record:
      enabled: true
      retain:
        days: 7
        mode: all
  Camera-ouest:
    ffmpeg:
      inputs:
        - path: rtsp://ultra.kervao.fr:8554/cam1
          roles:
            - detect
            - record
    objects:
      track:

        - person
        - dog
        - cat
        - bird

    detect:
      width: 640
      height: 360
    record:
      enabled: true
      retain:
        days: 7
        mode: all
detectors:
  cpu1:
    type: cpu
    num_threads: 3
detect:
  enabled: true
version: 0.16-0

If you have a Google Coral USB accelerator , we will replace it with the detectors.

 coral:
    type: edgetpu
    device: usb

Then type in this same directory

docker compose -f docker-compose.yml up -d

Here is the result: 9.6s

+] Running 10/10
 ✔ frigate 9 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled                                                                                                                           79.5s
   ✔ b1badc6e5066 Pull complete                                                                                                                                                   1.2s
   ✔ 4f4fb700ef54 Pull complete                                                                                                                                                   0.3s
   ✔ 14d4601b76c8 Pull complete                                                                                                                                                  14.6s
   ✔ cab46c26a5aa Pull complete                                                                                                                                                   1.1s
   ✔ 6891a7512d41 Pull complete                                                                                                                                                  14.3s
   ✔ b44b002328e4 Pull complete                                                                                                                                                   8.3s
   ✔ 8074b201d282 Pull complete                                                                                                                                                   8.6s
   ✔ d823104cefbd Pull complete                                                                                                                                                   9.0s
   ✔ f86078113133 Pull complete                                                                                                                                                   9.6s
[+] Running 2/2
 ✔ Network config_default  Created                                                                                                                                                0.1s
 ✔ Container frigate       Started

some useful commands, restart frigate

docker restart frigate

stopper frigate

docker stop frigate 
[ back to top of page ]

First launch

Frigate is now installed, launched, and accessible locally from the browser by typing

https://ultra.kervao.fr:8971/

To find out the password you will need to type

Docker logs frigate

and we see

2025-09-26 17:46:21.528704726  [2025-09-26 17:46:21] frigate.app                    INFO    : ********************************************************
2025-09-26 17:46:21.529867665  [2025-09-26 17:46:21] frigate.app                    INFO    : ********************************************************
2025-09-26 17:46:21.530590965  [2025-09-26 17:46:21] frigate.app                    INFO    : ***    Auth is enabled, but no users exist.          ***
2025-09-26 17:46:21.531237207  [2025-09-26 17:46:21] frigate.app                    INFO    : ***    Created a default user:                       ***
2025-09-26 17:46:21.542212889  [2025-09-26 17:46:21] frigate.app                    INFO    : ***    User: admin                                   ***
2025-09-26 17:46:21.566794613  [2025-09-26 17:46:21] frigate.app                    INFO    : ***    Password: 2bf8aeb98g16b66f54e70a8e8f121076   ***
2025-09-26 17:46:21.577589942  [2025-09-26 17:46:21] frigate.app                    INFO    : ********************************************************
2025-09-26 17:46:21.598394530  [2025-09-26 17:46:21] frigate.app                    INFO    : ********************************************************

With a TPU, we should get a message that looks like this.

2025-10-30 07:55:40.442764361  [2025-10-30 07:55:40] frigate.detectors.plugins.edgetpu_tfl INFO    : TPU found
2025-10-30 07:55:40.443899970  INFO: Created TensorFlow Lite XNNPACK delegate for CPU.

This allows you to log in, and here's the general interface with the latest events at the top and the live views just below.

With only the TPU, it's practically unusable on a daily basis; the program constantly uses almost 100% of the resources.

And with a TPU, it's like night and day!!

[ back to top of page ]

Configuration

Before going any further, it is important to understand some basic concepts of how Frigate works. We talk about alerts and detections. Alerts are based on detections but are considered priority events to be reported, while detections are less significant events that do not warrant notification but are still recorded and visible in the event review (see the documentation in English here https://docs.frigate.video/configuration/review/ ).

Let's move on to the settings, accessible via the gear icon in the bottom left corner of the main screen. In the first tab, User Interface , there are general settings that I haven't changed. In the Augmented Data tab , you can enable them (they are disabled by default).

  • semantic search allows you to find tracked objects in your event review using either the image itself, a user-defined text description, or an automatically generated description.
  • facial recognition
  • license plate recognition
  • bird identification

We start with the Masks/Zones tab. For each camera selectable from the blue button in the upper right corner, we define detection zones; other areas of the image will be ignored for detection.



Note that you can select the type of object that can be detected and estimate the speed of the movement.



On the other hand, if we want only people and cars to be considered as alerts, we will need to modify the configuration file for the camera in question in the review section by adding a sub-section labels like this

    review:
      alerts:
        labels:
          - person
          - car
        required_zones: Zone-det-camera-sud
      detections:
        required_zones: Zone-det-camera-sud

We can also declare motion masks to prevent detection in places where there is a risk of unwanted movement (vegetation), which can disrupt object tracking.



To prevent your car, usually parked in its spot, from appearing as a false positive, you will need to create a specific object mask like this:


Note that you will need to restart Frigate for this to take effect; this can be done from the Settings menu.

We now return to the Camera Settings tab , in the configuration below, only Person and Car objects will be displayed as alerts in the predefined area and other detected objects will be classified as detections in the same area.

and so on for all the cameras.

In the Motion Settings tab , you can fine-tune certain parameters for each camera so that it is considered as movement; I left the default values.


The Debug tab can be useful for displaying certain information in real time. The Users tab , as its name suggests, allows you to manage users. Two types of users are possible: administrators have access to all interface features, while observers are limited to viewing cameras, reviewing events, and viewing recording history within the user interface. The Notifications tab allows you to send email alerts.

Regarding recordings, by default we have

    record:
      enabled: true
      retain:
        days: 7
        mode: all

This means that both alerts and detections are recorded and stored for 7 days. For more detailed recording management, see this page: https://docs.frigate.video/configuration/record/

[ back to top of page ]

Advanced configuration

Adjust object detection

According to the page https://docs.frigate.video/frigate/camera_setup/#choosing-a-detect-resolution, the ideal resolution for an object to be detected should fit within a 320x320 pixel frame, which corresponds to the model used by Frigate . If the area of ​​motion is larger than 320x320, it will crop and resize it if necessary, potentially losing some detail in the process. Therefore, higher resolutions do not significantly improve detection accuracy; however, they do improve performance if the objects are very small in the image.
This is all rather counterintuitive because when I place a 320x320 frame on the camera image, which has a resolution of 1280x720, I think I'm unlikely to detect people at that scale with this camera, whereas a higher resolution could allow the detection of smaller objects.



By setting the maximum resolution of my camera to 3072x1728, this is what a 320x320 pixel box corresponds to; it's not a panacea for detection, but it's already better.


From this, we can derive the following rule: for a camera with a close field of view (an indoor camera, for example), a low resolution will suffice, while for a camera with a distant field of view (primarily an outdoor camera), a high resolution is preferable for better object detection.
I encourage you to place a 320x320 pixel frame over each of your scaled images to see if it's necessary to increase the camera resolution corresponding to the perspective of the objects you wish to detect.

Now, in case of a false positive, it will likely be necessary to adjust some settings; for details, please consult this page https://docs.frigate.video/configuration/object_filters. In fact, several parameters must be considered for each object:
  • score: this is a non-modifiable parameter calculated for each image for each detected object
  • min_score : all detected objects with a score lower than this parameter will be ignored.
  • Threshold : This is the average of the scores for an object detected over several consecutive images.

Frigate calculates a score for each object detected in every image, and the object is considered positive when both the score exceeds the min_score and the threshold, which is the average of the scores over several consecutive images. This last parameter confirms the detection.
Here's what can be added to the config.yaml file as a common section for all cameras; these are values ​​commonly shared by the Frigate user community.

objects:
  filters:
    dog:
      min_score: .7
      threshold: .9
    cat:
      min_score: .65
      threshold: .8
    person:
      min_score: .7
      threshold: .9
    car:
      min_score: .65
      threshold: .85

These values ​​should not be considered ideal. Personally, with outdoor cameras that tend to have a wider field of view, I preferred to add a filters subsection to each objects section for each of my cameras to adjust these values ​​according to the camera, like this:

    objects:
      track:
        - person
        - dog
        - cat
        - face
      filters:
        person:
          min_score: .7
          threshold: .8

To further reduce false positives, a minimum and maximum detection zone can be defined; that is, if the object is too large or too small, it will be automatically rejected. For a stream with a resolution of 3072x1728, an image can be extracted at that size and opened in GIMP.

Using the selection tool, draw the min and max boxes to detect a car (for example). The width and height appear at the bottom center. Rectangle: 245x252

The minimum detection box parameter is min_area and has a value of width*height, so for the example above, min_area=245x252=61470. The same applies to the max_area parameter. In practice, I set for a car

min_area 22000 max_area 230000

for one person

min_area 6000 max_area 30000

which gives us the following in config.yaml

filters:       
 car:
        
  min_score: .7
         
  threshold: .9
         
  min_area: 22000
         
  max_area: 230000
       
 person:
         
  min_score: .7
         
  threshold: .8
         
  min_area: 6000
         
  max_area: 3000

 [ Back to top of page ]

Enable face detection

To enable face detection, we will first add the corresponding section to the config.yaml file.

face_recognition:  
  enabled: true

And for the cameras in question, we will add the mention " face" in the track subsection.

objects:
      track:
        - person
        - dog
        - cat
        - bicycle
        - car
        - motorcycle
        - face

Frigate is restarted and the logs return the following messages

2025-11-02 11:20:57.493001613  [2025-11-02 11:20:57] frigate.config.config          WARNING : Camera-entree is configured to track ['face'] objects, which are not supported by the current model.
2025-11-02 11:20:57.495025758  [2025-11-02 11:20:57] frigate.config.config          WARNING : Camera-piscine is configured to track ['face'] objects, which are not supported by the current model.
2025-11-02 11:20:57.519957917  [2025-11-02 11:20:57] frigate.app                    INFO    : Starting Frigate (0.16.1-e664cb2)
2025-11-02 11:20:57.520656637  [2025-11-02 11:20:57] frigate.app                    INFO    : Creating directory: /media/frigate/clips/faces

(...)

2025-11-02 11:20:58.822822712  [2025-11-02 11:20:58] frigate.api.fastapi_app        INFO    : FastAPI started
2025-11-02 11:21:00.117012864  [2025-11-02 11:21:00] frigate.util.downloader        INFO    : Downloading complete: https://github.com/NickM-27/facenet-onnx/releases/download/v1.0/facenet.tflite
2025-11-02 11:21:00.269584095  [2025-11-02 11:21:00] frigate.detectors.plugins.edgetpu_tfl INFO    : TPU found
2025-11-02 11:21:00.270930420  INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
2025-11-02 11:21:03.456767865  [2025-11-02 11:21:03] frigate.util.downloader        INFO    : Downloading complete: https://github.com/NickM-27/facenet-onnx/releases/download/v1.0/landmarkdet.yaml

A Face Library icon appears



We add familiar faces by clicking on Add a face; I selected two easily identifiable front-facing images to start with, one at a time.





Next, click the Train button in the top left corner and upload images of the person in different situations.







It adds the photo by zooming in on the face if it has been clearly identified. It is recommended to add a total of 20 to 30 images for maximum reliability. This is a bit tedious to do because it has to be done image by image. On my system, the images will be placed under /media/frigate/clips/faces.
And here's what it will look like when it identifies people.



Now you can train the models by clicking on the icon , you can confirm the detection by clicking on the people that were created previously.




However, if Frigate makes a mistake by displaying a false positive, you can delete them by selecting them using the CTRL command. Then click the Delete faces button in the top right corner.



More information here https://docs.frigate.video/configuration/face_recognition.

 [ Back to top of page ]

Connecting an ONVIF-compatible PTZ camera

PTZ cameras can also be animated using the ONVIF protocol. OnvifDeviceManager, presented here, can be used to determine how to access the camera's ONVIF settings. In the config.yaml file for the camera in question, add an onvif section after the ffmpeg section, like this:

Camera-est:
    ffmpeg:
      inputs:
        - path: rtsp://user:motdepasse@192.168.2.187:554/11
          roles:
            - detect
            - record
      hwaccel_args: []
  onvif:
      host: 192.168.2.187
      port: 8080
      user: "user"
      password: "motdepasse"

Restart
Frigate , and the commands will appear in the interface.




in the logs, for each command this gives

2025-12-14 16:23:19.863412328  [2025-12-14 16:23:19] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.move_down for Camera-est
2025-12-14 16:23:20.014362034  [2025-12-14 16:23:20] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.stop for Camera-est
2025-12-14 16:23:24.154372463  [2025-12-14 16:23:24] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.move_left for Camera-est
2025-12-14 16:23:24.324886496  [2025-12-14 16:23:24] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.stop for Camera-est
2025-12-14 16:23:27.660911995  [2025-12-14 16:23:27] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.move_left for Camera-est
2025-12-14 16:23:27.831550797  [2025-12-14 16:23:27] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.stop for Camera-est
2025-12-14 16:23:31.340495182  [2025-12-14 16:23:31] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.move_left for Camera-est
2025-12-14 16:23:31.471007427  [2025-12-14 16:23:31] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.stop for Camera-est
2025-12-14 16:23:35.053131483  [2025-12-14 16:23:35] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.move_left for Camera-est
2025-12-14 16:23:35.203476745  [2025-12-14 16:23:35] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.stop for Camera-est
2025-12-14 16:23:38.560508556  [2025-12-14 16:23:38] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.move_left for Camera-est
2025-12-14 16:23:38.691835827  [2025-12-14 16:23:38] frigate.comms.dispatcher       INFO    : Setting ptz command to OnvifCommandEnum.stop for Camera-est

Add a Let's Encrypt certificate

By default, Frigate generates a self-signed certificate to use port 8971, which triggers a security warning in the browser. In Firefox , you can accept the risk to access it. But this isn't ideal, especially if you're accessing Frigate from the internet. In the configuration presented here, we'll use Apache, not Nginx as is often suggested. For Let's Encrypt configuration with Apache, see this page.
The principle is as follows:

Internet -> HTTPS port 443 -> reverse proxy -> internal HTTP -> Frigate port 8971

Apache acts as a reverse proxy, meaning it allows access to an internal URL by automatically modifying the URL and pointing to the correct port. My internet-accessible address is https://adresseperso.ddns.net, which already points to an index.html page . This configuration therefore allows access to Frigate at https://adresseperso.ddns.net/frigate

In the Apache configuration file httpd.conf , the following modules will be enabled:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

and we will add the virtual host

<VirtualHost 192.168.2.13:443>
   ServerName adresseperso.ddns.net

   SSLEngine on
   SSLCertificateFile /etc/letsencrypt/live/adresseperso.ddns.net/fullchain.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/adresseperso.ddns.net/privkey.pem

   ProxyPreserveHost On
   ProxyRequests Off

   # Redirection vers Frigate sur port 8971
   ProxyPass /frigate http://127.0.0.1:8971/frigate
   ProxyPassReverse /frigate http://127.0.0.1:8971/frigate

   # Websocket support
   RewriteEngine On
   RewriteCond %{HTTP:Upgrade} =websocket [NC]
   RewriteRule ^/frigate/(.*) ws://127.0.0.1:8971/frigate/$1 [P,L]
</VirtualHost>

We restart Apache by typing `systemctl restart httpd`

In the docker-compose.ym file, we will modify the default path in the environment section by adding

environment:    
   FRIGATE_BASE_PATH: "/frigate"


To apply the changes, stop Frigate by typing docker stop frigate, then

run docker compose -f docker-compose.yml up -d

and restart
Frigate by typing docker start frigate.

[ back to top of page ]

Perform an update

To perform an update, first stop Frigate by typing docker stop frigate. Now edit the docker-compose.yml file and specify the latest stable version in the image section.

services:
 frigate:
  (...)
   image: ghcr.io/blakeblackshear/frigate:0.16.3


The change is applied by typing
docker compose up -d and can be seen in the logs that it has been applied by typing docker logs frigate.


2025-12-27 16:20:48.200509700 [2025-12-27 16:20:48] frigate.app INFO: Starting Frigate (0.16.3-9034454)

more info here https://docs.frigate.video/frigate/updating/

[ back to top of page ]

Use

Now let's return to the main interface. We saw earlier that the main view links to the camera views; it is accessible by clicking on the icon representing a camera on the left.

Clicking on the Event Review on the left displays all recent events (alerts, detections, movement). The detected object appears as an icon in the top left corner of the image; you can access the replay by clicking on the image. You can save the review by clicking on Mark these items as reviewed at the bottom.



When you click on the small icon in the top left corner that represents the detected object, you'll see the event details. You can go even further by clicking on the symbol  to the right of the detected object.




We see a zoomed-in view of the detected object, and if we click on it , a menu appears; we click on View object lifecycle.



You can visualize its trajectory within the detection zone; I don't seem to have found any functions to invalidate a detection/alert due to a false positive, a function that exists in the paid version Frigate+.



In cas of licence plate detection, you will see



The Explorer menu on the left allows you to display all detected objects, which can be filtered using the tools in the top right corner.




You can delete them one by one using the context menu; I haven't found how to select them to do a group attack.

As we saw earlier, we could access the system resource status via the System->System Indicators menu ; there is also a Storage tab that provides a status of the recordings



And the Cameras tab, which provides a status of the resources used by each camera, even if the TPU is not visible.


For the rest, I refer you to the Frigate documentation for usage instructions, which includes some useful URLs.

https://docs.frigate.video/guides/getting_started
https://community.jeedom.com/t/tuto-integrer-frigate-et-faire-de-la-reconnaissance-video-dobjet-par-ia-en-local-dans-son-jeedom/117108
https://www.simplehomelab.com/frigate-docker-guide/


View Frigate from a mobile device

Regarding remote viewing on a mobile device, there is indeed an unofficial Android application , but I don't really see the point because simply accessing the address directly (once it's made accessible on the internet) from a mobile browser is quite user-friendly, as you can see below.


Notifications with Signal via MQTT

Presentation

Frigate already integrates an email notification service, as mentioned above, which doesn't work for me, but regardless, this paragraph explains how to receive alert notifications with Signal using the MQTT service. MQTT (Message Queuing Telemetry Transport) is a messaging protocol that works on a subscription/publish basis, meaning that a server (or broker) can publish notifications on a channel, and clients can subscribe to view them. With Frigate, by enabling MQTT, you can run a script that triggers an action upon receiving an event, such as an alert. It's also possible to make the MQTT broker accessible from the internet, and an Android MQTT client application can be installed to receive alerts.

Mosquito Installation

The official website is https://mosquitto.org. On my Mageia system, I simply installed it by typing urpmi mosquitto. We created a user with their password:

mosquitto_passwd -c /etc/mosquitto/passwd olivier
Password:
Re-enter password:

in the file
/etc/mosquitto/mosquitto.conf we uncommented and modified the following two lines:

allow_anonymous false
password_file /etc/mosquitto/passwd

We changed the owner of the passwd file :

chown mosquitto:mosquitto /etc/mosquitto/passwd

We can then launch mosquitto with

systemctl start mosquitto

Here is the output of the command systemctl status mosquitto

mosquitto.service - Mosquitto MQTT Broker
    Loaded: loaded (/usr/lib/systemd/system/mosquitto.service; disabled; preset: disabled)
    Active: active (running) since Sun 2025-12-07 09:14:56 CET; 2min 12s ago
      Docs: man:mosquitto.conf(5)
            man:mosquitto(8)
   Process: 1426932 ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto (code=exited, status=0/SUCCESS)
   Process: 1426933 ExecStartPre=/bin/chown mosquitto:mosquitto /var/log/mosquitto (code=exited, status=0/SUCCESS)
   Process: 1426934 ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto (code=exited, status=0/SUCCESS)
   Process: 1426935 ExecStartPre=/bin/chown mosquitto:mosquitto /run/mosquitto (code=exited, status=0/SUCCESS)
  Main PID: 1426936 (mosquitto)
     Tasks: 1 (limit: 18901)
    Memory: 1004.0K
       CPU: 43ms
    CGroup: /system.slice/mosquitto.service
            └─1426936 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

déc. 07 09:14:56 ultra.kervao.fr systemd[1]: Starting mosquitto.service...
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: mosquitto version 2.0.21 starting
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: Config loaded from /etc/mosquitto/mosquitto.conf.
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: Starting in local only mode. Connections will only be possible from clients running on this machine.
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: Create a configuration file which defines a listener to allow remote access.
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: For more details see https://mosquitto.org/documentation/authentication-methods/
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: Opening ipv4 listen socket on port 1883.
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: Opening ipv6 listen socket on port 1883.
déc. 07 09:14:56 ultra.kervao.fr mosquitto[1426936]: 1765095296: mosquitto version 2.0.21 running
déc. 07 09:14:56 ultra.kervao.fr systemd[1]: Started mosquitto.service.

Don't forget to open TCP port 1883 used by MQTT via Shorewall. To see if it works well, we can launch a client that will wait for a notification from a broker:

mosquitto_sub -v -t 'test/topic' -u olivier -P password

Now we will launch a broker by publishing a notification:

mosquitto_pub -u olivier -P password -t 'test/topic' -m 'helloWorld'


and from the client we will see
test/topic helloWorld displayed. Note that the broker runs on the server where Frigate is located, the whole thing runs locally and I don't need it to be accessible from the internet.




Frigate configuration and alert management scripts

Now, in the Frigate configuration file config.yaml, we'll enable MQTT :

mqtt:
 enabled: true
 host: localhost
 user: olivier
 password: motdepasse
 port: 1883

We'll create the listening script
/usr/local/bin/alerte_frigate which will send an email as soon as there's an alert. We'll see about Signal later.


#!/bin/bash
mosquitto_sub -t "frigate/events" -u olivier -P motdepasse | while read -r payload
do
   #à décommenter pour visualiser pour des tests de fonctionnemnet
   #echo "Rx MQTT: ${payload}"
   #envoi d'un mail pour chaque nouveau évènement
   if echo "${payload}" | grep -q '"type": "new"'; then
       echo "${payload}" | mail -s "Frigate alerte" olivier
   fi
done

The email will contain


{"before": {"id": "1765103169.376268-4ybyyv", "camera": "Camera-sud", "frame_time": 1765103169.376268, "snapshot": null, "label": "car", "sub_label": null, "top_score": 0.0, "false_positive": true, "start_time": 1765103169.376268, "end_time": null, "score": 0.9765625, "box": [1876, 1001, 2407, 1285], "area": 150804, "ratio": 1.869718309859155, "region": [1356, 0, 3072, 1716], "active": true, "stationary": false, "motionless_count": 0, "position_changes": 0, "current_zones": [], "entered_zones": [], "has_clip": false, "has_snapshot": false, "attributes": {}, "current_attributes": [], "pending_loitering": false, "max_severity": null, "current_estimated_speed": 0, "average_estimated_speed": 0, "velocity_angle": 0, "path_data": [], "recognized_license_plate": null}, "after": {"id": "1765103169.376268-4ybyyv", "camera": "Camera-sud", "frame_time": 1765103169.59021, "snapshot": {"frame_time": 1765103169.376268, "box": [1876, 1001, 2407, 1285], "area": 150804, "region": [1356, 0, 3072, 1716], "score": 0.9765625, "attributes": [], "current_estimated_speed": 0, "velocity_angle": 0, "path_data": [], "recognized_license_plate": null, "recognized_license_plate_score": null}, "label": "car", "sub_label": null, "top_score": 0.9765625, "false_positive": false, "start_time": 1765103169.376268, "end_time": null, "score": 0.9765625, "box": [1872, 1003, 2411, 1287], "area": 153076, "ratio": 1.897887323943662, "region": [1356, 0, 3072, 1716], "active": true, "stationary": false, "motionless_count": 1, "position_changes": 0, "current_zones": [], "entered_zones": [], "has_clip": false, "has_snapshot": false, "attributes": {}, "current_attributes": [], "pending_loitering": false, "max_severity": null, "current_estimated_speed": 0, "average_estimated_speed": 0, "velocity_angle": 0, "path_data": [[[0.6969, 0.7448], 1765103169.59021]], "recognized_license_plate": null}, "type": "new"}

The script will filter only new alerts; however, it will handle both alerts and detections, as there are no fields to distinguish between them.

Here's a more advanced script (thanks ChatGPT !!) that will send an alert email only for person and car objects, attaching a snapshot with the outline around the object. It will require the installation of the jq package, which will allow for easier extraction of useful information.

#!/bin/bash
# /usr/local/bin/alerte_frigate
# Attendre que le clip soit complètement écrit (taille stable) avant envoi

MQTT_USER="olivier"
MQTT_PASS="motdepasse"
MQTT_TOPIC="frigate/events"

CLIP_DIR="/media/frigate/clips"
FRIGATE_API="http://localhost:8971"
MAIL_TO="olivier"

LOGGER_TAG="alerte_frigate"

### --- LOG FUNCTION ---
log()     { logger -t "$LOGGER_TAG" "[INFO] $*"; }
log_warn(){ logger -t "$LOGGER_TAG" "[WARN] $*"; }
log_dbg() { logger -t "$LOGGER_TAG" "[DEBUG] $*"; }


# Paramètres d'attente pour la stabilité du fichier
WAIT_MAX_SECS=20       # temps max d'attente pour que le fichier soit complet
CHECK_STEP=0.5         # intervalle entre deux vérifs de taille (sec)
STABLE_ROUNDS=2        # nombre de mesures identiques successives pour considérer "stable"

mosquitto_sub -t "$MQTT_TOPIC" -u "$MQTT_USER" -P "$MQTT_PASS" | while read -r payload
do
   # Ne traiter que les "new"
   if echo "$payload" | jq -e . >/dev/null 2>&1; then
       if ! echo "$payload" | grep -q '"type"[[:space:]]*:[[:space:]]*"new"'; then
           continue
       fi
   else
       continue
   fi

   # Extraire infos
   camera=$(echo "$payload" | jq -r '.after.camera // .camera // empty')
   label=$(echo "$payload" | jq -r '.after.label // "inconnu"')
   id=$(echo "$payload" | jq -r '.after.id // .id // empty')


   # Filtrer uniquement les labels car et person
   if [[ "${label}" != "car" && "${label}" != "person" ]]; then
       log_dbg "Événement ignoré pour label=${label}"
       continue
   fi

   if [ -z "$id" ] || [ -z "${camera}" ]; then
       log_warn "Événement MQTT invalide, ignoré."
       continue
   fi

   EVENT_ID="$id"
   log "Détection : caméra=${camera}, label=${label}, id=${EVENT_ID}"
   log_dbg "Recherche du fichier annoté…"

   
   # il faut attendre que Frigate crée le fichier et ne pas aller trop vite, ça peut prendre quelques secondes
   CLIP_FILE=""
   MAX_WAIT=10   # secondes
   WAIT=0  
   while [ $WAIT -lt $MAX_WAIT ]; do
       CLIP_FILE=$(find "$CLIP_DIR" -type f -iname "*${EVENT_ID}*.jpg" | head -n 1)

       if [ -n "$CLIP_FILE" ]; then
               log_dbg "Fichier trouvé après ${WAIT}s : $CLIP_FILE"
               break
       fi

       sleep 1
       WAIT=$((WAIT+1))
   done

   if [ -z "$CLIP_FILE" ]; then
          log_warn "Aucun snapshot annoté trouvé pour $EVENT_ID après ${MAX_WAIT}s."
   else
       log "[INFO] Clip annoté trouvé:  $CLIP_FILE"

   fi

   ATTACH=""
   # Si clip trouvé, attendre la stabilisation de la taille
   if [[ -n "$CLIP_FILE" && -f "$CLIP_FILE" ]]; then
       log "Clip candidate trouvé: $CLIP_FILE"
       elapsed=0
       stable_count=0
       last_size=-1

       while (( $(echo "$elapsed < $WAIT_MAX_SECS" | bc -l) )); do
           if [[ -f "$CLIP_FILE" ]]; then
               size=$(stat -c %s "$CLIP_FILE" 2>/dev/null || echo 0)
           else
               size=0
           fi

           if [[ "$size" -eq "$last_size" && "$size" -gt 0 ]]; then
               stable_count=$((stable_count+1))
           else
               stable_count=0
           fi

           # Si on a STABLE_ROUNDS mesures identiques => on le considère complet
           if (( stable_count >= STABLE_ROUNDS )); then
               log "Fichier stable (taille=$size). Prêt à être envoyé."
               ATTACH="$CLIP_FILE"
               break
           fi

           last_size=$size
           sleep "$CHECK_STEP"
           elapsed=$(echo "$elapsed + $CHECK_STEP" | bc -l)
       done

       # si pas stable au bout du timeout, on considère quand même (mais on peut fallback)
       if [[ -z "$ATTACH" ]]; then
           log_warn "Fichier non stable après ${WAIT_MAX_SECS}s (taille actuelle=${last_size}). Tentative fallback API."
       fi
   else
       log_warn "Aucun clip annoté trouvé localement pour ${EVENT_ID}."
   fi

   # Si pas d'attach encore, tenter de récupérer la snapshot via API
   if [[ -z "$ATTACH" ]]; then
       TMPFILE="/tmp/frigate_snapshot_${EVENT_ID//[^a-zA-Z0-9._-]/_}.jpg"
       rm -f "$TMPFILE"

       # Récupération via API (retry court car la snapshot peut être générée juste après l'event)
       got=0
       retries=8
       sleep_between=0.5
       for ((i=0;i<retries;i++)); do
           curl -s -f "${FRIGATE_API}/api/events/${EVENT_ID}/snapshot.jpg" -o "$TMPFILE"
           if [[ $? -eq 0 && -s "$TMPFILE" ]]; then
               log "Snapshot récupérée via API -> $TMPFILE"
               ATTACH="$TMPFILE"
               got=1
               break
           fi
           sleep "$sleep_between"
       done

       if [[ $got -ne 1 ]]; then
           echo "[WARN] API snapshot échouée ou introuvable pour ${EVENT_ID}."
       fi
   fi

   # Corps et envoi du mail
   subject="Frigate : détection de ${label} sur ${camera}"
   body="Nouvelle détection Frigate.\n\nCaméra : ${camera}\nObjet  : ${label}\nID     : ${EVENT_ID}\n\nPayload brut :\n${payload}"

   if [[ -n "$ATTACH" && -f "$ATTACH" ]]; then
       echo -e "$body" | mail -s "$subject" -a "$ATTACH" "$MAIL_TO"
       log "Mail envoyé avec pièce jointe : $ATTACH"
       # si tmp file, on peut le supprimer
       if [[ "$ATTACH" == /tmp/frigate_snapshot_* ]]; then
           rm -f "$ATTACH"
       fi
   else
       echo -e "$body" | mail -s "$subject" "$MAIL_TO"
       log "Mail envoyé sans pièce jointe."
   fi

done
Okay, so we'll create a systemd service so the script runs automatically. Here's the content of /usr/lib/systemd/system/frigate_alert.service:

[Unit]
Description=Frigate MQTT Alert Email Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/alerte_frigate
Restart=always
RestartSec=5
User=root
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[Install]
WantedBy=multi-user.target

It is activated by typing

systemctl enable frigate_alert

and then launched using the command


systemctl start frigate_alert

We're thinking of restarting Frigate because we've changed its configuration.

docker stop frigate
docker start frigate

Here's what journalctl returns :

déc. 07 12:20:43 ultra.kervao.fr systemd[1]: Started frigate_alert.service.
déc. 07 12:20:43 ultra.kervao.fr mosquitto[1436264]: 1765106443: New connection from 127.0.0.1:55164 on port 1883.
déc. 07 12:20:43 ultra.kervao.fr mosquitto[1436264]: 1765106443: New client connected from 127.0.0.1:55164 as auto-5B7917FC-A109-8461-E38C-B893A8928EA6 (p2, c1, k60, u'olivier').

and for detection

déc. 07 19:47:55 ultra.kervao.fr alerte_frigate[1596716]: [INFO] Detected: camera=Camera-entree, label=person, id=1765133275.303314-xxsfrt
déc. 07 19:47:59 ultra.kervao.fr alerte_frigate[1596716]: [DEBUG] Trouvé après 3 seconde(s): /media/frigate/clips/Camera-entree-1765133275.303314-xxsfrt.jpg
déc. 07 19:47:59 ultra.kervao.fr alerte_frigate[1596716]: [INFO] Clip annoté trouvé: /media/frigate/clips/Camera-entree-1765133275.303314-xxsfrt.jpg
déc. 07 19:47:59 ultra.kervao.fr alerte_frigate[1596716]: [INFO] Clip candidate trouvé: /media/frigate/clips/Camera-entree-1765133275.303314-xxsfrt.jpg
déc. 07 19:48:00 ultra.kervao.fr alerte_frigate[1596716]: [INFO] Fichier stable (taille=223910). Prêt à être envoyé.

The email content is as follows in case of a New Frigate detection alert.

Nouvelle détection Frigate.

Caméra : Camera-entree
Objet  : person
ID     : 1765133275.303314-xxsfrt

Payload brut :
{"before": {"id": "1765133275.303314-xxsfrt", "camera": "Camera-entree", "frame_time": 1765133275.303314, "snapshot": null, "label": "person", "sub_label": null, "top_score": 0.0, "false_positive": true, "start_time": 1765133275.303314, "end_time": null, "score": 0.89453125, "box": [832, 201, 907, 368], "area": 12525, "ratio": 0.4491017964071856, "region": [724, 143, 1044, 463], "active": true, "stationary": false, "motionless_count": 0, "position_changes": 0, "current_zones": [], "entered_zones": [], "has_clip": false, "has_snapshot": false, "attributes": {}, "current_attributes": [], "pending_loitering": false, "max_severity": null, "current_estimated_speed": 0, "average_estimated_speed": 0, "velocity_angle": 0, "path_data": [], "recognized_license_plate": null}, "after": {"id": "1765133275.303314-xxsfrt", "camera": "Camera-entree", "frame_time": 1765133275.499867, "snapshot": {"frame_time": 1765133275.303314, "box": [832, 201, 907, 368], "area": 12525, "region": [724, 143, 1044, 463], "score": 0.89453125, "attributes": [], "current_estimated_speed": 0, "velocity_angle": 0, "path_data": [], "recognized_license_plate": null, "recognized_license_plate_score": null}, "label": "person", "sub_label": null, "top_score": 0.8671875, "false_positive": false, "start_time": 1765133275.303314, "end_time": null, "score": 0.84765625, "box": [815, 201, 897, 364], "area": 13366, "ratio": 0.5030674846625767, "region": [716, 134, 1036, 454], "active": true, "stationary": false, "motionless_count": 0, "position_changes": 1, "current_zones": [], "entered_zones": [], "has_clip": false, "has_snapshot": true, "attributes": {}, "current_attributes": [], "pending_loitering": false, "max_severity": null, "current_estimated_speed": 0, "average_estimated_speed": 0, "velocity_angle": 0, "path_data": [[[0.6687, 0.5056], 1765133275.499867]], "recognized_license_plate": null}, "type": "new"}


with the snapshot image attached. And here's another variation with an HTML email in the message body

### --- MAIL HTML ---
   TMPMAIL=$(mktemp)
   cat > "$TMPMAIL" <<EOF
<html>
<body style="font-family:Arial,sans-serif">
<h2 style="color:#c00">🚨 Alerte Frigate</h2>
<p>
<b>Caméra :</b> ${camera}<br>
<b>Objet détecté :</b> ${label}<br>
<b>ID événement :</b> ${EVENT_ID}<br>
<b>Date :</b> $(date +"%Y-%m-%d %H:%M:%S")
</p>
<p>Snapshot annoté :</p>
</body>
</html>
EOF

   s-nail \
     -S smtp="$SMTP_URL" \
     -S from="$MAIL_FROM" \
     -s "Alerte Frigate — ${label} (${camera})" \
     -a "$ATTACH" \
     -M "text/html" \
     "$MAIL_TO" < "$TMPMAIL"

   log "Mail envoyé avec snapshot : $CLIP_FILE"
   rm -f "$TMPMAIL"

Sending alerts with Signal

We now come to Signal, or rather signal-cli, the command-line version whose URL is https://github.comAsamK/signal-cli. I retrieved the binary, decompressed it, and placed it in the correct location:

tar xvfz signal-cli-0.13.22-Linux-native.tar.gz
mv signal-cli /usr/local/bin

We will also need the qrencode generator, which we will install via urpmi. Assuming you already have a Signal account, we will link the Frigate device to the main account on the mobile device by typing

signal-cli link -n "FrigateAlert"

This will give something like

sgnl://linkdevice?uuid=17dgwYBh(...)G4GGmFEZDA%3D%3D&pub_key=BTR9CHVvtKrEmw7D(...)7r31bIG%2ByFmxv3O7q4nagj

without further delay you must type

echo "sgnl://linkdevice?uuid=17dgwYBh(...)G4GGmFEZDA%3D%3D&pub_key=BTR9CHVvtKrEmw7D(...)7r31bIG%2ByFmxv3O7q4nagj" | qrencode -t ANSIUTF8

here is the result

█████████████████████████████████████████████████
█████████████████████████████████████████████████
████ ▄▄▄▄▄ █▀▄█▀   ▀  ▄▄█▄ █▀ ▄▀ ▄▀▄ █ ▄▄▄▄▄ ████
████ █   █ █▀▄  ▀▄▀  ▄▄█ ▄▀ ▀▀▄▀█▀▀  █ █   █ ████
████ █▄▄▄█ █▀  ▄▀▄█ ▀█▄█▀▄▀█▀▄▄▀▄███ █ █▄▄▄█ ████
████▄▄▄▄▄▄▄█▄▀ █▄█ ▀▄█▄█▄▀▄▀ █ ▀▄█▄▀ █▄▄▄▄▄▄▄████
████   ▄ █▄ ▄▀▄ █▄▀▄▀ ▄█▀▀▄▀▄▀ █▄▄█ ▄ ▀ ▀  ▀▀████
████  ▀ █ ▄██ ▀█▀█▀▄▄█▄▀▄▀▀▀▄██  █▄█ ▄▄▀█▀▄▀▀████
████▄█▄▀▀ ▄▄▄ ▄▄▄▀▀▀▀█▄█▀█  ▀▄▀▄▀▄██▀▀█▄▀█   ████
█████▀▀ ██▄▀▄▄█ ▄█ █▀▄▄ ▀  ██▄█▄▄███ ▄ ▀ █▄█▀████
█████▀ ▄██▄▄▀▄  ▄▀▄█▀▀▀ ▄▀▀▀▄ ▀▄ ▄▀▀▀▀▀▀▀  ▀█████
████  ██ ▄█▄ █ ██ ▄▄  ▀█  ▄█ █▀▄▀█▄▀▄██▄▄██ █████
█████▄    ▄▀ ▄▀▄▀█▄▀▄█▀█▄ █   ▄▄   ▀ █▀▄▀▄▄ ▀████
████▄▀▀ ▄▀▄▀▀ ▄█▀▄█ ▄█▀█▄▀██▄█▀▄▄█▄▀ ▀█▀▀ ██▀████
████▀  █ ▀▄█▀▄██▄█   ▄ ▀█▄ ▀█  ▀▀▄▀▀▀▀▀▀▀█ ▄▀████
████ █ ██ ▄▀▄▀▄▀▄█▀▄██▄█▄▀█▀ █▀ ████▄▀█▀▄█▄ ▀████
████ ██ ▄█▄▄▄▀▄█▄▀▀ ▀█▄█▀ █ ▄█ █▀▄▄  ▀▀▀ ▀▄█ ████
████ █▀█▄█▄ ▀▄▄ ▄▄██▀▄▀ ▀  ▀ ▄▀▄ █▀▀▄██▄█ ▄██████
████▄█▄▄▄█▄▄▀▀▄ ▄▀▄█▀ █▄ ▄ ▄▄▄▄▄▀▄▄▄ ▄▄▄ ▀ ▀ ████
████ ▄▄▄▄▄ █▄▀██▄ ▄   ▀█▀█▄█▀█▀ ▄▄   █▄█ ▄▄▀▀████
████ █   █ █ ▀█▄▀▀▄ ▄█▀█▄▄▄▀▄▀ █▄▀▀█ ▄▄▄▄█   ████
████ █▄▄▄█ █ █▀█▀█  ▄█ █▄▀█▀█▄ ▄███▄▀▀▄ ▄ ▄▀█████
████▄▄▄▄▄▄▄█▄▄██▄█▄▄▄▄███▄▄█▄▄▄▄███▄███▄█████████
█████████████████████████████████████████████████
█████████████████████████████████████████████████
with the mobile phone we associate the Frigate unit by viewing the QR code thus obtained and in the first shell we have the following message

INFO  ProvisioningManagerImpl - Received link information from +336XXXXXXXX, linking in progress ...
Associated with: +336XXXXXXXX

Frigate is now correctly associated with the main Signal account. To check if it's working, you can type

signal-cli --username +336XXXXXXXX send -m "This is a message" 06YYYYYYYY

Now we can add to the main script

### --- ENVOI SIGNAL ---
   SIGNAL_USER="+336XXXXXXXX"       # ton numéro Signal
   SIGNAL_DEST="+336YYYYYYYY"       # numéro qui reçoit les alertes qui peut être le même numéro, ça apparaitra dans les Notes perso

   signal-cli \
      send -u "$SIGNAL_USER"\
      -a "$ATTACH"\
      -m "🚨 Alerte Frigate
      Caméra : ${camera}
      Objet  : ${label}
      ID     : ${EVENT_ID}
      Date   : $(date)" \
      "$SIGNAL_DEST"

  log "Alerte envoyée par Signal à $SIGNAL_DEST"

And here's what it looks like when sent to my own number
  


In case of an alert that does not correspond to person or car, here is what journalctl will report

Dec 12 18:39:10 ultra.kervao.fr alerte_frigate[3356635]: [DEBUG] Event ignored for label=cat

Here's a variation for sending to a specific group where you can add other people. To list the groups, type

signal-cli listGroups

here is the result

INFO  AccountHelper - The Signal protocol expects that incoming messages are regularly received.
Id: 2BVGj6gu1es4K9(...)4BdAwavlpon8rE= Name: groupe1  Active: true Blocked: false
Id: vToJsVzeJeME(...)iyP+Xxf61plZA8= Name: groupe2  Active: true Blocked: false
Id: ZWLvp3vW(....)vYy5hse3hpTQ0= Name: groupe3  Active: true Blocked: false
Id: 9dhS9vM5(...)rVVUJSM/7jYIrIU84= Name: groupe4  Active: true Blocked: false
Id: puoaoo7(...)8hm62WWcMlFqo= Name: groupe5  Active: true Blocked: false

and we put the id of the group concerned, to send a message it will give

signal-cli --username +336XXXXXXXX send -g vToJsVzeJeME(...)iyP+Xxf61plZA8=  -m "This is a test message"

and we can adapt the script accordingly.

[ back to top of page ]

Frigate+

Frigate+ is the paid option for Frigate. For a subscription of $50 (payable via PayPal) per year, the main advantage of this version is the ability to use a custom model that refines detection by classifying true and false positives, and also provides access to community models. Through continuous learning, the custom model becomes increasingly accurate and requires fewer and fewer resources.
The official page is https://plus.frigate.video. Once the subscription is paid, the first step is to create the API key and then set up the cameras.



In the Frigate configuration, we will now specify the key and enable snapshots. In the docker-compose.yml file, add the following to the environment section   :

environment:
    
  PLUS_API_KEY: your-API-key


In the
config.yaml file, add a snapshots section if it doesn't already exist:

snapshots:
 enabled: true
 timestamp: true
 bounding_box: true
 retain:
   objects:
     person: 7
 clean_copy: true

To apply the changes, stop
Frigate by typing docker stop frigate,  then

docker compose -f docker-compose.yml up -d

and restart
Frigate by typing docker start frigate. You should then see that Frigate+ is working correct



Now we click on Explore and in the filters, we select only the objects that have a snapshot and that have not yet been submitted to the Frigate+ centralized database.



Click on an image of an object and then on Snapshot ; confirm if the object detected in the bottom right of the image is correctly identified.


The image is submitted to the centralized server, and so on. We now go to https://plus.frigate.video/dashboard/images/?tab=0 where we find all the submitted images. Clicking on an image displays the objects that have been detected.




If we agree, we click on Verify & Save



Now, if an object has not been detected, you can indicate it by clicking on Add (w) and place the detection box in the correct location, clearly identifying the object (in the image below there is no one, it is for illustration).



a fortiori if there is a false positive, we will click on the box to delete it and we will see that the object's label is crossed out.



We will now generate a custom model in addition to the basic Frigate+ model, which is itself enriched and trained by objects identified by the community. To create it, you need to upload at least ten images that have been properly annotated and verified, then enrich it by continuing to upload images. Ideally, you should have around a hundred images in all weather and lighting conditions for the outdoor cameras.
You can create up to 12 models per year based on different base models. Let's start to create the first model by clicking on Request Model.



I chose mobiledet, which corresponds to my TPU key.



And here's the result.





The Base Models tab lists the base models used by default.



Once the model generation is complete, which can be quite quick if you only have about ten images uploaded, you get an identifier. Below, it created two for me.



I limit myself to models for my TPU key and I specify its ID in the config.yaml file with a new section

model:
  path: plus://model-id

We restart Frigate so that the file is recognized, and here's what it looks like in the interface.

From then on, it picked up many more objects, like this cat, that I couldn't detect before.

When the model is well trained, we can review the object detection threshold settings to lower them in order to capture more objects.

Frigate+ allows you to generate up to 12 models per year. The advantage of generating multiple models is that, model by model, you can create refined models that precisely adapt to the cameras' environment. Successive models improve false positive detection, adapt to varying conditions (season, wind, lighting, etc.), and better detect certain objects (animals, stationary objects, etc.). Generating an additional model does not mean using multiple models until the system's resources are exhausted; the new model simply replaces the previous one.

Generating one model per month is a good pace; during the life of a model, it will be necessary to continue annotating the images; ideally, at least 200 to 300 annotated images are needed for it to be worthwhile to change models and for a real improvement to be observed.

A word of caution regarding image annotation: when submitting images, don't limit yourself to false positives, otherwise the model will become paranoid and stop detecting anything, or it will make mistakes in detection, for example, mistaking a person for a cat. Therefore, it's essential to also submit positive detections. The ideal ratio is 80% true positives and 20% false positives.

If it regularly detects a gatepost as a person, it will also be necessary to submit images where a real person walks past the gatepost so that it can see the difference; this is called contrastive learning .

To create a new model in the Frigate+ interface, click on Request Model




Then Continue, I chose the model adapted to the Coral key



It will take some time to generate it


We are notified by email when the model is ready.


Next, you need to modify the config.yaml file to indicate the identifier of the new model and restart frigate .

model:  path: plus://new-identifier

Note that if the base model evolves to a new version, it will be necessary to request the generation of a new customized model for it to be taken into account.

If the subscription is not renewed, access to the personalized template will still be available.

Here are some links to learn more