New comprehensive Frigate binding

Unlikely - see my earlier post on the matter of the Frigate binding being included in mainline. It would seem that I would have to undertake a significant amount of work simply to get it included; and I have neither the time nor the inclination to do this when I could be spending the limited amount of time I have to work on this project developing and improving it.

That having been said - I hope to release as a third-party add-on via the ‘marketplace’ when it is sufficiently stable.

1 Like

It would be worth the effort long term, I believe.

1 Like

Unlikely - see my earlier post on the matter of the Frigate binding being included in mainline. It would seem that I would have to undertake a significant amount of work simply to get it included;

That’s fair, but on the other hand you would not have to do any work to keep it up to date with new OH releases. It would be useful to be able to install eg milestone builds and not lose the binding.

Perhaps we can crowdsource the work? Would you be willing to submit the PR for mainline, and then I can help address any review comments, as long as it’s not a major rewrite? I’ve contributed a binding before so I have some experience with the codebase.

Hello there!
if you have the time, I would like you to comment on the result you got, if your scenario is different than mine: I am trying to get this binding to work with OpenHAB 4.2.1 and Frigate 0.14.1; I’m open to suggestions on ways to debug this behaviour, if is not the intended one. Otherwise, I’d be glad to know what I am missing.

I compiled the repository at the main branch and commit 14007fd, checking it out inside the openhab-addons repo at version 4.2.1.

Following the build instructions I obtained a JAR for OpenHAB 4.2.1 and after copying it inside the addon folder of a running OpenHAB 4.2.1 instance, it was detected and loaded without errors.

However, I am not able to add cameras after creating the Frigate server Thing in OpenHAB:

I am running Frigate 0.14.1

After creating correctly the frigate server Thing and going back to Things > + > MQTT Binding > Search the Camera I am using from the Frigate configuration is discovered automatically, then I click on it and choose a name and in the end it never gets past the offline status “CONFIGURATION_PENDING waiting for status”. The OpenHAB logs do not report any error or warning, nor the Frigate logs do.

Using the TRACE log level when adding the camera device does not reveal any information either; the following is what appear on the log at DEBUG level when adding the camera device I would like to use:

16:53:22.986 [INFO ] [ig.discovery.internal.PersistentInbox] - Added new thing 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' to inbox.
16:53:22.987 [INFO ] [openhab.event.InboxAddedEvent        ] - Discovery Result with UID 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' has been added.
...
16:54:29.405 [DEBUG] [rnal.handlers.frigateSVRServerHandler] - keep-alive: device is online
16:54:30.287 [INFO ] [openhab.event.InboxRemovedEvent      ] - Discovery Result with UID 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' has been r
emoved.
16:54:30.294 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' changed from UNINITIALIZED to 
INITIALIZING
16:54:30.297 [INFO ] [rnal.handlers.frigateSVRCameraHandler] - camera libreria_sala INITIALIZATION handler called 
16:54:30.297 [INFO ] [rnal.handlers.frigateSVRCameraHandler] - camera: SetOffline called, stopping streamer
16:54:30.297 [INFO ] [rnal.handlers.frigateSVRCameraHandler] - camera libreria_sala: unsubscribing from MQTT
16:54:30.298 [INFO ] [rnal.handlers.frigateSVRCameraHandler] - unsubscribe: connection is null
16:54:30.298 [DEBUG] [rnal.handlers.frigateSVRCameraHandler] - offlining device
16:54:30.298 [INFO ] [vr.internal.servlet.frigateSVRServlet] - StopServer called: stopping streaming server
16:54:30.298 [INFO ] [rnal.handlers.frigateSVRCameraHandler] - camera libreria_sala: bridge going online
16:54:30.299 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' changed from INITIALIZING to O
FFLINE (BRIDGE_OFFLINE)
16:54:30.299 [INFO ] [rnal.handlers.frigateSVRCameraHandler] - cam going online: requesting status: frigateSVR/mqtt:frigateServer:460b8fd214:frigate_auriga/lib
reria_sala/camOnLine
16:54:30.299 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' changed from OFFLINE (BRIDGE_O
FFLINE) to OFFLINE (CONFIGURATION_PENDING)
16:54:30.300 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000' changed from OFFLINE (CONFIGUR
ATION_PENDING) to OFFLINE (CONFIGURATION_PENDING): waiting for status
16:54:34.417 [DEBUG] [rnal.handlers.frigateSVRServerHandler] - keep-alive: device is online

