Saving an url-defined image as a file

Assume there is an entity with entity_picture defined as

/api/media_player_proxy/media_player.kodi_rpi_1?token=b684340411dbbb3e884c394b311ce6a57c5d09d430d6bb6335bce3b4e04ab2ad&cache=b6e3f2f3fb9fbc95

or simply as

/local/images/image.jpg

How to save this as an image file in some directory?

For the first one you could create a generic camera and use the snapshot service.

That is already an image file in some directory. if you want to copy or move it use a shell command.

Thanks for a feedback.
Initial goal was to create a Logbook for a template sensor which has a dynamically changing “entity_picture”.
Particularly - I need a list of media content watched in Kodi (movies, music, …).
I can get a current “entity_picture” from some “media_player” entity & then use it for that template sensor (updated on every new played content).
But my attempt to see pictures in Logbook failed.
So I started looking for “ways”.

I speculated that may be storing these images locally in some folder may help me somehow.

Problem is that this address “/api/media_player_proxy/media_player.kodi_rpi_1?token=xxxx” is different for every played media content, i.e. not static. So I have no idea how to save these images in some kind of automation.

templates are allowed in the generic camera, so you should be able to point it to the media player url with the changing token. then do the snapshot when the content of that changes

Thanks for advising a Generic camera, started learning…

Generic camera was moved to UI from yaml, omg.
What a great joy to define templates in UI…

First step: testing a locally stored image.

Assume an image is stored in “/local/images/test/pink.jpg”.
Config for camera - a challenge with such a “convenient” UI:

Address is

http://localhost:8123/local/images/test/pink.jpg

We cannot use a “/local” address here:
изображение

Renamed the created camera entity to “camera.test_static_pink”.
Created a directory “snapshots” in “www/images/”.
Added permissions:

sudo chmod -Rc 777 www/images/snapshots

Added to “allowlist_external_dirs”: (update 26.11.24 - not needed since I already had “/config” in “allowlist_external_dirs”)

homeassistant:
  ...
  allowlist_external_dirs:
    ...
    - /config/www/images/snapshots

Failed to define a “/local” path here:

Called a service:

service: camera.snapshot
target:
  entity_id: camera.test_static_pink
data:
  filename: /config/www/images/snapshots/2.jpg

Failed to use a “/local” path here:

And got my jpg file.

did you get it all to work? wasn’t clear since you posted a lot of errors but then in the end you said you got your jpg.

if it helps, this is what i have in one of my generic cameras:

http://homeassistant.local:8123{{ state_attr('camera.ring', 'entity_picture') }}

and that attribute points to

/api/camera_proxy/camera.ring?token=xxxxxxx

of course i verified in my browser that the above url works fine… presume you did as well for your localhost address.

1 Like
  1. I got a jpg image, it is OK.
  2. Errors were reported to prevent users to repeat them. See, using a “/local” path is a common thing in HA settings; it is rather weird NOT to allow using “local” in some places.
1 Like

and url is like

/api/media_player_proxy/media_player.kodi_rpi_1?token=65d56d55d52a2ca689a05abf9016933986e736c555218742bae20c553de02a43&cache=b6e3f2f3fb9fbc95

I am testing now with

http://localhost:8123{{state_attr('media_player.kodi_rpi_1','entity_picture')}}

it creates a camera entity fine.
Now I am making a test automation to save snapshots on every new media played…

Will publish here a ready result.

1 Like

not sure if this helps you, but the snapshot can be made in local, and on the /media share if you want

      - service: camera.snapshot
        data:
          filename: >
            /media/snapshots/oprit_{{now().strftime('%Y_%m_%d_%H_%M')}}.jpg
        target:
          entity_id: camera.oprit
      - service: camera.snapshot
        data:
          filename: /media/snapshots/camera_oprit.jpg
        target:
          entity_id: camera.oprit
      - service: camera.snapshot
        data:
          filename: /config/www/images/snapshots/camera_oprit.jpg
        target:
          entity_id: camera.oprit

