Imagelist Camera, integration for handeling snapshot files (camera,browse, move, delete and create mp4/gif)

It offers the following functionality:

  • Create a camera entity from images. It can be used for several images in a directory, to show a slideshow/timelaps from these images without generating a intermediate file
    The orignal homeassistant local file camera, allows only to display a single image. This camera shows an imagelist as slideshow/Timelapse. The delay time between the images can bet set in the configuration or with a service. For more info, see the repository

  • create a animated GIF or MP4

  • File handeling services for snapshots (JPG,PNG,GIF and MP4), delete and Move

Examples are provide how to easily create a smart surveillance system within homeassistant with a few simple script.

1 Like

I just release a new version of this component.

The new release has some exiting features that is usefull for people who are using deepstack as a surveillance detection for objects (for example people) that are entering you property and you want to view the object detections in the images as slideshow.

The new version allows you to pause and browse (prev. and next) a slideshow that is composed of snapshots that are captured by the deepstack component.
alt text

Hi Jodur

Just playing with the component - and was just wondering, is there a way to force the camera entity to refresh the images from the directory, or do you need to call imagedirectory.camera_update_image_filelist manually each time there’s a new image?

Thanks

The implementation, right now is that you have to call the update image list manually.
You could use the Folder watcher integration to call this service when a new image is added

I have been wondering what I should do about my growing folder of Deepstack person snapshots. I’d especially like to to view just the ones with people in them (and maybe even auto delete the empty ones).

I have to focus on troubleshooting my 2 Internet outages in the last 24 hours and finish rebuilding my Z-Wave network first. I have bookmarked this to look at later.

1 If you only want images with people, just set the object detection targets in the deepstack object to persons only, and you only get images where people are detected

2 The imagelist component is also providing a delete files service. I use this service to schedule every night a script that call the service to deletes the images of the previous day.

1 Like

@jodur Just wondering if you have updated to the latest HA release at your end? I’m getting the following error back?

Platform error camera.imagedirectory - cannot import name 'CAMERA_SERVICE_SCHEMA' from 'homeassistant.components.camera' (/usr/src/homeassistant/homeassistant/components/camera/__init__.py)

Thanks!

@kanebullen , thnx for pointing to me. I didn’t noted it yet because i don’t upgrade always immediate to the latest version. This issue is now resolved. Latest version on github or update trough hacs

Thanks - confirming all good now.

Hi @jodur,

Is there a way to use it with Frigate? I tried to use the deepstack object and calling the image_processing to take a snapshot, but I get a lot of delays and sometimes I get an old image instead of the last motion image (I don’t understand how). but it all seems so confusing, I’m trying to determine the best solution for motion detection and clips. Frigate has a nice one with constantly updating the last snapshot but it’s also not very efficient since I’m losing the best image of the object detection. Can you please shed some light here? how do you implement it for the best results?

Many thanks,
Didi

@didi767 Didi, if deepstack is generating snapshots of events, you could also use this library. In the documentation i provided some example script how i use it with deepstack.

jodur,

thanks for a great add-on, just what I was looking for.
I’m having a little problem with your example script to delete files based on date as shown in the github.

I can make the individual sections work, so I successfully create an MP4 file but the script seems to hang up on the wait for trigger section and never progress to section 4 and 5, the script doesn’t seem to register the event.

Separately I can refresh the camera filelist and delete or move files from my chosen directories etc. How can I test the event has fired or perhaps that the mp4 file has finished being created?

F

You must have same kind of mistake then in your automation. In the example there is also a timeout defined in #STEP3. If you enable the timeout It wil step to #STEP4 if the event ‘create_gif_mp4’ is not generated. Make sure that you configure the ’ destinationpath’ to the right directory as you specified in previous service call imagedirectory.create_gif_mp4

Jodur,

thanks for the reply. Having scratched my head a bit more about this I think there are 2 issues.

