Skip to content

Instantly share code, notes, and snippets.

Created Oct 17, 2014
What would you like to do?
Sonos Now Playing


A Dashing widget that searches for a Sonos device that is currently playing music, and displays Now Playing information and album artwork.

Utilises soffe's Sonos controller.


Please add the following lines to your gemfile:

require 'rubygems'
require 'sonos'


Place sonos.rb in /jobs.

Edit your dashboard and add these widgets:

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-id="nowplaying" data-view="Text" data-title="NOW PLAYING" data-text="Artist - Track"></div>

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-id="albumart" data-view="Image" data-title="Album Name"></div>



require 'rubygems'
require 'sonos'
def send_transport_message(name, player, part = '<Speed>1</Speed>')
@transport_client ||= Savon.client endpoint: "http://#{player.ip}:#{Sonos::PORT}#{TRANSPORT_ENDPOINT}", namespace: Sonos::NAMESPACE, log: Sonos.logging_enabled
action = "#{TRANSPORT_XMLNS}##{name}"
message = %Q{<u:#{name} xmlns:u="#{TRANSPORT_XMLNS}"><InstanceID>0</InstanceID>#{part}</u:#{name}>}, soap_action: action, message: message)
# Get information about the currently playing track.
# @return [Hash] information about the current track.
def get_now_playing(player)
return nil if player == nil
response = send_transport_message('GetPositionInfo', player)
body = response.body[:get_position_info_response]
doc = Nokogiri::XML(body[:track_meta_data])
# No music
return nil if doc.children.length == 0
art_path = doc.xpath('//upnp:albumArtURI').inner_text
# TODO: No idea why this is necessary. Maybe its a Nokogiri thing
art_path.sub!('/getaa?s=1=x-sonos-http', '/getaa?s=1&u=x-sonos-http')
title: doc.xpath('//dc:title').inner_text,
artist: doc.xpath('//dc:creator').inner_text,
album: doc.xpath('//upnp:album').inner_text,
info: doc.xpath('//r:streamContent').inner_text,
queue_position: body[:track],
track_duration: body[:track_duration],
current_position: body[:rel_time],
uri: body[:track_uri],
album_art: "http://#{player.ip}:#{Sonos::PORT}#{art_path}"
TRANSPORT_ENDPOINT = '/MediaRenderer/AVTransport/Control'
TRANSPORT_XMLNS = 'urn:schemas-upnp-org:service:AVTransport:1'
system =
player = nil
system.speakers.each do |speaker|
if speaker.is_playing?
player = speaker
SCHEDULER.every '10s' do
metadata = get_now_playing(player)
if metadata and player
send_event("albumart", { image: metadata[:album_art] })
send_event("nowplaying", { text: metadata[:artist] + ' - ' + metadata[:title], moreinfo: })
elsif player
send_event("albumart", { image: 'assets/sonoslogo.png' })
send_event("nowplaying", { text: "Nothing playing in " + })
send_event("albumart", { image: 'assets/sonoslogo.png' })
send_event("nowplaying", { text: "Unable to connect to any player" })
Copy link

wpeterw commented Nov 10, 2014

It does not display the albumart. When I look at the properties of the, broken, image I see that the url looks like: http://ipofthedasboard/assets/hhtp://sonosplayerip/etcetc/.. How do i strip the first part from this url ? (the part after /assets/ points to the correct location).

Copy link

crummy commented Nov 11, 2014

What service are you playing from?

Copy link

wpeterw commented Nov 11, 2014

I'm playing from Deezer. The albumart url is correct but "somewhere" it is prefixed with the url to the dashing server:

Copy link

crummy commented Nov 11, 2014

Ah, I forgot I tweaked the image widget. You can fix this by editing image.html and removing prepend '/assets' or adding another widget, identical to the existing image widget but for that change, and use that instead.

Copy link

fliptrocity commented Sep 3, 2015

Any insight on how I can get this to point to a specific bridge rather than it picking a random one on the network?

Copy link

stigert commented Mar 7, 2019

This isn't working for me. The dashboard won't load at all after installing this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment