Skip to content

shunte88/LyMonS

Repository files navigation

LyMonS

Build Status License: GPL v3 Platform version

Buy Me A Coffee Like my work, then Buy Me A Coffee

An LMS Monitor For The Future

OLED information display control program for piCorePlayer or other Raspberry Pi and Lyrion Music Server (formerly Logitech Media Server) based audio device.

Download

Pre-compiled binaries for Raspberry Pi are available on the binaries branch:

Quick Install

# Download for your Pi (32-bit example)
wget https://github.com/shunte88/LyMonS/raw/binaries/latest/lymons-latest-pcp-armv7.tgz

# Extract
tar xzf lymons-latest-pcp-armv7.tgz

# Install
cd lymons-*-pcp-armv7
sudo ./install.sh
# and follow the directions...

Building from source? See CROSS_COMPILE.md for cross-compilation instructions.

Features

  • OLED drivers loaded on demand, delete the ones you don't use and save space
  • SVG rendering gives clean, sharp graphics across many different OLED displays
  • Mono, Gray4, and Color support depending on the display you use
  • SVGs are lightweight external files, not baked into the binary
  • Track details are displayed only when playing
  • Display features independent scrolling of track details as required
  • When playing, remaining time can be displayed rather than total time
  • Audio attributes: volume, sample depth, and sample rate, are shown
  • Player attributes: shuffle, repeat, and fidelity glyphs, are shown
  • A retro clock is displayed when the audio is paused or stopped
  • Display regions handle alignment, text wrapping, and layout
  • Current weather and time display. Requires a free API key from tommorow.io
  • Weather descriptions can be translated to any language, though Japanese, Korean, Chinese, and Cyrillic scripts are not yet fully supported
  • Automatically sets display brightness at dawn and dusk
  • Multiple audio visualization modes, see below
  • If monitoring from a separate device, animations can be displayed as the track plays
  • Written in Rust: robust and memory safe

Options

Usage: LyMonS [OPTIONS] --name <name>

LMS monitor, worth the squeeze

Usage: LyMonS [OPTIONS]

Options:
  -c, --config <CONFIG>
          Path to YAML config file (overrides default search)
  -v, --debug
          Enable debug logging
  -N, --name <NAME>
          LMS player name to monitor (required unless set in config file)
  -W, --weather <WEATHER>
          Weather: API key,units,lang,latitude,longitude (comma-separated)
      --weather-api <WEATHER_API>
          Tomorrow.io API key (overrides --weather key field)
      --weather-units <WEATHER_UNITS>
          Weather units: metric (default) or imperial (overrides --weather units field)
      --weather-lang <WEATHER_LANG>
          Weather language/translation code (overrides --weather lang field)
      --lat <LAT>
          Latitude, overrides config file and GeoIP
      --lon <LON>
          Longitude, overrides config file and GeoIP
  -z, --scroll <SCROLL>
          Text scroll mode [possible values: loop, loopleft, cylon]
  -r, --remain
          Show remaining time instead of total duration
  -F, --text_font <TEXT_FONT>
          TTF text font name (must have ./data/{name}-text.zip)
  -f, --text_font_size <TEXT_FONT_SIZE>
          TTF text font size (must have ./data/{name}-text.zip)
  -C, --clock_font <CLOCK_FONT>
          Clock font [possible values: 7seg, dejavu, dotty, gawker, ledreal, mackintosh, marvel, moomy, noto, poppins, roboto]
  -E, --eggs <EGGS>
          Easter egg animation [possible values: bass, blackfly, cassette, ibmpc, moog, pipboy, radio40, radio50, reel2reel, scope, technics, tubeamp, tvtime, vcr, none]
      --no-splash
          Skip splash screen
  -k, --metrics
          Show device metrics overlay
      --i2c-bus <I2C_BUS>
          I2C bus device path [default: /dev/i2c-1]
  -d, --driver <DRIVER>
          Display driver (emulator / config override) [possible values: ssd1306, ssd1309, ssd1322, sh1106, sh1122, sharpmemory, st7789, st7796s]
  -a, --viz <VIZ>
          Visualizer type [possible values: combination, hist_aio, hist_mono, hist_stereo, peak_mono, peak_stereo, vu_aio, vu_mono, vu_stereo, waveform_spectrum, no_viz]
      --hist-scheme <HIST_SCHEME>
          Histogram color scheme [possible values: classic, ocean, fire, neon]
      --dump-config
          Print fully merged config and exit
  -h, --help
          Print help
  -V, --version
          Print version