Firstly in your code example on github (which i shamelessly copied) in section 5 you use the parameter “excludelist”

 #STEP 5
 - service: imagedirectory.delete_files
    data:
      sourcepath: /config/snapshots/achtertuin
      excludelist: deepstack_object_achtertuin_latest.jpg
      endtimestamp: '{{endtime}}'
mode: single

This should be “exclude” as per the documentation, including it as written makes the script fail/hang or otherwise not work, obviously easy enough to fix, you might want to update the readme at some point.

I think you also refer to the services imagedirectory.move and
imagedirectory.delete which appear as ‘imagedirectory.move_files’ and ‘imagedirectory.delete_files’ in the Home Assistant services tab. Mentioned here only for consistency and for those who come looking.

Additionally I think there is an issue, as per my original problem that if you call imagedirectory.create_gif_mp4 and there are no files (within the date parameters you specify) the script seems to hang rather than exit gracefully or pop an error and so the event we were checking for does not fire. Obviously it’s redundant to call this service when you have no images but unless the script knows that, it seems it would cause an error. In my normal use case and yours I think, we should never come across this problem.

I wonder, is there a way to expose the number of files in the filelist and to expose their filedate? It would be handy to be able to display on the cameraview (picture-elements card) how many images it’s scrolling through and their file details, my camera prints the timestamp so small that it’s very hard to read on anything smaller than my desktop display.

I’ve learned quite a lot looking into this so thank you for inspiring me to look and thanks again for a really useful component.

F.

@FragRock , thx for pointing out the typo-bugs in the examples. In a new version, i renamed the parameters to get equal names in all services. I will correct this in the examples.

First, the number of files and the file-list that the camera object is using, is exposed as an attribute “imagecount”

You can obtain this value for example, with a template like this :

{{states.camera.achtertuin_motion.attributes.imagecount}}

Also the list of images that are in the list can be retrieved with:

{{states.camera.achtertuin_motion.attributes.files}}

To bad for your question, regarding to show the current file or indexnumber of the list, that is displayed in the camera. This is not included as attribute. This was done by design because it would raise a lot attribute state changes (every time when a new image is show)

You can test these templates under the developer tools

Second, when no images are present in the time range you selected for mp3/gif creation, the script wil run normally (certainly it will not hang, this is forseen by design), but no mp3/gif file will be created.
By design the event for file creation will also not be fired, this is probally the cause your script will “stall”. Therefore it is wise to use the timeout when using a wait_for_trigger, so you alway continue the script. When you have a lot of images in the selected timerange, it can take some long time, before all files are processed and the event will be raised, so make sure you set it long enough for the longest no. images possible.
I agree i would be nicer to also raise the event with a count of zero and a empty file-list. This could be a improvement. Please create a request for this on github. I normally only do ‘coding’ in the wintertime, as in summertime i have other hobbies, so don’t expect it soon.

You can look in the home-assistant log for calls where nog files where found within the specified time-range, you will find a messages like:

No files found in the specified time range: [09/07/2021 19:55:44 , 09/07/2021 19:55:51] in :/config/snapshots/achtertuin

Jodur,

thank you for the detailed reply, makes perfect sense on all counts, I suspect I saw 2 issues simultaneously and jumped to the wrong conclusion. My setup now works great.

Also totally understand not wanting to update your code when the sun is shining!

For those following this thread I’ve also updated your picture-elements card example to add some additional buttons to run the backup script on demand, create a timelapse, reload the image list and show the current image count.

it looks a bit like this but you may need to adjust the position/color/size of the icons for your own use case and display size.camview