For reference, this is the YAML of the frigate server Thing:

UID: mqtt:frigateServer:460b8fd214:frigate_auriga
label: frigateSVR Auriga
thingTypeUID: mqtt:frigateServer
configuration:
  ffDASHPackageCommands: -seg_duration 1 -streaming 1
  serverClientID: ""
  ffDASHTranscodeCommands: -acodec copy -vcodec copy
  enableAPIForwarder: true
  ffMJPEGTranscodeCommands: -q:v 5 -r 2 -vf scale=640:-2 -update 1
  ffmpegLocation: /usr/bin/ffmpeg
  ffHLSStartProducerOnLoad: false
  enableStream: true
  streamWhitelist: DISABLE
  ffTempDir: ""
  ffMJPEGStartProducerOnLoad: false
  ffHLSTranscodeCommands: -acodec copy -vcodec copy
  ffMinFramesToStart: 10
  serverURL: http://127.0.0.1:5000
  serverKeepAlive: 5
  HTTPTimeout: 100
  ffDASHStartProducerOnLoad: false
  ffKeepalivesBeforeExit: 2
bridgeUID: mqtt:broker:460b8fd214
location: Sala

And here it is the YAML of the Camera Thing:

UID: mqtt:frigateCamera:460b8fd214:libreria_sala-127-0-0-15000
label: "Camera : libreria_sala"
thingTypeUID: mqtt:frigateCamera
configuration:
  ffDASHPackageCommands: -seg_duration 1 -streaming 1
  ffmpegCameraNameOverride: ""
  ffDASHTranscodeCommands: -acodec copy -vcodec copy
  ffMJPEGTranscodeCommands: -q:v 5 -r 2 -vf scale=640:-2 -update 1
  ffHLSStartProducerOnLoad: false
  enableStream: true
  serverID: mqtt:frigateServer:460b8fd214:frigate_auriga
  ffTempDir: ""
  ffMJPEGStartProducerOnLoad: false
  ffHLSTranscodeCommands: -acodec copy -vcodec copy
  ffMinFramesToStart: 10
  ffDASHStartProducerOnLoad: false
  ffKeepalivesBeforeExit: 2
  cameraName: libreria_sala
bridgeUID: mqtt:broker:460b8fd214

Finally, the configuration snippet in Frigate for that camera I am exposing to MQTT

go2rtc:
  streams:
    libreria_sala:
      - rtsp://user:passwd@192.168.1.90:554/live2.sdp

cameras:
  libreria_sala:
    ffmpeg:
      inputs:
        - path: rtsp://127.0.0.1:8554/libreria_sala
          input_args: preset-rtsp-restream
          roles:
            - detect
    detect:
      enabled: true
      width: 1280
      height: 720

I’ll have a look at this in more depth when I next have some time available to do so. What seems to be happening is that the camera Thing does not appear to be receiving the MQTT status messages from the server Thing that would online the camera. Does your Frigate server have a client_id set?

Thanks for your response! I will keep an eye on the email notifications for when you or maybe another user will have time to give me a new idea or to help investigate.


I did not set the client id parameter in Frigate’s config nor inside the Thing settings in OH, relying on the default which should have the value frigate (according to Frigate’s own Full config reference )

In this first case I describe above, the server Thing connects to the Frigate instance without errors, at least on the OpenHAB logs:

22:52:50.077 [INFO ] [rnal.handlers.frigateSVRServerHandler] -  - Frigate server is offline
22:52:50.094 [INFO ] [rnal.handlers.frigateSVRServerHandler] - onlining server thing
22:52:50.094 [INFO ] [rnal.handlers.frigateSVRServerHandler] - enabling API forwarder
22:52:50.094 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'mqtt:frigateServer:460b8fd214:frigate_auriga' changed from OFFLINE (CONFIGURATION_PENDING) to ONLINE
22:52:50.094 [INFO ] [rnal.handlers.frigateSVRServerHandler] - enabling birdseye streaming server
22:52:50.095 [INFO ] [vr.internal.servlet.streams.HLSStream] - stream entry point set to birdseye.m3u8
22:52:50.095 [INFO ] [nternal.servlet.streams.FFmpegManager] - created working path STM2020091456089636599
22:52:50.095 [INFO ] [r.internal.servlet.streams.DASHStream] - sending stream to birdseye.mpd
22:52:50.096 [INFO ] [nternal.servlet.streams.FFmpegManager] - created working path STM705503912119675277
22:52:50.096 [INFO ] [rnal.handlers.frigateSVRServerHandler] - starting streaming server
22:52:50.096 [INFO ] [vr.internal.servlet.frigateSVRServlet] - Starting server at /frigate
22:52:50.098 [INFO ] [vr.internal.servlet.frigateSVRServlet] - streaming servlet started

