Turn a Google Photos shared album or local/NAS folder into a fully controllable Home Assistant camera slideshow.
Clean. Flexible. Fully runtime configurable. Designed for dashboards.
Album Slideshow creates a camera entity that automatically cycles through images from:
- Google Photos shared albums
- Local folders
- NAS mounted directories
All behavior is exposed as Home Assistant entities. Adjust everything live without YAML edits or restarts.
- Auto advancing camera entity
- Configurable slide interval
- Manual next slide button
- Album refresh control
- Google Photos shared albums
- Local folder paths
- NAS mounted directories
- Optional recursive scanning
- Reads EXIF capture date (and
OffsetTimeOriginalwhen present) so date-filter modes work for local files too - Surfaces EXIF GPS as
latitude/longitudecamera attributes - Optional reverse geocoding via OpenStreetMap Nominatim for a human-readable
location(e.g."Lisbon, Portugal"); per-album opt-out in the integration's Configure dialog
- Date filter: last 7 / 30 / 365 days, this month, this year, On this day memories
- Order modes: random, album order, newest taken, oldest taken, newest added, oldest added
- Capture date and upload date exposed as camera attributes (with paired-photo support)
- Pause switch holds the current slide indefinitely
- Manual "Next slide" button still works while paused
- Survives Home Assistant restarts
- Smooth slide transitions rendered in the browser, so they stay buttery even on lower-end hardware
- Effects:
random,none,fade,slide-left,slide-right,slide-up,slide-down,wipe-left,wipe-right,zoom randompicks a different effect per slide (and avoids repeating the previous one)- Configurable duration and CSS easing
- Aspect ratio + fill mode inheritance from the camera entity (cover / contain / blur backdrop)
| Mode | Behavior |
|---|---|
| Pair | Display two mismatched images side by side |
| Single | Render single image using selected fill mode |
| Avoid | Skip mismatched images |
| Mode | Behavior |
|---|---|
| Blur | Image over blurred background |
| Cover | Crop to fill canvas |
| Contain | Fit inside canvas with bars |
- Configurable aspect ratio such as 16:9, 4:3, 1:1, 9:16
- Shuffle or album order
- Pair divider size/color control
The following entities allow you to adjust slideshow behavior without restarting Home Assistant.
| Entity Type | Name | Default | Accepted Values | Description |
|---|---|---|---|---|
| Number | Slide interval | 60 | Any positive integer (seconds) | Time between slides |
| Number | Album refresh | 24 | Any positive integer (hours) | How often album contents refresh |
| Number | Pair divider size | 8 | 0-64 (px) | Width of divider between paired images |
| Number | Image cache size | 75 | 50-1000 (MB) | Memory budget for downloaded image data (per album) |
| Select | Fill mode | blur | blur, cover, contain | How images fill the canvas |
| Select | Orientation mismatch | pair | pair, single, avoid | Handling of portrait and landscape mismatch |
| Select | Order mode | random | random, album_order, newest_taken, oldest_taken, newest_added, oldest_added | Slide ordering behavior |
| Select | Aspect ratio | 16:9 | 16:9, 4:3, 1:1, 9:16, and more | Canvas aspect ratio |
| Select | Max resolution | 4K (2160p) | 480p, 720p, 1080p, 1440p, 4K (2160p), original | Cap output resolution by short edge; use original to render at native size |
| Select | Date filter | off | off, last_7_days, last_30_days, last_365_days, this_month, this_year, on_this_day | Restrict the slideshow to a date window based on photo capture date |
| Text | Pair divider color | #FFFFFF | Hex, named colors, transparent | Divider color between paired images |
| Switch | Pause slideshow | off | on / off | Hold the current frame; advances pause until turned off |
Album Slideshow Camera is available in HACS.
- Download the latest release
- Copy
custom_components/album_slideshow
into
config/custom_components/
- Restart Home Assistant
- Add the integration from Devices & services
- Open a shared Google Photos album
- Copy the shared link such as
https://photos.app.goo.gl/... - Add the integration
- Paste the link
Use any folder accessible to Home Assistant.
Helpful path mappings:
| Input | Resolves To |
|---|---|
/local/... |
/config/www/... |
media/... |
/media/... |
media/local/... |
/media/... |
For NAS:
- Mount it first
- Use the mounted path
For local-folder entries the integration reads EXIF metadata in the background after every refresh:
- Capture date —
DateTimeOriginalis preferred; if missing, the file's modification time is used so date-based ordering still works for screenshots and scans. WhenOffsetTimeOriginalis present (most modern cameras and phones) it is honoured; otherwise the timestamp is interpreted as the host's local time. - GPS coordinates —
GPSLatitude/GPSLongitudeare exposed as thelatitude/longitudecamera attributes.(0, 0)"null island" stamps are ignored. - Reverse-geocoded location — by default the integration calls the
public Nominatim (OpenStreetMap)
service to translate coordinates into a human-readable label such as
"Lisbon, Portugal", exposed as thelocationattribute. Coordinates are rounded to ~100 m before lookup and the answer is cached on disk, so the same neighbourhood is only ever fetched once. Nominatim's free-tier policy (1 req/sec, identifying User-Agent) is respected.
Privacy / opt-out: if you'd rather not send any coordinates to
OpenStreetMap, open Settings → Devices & Services → Album Slideshow → your
album → Configure and turn off Reverse-geocode EXIF GPS coordinates.
The latitude/longitude attributes still work; only the location
label is suppressed. The opt-out is per-album.
Progress for both phases is exposed as the Enrichment progress
diagnostic sensor (percent complete, with phase, exif_done,
geocode_done etc. as attributes).
Each album you configure creates the following entities in Home Assistant.
| Entity | Description |
|---|---|
| Slideshow camera | The live slideshow feed rendered according to your current settings |
| Entity | Description |
|---|---|
| Next slide | Immediately advances to the next image |
| Refresh album | Re-fetches album contents |
| Entity | Source | Description |
|---|---|---|
| Album title | All | Title of the source album |
| Media count | All | Number of images currently available |
| Image cache usage (diagnostic) | All | Current download cache size in MB |
| Enrichment progress (diagnostic) | Local folder | Percent of files whose EXIF/GPS has been read (and, when enabled, reverse-geocoded). Attributes include phase, exif_done/exif_total, geocode_done/geocode_total. |
The slideshow camera exposes per-frame metadata as attributes (use with state_attr('camera.x', '<name>') in templates):
| Attribute | Type | Description |
|---|---|---|
album_title |
string | Title of the source album |
media_count |
int | Photos in the active playlist (after date filter) |
media_count_total |
int | Total photos available before filtering |
current_index |
int | Index of the current slide |
current_filename |
string | null | Source filename when known |
current_url |
string | null | URL of the current slide |
current_is_portrait |
bool | null | Orientation of the current slide |
captured_at |
string | list | null | ISO-8601 capture date. List of [primary, partner] when paired (top/left first). For local files this is read from EXIF (or the file's mtime as a fallback). |
captured_at_primary |
string | null | Capture date of the primary image only |
uploaded_at |
string | null | ISO-8601 date when added to the album (Google Photos only) |
byte_size |
int | null | Original file size in bytes (Google Photos only) |
latitude |
float | null | EXIF GPS latitude in decimal degrees (local folder only) |
longitude |
float | null | EXIF GPS longitude in decimal degrees (local folder only) |
location |
string | null | Reverse-geocoded label (e.g. "Lisbon, Portugal"). Empty when reverse-geocoding is disabled or has not yet completed for this file. |
caption_frames |
list | Structured per-image caption metadata: one entry for a normal slide, two (top/left first) for a pair. Each entry has captured_at, location, latitude, longitude. Used by the card's caption overlay. |
pair_orientation |
string | null | How a paired slide is split: horizontal (left/right) or vertical (top/bottom). null for single slides. |
paused |
bool | Whether the slideshow is paused |
date_filter |
string | Active date filter mode |
frame_id |
int | Monotonic counter incremented on every committed slide. Used by the card to detect new frames |
The integration ships with a custom Lovelace card that does the slide-to-slide transition entirely in the browser. The server only renders one still per slide change; the card cross-fades in CSS, which the browser composites on the GPU. Result: a smooth dissolve on a Pi 4, even with several albums on screen.
The card is registered automatically when the integration loads; you do not need to add it as a HACS frontend repository or configure a Lovelace resource manually. After installing or upgrading, hard-refresh the dashboard once (Ctrl+Shift+R) so the browser picks up the script.
A visual editor is available - pick Album Slideshow from the card picker in Lovelace and the form will appear automatically.
type: custom:album-slideshow-card
entity: camera.album_slideshow_living_roomtype: custom:album-slideshow-card
entity: camera.album_slideshow_living_room
transition: random # random | none | fade | slide-left
# | slide-right | slide-up | slide-down
# | wipe-left | wipe-right | zoom
duration: 800 # ms; CSS transition length
easing: ease-in-out # any CSS timing function (ease, linear, cubic-bezier(...))
aspect_ratio: 16/9 # CSS aspect-ratio value (16/9, 4/3, 1/1, auto)
fit: auto # auto | cover | contain
# auto inherits the camera's fill_mode (cover / contain / blur)
background: '#000' # color shown behind contained images
tap_action: none # none | more-info
caption: # overlay the photo's date and/or location
show: [date, location] # any of: date, location (order = display order)
position: bottom-left # top/center/bottom + -left/-center/-right, or center
date_format: medium # medium | full | month_year | year | numeric
# | weekday | relative, or a custom token string
# (YYYY, MMMM, MMM, MM, M, DD, D, dddd, ddd)
per_image: true # caption each half of a portrait pair separately
color: '#ffffff' # any CSS color
font_size: 14px # any CSS size
font_weight: medium # light | normal | medium | semibold | bold
shadow: true # drop shadow for readability on bright photostransition: randompicks a different effect per slide and avoids repeating the previous one.fit: autoreads the camera'sfill_modeattribute.blurrenders the slide ascontainplus a blurred backdrop layer behind it.- Caption overlay: omit the
caption:block (or setshow: []) to disable it. The date comes fromcaptured_at(EXIF or file mtime);locationcomes from EXIF reverse-geocoding and is simply skipped when a photo has none, so Google Photos slides show only the date. On a portrait pair,per_image: trueanchors each photo's own date/location to its half; set it tofalsefor a single caption over the whole frame. date_formataccepts a preset name or a custom token string. Presets are locale-aware (they follow your Home Assistant language). Example custom format:'D MMMM YYYY'->29 July 2023.- Every slide commit increments the camera's
frame_idattribute. The card cache-busts the camera proxy URL with that value, so the browser refetches a fresh JPEG on every change instead of serving a stale cached image. - If the entity is unavailable, the card shows a "Camera not ready" placeholder.
To remove visible spacing between paired images:
- Set Pair divider color to
transparent - Keep divider size greater than
0
Also accepted values:
noneclearrgba(0,0,0,0)transperantcommon misspelling
When transparency is used, the integration outputs PNG to preserve alpha.
- Public shared albums only (link sharing must be enabled)
- Up to 20,000 photos per album
- Videos are skipped
- Internet connection required
- Relies on Google's public web endpoints; if Google changes them, the integration falls back to a 300-photo limit until the scraper is updated
- The last successful album fetch is cached to disk; if a refresh fails or returns no photos, the slideshow keeps running with the cached list
- Images only
- No video support
If you enjoy this card and want to support its development: