A MagicMirror² module that automatically discovers your Sonos zones and shows what is playing – including title, artist, album, and which speakers are in the group. The layout is tuned for both small and large displays, and you keep full control over what should be shown.
Created by: Mats Kjoshagen Kolstad
- 🔍 Automatic Sonos discovery – no manual IP configuration required.
- 🎵 Displays the current track with title, artist, album, and album art.
- 🎶 Shows playback source icons (Spotify, Apple Music, Radio, Line-in) for easy identification.
- 📊 Progress indicator with visual bar and time counter for track playback.
- 🔊 Volume display with dynamic icons showing current volume level.
- 🧩 Groups are presented as a single unit (no duplicate speakers when they’re grouped).
- 🙈 Hide specific speakers or groups directly from the configuration – or use whitelists to show only what you want.
- 🧱 Flexible layouts: row, grid, mini, fullscreen, or automatic based on the number of groups.
- 🖥️ Fullscreen mode – display a single speaker's now-playing info as a prominent, full-width card with large album art and bold text. Perfect for a dedicated page in MagicMirror's page manager.
- 🎨 Accent colours derived from album art for a vibrant, personalised card background.
- ✨ Animated track transitions (fade, slide, scale) with per-card updates in all display modes.
- 📻 Enhanced radio metadata – station names, logos, and live "now playing" info.
- 🔠 Adjust text size, album art size, max groups, and module width via config.
- 🧭 Control alignment without extra CSS – choose left, center, right, or distributed spacing.
- 🕒 Show the last update time and optionally hide the module when nothing is playing.
- 👆 Touch control mode – tap a card to play/pause, adjust group volume, and browse/play your Sonos favorites directly from the mirror.
This module was produced with assistance from AI tools and was originally created for my personal use. The repository is shared in the hope that it is useful to others, but I cannot guarantee ongoing maintenance or updates. Users are responsible for keeping the module updated, adapting it to their own setup, and tracking upstream changes that may affect functionality.
-
Navigate to the MagicMirror
modulesfolder and clone (or copy) the directory:cd ~/MagicMirror/modules git clone https://github.com/matskkolstad/MMM-Sonos.git
Tip: If the module already exists locally (as in this exercise), simply copy the folder into your
modulesdirectory. -
Install dependencies:
cd MMM-Sonos npm install -
Add the module to
config/config.js. See Configuration Examples below for different setup options. -
Start (or restart) MagicMirror². The module appears once the first Sonos group is discovered.
The simplest setup requires no configuration at all – just add the module and it will work with default settings:
{
module: 'MMM-Sonos',
position: 'bottom_left'
}A typical setup with the most commonly used options:
{
module: 'MMM-Sonos',
position: 'bottom_left',
config: {
updateInterval: 15000, // Update every 15 seconds
displayMode: 'row', // Display groups in a horizontal row
albumArtSize: 80, // Album art size in pixels
hideWhenNothingPlaying: true, // Hide module when nothing is playing
showGroupMembers: true, // Show which rooms are in each group
hiddenSpeakers: ['Bathroom'], // Hide specific speakers
knownDevices: ['192.168.1.50'] // Optional: specify device IPs if auto-discovery fails
}
}An example showing all available configuration options:
{
module: 'MMM-Sonos',
position: 'bottom_left',
config: {
// Discovery and updates
updateInterval: 15000, // Polling interval in milliseconds (minimum: 5000)
discoveryTimeout: 5000, // Time to wait for device discovery (0 to skip auto-discovery)
knownDevices: [], // Array of static Sonos IPs for fallback
// Display mode and layout
displayMode: 'row', // 'row', 'grid', 'mini', 'fullscreen', or 'auto'
columns: 2, // Number of columns in grid mode (1-4)
maxGroups: 6, // Maximum groups to display
moduleWidth: null, // Constrain width (e.g., "600px" or "80%")
// Text styling
fontScale: 1, // Text size multiplier (e.g., 1.2 = 20% larger)
textSize: null, // Override text size in pixels (overrides fontScale)
textAlignment: 'center', // 'left', 'center', or 'right'
wrapText: true, // Allow text wrapping
maxTextLines: 2, // Max lines for title when wrapping is enabled
// Album art
albumArtSize: 80, // Album art size in pixels
forceHttps: false, // Force HTTPS for album art URLs
// Card layout
cardMinWidth: 150, // Minimum card width in pixels
cardMaxWidth: null, // Maximum card width in pixels (null = no limit)
justifyContent: 'center', // Horizontal distribution: 'flex-start', 'center', 'space-between', etc.
// Visibility and filtering
hideWhenNothingPlaying: true, // Hide module when nothing is playing
showWhenPaused: false, // Show groups even when paused
fadePausedGroups: true, // Dim groups that aren't playing
hiddenSpeakers: [], // Array of speaker/room names to hide
hiddenGroups: [], // Array of group names or IDs to hide
allowedSpeakers: [], // Whitelist: only show groups with at least one listed speaker
allowedGroups: [], // Whitelist: only show matching group names, IDs, or coordinator IPs
// Information display
showGroupMembers: true, // Show which rooms are in each group
showPlaybackState: false, // Show playback state label (Playing, Paused, etc.)
showLastUpdated: false, // Show timestamp of last update
timeFormat24: true, // Use 24-hour time format
dateLocale: 'en-US', // Locale for timestamp formatting
showAlbum: false, // Show album name under artist
accentuateActive: true, // Highlight actively playing groups
// New features
showPlaybackSource: true, // Show playback source icon (Spotify, Radio, Apple Music, Line-in, etc.)
showProgress: true, // Show progress bar and time for current track
showVolume: true, // Show volume level for each speaker/group
// Accent colours from album art (requires cacheAlbumArt: true)
albumArtColors: false, // Extract dominant colour from album art and tint the card
albumArtColorsOpacity: 0.45, // Opacity of the accent colour overlay (0.0–1.0)
albumArtColorsMode: 'gradient', // 'gradient' (left→dark) or 'solid' (flat colour block)
// Track-change transition animations
transitionAnimation: 'fade', // 'fade', 'slide-up', 'slide-down', 'slide-left', 'slide-right',
// 'scale', 'zoom-in', 'zoom-out', 'flip', 'pixelate', or 'none'
transitionDuration: 400, // Animation duration in milliseconds
// Mini-mode options (displayMode: 'mini')
miniAlbumArtSize: 40, // Thumbnail size in pixels for mini-mode cards
miniShowGroupName: true, // Show room/group name badge in mini-mode
miniShowArtist: true, // Append artist to the track title line in mini-mode
miniShowSource: false, // Show playback source label in mini-mode
miniWidth: null, // Constrain mini-mode card width (e.g., 400 or '400px')
// Fullscreen-mode options (displayMode: 'fullscreen')
fullscreenSpeaker: null, // Speaker/group to show; null = first playing speaker
// Accepts speaker name, group name, group ID, or coordinator IP
fullscreenAlbumArtSize: 300, // Album art size in pixels for fullscreen mode
fullscreenWidth: null, // Constrain fullscreen wrapper width (e.g., 600 or '600px')
// Album art caching
cacheAlbumArt: true, // Cache album art locally for faster loading on slow networks
albumArtCacheTTL: 2592000000, // How long to keep cached images (ms). Common values:
// 30 days: 2592000000 (30 * 24 * 60 * 60 * 1000)
// 90 days: 7776000000 (90 * 24 * 60 * 60 * 1000)
// 120 days: 10368000000 (120 * 24 * 60 * 60 * 1000)
// 365 days: 31536000000 (365 * 24 * 60 * 60 * 1000)
// 0 = cache forever (never expire)
clearCacheOnStart: false, // Delete all cached album art on every module start
// TV source configuration
showTvSource: true, // Show TV badge when TV input is active
showTvIcon: true, // Display TV icon in album art slot
tvIconMode: 'emoji', // 'emoji', 'text', or 'svg'
tvIcon: '📺', // Emoji to use when tvIconMode is 'emoji'
tvIconText: 'TV', // Text to use when tvIconMode is 'text'
tvIconSvgPath: null, // Path/URL to SVG when tvIconMode is 'svg' (defaults to bundled asset)
tvLabel: null, // Override TV badge text (defaults to translated "TV")
// Touch control mode
enableControls: false, // Turn cards into a tappable play/pause/volume/favorites control surface
controlShowIdleZones: true, // false = only show playing zones; idle ones reachable via the "+" button
favoritesRefreshInterval: 300000,// How often (ms) the favorites list is re-fetched from Sonos
maxFavorites: 12, // Max favorites shown in the overlay before it scrolls
controlVolumeStep: 5, // Step size of the volume slider in the control overlay
// Debugging
debug: false // Enable detailed logging
}
}When a new version is tagged, update the module with:
cd ~/MagicMirror/modules/MMM-Sonos
git pull
npm installRestart MagicMirror² afterwards to load the latest code.
| Key | Default | Description |
|---|---|---|
updateInterval |
15000 |
How often (ms) to poll Sonos for fresh data. Minimum of 5000 ms is recommended. |
discoveryTimeout |
5000 |
Time in ms spent discovering the first Sonos device. Increase if your network is slow. |
hiddenSpeakers |
[] |
Array of room/speaker names that should never be shown. Groups containing hidden speakers are skipped. |
hiddenGroups |
[] |
Hide groups by name or ID. |
allowedSpeakers |
[] |
Whitelist: only show groups that have at least one member in this list. When empty, all groups are shown (unless hidden by hiddenSpeakers/hiddenGroups). |
allowedGroups |
[] |
Whitelist: only show groups whose name, ID, or coordinator IP appears in this list. When empty, all groups are shown. |
knownDevices |
[] |
List of static Sonos IPs to try when automatic discovery fails. |
maxGroups |
6 |
Maximum number of groups to render (counted after allowedSpeakers/hiddenSpeakers and paused-group filtering). Handy for large Sonos setups. |
displayMode |
'row' |
auto, grid, row, mini, or fullscreen. row keeps groups on a single horizontal line with scrolling if required. grid arranges cards across columns columns. auto switches to grid when the number of groups exceeds columns. mini renders each group as a compact single-row card (thumbnail + title). fullscreen shows a single speaker as a large, full-width card with prominent album art. |
columns |
2 |
Number of columns in grid mode (1–4). Also used as the threshold when displayMode is auto. |
fontScale |
1 |
Multiplier for text size. 1.2 increases text by 20%. |
textSize |
null |
Override text size in pixels (e.g., 16 or 20). When set, this overrides fontScale. |
albumArtSize |
80 |
Album-art size in pixels. |
wrapText |
true |
Allow line wrapping. Set to false for single-line ellipsis. |
maxTextLines |
2 |
Maximum lines for the title (only when wrapText is true). |
textAlignment |
'center' |
Text alignment: 'left', 'center', or 'right'. When set to 'left', text appears on the left with album art on the right (text is right-aligned to hug the album). When set to 'right', album art appears on the left with text on the right (text is left-aligned to hug the album). |
justifyContent |
'center' |
Horizontal distribution of cards: 'flex-start', 'center', 'space-between', etc. |
moduleWidth |
null |
Constrain module width (e.g. "600px", "80%"). |
forceHttps |
false |
Force album art over HTTPS (useful when running behind an HTTPS reverse proxy). |
hideWhenNothingPlaying |
true |
Hide the module when nothing is playing. Otherwise a calm “Nothing is playing” message is shown. |
showWhenPaused |
false |
Display groups even if playback is paused. |
fadePausedGroups |
true |
Dim groups that aren’t actively playing. |
showGroupMembers |
true |
Show which rooms are part of the group (only when there is more than one). |
showPlaybackState |
false |
Display a label for the playback state (Playing, Paused, etc.). |
showLastUpdated |
false |
Show a timestamp for when the data was last refreshed. |
timeFormat24 |
true |
Use 24-hour time in the timestamp. |
dateLocale |
'en-US' |
Locale for timestamp formatting. |
accentuateActive |
true |
Highlight actively playing groups with a stronger background. |
showAlbum |
false |
Display album title under the artist when available. |
cardMinWidth |
150 |
Minimum width for each card in pixels, used to adapt row/grid layouts. In row mode, cards are given a fixed width equal to this value so that wrapText and maxTextLines work correctly. |
cardMaxWidth |
null |
Maximum width for each card in pixels. When set, cards will not grow beyond this width in any display mode. Use together with cardMinWidth to create fixed-size cards. |
showPlaybackSource |
true |
Display the playback source icon and label (Spotify, Apple Music, Radio, Line-in, etc.). Icons automatically adjust based on the source. |
showProgress |
true |
Show a progress bar and time counter for the current track. Only displayed when track position and duration information is available. |
showVolume |
true |
Display the current volume level with an icon that changes based on volume (muted, low, medium, high). |
albumArtColors |
false |
Extract the dominant colour from each group's cached album art and apply it as a tinted gradient background on the card. Requires cacheAlbumArt: true. Uses node-vibrant under the hood. |
albumArtColorsOpacity |
0.45 |
Opacity of the accent-colour overlay (0.0–1.0). Increase for a stronger tint. |
albumArtColorsMode |
'gradient' |
'gradient' fades the accent colour into a dark background; 'solid' applies a flat colour block. |
transitionAnimation |
'fade' |
Animation used when a track changes: 'fade', 'slide-up', 'slide-down', 'slide-left', 'slide-right', 'scale', 'zoom-in', 'zoom-out', 'flip', 'pixelate', or 'none'. Only the card whose track actually changed is animated — all other cards stay static. |
transitionDuration |
400 |
Duration of the track-change animation in milliseconds. |
miniAlbumArtSize |
40 |
Thumbnail size in pixels for cards in mini mode. |
miniShowGroupName |
true |
Show the room/group name as a small badge in mini mode. |
miniShowArtist |
true |
Append the artist to the title line in mini mode ("Track · Artist"). |
miniShowSource |
false |
Show the playback source label (Spotify, Radio, etc.) in mini mode. |
miniWidth |
null |
Constrain the width of each mini-mode card (e.g., 400 or '400px'). |
fullscreenSpeaker |
null |
Speaker/group to display in fullscreen mode. Accepts a speaker name, group name, group ID, or coordinator IP. When null, the first playing group that passes allowedSpeakers/hiddenSpeakers is used. |
fullscreenAlbumArtSize |
300 |
Album art size in pixels for fullscreen mode cards. |
fullscreenWidth |
null |
Constrain the fullscreen wrapper width (e.g., 600 or '600px'). |
cacheAlbumArt |
true |
Download and cache album art images locally so they load instantly on subsequent polls. Cached files are stored in <module>/cache/album-art/ and served by MagicMirror's built-in static file server. |
albumArtCacheTTL |
2592000000 |
How long (in milliseconds) to keep a cached image before re-downloading it. Set to 0 to cache images forever and never expire them. Common values: 30 days = 2592000000, 90 days = 7776000000, 120 days = 10368000000, 365 days = 31536000000. |
clearCacheOnStart |
false |
When true, all locally cached album art images are deleted every time the module starts. Useful after a config change or to reclaim disk space. |
showTvSource |
true |
Show a TV badge when a home-theater input (TV) is active. |
showTvIcon |
true |
Display a TV icon in the album-art slot when TV is active. Set to false to keep the placeholder without the icon. |
tvIconMode |
'emoji' |
Choose the TV icon type: 'emoji' (default), 'text', or 'svg'. |
tvIcon |
'📺' |
Emoji used when tvIconMode is 'emoji'. |
tvIconText |
'TV' |
Text shown when tvIconMode is 'text'. Scales with albumArtSize. |
tvIconSvgPath |
null |
Path or URL to an SVG used when tvIconMode is 'svg'. If null, a bundled assets/tv-default.svg is used. |
tvLabel |
null |
Override the text label for the TV badge (defaults to the translated "TV"). |
enableControls |
false |
Master switch for touch control mode. |
controlShowIdleZones |
true |
When true, every zone is always shown in control mode (idle ones get a "Nothing playing" card). When false, only playing zones are shown, matching normal mode — idle zones are reached via the "+" more-speakers button. |
favoritesRefreshInterval |
300000 |
How often (ms) the favorites list is re-fetched from Sonos. |
maxFavorites |
12 |
Maximum number of favorites shown in the overlay before it scrolls. |
controlVolumeStep |
5 |
Step size of the volume slider in the control overlay. |
debug |
false |
Log extra information to the MagicMirror console. |
- Emoji (default):
tvIconMode: 'emoji'withtvIconset to your preferred emoji. - Text:
tvIconMode: 'text'withtvIconText: 'TV'(or another string). The text scales toalbumArtSize. - SVG:
tvIconMode: 'svg'withtvIconSvgPathpointing to the SVG file. You can place your file inside this module atmodules/MMM-Sonos/assets/your-tv.svgand settvIconSvgPath: 'assets/your-tv.svg'. Remote URLs are also supported. If no path is provided, the bundledassets/tv-default.svgis used. - Hide icon: set
showTvIcon: falseto keep the album-art placeholder without an icon.
displayMode: 'mini' renders each playing group as a compact single-line row — ideal for placing the module in a corner without taking up much screen space.
Example configuration:
{
module: 'MMM-Sonos',
position: 'top_right',
config: {
displayMode: 'mini',
miniAlbumArtSize: 40, // thumbnail size in px (default 40)
miniShowGroupName: true, // show room name badge above the title
miniShowArtist: true, // append " · Artist" to the title line
miniShowSource: false, // show source label (Spotify, Radio, …)
miniWidth: 320, // optional: max width of each row in px
transitionAnimation: 'fade' // animation when a track changes
}
}Each row shows:
- Thumbnail — small square album art (or a placeholder if none available)
- Room badge — the speaker/group name (e.g. "Stue"), when
miniShowGroupName: true - Track line — title, optionally followed by
· ArtistwhenminiShowArtist: true - Source label — e.g. "Spotify", "Radio", when
miniShowSource: true
Note: Mini mode does not display the progress bar, volume level, or individual group member names, keeping the layout as compact as possible.
Tip: Use
allowedSpeakersorallowedGroupsto limit which rooms are shown, andhiddenSpeakers/hiddenGroupsto exclude specific rooms.
Mini mode option reference:
| Option | Default | Description |
|---|---|---|
miniAlbumArtSize |
40 |
Thumbnail size in pixels. |
miniShowGroupName |
true |
Show a small uppercase badge with the room/group name above the track title. |
miniShowArtist |
true |
Append · Artist after the track title on the same line. |
miniShowSource |
false |
Show a small label below the title indicating the playback source (Spotify, Apple Music, Radio, etc.). |
miniWidth |
null |
Set a maximum pixel width for each mini row (e.g. 320 or '320px'). Useful when placing the module in a narrow sidebar. |
displayMode: 'fullscreen' renders a single speaker's now-playing info as a large, full-width card — ideal for a dedicated MagicMirror page (e.g. using a page manager module) where you want Sonos info front-and-centre with a prominent album art display.
Example configuration:
{
module: 'MMM-Sonos',
position: 'fullscreen_below',
config: {
displayMode: 'fullscreen',
fullscreenSpeaker: 'Stue', // optional: which speaker to show (null = first playing)
fullscreenAlbumArtSize: 300, // album art size in pixels (default 300)
fullscreenWidth: null, // optional: constrain width (e.g. 600 or '600px')
showAlbum: true, // show album name under artist
showProgress: true, // show progress bar and time
showVolume: true, // show volume level
showGroupMembers: true, // show which rooms are in the group
transitionAnimation: 'fade', // animation when track changes
albumArtColors: true, // tint card with album art dominant colour
cacheAlbumArt: true // required for albumArtColors
}
}The fullscreen card shows:
- Album art — large square image (configurable with
fullscreenAlbumArtSize) - Group name — small uppercase badge identifying the speaker/group
- Track title — large, bold, up to 2 lines
- Artist — beneath the title
- Album — when
showAlbum: true - Playback source — when
showPlaybackSource: true - Progress bar — when
showProgress: trueand duration is known - Volume — when
showVolume: true - Group members — when
showGroupMembers: trueand there are multiple members
Use fullscreenSpeaker to pin the card to a specific speaker. The value can be a speaker name (e.g. 'Stue'), group name, group ID, or coordinator IP. When left as null, the first group that is currently playing is shown.
Tip: Combine fullscreen mode with a page-manager module to automatically switch to the fullscreen page whenever music is playing. Use
allowedSpeakersto restrict the module to a single room, and setfullscreenSpeakerto the same room name for a dedicated room display.
Fullscreen mode option reference:
| Option | Default | Description |
|---|---|---|
fullscreenSpeaker |
null |
Speaker/group to show. Accepts a speaker name, group name, group ID, or coordinator IP. When null, the first currently-playing group is used. |
fullscreenAlbumArtSize |
300 |
Album art size in pixels. |
fullscreenWidth |
null |
Set a maximum width for the fullscreen card (e.g. 600 or '600px'). |
Setting enableControls: true turns MMM-Sonos from a pure display into a
tappable control surface, for use on a touch-screen (or any mirror you're
willing to touch). It only changes behavior in row and grid
displayMode — mini and fullscreen are unaffected.
{
module: 'MMM-Sonos',
position: 'bottom_left',
config: {
displayMode: 'row',
enableControls: true,
controlShowIdleZones: true, // false = only show playing zones; reach idle ones via the "+" button
favoritesRefreshInterval: 300000, // how often the favorites list is re-fetched (ms)
maxFavorites: 12, // max favorites shown before the list scrolls
controlVolumeStep: 5 // slider step size
}
}With enableControls: true:
- By default (
controlShowIdleZones: true), every zone on the network is shown, not just ones currently playing — idle speakers get a simple "Nothing playing" card instead of being hidden (hideWhenNothingPlayingandshowWhenPausedno longer apply). - Set
controlShowIdleZones: falseto only show zones that are actually playing, just like normal (non-control) mode. Idle zones are then reached through a small "+" button that appears in the corner of the module — tapping it lists the hidden zones so you can open one and start playback there. - Tapping any visible card (playing or idle) opens a control overlay with play/pause, previous/next track, shuffle, repeat (off → all → one), a mute button, a volume slider, and a list of your Sonos favorites. Previous/next, shuffle and repeat are hidden for radio and TV, which have no track list to move through.
- The volume slider controls the whole group together: every speaker in that group is set to the same volume level, not just the coordinator.
- Once a zone has more than one speaker, a collapsed "▾ Per-speaker volume" section appears below the group slider with one slider and one mute button per member, for adjusting a single speaker without changing the rest of the group. The group mute button mutes every speaker in it.
- A "Speakers" button in the overlay header opens a picker for changing group membership: pick another zone to merge every one of its speakers into the one you're viewing, or tap "Remove" next to a member to split it back out into its own standalone zone. The picker stays open after each tap (each row briefly disables itself mid-request) so you can pull in several zones, or remove several members, in one sitting.
- Favorites come directly from what you've saved in the Sonos app (via Sonos' own favorites list) — there is no separate config-defined station list to maintain.
- The overlays follow the module's look (fonts, colours,
fontScale/textSize), and every label is translated.
Security note: anyone who can open your MagicMirror² page in a browser can control your speakers while
enableControlsis on. KeepipWhitelist/addressin your MagicMirror config restricted to devices you trust (the default only allows the mirror itself).
Cards with idle speakers (controlShowIdleZones: true):
Control overlay (playback, shuffle/repeat, mute, group and per-speaker volume, favorites):
Speakers picker (group / ungroup):
"+" tile for idle speakers (controlShowIdleZones: false):
Touch control mode option reference:
| Option | Default | Description |
|---|---|---|
enableControls |
false |
Master switch for touch control mode. |
controlShowIdleZones |
true |
When true, every zone is always shown (idle ones get a "Nothing playing" card). When false, only playing zones are shown, matching normal mode — idle zones are reached via the "+" more-speakers button. |
favoritesRefreshInterval |
300000 |
How often (ms) the favorites list is re-fetched from Sonos. |
maxFavorites |
12 |
Maximum number of favorites shown in the overlay before it scrolls. |
controlVolumeStep |
5 |
Step size of the volume slider in the control overlay. |
maxGroups(default6) also limits how many cards control mode shows. Raise it if you have more zones than that; idle speakers behind the "+" tile are not limited.- Favorites are played the way the Sonos app plays them: stations and
streams directly, playlists and albums by replacing the queue. If a
favorite does not start, the reason is written to the MagicMirror log
(
Control action "playFavorite" failed …) — please include it in a report. - Sonos Radio station collections (such as "Discover Sonos Radio") are stored without a playable address and are not listed.
- Automatic re-discovery: If the Sonos device drops off the network, the module will try to find it again.
- Fast initial load: When the frontend reconnects (e.g. after a browser refresh), data is served immediately if a coordinator was already discovered during startup — no 5-second re-discovery stall on every reconnect.
- HTTPS-friendly album art: Set
forceHttps: truewhen your mirror runs behind an HTTPS proxy and browsers block mixed content. - Responsive layout: The
row,grid,auto,mini, andfullscreenlayouts adapt to any display size. - Snappy updates: Polling combined with caching keeps the UI fresh without noticeable lag.
- Local album art cache: Album art images are downloaded once and served from disk on subsequent polls, giving instant display even on slow networks. See the
cacheAlbumArt,albumArtCacheTTL, andclearCacheOnStartoptions above. - Accent colours: Enable
albumArtColors: true(withcacheAlbumArt: true) to automatically tint each card with the dominant colour extracted from its album art. - Smooth transitions: Track changes animate in/out with configurable styles (
transitionAnimation) and duration (transitionDuration). In all modes (mini, row, grid, fullscreen), only the changing card is animated — the rest stay put. - Mini mode:
displayMode: 'mini'renders a compact stacked list of now-playing rows — ideal for a small corner of your display. - Fullscreen mode:
displayMode: 'fullscreen'shows a single speaker as a large card with prominent album art — ideal for a dedicated MagicMirror page. - Dual-mode support: You can add MMM-Sonos twice in your config (e.g. once as
miniin a corner and once asfullscreenon a separate page). Each instance is fully independent — track changes update each instance correctly without cross-contamination. - Apple Music support: The module correctly identifies and labels Apple Music streams.
- Improved radio metadata: Station names, logos, and "now playing" stream content are extracted from the Sonos AVTransport metadata for a richer display.
- Whitelist filtering: Use
allowedGroups/allowedSpeakersto restrict the module to only the rooms or groups you care about, without needing to list every other room as hidden.
There are three ways to clear the cached album art images:
- On the next restart — set
clearCacheOnStart: truein your config, restart MagicMirror, then set it back tofalse. - From the browser console — open the browser console on your mirror and run:
MM.getModules().withClass('MMM-Sonos')[0].clearAlbumArtCache()
- Manually — delete the
modules/MMM-Sonos/cache/album-art/directory and restart MagicMirror.
The module consists of the following files:
MMM-Sonos.js- Main module file handling the UI and frontend logicnode_helper.js- Backend helper that communicates with Sonos devicespackage.json- Node.js dependencies and metadata
css/MMM-Sonos.css- All module styles including layout modes, animations, and themes
The module includes multilingual support with translations for all languages supported by MagicMirror:
translations/af.json- Afrikaanstranslations/ar.json- Arabictranslations/bg.json- Bulgariantranslations/bn.json- Bengalitranslations/ca.json- Catalantranslations/cs.json- Czechtranslations/cy.json- Welshtranslations/da.json- Danishtranslations/de.json- Germantranslations/el.json- Greektranslations/en.json- Englishtranslations/es.json- Spanishtranslations/et.json- Estoniantranslations/fi.json- Finnishtranslations/fr.json- Frenchtranslations/fy.json- Frisiantranslations/ga.json- Irishtranslations/gl.json- Galiciantranslations/he.json- Hebrewtranslations/hi.json- Hinditranslations/hr.json- Croatiantranslations/hu.json- Hungariantranslations/id.json- Indonesiantranslations/is.json- Icelandictranslations/it.json- Italiantranslations/ja.json- Japanesetranslations/ko.json- Koreantranslations/lt.json- Lithuaniantranslations/lv.json- Latviantranslations/ms.json- Malaytranslations/nb.json- Norwegian Bokmåltranslations/nl.json- Dutchtranslations/pl.json- Polishtranslations/pt.json- Portuguesetranslations/pt-BR.json- Portuguese (Brazilian)translations/ro.json- Romaniantranslations/ru.json- Russiantranslations/sk.json- Slovaktranslations/sl.json- Sloveniantranslations/sv.json- Swedishtranslations/th.json- Thaitranslations/tr.json- Turkishtranslations/uk.json- Ukrainiantranslations/vi.json- Vietnamesetranslations/zh-CN.json- Chinese (Simplified)translations/zh-TW.json- Chinese (Traditional)
Supported translation keys include error messages, playback states, and UI labels. Add your own language by creating a new JSON file in the translations folder and adding it to the getTranslations() method in MMM-Sonos.js.
assets/tv-default.svg- Default TV icon for home theater sourcesassets/tv.svg- Alternative TV icon
You can add custom TV icons by placing SVG files in the assets folder and referencing them with the tvIconSvgPath configuration option.
The module includes several npm scripts for development and maintenance:
npm run lint # Run ESLint to check code quality
npm test # Unit and integration tests (fast, no MagicMirror needed)
npm run test:e2e # End-to-end test in a real MagicMirror² with simulated Sonos speakers
npm run sim # Start the Sonos simulator on 127.0.0.1:1400+ for manual testing
npm run audit # Check for security vulnerabilities in dependenciesThe end-to-end test installs MagicMirror² into .e2e/ on first run, starts simulated speakers playing Spotify, Apple Music, Amazon Music, radio, TV and a local library, and checks every display mode in headless Chromium. Screenshots end up in test/e2e/output/. All tests run in GitHub Actions for every pull request. See test/README.md for details.
This module uses dependency overrides to mitigate known security vulnerabilities in transitive dependencies:
- axios: Overridden to
^1.13.1(fixes CSRF, SSRF, and DoS vulnerabilities; the lockfile currently resolves 1.20.0) - xml2js: Overridden to
^0.6.2(fixes prototype pollution vulnerability) - ip: Overridden to
^2.0.1(latest available version)
Note: The ip package has a known SSRF vulnerability (GHSA-2p57-rm9w-gvfp) that affects all versions ≤2.0.1. This is a transitive dependency from the sonos package. No patch is currently available. The vulnerability relates to improper categorization in the isPublic function. Users should assess their own network configuration and threat model to determine if this poses a risk in their environment.
- Set
debug: trueto inspect what happens in both the browser module and the node helper (visible in the MagicMirror console). The debug log includes the raw track data from each speaker (Raw track object), which is the most useful thing to include when reporting that a service shows the wrong title or source. - Running several MMM-Sonos instances (e.g. a row and a fullscreen one)? They share one node helper. Each instance applies its own
allowedSpeakers,hiddenSpeakers,showWhenPausedandmaxGroups; features such asalbumArtColorsare fetched when any instance enables them. - Increase
discoveryTimeoutif no players are found. On mesh networks 10000–15000 ms is sometimes required. - Run
npm installagain whenever dependencies appear to be missing. - Missing album art? Try
forceHttps: trueif MagicMirror runs over HTTPS and the browser blocks plain HTTP images. - To check for dependency vulnerabilities, run
npm run audit.
Some ideas for future improvements:
Add volume control through touch or remote notifications.✅ CompletedShow the playback source (Spotify, Radio, Line-in) with an icon.✅ CompletedInclude a simple progress indicator for the current track.✅ CompletedCache album art locally for faster loading on slower networks.✅ CompletedAdjust volume on individual speakers in a group, in addition to group volume.✅ CompletedPossibility to group and ungroup speakers.✅ Completed- Add a sleep timer — automatically pause playback after N minutes.
- Show a small icon per favorite indicating its type (radio, playlist, stream).
Published under the MIT License. Contributions and pull requests are always welcome!




