DIY Interactive Photo Frame with Pop Up Cards, Music, Camera Feeds etc

I recently salvaged a screen from a broken laptop that my neighbor wanted to give for recycling.
I wanted to build a Photo Frame that would display a slideshow background with personal images and also popup cards with any useful information regarding my home status.

Here’s a photo from the early stages of this project.

Hardware

  • Sony VAIO LTN154XB-L01 screen
  • External controller board for the screen
  • A sonoff basic with ESPHome, to remotely turn on and off the screen via homeassistant.
  • A Xiaomi Mi Box S Android TV Box which runs the Fully Kiosk Browser for the Home Assistant part, and also supports Google Play Apps such as Youtube or even Netflix.
  • A pair of external speakers connected to the board’s audio jack output (for Radio, YouTube etc).
  • An actual wooden frame that my father built to match the screen’s dimensions.

Main Custom Cards Used

Some usage examples

  • Image slideshow using a very simple python script to cycle through personal images, that I later load into HA using the local_file camera component.
  • Clock with the current weather icon (I am using wunderground as provider)
  • Camera pop-ups when movement is detected
  • Various alerts using the auto-entities card (for example, high energy consumption, bad air quality, weather alerts, smoke alarms etc)
  • A card that shows the remaining time of our cooking countdown timer.
    Plus using the media_player component of browser-mod an alarm sound is played when the timer runs out.
  • Of course the possibilities are limitless, it all depends on your setup and needs.

Lovelace setup

I have created a dedicated Lovelace Dashboard for the Frame.
The lovelace card, is a Picture-Elements card in Panel Mode.
See an example here.

Screenshots

A regular view.

A Camera Pop-up

The Kitchen Timer

Some Alert examples

14 Likes

Looks nice, do you use a seperate home assistant setup for the photo-frame or same instanance with seperate love-lace dashboard?
and what tablet is used, hardware specs? I have a iPad2 with HDMI output, but think it is to old to run Hass in the browser

Hello, I only have one instance of home assistant.
Among my other tabs, I have one dedicated to the photo-frame.
(edit: Now there is a dedicated Lovelace dashboard).

It displays the above picture-element card in panel mode.
However, I have created a separate user specifically for the frame.
Then, using the custom-header plugin I have set up this specific user to use kiosk mode with the default tab being the slideshow one.
As a result, the frame always loads this specific tab without the header or the sidebar being visible.
(edit: custom-header no longer exists).

As for the tablet, it is just a very cheap old Android tablet. Specwise it has just 1 gig of RAM and a 4 core CPU at 1.3 GHz.
(edit: now i’ve switched to an android tv box).

However, If you’re interested in bulding something similar I would recommend using an Android TV Box instead, something like the MiBox S.
Besides the whole home assistant stuff, it will give the ability to also easily watch youtube, netflix or anything else on the frame.

Really nice project. Very inspiring. Thanks for sharing!

1 Like

@valvex

The image slideshow using a very simple python script to cycle through some images, that I later load into HA using the local_file camera component.

Can you please share the python code for this?

Thanks!

@jonnyrider Sure. Here’s the script.

import random, os
import shutil
path = (r'C:/Users/Administrator/Pictures/Slideshow/')
random_image = random.choice([x for x in os.listdir(path)])
picture = os.path.join(path  + random_image)
shutil.copyfile(picture, r'C:\Users\Administrator\AppData\Roaming\.homeassistant\www\slide.jpg')
exit()

It picks a random image from the Slideshow folder and then copies it as slide.jpg in the www folder.

The script is integrated in HA as a shell command

slideshow: 'C:\Users\Administrator\AppData\Roaming\.homeassistant\python_scripts\slideshow.py'

And is run with an automation every 3 minutes.

- id: auto_slideshow
  alias: auto_slideshow
  description: ''
  trigger:
  - minutes: /3
    platform: time_pattern
  condition: []
  action:
  - data: {}
    service: shell_command.slideshow

Afterwards, the image is picked by the local_file camera integration and it’s displayed in the frontend with a picture-entity card.

- platform: local_file
  name: Slide
  file_path: 'C:\Users\Administrator\AppData\Roaming\.homeassistant\www\slide.jpg'
4 Likes

@valvex would love to see your code for the dashboard its self, do you still have it? I’m trying to build something like this myself.

Sure here’s an example @tamarisk

### the card is a picture-elements card in panel mode ###
type: picture-elements
image: /local/720.jpg
elements:
### photo slideshow ###
  - aspect_ratio: 60%
    type: custom:hui-element
    card_type: picture-entity
    entity: camera.slide
    show_name: false
    show_state: false
    style:
      height: 100%
      left: 50%
      top: 50%
      width: 100%
    
### camera movement example ###
  - type: conditional
    conditions:
      - entity: binary_sensor.garage_movement
        state: 'on'
    elements:
      - type: picture-entity
        entity: camera.garage
        camera_view: live
        aspect_ratio: 80%
        style:
          height: 65%
          left: 60%
          top: 40%
          width: 60%
          
### weather and time ###
  - type: custom:paper-buttons-row
    style:
      left: 12%
      width: 300px
      bottom: 0px
    buttons:
      - image: |
          {{ state_attr('sensor.weather_now','entity_picture') }}
        entity: sensor.time
        layout: icon|state
        tap_action:
          action: none
        style:
          state:
            color: '#f2f2f2'
            font-size: 70px
            text-shadow: 4px 4px 3px black
          icon:
            width: 70px
            height: 70px
            
### meteoalarm active icon ###           
  - type: custom:paper-buttons-row
    style:
      left: 5%
      width: 300px
      bottom: 20px
    buttons:
      - image: |
          {% if is_state('binary_sensor.meteoalarm','on') %}
          /local/hazard.png
          {% endif %}
        layout: icon
        tap_action:
          action: none
        style:
          icon:
            width: 30px
            height: 30px
            border-radius: 0px
            
### kitchen countdown timer ###
  - type: conditional
    conditions:
      - entity: timer.countdown
        state: active
    elements:
      - type: custom:button-card
        entity: timer.countdown
        show_state: true
        show_entity_picture: true
        entity_picture: /local/blueh.gif
        show_name: false
        size: 65px
        styles:
          state:
            - font-size: 40px
            - line-height: 2
        style:
          border-radius: 15%
          height: 120px
          left: 13%
          width: 200px
          bottom: 16%
          
### auto-entities card for various alerts ###          
  - style:
      left: 50%
      width: 400px
      top: 15%
    type: custom:auto-entities
    show_empty: false
    card:
      show_header_toggle: false
      type: entities
    filter:
      exclude:
        - state: unavailable
      include:
      ### examples ###
        - entity_id: sensor.home_iaq_level
          state: Inadequate
          options:
            name: Κακή ποιότητα εσωτ. αέρα
            entity: sensor.empty
            icon: mdi:weather-windy
        - entity_id: sensor.fridge_temperature
          options:
            name: Ψυγείο
            icon: mdi:fridge-outline
          state: '>11'
        - entity_id: binary_sensor.low_diesel
          options:
            name: Πετρέλαιο
            entity: sensor.diesel_litres
            icon: mdi:gas-station
          state: 'on'
        - entity_id: binary_sensor.network_smoke
          options:
            name: Ανιχν. Καπνού
            icon: mdi:fire
            type: custom:template-entity-row
            state: ' '
            tap_action:
              action: none
          state: 'on'

So for anyone wondering, this is how I used the script from @valvex on Synology, inside Docker, after installing pyscript in HACS.

It only took me about 8 hours to figure it. This being the first time messing with python, I think that’s not too bad…

slideshow.py file placed in /config/pyscript

@service
def slideshow():
	import random
	import os
	import shutil
	path = '/Completed' #my custom folder to watch
	random_image = random.choice([x for x in os.listdir(path)])
	image_path = '{}/{}'.format(path,random_image)
	shutil.copy2(image_path, '/config/www/slide.jpg')

What caused me most problems was the / (slash) between the path folder and the actual file to copy

6 Likes

@valvex Very well done looks good :+1:t3:
Do you think you could make this touch screen?

This is so close to what I’m trying to accomplish. I want a rotating background as you have, but every time I try to add conditional media card it doesn’t display over the initial “slide” background pic. It just shows up as a tiny icon on the far left corner of my screen. I know it’s something simple I’m missing. Any ideas?