LyMonS:
LMS monitor

	Display LMS details and animations
	Clock, Weather, Meters, and more


Supported OLED types:
    SH1106
    SH1122
    SSD1306
    SSD1309
    SSD1322
    SHARP-memory
    ST7789

OLED Clock Fonts:
    7seg ........: Classic LCD Clock Font
    dejavu ......: DejaVu - or is that VU
    dotty .......: Dotmatrix style font
    gawker ......: Get an eyefull, use Gawker
    ledreal .....: A slightly more complex LED font
    mackintosh ..: C.R. Mackintosh perfection
    marvel ......: Marvel movie poster font
    moomy .......: More fontage, it's moomy
    noto ........: Clasic san-serif Noto
    poppins .....: Poppins, oh yes...
    roboto ......: Roboto Thin

Screenshots

Playback Scroller

SSD1309 (128×64 mono) SSD1322 (256×64 gray4) ST7789 (320×170 color)
SSD1309 scroller SSD1322 scroller ST7789 scroller

TTF font on ST7789:

ST7789 scroller TTF font

Clock, Marvel Font

SSD1309 (128×64 mono) SSD1322 (256×64 gray4) ST7789 (320×170 color)
SSD1309 clock SSD1322 clock ST7789 clock

Weather, Current Conditions

SSD1322 (256×64 gray4) ST7789 (320×170 color)
SSD1322 weather current ST7789 weather current

Weather, Forecast

SSD1309 (128×64 mono) SSD1322 (256×64 gray4) ST7789 (320×170 color)
SSD1309 forecast SSD1322 forecast ST7789 forecast

Visualizer Modes

Several visualizer modes are supported:

  • Stereo VU Meters - dBFS metered
  • Stereo 12-band Spectrum Analysis
  • Stereo 20-band Spectrum Analysis for wide displays
  • Stereo Peak Meter - dBFS metered
  • Downmix Peak Meter
  • Large Downmix VU meter
  • Large Downmix Spectrum
  • All-In-One - track details alongside spectrum or VU meter
  • Wave Forms - coming soon
  • Easter Eggs - fixed mode (use --egg <name>)

TTF Scrolling Fonts

By default LyMonS renders track details using its built-in bitmap fonts. You can replace these with any TrueType or OpenType font for richer text rendering, including full Unicode and CJK character support.

How It Works

LyMonS loads a TTF/OTF font from a zip archive at startup. The archive can contain a single font file (.ttf or .otf), LyMonS picks the first one it finds. Font metrics (ascent, descent, line height) are read directly from the font file, so vertical centering is always accurate regardless of the size you choose.

Adding a Font

  1. Create the zip archive containing your .ttf or .otf file:

    zip NotoSansMonoCJKjp-text.zip NotoSansMonoCJKjp-Regular.otf
  2. Place it in the data/ folder next to the LyMonS binary, named {name}-text.zip, the {name} part is how you refer to it on the command line or in the config file:

    data/
      NotoSansMonoCJKjp-text.zip
    
  3. Enable it via CLI or config (see below).

CLI

LyMonS --name myplayer -F NotoSansMonoCJKjp -f 24
Flag Description
-F / --text_font Font name - must match data/{name}-text.zip
-f / --text_font_size Point size (floating point)

Config File

text_font: NotoSansMonoCJKjp
text_font_size: 24

CJK Fonts

For Japanese, Chinese (Simplified, Traditional, Hong Kong), and Korean text, the Noto Sans Mono CJK family is an excellent choice. It is open source, metrically consistent, and covers all CJK scripts in a single font family.

Note: CJK fonts contain a very large glyph set and require a minimum rendered size to be legible. A point size of 24 or above is recommended; smaller sizes may fail to load or render poorly but this is also screen size dependent - YMMV.

