Automatically sync artwork from a local folder to Samsung Frame TVs using Docker.
Docker Hub: turley/frame-tv-artwork-sync
- Sync artwork to one or multiple Frame TVs
- Automatic periodic sync (configurable interval)
- Auto-cleanup: removes images from TVs when deleted locally
- Persistent file tracking to avoid re-uploading
- Configurable matte/border style
- Slideshow control: preserve TV settings or override with custom interval/type
- Optional solar-based brightness adjustment using sun position and atmospheric modeling
- Manual brightness control with fixed values
- Skips offline TVs and continues syncing others
- Skips TVs not in art mode (e.g., when watching content via HDMI)
- Lightweight Alpine-based Docker image
- Download docker-compose.yml
- Create folders:
mkdir -p artwork tokens
- Add your images to the artwork folder
- Edit
docker-compose.ymlwith your TV IP addresses - Run:
docker-compose up -d
On first run, approve the connection on each TV when prompted. Tokens are saved for future use.
# Create folders
mkdir -p artwork tokens
# Run container
docker run -d \
--name frame-tv-sync \
--restart unless-stopped \
-e TV_IPS="192.168.1.100,192.168.1.101" \
-e SYNC_INTERVAL_MINUTES="5" \
-v ./artwork:/artwork \
-v ./tokens:/tokens \
turley/frame-tv-artwork-syncAll settings are configured via environment variables:
| Variable | Description | Default |
|---|---|---|
TV_IPS |
Comma-separated TV IP addresses (required) | - |
SYNC_INTERVAL_MINUTES |
How often to sync (in minutes) | 5 |
MATTE_STYLE |
Border style (see Matte Styles below) | none |
SLIDESHOW_ENABLED |
Enable slideshow (true/false) - overrides TV settings if set | (unset) |
SLIDESHOW_INTERVAL |
Slideshow interval in minutes (use values supported by your TV model) | 15 |
SLIDESHOW_TYPE |
Slideshow type: shuffle or sequential |
shuffle |
BRIGHTNESS |
Manual brightness override (use values supported by your TV model, commonly 0-10 or 0-50) | (unset) |
SOLAR_BRIGHTNESS_ENABLED |
Enable automatic solar-based brightness adjustment (true/false) | (unset) |
LOCATION_LATITUDE |
Latitude for solar calculations (e.g., 42.3601) | - |
LOCATION_LONGITUDE |
Longitude for solar calculations (e.g., -71.0589) | - |
LOCATION_TIMEZONE |
Timezone name (e.g., America/New_York) | UTC |
BRIGHTNESS_MIN |
Minimum brightness when sun is below horizon | 2 |
BRIGHTNESS_MAX |
Maximum brightness if sun were at zenith (90°) | 10 |
REMOVE_UNKNOWN_IMAGES |
Remove images from TV that aren't in the artwork folder (true/false) | false |
AUTO_OFF_TIME |
Time to turn off TVs in art mode (24-hour format, e.g., 22:00) |
(unset) |
AUTO_OFF_GRACE_HOURS |
Hours after AUTO_OFF_TIME to keep trying to turn off TVs |
2 |
Default Behavior (no override variables set):
- When images are added or removed during sync, the script preserves and restores your TV's current slideshow settings
- If no images change, slideshow settings are not modified
Override Behavior (if any slideshow variable is set):
- When images are added or removed during sync, the script applies slideshow settings from environment variables
- If you set
SLIDESHOW_ENABLED,SLIDESHOW_INTERVAL, orSLIDESHOW_TYPE, all slideshow variables use defaults for any unset values - If no images change, slideshow settings are not modified
Note: Slideshow interval values vary by TV model year. Common values include 3, 15, 60, 720, 1440 minutes. Check your TV's slideshow settings menu to see which intervals are supported by your specific model.
Manual Brightness:
- Set
BRIGHTNESSto a fixed value (commonly 0-10 or 0-50 depending on your TV model) - Applied every sync run when set
Solar-Based Brightness (Automatic):
- Enable
SOLAR_BRIGHTNESS_ENABLED=trueto automatically adjust brightness based on sun position - Requires
LOCATION_LATITUDE,LOCATION_LONGITUDE, andLOCATION_TIMEZONE - Set
BRIGHTNESS_MIN(brightness when sun is below horizon) andBRIGHTNESS_MAX(brightness for sun at zenith) - Brightness is calculated every sync run using physics-based atmospheric air mass model
- Uses Kasten-Young formula to model how sunlight intensity changes through the atmosphere
- Takes precedence over manual
BRIGHTNESSsetting when enabled
Example Solar Setup:
SOLAR_BRIGHTNESS_ENABLED=true
LOCATION_LATITUDE=42.3601
LOCATION_LONGITUDE=-71.0589
LOCATION_TIMEZONE=America/New_York
BRIGHTNESS_MIN=2
BRIGHTNESS_MAX=10With this configuration (example for Boston, MA):
- At night (sun below horizon): brightness = 2
- At solar noon in summer (sun ~71°): brightness ≈ 7
- At solar noon in winter (sun ~24°): brightness ≈ 6
- At sunrise/sunset (sun near 0°): brightness = 2
Testing Solar Brightness:
To preview how brightness will change throughout the year at your location:
# Set your location variables
export LOCATION_LATITUDE=42.3601
export LOCATION_LONGITUDE=-71.0589
export LOCATION_TIMEZONE=America/New_York
export BRIGHTNESS_MIN=2
export BRIGHTNESS_MAX=10
# Run in test mode
python sync_artwork.py --test-solarThis displays hourly brightness levels for key solar positions (March Equinox, June Solstice, December Solstice), helping you verify your settings before deploying.
REMOVE_UNKNOWN_IMAGES - Controls whether the script removes images from your TV that aren't in your local artwork folder.
Default behavior (REMOVE_UNKNOWN_IMAGES=false or unset):
- Preserves any images already on the TV that were uploaded manually or before the script started tracking
- Only manages images that the script has uploaded
- Logs a warning when unknown images are detected, listing their content IDs
When enabled (REMOVE_UNKNOWN_IMAGES=true):
- Removes any images from the TV that aren't in your local artwork folder
- Ensures your TV only displays images from your synced collection
- Useful for maintaining a "clean slate" that exactly matches your local folder
AUTO_OFF_TIME - Automatically turn off TVs at a specific time, but only when they're in art mode. This feature only works on some Frame TV models.
This feature is useful when you want TVs to turn off at night but only if they're displaying art. If someone is actively watching the TV, it won't be interrupted.
How it works:
- Set
AUTO_OFF_TIMEto a time in 24-hour format (e.g.,22:00for 10 PM) - The script checks during each sync if the current time is within the turn-off window
- If a TV is in art mode during this window, it will be turned off after the sync completes
- TVs not in art mode (e.g., watching HDMI content) are left alone
Grace period:
AUTO_OFF_GRACE_HOURSdefines how long afterAUTO_OFF_TIMEthe script will keep trying to turn off TVs- Default is 2 hours, so if
AUTO_OFF_TIME=22:00, it will try until midnight - After the grace period ends, the script stops attempting to turn off TVs until the next day
- This handles cases where a TV wasn't in art mode at the exact off time
Example setup:
AUTO_OFF_TIME=22:00
AUTO_OFF_GRACE_HOURS=2
LOCATION_TIMEZONE=America/New_YorkWith this configuration:
- Starting at 10 PM (in your timezone), TVs in art mode will be turned off after sync
- If a TV is being used at 10 PM but returns to art mode by 11 PM, it will be turned off then
- After midnight, no turn-off attempts are made until the next day's 10 PM
Note: LOCATION_TIMEZONE is required for this feature to work correctly.
Advanced knobs for the TV WebSocket connection. Defaults work for most setups; tune these only if you're seeing flaky connects, repeated re-auth prompts, or pairing failures.
| Variable | Description | Default |
|---|---|---|
CONNECTION_TIMEOUT |
WebSocket timeout (seconds) for normal connects with an existing token | 10.0 |
AUTH_TIMEOUT |
WebSocket timeout (seconds) during first-time pairing (allows time for approval on the TV) | 30.0 |
KEEPALIVE_INTERVAL |
Seconds between keepalive pings while waiting for the next sync (must be >= 1) | 60 |
CONNECT_MAX_ATTEMPTS |
Retry budget for connect errors (channel drops, transient failures). Excludes pairing retries. | 3 |
CHANNEL_DROP_RETRY_DELAY |
Seconds to wait between connect retries after a channel drop | 3.0 |
PAIRING_MAX_RETRIES |
Retries while waiting for first-time pairing approval on the TV | 5 |
PAIRING_RETRY_DELAY |
Seconds between pairing retries (sized for human reaction time) | 5.0 |
The keepalive ping prevents some Frame TVs from prompting for re-authentication between syncs. If you have a flaky network or notice repeated re-auth prompts, you can increase PAIRING_MAX_RETRIES or shorten KEEPALIVE_INTERVAL.
Supported Formats: JPEG, JPG, PNG
Recommended Specs:
- Resolution: 3840 x 2160 pixels (4K) for 43"+ TVs, 1920 x 1080 for 32" TVs
- Aspect ratio: 16:9
- File size: Under 20MB
- Color space: sRGB
Matte styles combine a border style with a color in the format {style}_{color}, or use none for no border.
Available Styles:
modernthin, modern, modernwide, flexible, shadowbox, panoramic, triptych, mix, squares
Available Colors:
black, neutral, antique, warm, polar, sand, seafoam, sage, burgandy, navy, apricot, byzantine, lavender, redorange, skyblue, turquoise
Examples:
shadowbox_polar- shadowbox border in polar colormodern_apricot- modern border in apricot colorflexible_antique- flexible border in antique colornone- no border (full screen)
To test without Docker:
- Install dependencies:
pip install git+https://github.com/NickWaterton/samsung-tv-ws-api.git pysolar- Set up environment:
# Copy and edit with your TV IP
cp .env.example .env
# Create directories
mkdir -p artwork tokens
# Add test images to artwork folder- Run the script:
export $(grep -v '^#' .env | xargs) && python sync_artwork.pyOn first run, approve the connection on your TV. Press Ctrl+C to stop.
Testing solar brightness calculations:
If you've configured solar brightness settings, test them before running the full sync:
export $(grep -v '^#' .env | xargs) && python sync_artwork.py --test-solarThis shows hourly brightness predictions for key solar positions (March Equinox, June Solstice, December Solstice) without connecting to TVs.
Dry run mode:
Preview what changes would be made without actually modifying your TVs:
export $(grep -v '^#' .env | xargs) && python sync_artwork.py --dry-runThis connects to TVs to read their current state but won't upload, delete, or modify any settings.
When the sync script uploads new images or deletes old ones:
- Syncs the artwork (uploads new, deletes removed)
- Selects an image to prevent the TV from showing default art (random image for shuffle mode, first image otherwise)
- Applies slideshow settings based on your configuration:
- If slideshow override variables are set (
SLIDESHOW_ENABLED,SLIDESHOW_INTERVAL, orSLIDESHOW_TYPE), uses those settings - If no override variables are set, preserves and restores your TV's current slideshow settings
- If slideshow override variables are set (
If no images change during a sync cycle, slideshow settings are not modified.
- Samsung Frame TV (2016+ models with Tizen OS)
- Docker and Docker Compose (or Python 3.9+ for local testing)
- Network access to TVs
Set LOG_LEVEL=DEBUG in your environment to see detailed sync operations and TV responses.
Built using samsung-tv-ws-api by NickWaterton.
This project was created with the assistance of AI tools.
MIT