In lovelace this is produced with the code below :slight_smile:

  - type: picture-elements
    entity: camera.frontcam_motion
    camera_image: camera.frontcam_motion
    camera_view: live
    elements:
      - type: icon
        icon: mdi:cloud-upload
        style:
          background: rgba(255, 255, 255, 0.0)
          left: 20px
          bottom: 0px
          color: rgba(50, 50, 200, 0.9)
        tap_action:
          action: call-service
          service: script.cam_image_backup
          service_data:
            entity_id: script.cam_image_backup
      - type: icon
        icon: mdi:video-vintage
        style:
          background: rgba(255, 255, 255, 0.0)
          left: 55px
          bottom: 0px
          color: rgba(50, 50, 200, 0.9)
        tap_action:
          action: call-service
          service: script.cam_tl
          service_data:
            entity_id: script.cam_tl
      - type: icon
        icon: mdi:reload
        style:
          background: rgba(255, 255, 255, 0.0)
          left: 90px
          bottom: 0px
          color: rgba(50, 50, 200, 0.9)
        tap_action:
          action: call-service
          service: script.cam_upd
          service_data:
            entity_id: script.cam_upd
      - type: state-label
        entity: camera.frontcam_motion
        attribute: imagecount
        style:
          left: 125px
          bottom: '-12px'
          color: rgba(50, 50, 200, 0.9)
          font-size: 150%
      - type: icon
        icon: mdi:skip-previous
        style:
          background: rgba(255, 255, 255, 0.25)
          right: 50px
          bottom: 25px
        tap_action:
          action: call-service
          service: imagedirectory.camera_prev_image
          service_data:
            entity_id: camera.frontcam_motion
      - type: icon
        icon: mdi:skip-next
        style:
          background: rgba(255, 255, 255, 0.25)
          right: 0px
          bottom: 25px
        tap_action:
          action: call-service
          service: imagedirectory.camera_next_image
          service_data:
            entity_id: camera.frontcam_motion
      - type: conditional
        conditions:
          - entity: camera.frontcam_motion
            state: streaming
        elements:
          - type: icon
            icon: mdi:pause
            style:
              background: rgba(255, 255, 255, 0.25)
              bottom: 25px
              right: 25px
            tap_action:
              action: call-service
              service: imagedirectory.camera_toggle_pause
              service_data:
                entity_id: camera.frontcam_motion
      - type: conditional
        conditions:
          - entity: camera.frontcam_motion
            state: paused
        elements:
          - type: icon
            icon: mdi:play
            style:
              background: rgba(255, 255, 255, 0.25)
              bottom: 25px
              right: 25px
            tap_action:
              action: call-service
              service: imagedirectory.camera_toggle_pause
              service_data:
                entity_id: camera.frontcam_motion

As well as Jodur’s image_backup script this card also relies on 2 additional scripts .

cam_tl:
  alias: "Create tl" #uses all images in the current image forlder
  sequence:
    - service: imagedirectory.create_gif_mp4
      data:
        sourcepath: /config/www/camimages
        destinationpath: /config/www/camimages/archive
        filename: frontcam_backup_{{(now()-timedelta(days=1)).strftime("%d_%m_%Y")}}
        format: mp4
        exclude: campic1.jpg
#        begintimestamp: '{{begintime}}'
        endtimestamp: '{{(now()).strftime("%d/%m/%Y")}} 23:59:59'
        lasthours: 24.0
  mode: single

cam_upd:
  alias: "Update Image List"
  sequence:
    - service: imagedirectory.camera_update_image_filelist
      data:
        entity_id: camera.frontcam_motion
        sourcepath: /config/www/camimages
  mode: single

Hope this is helps someone in the future.

F

1 Like

Thank you Jodur for such detailed explanation to the configuration. Sometimes, I feel flustered on having certain issues which had me look into this forum in hope for receiving assistance. And I finally got your explanation. The templates you mentioned under the developer tools have indeed proved to be quite helpful to run the setup well.

Hi Jodur, appreciate the great work.
I managed to define my preferred fps by modifying line 142 of the init.py file

        writer = imageio.get_writer(
            os.path.join(outputfolder, outputfile), mode="I", fps=1
        )

I know this was created very long ago but is there a way to resize the mp4 after converting it from multiple images?

Indeed a long time ago. I am not as active anymore as before with homeassistant. You could possible do this with GitHub - kkroening/ffmpeg-python: Python bindings for FFmpeg - with complex filtering support