Camera feeds with movement snapshots (picture carousel)

Last weeks I was working on a specific usecase after finding out there is no proper card of a picture carousel.

(sorry for all the dutch variable names, I still consider a non native dutch speaking person will understand)

What I wanted
I wanted to have my camera take a snapshot of every movement and store the image (with a max number) and show them on my dashboard with a timestamp so I can see what happened without opening the slow camera app from TP link (which also sometimes is faulty in saving the video).

In short what I did
Created an automation which stores up to 10 images (and saves timestamp information) in a folder on my home assistant. Added a card on the dashboard to have a picture element cycling through the images.

Requirements

  • Camera with sensor for movement
  • tabbed-card (optional, can be several cards on the board, but this worked for me)
  • template-card: Needed for templating the picture elements card

Steps to create it yourself
Add helpers, I created the following:

Add the folder where you want to store the images to your configuration.yaml

  • Helper to set the number of photos to store (beware of the scripts string handling only max to 255 characters, so somewhere between 10 and 20 is the limit where I came into)
  • Helper to store all timestamps
  • Helper to store the latest taken picture
  • Helpers for the dashboard (which picture is now, which label should be shown, current url of the picture)

Create an automation to store the images when movement.

alias: Beweging Snapshot
description: ""
triggers:
  - type: motion
    device_id: 6cdc82ac5ff383f598906508d27bdccb
    entity_id: 175e02d480685f50bd9226383ab81d79
    domain: binary_sensor
    trigger: device
    alias: Beweging camera voorkant gedetecteerd
    enabled: true
  - trigger: time_pattern
    seconds: /10
    alias: Every 10 second trigger (for testing purposes)
    enabled: false
conditions: []
actions:
  - sequence:
      - metadata: {}
        data:
          filename: >-
            /config/www/BewegingVoorkant/{{
            states('input_number.beweging_voorkant_foto_volgnummer') | int
            }}.jpg
        target:
          entity_id: camera.tapo_voorkant_hd_stream
        action: camera.snapshot
        alias: Maak een foto met de camera aan de voorkant
        enabled: true
      - action: input_text.set_value
        data:
          entity_id: input_text.beweging_voorkant_foto_timestamps
          value: >
            {% set total = 25 %} {% set index =
            states('input_number.beweging_voorkant_foto_volgnummer') | int - 1
            %} {% set now_ts = now().strftime('%d-%m %H:%M') %} {% set raw =
            states('input_text.beweging_voorkant_foto_timestamps') %} {% set
            timestamps = raw.split(',') if raw else [] %}

            {% set lijst = namespace(result=[]) %} {% for i in range(total) %}
              {% if i == index %}
                {% set lijst.result = lijst.result + [ now_ts] %}
              {% elif i < timestamps | length %}
                {% set value = timestamps[i] %}
                {% if value == '???' %}
                  {% set lijst.result = lijst.result + [''] %}
                {% else %}
                  {% set lijst.result = lijst.result + [ value ] %}
                {% endif %}
              {% else %}
                {% set lijst.result = lijst.result + [''] %}
              {% endif %}
            {% endfor %}

            {{ lijst.result | join(',') }}
        alias: Tijdstip onthouden voor dit plaatje
      - action: input_number.set_value
        data:
          entity_id: input_number.beweging_voorkant_foto_volgnummer
          value: >-
            {{ (states('input_number.beweging_voorkant_foto_volgnummer') | int %
            states('input_number.beweging_voorkant_number_of_stored_images') |
            int) + 1 }}
        alias: Volgnummer ophogen, bij max terug naar 1
      - delay:
          hours: 0
          minutes: 0
          seconds: 10
          milliseconds: 0
mode: single

The script does the following:
When movement is triggered, a picture is stored in the folder created, the timestamp is stored (so I can show it on the card), the number of current image is changed with +1 and we wait for 10 seconds because I don’t want a burst of pictures when someone walks by

Next I created a script:

sequence:
  - action: input_number.set_value
    data:
      entity_id: input_number.beweging_voorkant_foto_volgnummer_dashboard
      value: >-
        {{ (states('input_number.beweging_voorkant_foto_volgnummer_dashboard') |
        int % states('input_number.beweging_voorkant_number_of_stored_images') |
        int) + 1 }}
    alias: Volgnummer ophogen, bij max terug naar 1
  - action: input_text.set_value
    data:
      entity_id: input_text.beweging_voorkant_foto_timestamp_dashboard
      value: >-
        {% set timestamps =
        states('input_text.beweging_voorkant_foto_timestamps').split(',') %} {%
        set current_index =
        states('input_number.beweging_voorkant_foto_volgnummer_dashboard') | int
        - 1 %} {{ timestamps[current_index] }}
    alias: Datum op basis van volgnummer veranderen, bij max terug naar 1
  - action: input_text.set_value
    data:
      entity_id: input_text.beweging_voorkant_foto_file_dashboard
      value: >-
        {% set timestamps =
        states('input_text.beweging_voorkant_foto_timestamps').split(',') %} {%
        set current_index =
        states('input_number.beweging_voorkant_foto_volgnummer_dashboard') | int
        - 1 %} {% set current_date = now().strftime('%m%d') %}

        {% if current_index < timestamps | length %}
          {% set timestamp = timestamps[current_index] %}
          {% if timestamp | length > 1 %}
            {{ (current_index + 1) }}.jpg?v={{ timestamp }}
          {% else %}
            {{ (current_index + 1) }}.jpg?v={{ current_date }}
          {% endif %}
        {% else %}
          {{ (current_index + 1) }}.jpg?v={{ current_date }}
        {% endif %}
    alias: Filename op basis van volgnummer veranderen
alias: Go To Next Beweging Voorkant
description: ""
icon: mdi:content-save-move

This scripts causes the card on the dashboard moves to the next picture available on the dashboard.

Now, just create a dashboard card. I created a tabbed card, because that more beautiful. I have 3 tabs. One with the live feed, one with the movement picture card (carousel) and one is the live feed of my wall mounted tablet.

The script for the card is as follows:

type: custom:tabbed-card
tabs:
  - attributes:
      label: Live
    card:
      type: picture-entity
      entity: camera.tapo_voorkant_hd_stream
      camera_image: camera.tapo_voorkant_hd_stream
      camera_view: live
      show_state: false
      show_name: false
      name: Voorkant
      image: https://demo.home-assistant.io/stub_config/bedroom.png
  - attributes:
      label: Beweging
    card:
      type: custom:config-template-card
      variables:
        fotourl: >
          '/local/BewegingVoorkant/' +
          states['input_text.beweging_voorkant_foto_file_dashboard'].state +
          '?v=' + Date.now()
      entities:
        - input_text.beweging_voorkant_foto_file_dashboard
      card:
        type: picture-elements
        image: ${fotourl}
        elements:
          - type: image
            image: ${fotourl}
            style:
              top: 50%
              left: 50%
              width: 100%
              height: 100%
            tap_action:
              action: none
          - type: state-label
            entity: input_text.beweging_voorkant_foto_timestamp_dashboard
            style:
              top: 95%
              left: 50%
              transform: translate(-50%, -50%)
              color: white
              font-size: 12px
              background: rgba(0, 0, 0, 0.5)
              padding: 2px 4px
              border-radius: 4px
          - type: icon
            icon: mdi:arrow-right-bold
            style:
              top: 5%
              right: 5%
              transform: translate(50%, -50%)
              color: white
              background: rgba(0, 0, 0, 0.5)
              padding: 8px
              border-radius: 50%
            tap_action:
              action: call-service
              service: script.go_to_next_beweging_voorkant
  - attributes:
      label: Woonkamer
    card:
      show_state: false
      show_name: false
      camera_view: live
      type: picture-entity
      entity: camera.lenovo_tab_m10_3rd_gen
      image: https://demo.home-assistant.io/stub_config/bedroom.png
      name: Voorkant
      camera_image: camera.lenovo_tab_m10_3rd_gen

I first had the script being executed every 5 seconds, This way you have an automated carousel, but I wanted to change it to manual, so added the button.

I hope I helped someone with this idea. Please let me know if any questions. I can imaging the dutch names can be confusing for someone.

1 Like