CJK font in use, Japanese track details

Japanese track metadata rendered at 24pt on ST7789 (320×170 color) in AIO histogram mode.

Noto Sans Mono CJK Variants

Font Script
NotoSansMonoCJKjp Japanese
NotoSansMonoCJKkr Korean
NotoSansMonoCJKsc Simplified Chinese
NotoSansMonoCJKtc Traditional Chinese
NotoSansMonoCJKhk Hong Kong Chinese

Fonts can be found on the web or downloaded from the official Noto CJK GitHub repository:

Download the Mono variant in OTF format, zip the .otf file, and drop it in the data/ folder as described above.

Installation

LyMonS can run in two configurations:

On the player device, installed directly on a piCorePlayer or any Pi running Squeezelite. LyMonS reads audio data from Squeezelite's shared memory, which gives it access to real-time PCM data for VU meters, peak meters, and spectrum analysis.

On a separate device, installed on another machine on the same network, pointing at the LMS player by name. In this case LyMonS connects to the visionon streaming daemon running on the player device and receives audio metrics over the network. LyMonS figures out which approach to use on its own, if shared memory is available it uses it, otherwise it connects to visionon. No flags, no configuration switches.

The only thing you need for remote visualization is the visionon daemon running on the player device. Point LyMonS at the player name and the rest is handled for you.

Prerequisites

If you intend to use visualization you need to configure Squeezelite to expose its shared memory.

From the Squeezelite page of the pCP web frontend, type 1 in the "m" ALSA parameter section and add -v in the Various Options field.

See the Squeezelite page for more details.

For remote visualization (LyMonS on a separate device), you also need the visionon daemon running on the player device. Visionon is a lightweight process that reads Squeezelite's shared memory and streams the audio metrics out over HTTP. Once it's running, LyMonS connects to it automatically using the player's IP.

Easter Eggs

There are several "easter egg" modes for setups that can't or don't want to process audio data for visualization. There's nothing stopping you using them as your main display mode either.

Cassette

SSD1309 (128×64 mono) SSD1322 (256×64 gray4) ST7789 (320×170 color)
SSD1309 cassette SSD1322 cassette ST7789 cassette

Oscilloscope

SSD1309 (128×64 mono) SSD1322 (256×64 gray4) ST7789 (320×170 color)
SSD1309 scope SSD1322 scope ST7789 scope

There are currently 10 easter egg modes:

  • [cassette] Compact Cassette, as visually accurate as the OLED allows. Hubs turn and the tape loops from one hub to the other with the tape window showing track progress.
  • [technics] Technics SL-1200, as visually accurate as the OLED allows. Tone arm traverses the platter to indicate progress.
  • [reel2reel] Open Reel To Reel, pure fantasy. Reels rotate, minor animation.
  • [vcr] VCR with flashing 12:00 AM clock. No additional animation - the clock is annoying enough.
  • [radio40] A large ornate radio. Minor animation, station changes as the track progresses.
  • [radio50] An old Bakelite radio. Minor animation, station changes as the track progresses.
  • [tvtime] An old analog TV in all its 5x4 glory. VHF or UHF - no, a dancing news reader.
  • [ibmpc] A crusty old IBM PS/2 clone. Simple starfield animation, just for fun.
  • [bass] A rubbish bass guitar or bass ?? - and why not.
  • [pipboy] It's Pip-Boy.

Specify --egg <name> to display an easter egg during track playback.

Supported Displays

Each driver speaks a single bus and a single color depth. Color depth is a property of the driver, not the panel size, choosing --driver st7789 implies Rgb565 even on a 240×135 panel; --driver ssd1322 implies Gray4 regardless of physical dimensions.

Driver Bus Color depth Panel sizes (long × short)
ssd1306 I²C/SPI Mono (1bpp) 128×64
ssd1309 I²C/SPI Mono (1bpp) 128×64
sh1106 I²C Mono (1bpp) 132×64
ssd1322 SPI Gray4 (4bpp) 256×64
sh1122 SPI Gray4 (4bpp) 256×64
st7789 SPI Rgb565 (16bpp) 320×240, 320×170, 280×240, 240×240, 240×135, 160×80
st7796s SPI Rgb565 (16bpp) 480×320
sharpmemory SPI Mono (1bpp) 400×240