At the time of writing this, I just tested the addition of a client_id parameter in both Frigate’s MQTT config and in the OH MQTT frigateSVR Thing, using both the default frigate value and also trying a custom one: in both cases, the server Thing will never connect to the Frigate instance, reporting the following warning at each retry on OH’s logs:

22:49:06.345 [INFO ] [rnal.handlers.frigateSVRServerHandler] -  - Frigate server is offline
22:49:06.352 [WARN ] [rnal.handlers.frigateSVRServerHandler] - server config block not valid (java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $)

NOTE: the rest of the Thing’s configuration is the same as my post above, with the addition of the key-value

serverClientID: frigate

This is a very useful binding! Thanks a lot for providing and maintaining it!

Does anyone have any sample rules for notifications, e.g. through Telegram?
I noticed that somehow I get the previous Snapshot, due to the order/delays in which the messages arrive.

Currently, this works more or less:

var Timer timer = null

rule "Send snapshot and clip when event ends"
when
    Item Camera__cam1_Current_Event_Type changed to "end"
then
    timer = createTimer(now.plusSeconds(5), [ |
            val telegramAction = getActions("telegram", "telegram:telegramBot:xxx")
            
            // URLs for snapshot and clip
            val snapshotUrl = Camera__cam1_Last_snapshot.state.toFullString()
            val clipUrl = Camera__cam1_URL_for_current_event_clip.state.toString
            
            // Send notification with snapshot and link to clip
            telegramAction.sendTelegramPhoto(snapshotUrl, "Alarm! Watch Clip: " + clipUrl)
            
            timer = null // Clear the timer after completion
    ])
end


I am using the below DSL script to take a snapshot and send it via telegram when it was requested via telegram bot.

import java.util.Base64                                                                                                                                                                             
import java.io.ByteArrayOutputStream                                                                                                                                                                
import java.net.URL                                                                                                                                                                                 
                                                                                                                                                                                                    
rule "Receive telegram"                                                                                                                                                                             
when                                                                                                                                                                                                
        Item TelegramBotMessage received update "take a snapshot"                                                                                                                                   