this creates a file for each individual motion detection, one fixed named file that is overwritten (so we can use it in a template image, and also a fixed one in the /local folder

camera:

  - platform: local_file
    name: Snapshot Oprit
    file_path: /media/snapshots/camera_oprit.jpg

##########################################################################################
# Templates
##########################################################################################

template:

  - trigger:

      - platform: state
        entity_id:
          - binary_sensor.oprit_vehicle_detected
          - binary_sensor.oprit_person_detected
        to: 'on'
        for:
          seconds: 4

      - platform: event
        event_type: delayed_homeassistant_start
      - platform: event
        event_type: event_template_reloaded

    image:

      - unique_id: last_snapshot_oprit_camera
        url: !secret snapshot_camera_oprit

the secret is an url in the form of:

snapshot_camera_oprit: http://ha.local:<port>/local/images/snapshots/camera_oprit.jpg

Thanks for the example.

As I already explained - I failed to use “local” here:

and then failed to add to “allowlist” here:

That is why I had to use a “/config” method.

could it be the path you set? I have only this:

homeassistant:
  packages: !include_dir_named packages
  allowlist_external_dirs:
    - /config
    - /media

1 Like

No…
Seems that “local” cannot be used here.

if you test with the dev container, the camera will have an entity picture, but the snapshot will not be saved.

It seems to be properly saved.
Yes, I am using Docker.
Ofc I am making 1st steps here - so could easy miss smth.

Well, step two: testing with an “entity_picture” from Kodi

Create camera entity:


with URL

http://localhost:8123{{state_attr('media_player.kodi_rpi_1','entity_picture')}}

Rename it to “camera.test_kodi_rpi_1”.
Create a helper:

input_text:
  kodi_last_image:
    max: 255

which is used in automation to save the latest “entity_picture”.
Create an automation:

alias: "test: Kodi: store images"
id: test_kodi_store_images
mode: single

trigger:
  - platform: state
    entity_id: media_player.kodi_rpi_1
    to:
      - playing
      - idle
      - paused
action:
  - choose:
      - conditions:
          - condition: template
            value_template: >-
              {{ trigger.to_state.state == 'idle' or
                 trigger.to_state.state == 'paused' }}
        sequence:
          - service: input_text.set_value
            data:
              value: >-
                {% if trigger.from_state.attributes.entity_picture is defined -%}
                  {{ trigger.from_state.attributes.entity_picture }}
                {%- else -%}
                  'empty'
                {%- endif %}
            target:
              entity_id: input_text.kodi_last_image

      - conditions:
          - condition: template
            value_template: >-
              {{ trigger.to_state.state == 'playing' }}
        sequence:
          - if:
              - condition: template
                value_template: >-
                  {{ trigger.to_state.attributes.entity_picture != states('input_text.kodi_last_image') }}
            then:
              - service: camera.snapshot
                target:
                  entity_id: camera.testing_kodi_rpi_1
                data:
                  filename: >-
                    {% set FILENAME = (now()|string).split('.')[0].replace('-','').replace(' ','').replace(':','') -%}
                    /config/www/images/snapshots/{{FILENAME}}.jpg

Here:
1.When a player is paused or stopped - the latest image is saved in input_text.
2.When a player is started - compare a current image with that previously saved image: if not same → save as a file.

This is done to prevent consecutive storing same image in cases when:
– media is paused
– a music album is played

Result files have names like “YYYYMMDDHHMMSS”.

Plus - add a periodical purging old files in another automation, smth like

service: delete.files_in_folder
data:
  folder: "/config/www/images/snapshots"
  time: >-
    {{ VALUE_PURGE_KEEP_DAYS | int(default=1) * 86400 }}
  no_warn: true

Goal - learning. See not a lot of practical need.

fwiw, Ive also learnt…
cant use shell_commands on any other than /config.

so, I moved my timed snapshots to the /local aka /www folder.

      - service: camera.snapshot
        data:
          filename: >
            /config/www/snapshots/timed/oprit_{{now().strftime('%Y_%m_%d_%H_%M')}}.jpg

changed the shell_command to

shell_command:

  delete_snapshots: >
    find /config/www/snapshots/timed/ -mtime +{{states('input_number.ouder_dan')|int(600)}} -exec rm {} \;

and can add that service: shell_command.delete_snapshots to the automation, or a button in the dashboard:

  - type: button
    tap_action:
      action: call-service
      service: shell_command.delete_snapshots
    name: Delete snapshots
    icon: mdi:delete-forever

execution of the delete command is immediate like this, so, if you need extra options, change the shell_command

And no need for yet another CC that was not maintained for 2 years+

Agree, thinking about using a stock “shell_command”.
Never used it before, so 1st chose that CC way.

only issue with that (the /www option) is that if you do backups and have a lot of camera snapshots, those are all stored in the backup too…
it was the main reason I chose the /media folder before, so I could exclude that from the backups.

Now, I can no longer do that, so I have to make a choice… not sure which is best yet

I am making backups manually ((
Lots to learn & implement in HA, no time for all these toys…