> type: picture-elements
> image: /local/slide.jpg
> elements:
>   - aspect_ratio: 60%
>     type: custom:hui-element
>     card_type: picture-entity
>     entity: camera.slide
>     show_name: false
>     show_state: false
>     style:
>       height: 100%
>       left: 50%
>       top: 50%
>       width: 100%
>   - type: conditional
>     conditions:
>       - entity: media_player.entire_house_2
>         state: playing
>     elements:
>       - type: custom:mini-media-player
>         entity: media_player.entire_house_2
>         artwork: full-cover
>         hide:
>           power: true
>           volume: true
>           icon: true
>           info: true
>           progress: true
>           controls: true
>           name: true
>     info: short

@AttemptingZen You have to manually position your card by passing the style object.

for example,

   - type: conditional
     conditions:
       - entity: media_player.entire_house_2
         state: playing
     elements:
       - type: custom:mini-media-player
         entity: media_player.entire_house_2
         artwork: full-cover
         hide:
           power: true
           volume: true
           icon: true
           info: true
           progress: true
           controls: true
           name: true
        style:
          height: 65%
          left: 60%
          top: 40%
          width: 60%

Have a look here.

@valvex Awesome! I still gotta work my way around it, but I’m getting the gist, and have it showing up. Thanks! Great work on this, I’m using a tablet on a wireless charger, but love the idea of it doubling as a picture frame when not actively being used.

Hey,
It’s a cool project. Thanks for sharing it.
I started to implement it on my system.
Here is my lovelace config:

type: picture-elements
image: /local/nfts/Pavo_Aura_2022-02-01.jpg
elements:
  - type: custom:hui-element
    card_type: picture-entity
    entity: camera.nft_slide
    show_name: false
    show_state: false
    aspect_ratio: 60%
    style:
      height: 100%
      left: 50%
      top: 50%
      width: 100%

Unfortunately, the picture height doesn’t 100%, i have a free space on bottom.


Can someone help me?

I modified the config:

type: picture-elements
image: /local/nfts/Pavo_Aura_2022-02-01.jpg
aspect_ratio: 100%
style:
  height: 100%
  left: 50%
  top: 50%
  width: 100%
elements:
  - type: custom:hui-element
    card_type: picture-entity
    entity: camera.nft_slide
    show_name: false
    show_state: false
    aspect_ratio: 100%
    style:
      height: 100%
      left: 50%
      top: 50%
      width: 100%

Now, i see the whole picture :slight_smile: I think, i need to resize my images.

@gyengus Also remember to change the view type to “Panel”.

Thank you. I did it before.

You are a hero! Thank you. I was having such a hard time trying to figure out how to make this work with pyscript instead of a shell command. Can’t thank you enough for the time and effort you put into this, and for sharing it with the rest of us!

Thank you for all your hard work you put into this! This has helped me tremendously! I was finally able to get my TV’s showing what I want, and not what the chromecast thinks I want!

I do have a question about this though…although I know this was made years ago, I’m trying to use this same technique to cast a dashboard to my TV. Everything works as expected, except the hui-element. This works correctly on my dashboards that are running either fully kiosk, HA app, or on the web, but when casting, the hui-element does not appear.
Any ideas on how to resolve this?

edit: got this to work by removing the custom:hui-element and changing it to just type: image. This then followed all the same rules that your custom:hui-element follows in terms of aspect ratio, style, etc. but now is just considered an image. Only thing left to figure out is how to refresh the image consistently. I’ll update if I figure it out!

edit (2): All is working properly, and updating as expected. So, anyone who is trying to get this to work on a chromecast using a raspberry pi setup (pyscript, not shell) this is the element I added to the dashboard:

  - type: image
    entity: camera.slide
    camera_image: camera.slide
    aspect_ratio: 80%
    style:
      left: 50%
      top: 50%
      width: 100%
      height: 100%

I also have pyscript running in order to update the slideshow, this is using the code that @GKHerping kindly added here.

I’m also using the code that the OP provided to update the “slide.jpg” image by pulling images that I have now stored locally on my HA instance in ‘/config/www/images/slideshow’.
OP Slideshow Config setup

Hopefully this helps someone else!