framesmith 0.1.0

A Rust library for controlling Samsung Frame TVs over the local network
Documentation
# framesmith

Control Samsung Frame TVs over your local network — no cloud, no Samsung account.

`framesmith` is an async Rust library for managing artwork, display settings, slideshows, and more on Samsung's The Frame TV lineup. It communicates directly with the TV using WebSocket and HTTP protocols over your LAN.

## Features

- **Discover** Frame TVs on your network via SSDP multicast
- **Upload, select, and delete** artwork (JPEG and PNG)
- **Art Mode** — enable/disable the Frame's signature display mode
- **Slideshows** — cycle through artwork with configurable duration, shuffle, and category
- **Mattes & filters** — apply decorative borders and photo filters
- **Display settings** — brightness, color temperature, auto-brightness, rotation
- **Motion sensor** — configure the idle timer and sensitivity
- **Remote control** — simulate 40+ button presses (power, volume, navigation, HDMI input, etc.)
- **Authentication** — persistent token-based auth with pluggable storage
- **No native TLS dependency** — uses `rustls` under the hood

## Quick Start

Add `framesmith` to your `Cargo.toml`:

```toml
[dependencies]
framesmith = "0.1.0"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

### Connect and Upload Art

```rust
use std::net::Ipv4Addr;
use std::path::Path;
use framesmith::{FrameTv, FileAuthTokenStore, ArtImage};

#[tokio::main]
async fn main() -> Result<(), framesmith::Error> {
    let tv = FrameTv::connection_builder(Ipv4Addr::new(192, 168, 1, 100).into())
        .auth_token_store(FileAuthTokenStore::new(Path::new("tv_token.txt")))
        .connect()
        .await?;

    let image = ArtImage::builder()
        .load_jpeg(Path::new("artwork.jpg"))?
        .build()?;
    tv.upload_and_select_art_image(image).await?;
    tv.enable_artmode().await?;

    Ok(())
}
```

### Discover TVs

```rust
use framesmith::discover;

let tvs = discover().await?;
for tv in &tvs {
    println!("{} at {} ({})", tv.name(), tv.ip(), tv.model());
}
```

### Manage Art

```rust
// List all uploaded images
let images = tv.get_uploaded_art_images().await?;

// Get info for the currently displayed image
let current = tv.get_selected_art_image().await?;
println!("{}x{}", current.width(), current.height());

// Get info for a specific image by content ID
let info = tv.get_art_image_info("MY_F0001").await?;

// Select an image for display
tv.select_art_image_by_id("MY_F0001").await?;

// Delete images
tv.delete_uploaded_art_images(&["MY_F0001", "MY_F0002"]).await?;

// Download a thumbnail
let thumb = tv.get_art_image_thumbnail("MY_F0001").await?;
std::fs::write("thumb.jpg", thumb.as_bytes())?;
```

### Center Small Images on a Canvas

```rust
use framesmith::{ArtImage, Canvas};

let image = ArtImage::builder()
    .load_png(Path::new("small.png"))?
    .center_image(3840, 2160, Canvas::black())
    .build()?;
tv.upload_art_image(image).await?;
```

### Display Settings

```rust
use framesmith::{DisplayBrightness, DisplayColorTemp};

tv.set_display_brightness(DisplayBrightness::L7).await?;
tv.set_display_color_temp(DisplayColorTemp::Plus2).await?;
tv.enable_auto_brightness().await?;
```

### Slideshows

```rust
use framesmith::{SlideshowConfig, SlideshowCategory};
use std::time::Duration;

tv.enable_slideshow(Some(SlideshowConfig {
    art_image_duration: Duration::from_secs(300),
    shuffle: true,
    category: SlideshowCategory::Favorites,
})).await?;
```

### Remote Control

```rust
use framesmith::RemoteControlButton;

tv.press_remote_control_button(RemoteControlButton::PowerOff).await?;
tv.press_remote_control_button(RemoteControlButton::Hdmi1).await?;
```

### Custom Auth Token Storage

The default `FileAuthTokenStore` saves tokens to a file, but you can implement the `AuthTokenStore` trait to store tokens however you like (database, keychain, environment variable, etc.).

## Network Requirements

- Your machine and the TV must be on the **same local network** (same subnet, or use [SNAT masquerading]https://github.com/jeffmo/framesmith#cross-subnet--cross-vlan-access for cross-VLAN setups)
- The TV communicates over **port 8001** (HTTP) and **port 8002** (WSS)
- The TV must be powered on or in Art Mode / standby with network standby enabled
- On first connection, someone must physically approve the pairing prompt on the TV screen

## Error Handling

All operations return `Result<T, framesmith::Error>`. Error variants include `ConnectionFailed`, `Unauthorized`, `TvError`, `Timeout`, `IncorrectImageSize`, and wrappers for WebSocket, HTTP, JSON, I/O, and image processing errors.

## CLI

Looking for a command-line tool? See [`framesmith-cli`](https://crates.io/crates/framesmith-cli).

## License

MIT