then                                                                                                                                                                                                
        val String ruleID = "Receive telegram"                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                    
        // code partially taken from https://community.openhab.org/t/oh-3-1-download-an-image-from-the-internet-and-save-into-a-item-of-the-type-image/125277/4                                     
        // unfortunately sendHttpGetRequest modifies the retrieved picture; a few bytes at beginning are cut off and a few are modified                                                             
        // this is why the download of the picture needs to be done by java methods                                                                                                                 
                                                                                                                                                                                                    
                                                                                                                                                                                                    
        logInfo( ruleID, "telegram message take a snapshot received" )                                                                                                                              
                                                                                                                                                                                                    
        val telegramAction = getActions("telegram","telegram:telegramBot:<your bot here>")                                                                                                          
                                                                                                                                                                                                    
        if ( TelegramBotMessage.state.toString == "take a snapshot" )                                                                                                                               
        {                                                                                                                                                                                           
                logInfo( ruleID, "will take a snapshot" )                                                                                                                                           
                                                                                                                                                                                                    
                val String pictureurl = "<URL to take a snapshot - replace it with yours>"                                                         
                var userImageDataBytes = newByteArrayOfSize(0)                                                                                                                                      
                                                                                                                                                                                                    
                try                                                                                                                                                                                 
                {                                                                                                                                                                                   
                        // use the built in java URL class - pass it the url to download                                                                                                            
                        val url = new URL( pictureurl )                                                                                                                                             
                                                                                                                                                                                                    
                        // create an output stream - we'll use it for building up our downloaded bytes                                                                                              
                        val byteStreamOutput = new ByteArrayOutputStream()                                                                                                                          
                                                                                                                                                                                                    
                        // open the url as a stream - aka - start getting stuff                                                                                                                     
                        val inputStream = url.openStream()                                                                                                                                          
                                                                                                                                                                                                    
                        // n is a variable for tracking how much data we have read off the inputStream per loop (and how much we write to the output stream)                                        
                        var n = 0                                                                                                                                                                   
                                                                                                                                                                                                    
                        // buffer is another byte array. basically we're using it as a fixed size copy byte array                                                                                   
                        var buffer = newByteArrayOfSize(1024)                                                                                                                                       
                                                                                                                                                                                                    
                        do                                                                                                                                                                          
                        {                                                                                                                                                                           
                                // read from input stream (the data at the url) into buffer - and place how many bytes were read into n                                                             
                                n = inputStream.read(buffer)                                                                                                                                        
                                                                                                                                                                                                    
                                if (n > 0)                                                                                                                                                          
                                {                                                                                                                                                                   
                                        // if we read more than 0 bytes - copy them from buffer into our output stream                                                                              
                                        byteStreamOutput.write(buffer, 0, n)                                                                                                                        
                                }                
                        } while (n > 0) // keep doing this until we don't have anything to read.                                                                                                    
                                                                                                                                                                                                    
                        userImageDataBytes = byteStreamOutput.toByteArray() // assemble all the bytes we wrote into an actual byte array                                                            
                }                                                                                                                                                                                   
                                                                                                                                                                                                    
                catch(Throwable t)                                                                                                                                                                  
                {                                                                                                                                                                                   
                        logError(ruleID, "An error occured: " + t.toString)                                                                                                           
                        telegramAction.sendTelegram(-480301213L, "An error occured: " + t.toString)                                                                                   
                }                                                                                                                                                                                   
                                                                                                                                                                                                    
                logInfo( ruleID, "I have a picture")                                                                                                                                             
                                                                                                                                                                                                    
                // make a new RawType with the byte array and the mime type - the open hab type Image needs a raw type                                                                              
                // my images are all jpeg - so this mime type is right for me                                                                                                                       
                // val rawType = new RawType(userImageDataBytes, "image/jpeg")                                                                                                                      
                                                                                                                                                                                                    
                                                                                                                                                                                                    
                val encoded = "data:image/jpg;base64," + Base64.getEncoder().encodeToString( userImageDataBytes )                                                                                   
                                                                                                                                                                                                    
                telegramAction.sendTelegramPhoto( encoded , "sent from openHAB")                                                                                                                    
        }                                                                                                                                                                                           
end
1 Like

I make it relatively simple, whenever the last snapshot item changes, I receive a message for the yard area. The other cameras only send pictures when nobody is at home.

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: Camera_Hof_Last_snapshot
    type: core.ItemStateChangeTrigger
conditions:
  - inputs: {}
    id: "3"
    configuration:
      itemName: VI_OH_SystemLevel
      state: "100"
      operator: =
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        val telegramAction =
        getActions("telegram","telegram:telegramBot:TelegramBotSec")

        val String Msg = "Bewegung im Kamerabereich - Hof"

        val CamSnapshotImage = Camera_Hof_Last_snapshot.state.toFullString


        if (Camera_Hof_Last_snapshot_object.state == "person" ||
        Camera_Hof_Last_snapshot_object.state == "car" ) {
          telegramAction.sendTelegramPhoto(CamSnapshotImage,Msg) 
          logInfo("Camera",Msg + "- Sende Snapshot") 
        }
    type: script.ScriptAction

thanks @Wolfgang_S!

@DrScr3w don’t you get a lot of pictures for the same event then?
I think Frigate is updating the snapshot if it calculates a higher confidence.

So I don’t get duplicate images, of course I get one to three images when someone enters the long driveway, depending on what the person does, but that’s okay for my needs. because I don’t want to look at the live stream every time, I can see what’s happening from the images. I have an extra TelegramBot just for the pictures from the camera. So it can’t happen that I overlook other messages.

1 Like

first, I like to say thank you for this great binding,
it works well for me except one small issue which i can’t figure out.

the Item “Current: Current Zones” stays always at the value NULL.
even the jason string shows a value for it.

i would be appreciated any hints of how to solve this.

{"before": {"id": "1732289489.19746-qfp33l", "camera": "front_door", "frame_time": 1732289492.024311, "snapshot": {"frame_time": 1732289491.436749, "box": [627, 84, 1115, 702], "area": 301584, "region": [28, 0, 1280, 1252], "score": 0.84375, "attributes": []}, "label": "person", "sub_label": null, "top_score": 0.82421875, "false_positive": false, "start_time": 1732289489.19746, "end_time": null, "score": 0.8125, "box": [874, 27, 1270, 719], "area": 274032, "ratio": 0.5722543352601156, "region": [436, 0, 1280, 844], "active": true, "stationary": false, "motionless_count": 0, "position_changes": 1, "current_zones": ["Front_Door"], "entered_zones": ["Front_Door"], "has_clip": true, "has_snapshot": true, "attributes": {}, "current_attributes": [], "pending_loitering": false}, "after": {"id": "1732289489.19746-qfp33l", "camera": "front_door", "frame_time": 1732289492.024311, "snapshot": {"frame_time": 1732289491.436749, "box": [627, 84, 1115, 702], "area": 301584, "region": [28, 0, 1280, 1252], "score": 0.84375, "attributes": []}, "label": "person", "sub_label": null, "top_score": 0.82421875, "false_positive": false, "start_time": 1732289489.19746, "end_time": 1732289496.097437, "score": 0.8125, "box": [874, 27, 1270, 719], "area": 274032, "ratio": 0.5722543352601156, "region": [436, 0, 1280, 844], "active": true, "stationary": false, "motionless_count": 0, "position_changes": 1, "current_zones": ["Front_Door"], "entered_zones": ["Front_Door"], "has_clip": true, "has_snapshot": true, "attributes": {}, "current_attributes": [], "pending_loitering": false}, "type": "end"}

Try the latest build. I was able to repeat this problem with the current binary but could not see any obvious reason in the code why this should be happening. I then tested the latest release and the problem disappeared. I am not yet sure as to the cause of this so please let me know if you see the same issue with the latest tree.

Hello there, I wanted to check with the other users the deployment flavour they are running: I am experiencing a very strange behaviour with the openhab-alpine container version 4.3.1: the bundle of this binding shows as active from oh-cli, however I cannot add new things from this binding (the entry in the UI is missing).

No errors or warnings are logged; moreover, no specific logger is created for the binding itself.

Are you successfully using the binding with the Debian-based container image, or maybe by installing it directly onto the host’s operating system?

SOLVED…

I don’t know what was the step that solved what wasn’t going right, however I will post here what I did:

  • compile the addon for the current OpenHAB version I am running (4.3.1, since at this time the author kindly shared a SNAPSHOT version of 4.3.0)
  • Stop the OpenHAB instance (Alpine)
  • Detele the cache and tmp directory contents
  • Move the compiled JAR inside the addon folder, and set ownership and permissions as needed
  • Start the OpenHAB instance (Debian)

Now I can see the frigateSVR entries in the MQTT thing creation. I switched to the Debian-based container image

… mostly

I am still stuck as when I posted before about the camera things staying in the CONFIGURATION_PENDING state; this leads me to think that there could be some other factor inside my infrastructure that differs from the other successful installs.

Basically if the cameras are stuck in CONFIGURATION_PENDING - assuming the MQTT broker is online - is because either the server Thing can’t communicate with the Frigate HTTP API, or because for some reason the camera Things and server Thing are not communicating. The latter communication is via MQTT, and should not be an issue if the broker is up. Thus I would switch on the DEBUG log messages on frigateSVR; it will be obvious if the server Thing is not able to communicate with the Frigate API. To online the cameras it needs to be able to retrieve the version string (it does this periodically as a keep-alive) and the server config block. If it can’t get these, the server Thing will not be able to configure the camera Things and the latter will remain in CONFIGURATION_PENDING.

Ack, I loathe containers and do not use them; in my experience they eat more storage space than necessary and cause more configuration-related problems than they are worth, in particular when you need whatever is in the container to talk to something outside the container! All my testing (and production system) is done with a direct install on the OS in a VM. If it works in this way, then any other issue is likely down to the container configuration and I’m afraid I can’t help with that.

Hi,
First of all, thank you for this wonderful binding!
Is it possible to get the event type (eg. alert, detection,etc.) from the binding? Info is available in Frigate Api (/api/review severity), but so far did not find exposed in the binding. Certainly can happen that I was not enough smart to find it… In my use case would be easier to trigger on alerts than check every detection against the zones again in OH, althogh Frigate did it already.
Thanks for your advise.