sonosmqtt

command module
v0.0.0-...-e14b457 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 20, 2022 License: MIT Imports: 21 Imported by: 0

README

This is an app I've been working on for a while off and on.  It is starting
to look slightly cleaner, but it is frankly still a bit of a mess.  It is
also constantly changing scope, which is a luxury I have on a passion
project.

I suspect I'll have to implement auth at some point as some of the cool
stuff that we want to display is locked down.  The good news is that only this
app cares, the clients will always get access via MQTT (or websockets, or REST,
or a simple endpoint that you can POST websocket-style commands to).


High level idea
---------------

I suppose I should start with describing what this actually did early on.  The 
general idea is to discover Sonos players on the LAN, subscribe to events on all 
of the group coordinators, and publish these events to a MQTT broker in a 
moderately sane fashion.  The topics used will be listed at the end of this, but 
for now the general idea is to subscribe to a topic for discovery and use the data
provided to find the other topics you want to subscribe to.  In each of the
cases below, you can pick what you want by setting the simplify config
option.

  - Subscribe to {base}/views/groups or {base}/views/players
    
    This will give you the list of groups or players. See below for more
    detail, but in general this is internal data that I've pulled in from
    a variety of sources.

  - Subscribe to {base}/group/{groupId}/{eventType} or {base}/player/{playerId}/{eventType}

    This is where you will get actual event from the player(s) you care about.
    At the moment I only support groupId targeted events, so you will get the
    former when simplify is not set and the latter when it is set.
    
    Note that in the current implementation I can't see any reason to deal
    with {base}/group/# for anything.  You get the same content in 
    {base}/player/{playerId}/#, and you can use any PlayerId in the group.

    Note that this data is either a raw event from Sonos or a simplifed version
    of that event.


Config file
-----------

I'll just slap a commented config file here.  You need one.  The app defaults
to looking for config.yml in the working directory, but that can be overridden
on the command line via --cfgpath.


    # General options
    #
    # debug: optional, set to true in order get overly verbose debug messages
    debug: false

    # Sonos options
    #
    # apikey:       required, and can be obtained from Sonos
    # household:    optional, and if present only players from that household are tracked
    # subcriptions: optional. but playbackExtended is recommended for now
    # simplify:     optional, set to true to simplify Muse events before publishing.
    # scantime:     optional, the number of seconds to wait for mDNS results.  Defaults to 5.
    sonos:
    apikey: "REDACTED"
    household: "REDACTED"
    subscriptions: 
        - playbackExtended
    simplify: true

    # MQTT options
    #
    # Omitting any of this "works", but defeats the purpose of the application.
    #
    # broker:
    #   host:     required, hostname or IP of MQTT server
    #   port:     required, port of MQTT server
    #   client:   required, name to use for this client on the MQTT server
    #   tls:      optional, and setting to true enables tls
    #   username: optional, and only valid if tls is true
    #   password: optional, and only valid if tls is true
    # topic:    required, base topic to put Sonos MQTT content on
    mqtt:
    broker:
        host: "127.0.0.1"
        port: 1883
        client: "sonosmqtt1"
    topic: "sonos"


MQTT topics used
----------------

  Simplify disabled
  -----------------

  When simplify is disabled, events come in exactly as sent by the Sonos
  devices.  As a result, I will only document the topic paths and not the
  content outside of mentioning the content type.  I don't want to have to
  adjust the docs every time the format changes, nor do I want to document the
  Sonos formats in gory detail.
  
  - {base}/groups

    The latest GroupsResponse as delivered by a Sonos device.  This contains
    all of the current groups, all of the current players, and some mapping
    between them.  There is also a LOT of detail available for the players if
    one cares (capabilities, protocol versions, etc).
    
  - {base}/views/groups

    A simplfied version of groups that has playback metadata added to it.

  - {base}/group/{groupCoordinatorId}/{eventType} or {base}/player/{playerId}/{eventType}
    
    Examples:    
      - {base}/{GroupCoordinatorId}/extendedPlaybackStatus
      - {base}/{PlayerId}/extendedPlaybackStatus

    The latest group level events from the namespaces specified in config.yml.
    The one I've been testing with, as it is all I need at the moment, is
    extendedPlaybackStatus.

    Note that I'm also not going to document the relationship between subscribing 
    to a namespace and the events that are received.  At the moment subscribing to
    playbackExtended only events extendedPlaybackStatus, but I have no insight
    into how that may change over time.


  Simplify enabled
  ----------------

  - {base}/views/groups

    A simplfied version of groups that has playback metadata added to it.

  - {base}/groupsSimple
  
    At the moment, this is a list of groups.  Each group contains an id and a list
    of players.  This can be used by more complete controllers, while /players is 
    more suitable for dump single-player displays.  This is just a mapping of the
    groupsResponse, so it does not contain metadata.
    
    {
      [
        { 
	  "id":   "GroupId1",
	  [
       	    { "id: "PlayerId 1", "name": "Player Name 1" },
	  ], 
      	},
      ]
    }
    
  
  
  - {base}/players

   At the moment it is a simple list of players, with playerName and playerId
   exposed:
    

    {
      [
        { 
	  "id":   "PlayerId1",
       	  "name": "Player Name 1", 
      	},
        ...
	{ 
	  "id":   "PlayerIdX",
       	  "name": "Player Name X", 
          
      	},
      ]
    }

  - {base}/{PlayerId}/extendedPlaybackStatusSimple

    If you subscribe to playbackExtended via the config file, all responses
    will get reduced to the following and will be published to
    {base}/{playerId}/extendedPlaybackStatusSimple for every player in the
    group when the group metadata or playback state changes.

    It looks like this:
    
    { 
        "playbackState": "Playback state as sent by Sonos player",
        "artist":        "ArtistName",
        "album":         "AlbumName",
        "track":         "TrackName",
        "imageUrl":      "URL for album art",
    }

Alternate control mechanisms
----------------------------

While this originally just published events to MQTT, I started to become 
obsessed with having a single point on my LAN I could always hit for control
in addition to getting events.  This, like everything else, has evolved and
is now a tightly wound ball of spaghetti.  At least I can read it, right?

Anyway, if you look in webserver.go you will see that a web interface has
been added.  You can hit send proper Sonos commands using it if you know
the namespace, and you can even cheat and hit any player in the group 
with play/pause commands (for example) since the code will find the proper
player to talk to.

This API looks like this:

  - {server}/v1/groups
    
    GET this in order to get a list of groups.  This is the same data published 
    to {base}/views/groups in MQTT.  I should probably make the paths match.

  - {server}/v1/players
    
    GET this in order to get a list of players.  This is the same data published 
    to {base}/views/players in MQTT.  I should probably make the paths match.

  - {server}/v1/group/{id}

    GET information about the group with a given id

  - {server}/v1/player/{id}

    GET information about the group with a given id

  - {server}/v1/player/{id}/{namespace}/{command}

    GET to get info, POST to send a command

  - {server}/v1/wsapi

    POST to send any Sonos websocket-formatted command.  It will send the data over 
    the proper websocket, wait for a response, and return the response.

    

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL