Skip to content
Get started

Sendspin Image

The sendspin image platform displays album and artist artwork streamed from a Sendspin group. The Sendspin hub must be configured on the same device.

The Sendspin server delivers the artwork already scaled to the requested size; it is decoded at runtime and exposed as a regular image that you can draw on a display or use with LVGL widgets.

Configure one entry per artwork you want to show, up to a maximum of four. This platform only works on ESP32-based chips.

# Example configuration entry
sendspin:
image:
- platform: sendspin
id: album_slot
format: JPEG
type: RGB565
resize: 240x240
current_image:
id: album_art

The entry’s own id refers to the slot, which is what the action targets. The id inside current_image is the image itself, and is what you reference from a display lambda or an LVGL widget.

  • id (Optional, ID): The ID of the artwork slot. Use this to target the action below.

  • format (Required): The format the artwork is encoded with. One of JPEG, PNG or BMP.

  • resize (Required, string): The size the artwork is requested and rendered at, as WIDTHxHEIGHT. The Sendspin server scales the artwork to these dimensions before sending it.

  • type (Required): Specifies how to encode the image internally.

    • BINARY: Two colors, suitable for 1 color displays or a 2 color image on color displays. Uses 1 bit per pixel, 8 pixels per byte. Only chroma_key transparency is available.
    • GRAYSCALE: Full scale grey. Uses 8 bits per pixel, 1 pixel per byte.
    • RGB565: Lossy RGB color. Uses 2 bytes per pixel, 3 with an alpha channel.
    • RGB: Full RGB color. Uses 3 bytes per pixel, 4 with an alpha channel.
  • current_image (Required): The image showing the artwork that is currently playing.

    • id (Required, ID): The ID to reference the image in your display or LVGL code.
  • transition_image (Optional): A second image holding the outgoing artwork while a transition runs, for transitions that must keep it on screen after on_image_display returns. It holds the current artwork at any other time, and is black until the first artwork has been shown. When set, the server is not told the device is ready for more artwork until sendspin.image.transition_finished runs. See Cross-fading between tracks.

    • id (Required, ID): The ID to reference the outgoing artwork.
  • source (Optional): Which artwork to display. One of album (default) or artist.

  • display_offset (Optional, Time): Request a shift when on_image_display fires relative to the moment the server asked for the artwork to appear. A positive value fires it early, a negative value delays it. Must be a whole number of milliseconds between -60s and 60s. Defaults to 0ms.

  • transparency (Optional): If set, the alpha channel of the artwork will be taken into account. The possible values are opaque (default), chroma_key and alpha_channel. See the discussion on transparency in the image component.

  • byte_order (Optional, string): For RGB565 images, the pixels are converted to 16 bit values. By default these are stored in little endian byte order (LSB first), but you can override this by setting byte_order to big_endian. Options are little_endian (default) and big_endian. Not applicable to other image formats.

  • placeholder (Optional, ID): ID of another image to display until the first artwork has been received. This placeholder image will not be resized. It only applies when the image is drawn from a display lambda; LVGL widgets show nothing instead.

  • sendspin_id (Optional, ID): The ID of the Sendspin hub to attach to. Only needed if you have more than one hub configured.

NOTE

Each entry permanently reserves memory for two pictures at the configured resize size. 240x240 artwork of type RGB565 costs 230 kB.

  • on_image_display (Optional, Automation): An automation to perform when new artwork is ready to be shown. A common use is to refresh the display so the new artwork is drawn.

    The variable lateness_ms is available in lambdas. It reports how many milliseconds past the intended moment the artwork actually arrived, so a transition can be shortened by that much and still finish on schedule.

  • on_image_clear (Optional, Automation): An automation to perform when the artwork is cleared, such as at the end of a stream. The image is blank from this point until new artwork arrives. An LVGL widget keeps drawing the artwork it was pointed at.

  • on_image_error (Optional, Automation): An automation to perform when the artwork could not be decoded, or when it decoded to dimensions other than the ones requested with resize. The artwork already on screen is left in place.

Report that the transition for the artwork just displayed has finished, telling the server the device is ready for more. Only needed when a transition_image is configured.

IMPORTANT

Every displayed artwork must be acknowledged with this action exactly once if transition_image is configured, either from on_image_display or from whatever finishes the transition it starts. If it is not run, no further artwork appears until the artwork is cleared, and a warning naming the slot is logged ten seconds after the artwork was displayed.

  • id (Required, ID): The artwork slot the transition belongs to.
on_...:
- sendspin.image.transition_finished: album_slot

Display album artwork and refresh the display whenever it changes:

sendspin:
image:
- platform: sendspin
id: album_slot
format: JPEG
type: RGB565
resize: 240x240
current_image:
id: album_art
on_image_display:
- component.update: my_display
display:
- platform: ...
id: my_display
# ...
lambda: |-
// Draw the album artwork at position [x=0,y=0]
it.image(0, 0, id(album_art));

Album and artist artwork can be requested at the same time by configuring one entry per source:

image:
- platform: sendspin
id: album_slot
format: JPEG
type: RGB565
resize: 240x240
source: album
current_image:
id: album_art
- platform: sendspin
id: artist_slot
format: PNG
type: RGB565
resize: 96x96
source: artist
current_image:
id: artist_art

To dissolve the old artwork into the new one, both have to be on screen at once, so this needs a transition_image and two stacked LVGL widgets. Later-declared widgets render on top, so declare the incoming one first and let the outgoing one fade out above it.

A widget keeps drawing whichever artwork it was last pointed at, so both widgets are pointed at their image again on every display. display_offset starts the fade early so it is centered on the change of track.

image:
- platform: sendspin
id: album_slot
format: JPEG
type: RGB565
resize: 240x240
display_offset: 1s
current_image:
id: album_art
transition_image:
id: album_art_transition
on_image_display:
- lvgl.image.update:
id: outgoing_art
src: album_art_transition
- lvgl.image.update:
id: incoming_art
src: album_art
- lvgl.animation.start: album_art_crossfade
lvgl:
animations:
- id: album_art_crossfade
duration: 2s
widgets:
- id: outgoing_art
opa:
from: 100%
to: 0%
on_stop:
- sendspin.image.transition_finished: album_slot
widgets:
- image:
id: incoming_art
src: album_art
- image:
id: outgoing_art
src: album_art

The fade outlives the automation that starts it, so the transition is reported as finished from the animation’s on_stop rather than at the end of on_image_display. The fade always runs for the same length here; to have it end on schedule even when artwork arrives late, pass a duration to lvgl.animation.start shortened by lateness_ms.