Specifying Panel Size

For drivers with more than one panel option (currently st7789; st7796s will follow if/when alternative panel sizes are supported), set width and height in the display: block of your config file:

display:
  driver: st7789
  width:  240
  height: 240

The configurator validates the requested size against the supported list and fails fast with a clear message if it doesn't match. For drivers with a single panel (e.g. ssd1322) the size is fixed and the values are ignored.

Orientation and Rotation

LyMonS treats every framebuffer as landscape-canonical: the longer axis is always width, the shorter axis is always height. If you supply portrait dimensions in YAML, e.g. width: 135, height: 240 for a 240×135 ST7789, the driver normalises silently and logs:

ST7789: normalised input 135x240 → 240x135 (long axis first)

As the dimension take the longest side as the width you may need to rotate the display image so that we correctly display your information. Physical orientation is then handled by rotate_deg (0, 90, 180, 270), which rotates the rendered framebuffer when blitted to the panel. This means the layout YAML never needs portrait-specific variants, author once in landscape and rotate at the panel.

SVG and Scaling

Most pixel-bearing assets in LyMonS are SVG (clock digits, weather glyphs, easter eggs, status icons, peak meters). They scale cleanly to whatever panel size the driver reports. Layout YAML, however, currently carries hand-tuned absolute coordinates for the canonical panel size of each driver, so a non-canonical ST7789 size (anything other than 320×170) will render but field positions and widths may need attention. Add a sized layout override using a dimensional variant named {width}x{height} (for example 240x240) within the driver's layout.yaml, see Dimensional Variants below. The underlying SVGs themselves should require no changes.

Layout System

LyMonS uses a declarative YAML layout system to define where and how every element appears on screen. All positions, sizes, fonts, colors, and alignment are data, and no recompilation needed. Driver-specific overrides let each display have its own tuned layout without touching shared definitions.

How It Works

Layouts are defined in assets/layout.yaml (the base, targeting 128×64 mono displays). Driver-specific overrides are placed alongside the driver in assets/{driver}/layout.yaml - for example assets/ssd1322/layout.yaml for the 256×64 gray4 display, or assets/st7789/layout.yaml for the 320×170 color display.

When LyMonS starts it loads the base layout, then merges the driver override on top. The merge is additive at the field level - the override can add new fields or change individual field properties without having to redeclare fields it doesn't touch.

Layout File Structure

components:
  my_panel:                     # reusable group of fields
    fields:
      - name: status_bar
        type: status_bar
        x: "0"
        y: "2"
        width: "parent.width"
        height: "9"

templates:
  playback:                     # page shown during track playback
    variants:
      - name: default           # catch-all variant (no match: rule)
        regions:
          - component: my_panel
            x: "0"
            y: "0"
            width: "display.width"
            height: "display.height"

Simple pages like easter egg overlays can define fields inline directly in the variant, skipping the component indirection entirely:

templates:
  easter_egg_cassette:
    variants:
      - name: default
        fields:
          - name: artist
            type: label
            x: "18"
            y: "6"
            width: "90"
            height: "6"
            font: font_4x6
            horizontal_alignment: Center

Expressions

Position and size values are expression strings, not bare numbers. The following variables are available:

Variable Meaning
display.width Full display width in pixels
display.height Full display height in pixels
parent.width Width of the enclosing region
parent.height Height of the enclosing region
font_height Character height of the field's font
<name>.top .bottom .left .right .width .height Geometry of any previously defined field

Arithmetic operators + - * / and parentheses are supported. Examples:

x: "display.width / 2"              # centre of display
y: "status_bar.bottom + 2"          # 2px below the status bar
width: "display.width - 43"         # fill to near right edge
height: "parent.height - 16"        # leave room for time at bottom

Because expressions reference display.width, the same component definition often adapts correctly to both 128px and 256px displays without a driver override.

Field Properties

Property Values Default
type label, scrolling_text, status_bar, track_progress_bar, info_line, clock_digits, weather_icon, weather_glyph, cover_image, custom ,
x / y integer or expression "0"
width / height integer or expression "parent.width" / "0"
font font_4x6 font_5x8 font_6x10 font_7x13 font_7x13_bold font_10x20 etc. type default
fg_color White Yellow Cyan Red Green Blue Orange Magenta or {r, g, b} White
scrollable true / false false
horizontal_alignment Left Center Right Left
vertical_alignment Top Middle Bottom Top

Variant Matching

A template can have multiple variants selected by display characteristics. The first matching variant wins; an entry with no match: block is a catch-all.

templates:
  weather_forecast:
    variants:
      - name: color               # matches ST7789 specifically
        match:
          color_depth: [Rgb565]
        regions:
          - component: weather_forecast_6col_st7789
            ...

      - name: wide                # matches SSD1322 / SH1122
        match:
          category: [Large]
        regions:
          - component: weather_forecast_ext_cols
            ...

      - name: default             # all other displays
        regions:
          - component: weather_forecast_3col
            ...

Match filters:

Filter Values
category Small (128px), Medium (132px), Large (256px), ExtraLarge (320px+)
color_depth Monochrome, Gray4, Rgb565

Dimensional Variants

A variant whose name is exactly {width}x{height} (e.g. 240x240, 320x170) is matched as an exact size override and wins over every other variant, no match: block required. This lets you ship a hand-tuned layout for a specific panel size without disturbing the catch-all default variant that other sizes fall back to.

templates:
  weather_current:
    variants:
      - name: 240x240             # exact size match, wins on 240×240 panels
        regions:
          - component: weather_current_240x240
            ...
      - name: default             # everything else
        regions:
          - component: weather_current_main
            ...

Resolution order: dimensional name match → variant with a matching match: block → first catch-all. Authoring convention: put dimensional variants and specific match-rule variants first, leave the catch-all default last.

Driver Overrides

Place a layout.yaml file inside the driver's asset folder. The file uses the same format as the base, it only needs to contain what differs. Components and templates not mentioned in the override are inherited unchanged from the base.

Example: add artist and title to the Pip-Boy easter egg on the wide gray4 display, which shows only a clock by default:

# assets/ssd1322/layout.yaml
templates:
  easter_egg_pipboy:
    variants:
      - name: default
        fields:
          - name: artist          # new, not in base template
            type: label
            x: "140"
            y: "3"
            width: "114"
            height: "28"
            font: font_4x6
            horizontal_alignment: Center
          - name: title           # new, not in base template
            type: label
            x: "140"
            y: "33"
            width: "114"
            height: "20"
            font: font_4x6
            horizontal_alignment: Center
          # time field is inherited from base, no need to redeclare it

Easter Egg Field Names

Each easter egg template supports any combination of the following named fields. Fields not present in the template are simply not rendered, add whichever ones make sense for the available screen space on each display.

Field name Content
artist Track artist
title Track title
album Album name
album_artist Album artist
combination "Artist, Title" combined scroller
year Release year
time Elapsed or remaining track time

Set scrollable: true on any of these for a horizontal scroller (text slides when it overflows the field width). Use type: label with scrollable: false for word-wrapped static text.

Error Reporting

Layout errors are reported at startup with enough context to find the problem quickly.

YAML syntax or type error (e.g. unknown font name, bad indentation):

ERROR layout: YAML error in ./assets/ssd1322/layout.yaml:
ERROR   unknown variant `font_4x66`, expected one of `font_4x6`, `font_5x7`, ...
ERROR   (in template 'easter_egg_pipboy')
WARN  layout: driver override ignored, using base layout only

Expression evaluation error (e.g. typo in a variable name, forward reference):

WARN  layout: easter_egg_reel2reel/default/time [x="display.widht - 43"]:
              unknown variable 'display.widht', using 0

Like The App - Git The Shirt

Team Badger shirts and other goodies are available at shunte88


Buy Me A Coffee Like my work, then Buy Me A Coffee

Packages

 
 
 

Contributors

Languages