summaryrefslogtreecommitdiff
path: root/MQTT.md
blob: da21a3fc0972a034a7d658945bcb6ff1ea0d159d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
Setting Up MQTT Publishing
====

This is a rough guide on the setup of MQTT publishing in ShairPort-Sync. The MQTT service listens for and publishes metadata generated by the airplay source and shairport-sync. 

Below is a simple example of configuring shairport-sync to send parsed metadata to a MQTT server under the topic "shairport"

Example Configuration
----

Shairport-sync is configured below to published parsed metadata information and album-art to a MQTT server.

```xml

metadata =
{
	enabled = "yes"; // set this to yes to get Shairport Sync to solicit metadata from the source and to pass it on via a pipe
	include_cover_art = "yes"; // set to "yes" to get Shairport Sync to solicit cover art from the source and pass it via the pipe. You must also set "enabled" to "yes".
	cover_art_cache_directory = "/tmp/shairport-sync/.cache/coverart"; // artwork will be  stored in this directory if the dbus or MPRIS interfaces are enabled or if the MQTT client is in use. Set it to "" to prevent caching, which may be useful on some systems
	pipe_name = "/tmp/shairport-sync-metadata";
	pipe_timeout = 5000; // wait for this number of milliseconds for a blocked pipe to unblock before giving up
};


mqtt =
{
	enabled = "yes"; // set this to yes to enable the mqtt-metadata-service
	hostname = "192.168.1.111"; // Hostname of the MQTT Broker
	port = 1883; // Port on the MQTT Broker to connect to
	username = "username"; //set this to a string to your username in order to enable username authentication
	password = "password"; //set this to a string you your password in order to enable username & password authentication
	topic = "shairport"; //MQTT topic where this instance of shairport-sync should publish. If not set, the general.name value is used.
//	publish_raw = "no"; //whether to publish all available metadata under the codes given in the 'metadata' docs.
	publish_parsed = "yes"; //whether to publish a small (but useful) subset of metadata under human-understandable topics
	publish_cover = "yes"; //whether to publish the cover over mqtt in binary form. This may lead to a bit of load on the broker
//	enable_remote = "no"; //whether to remote control via MQTT. RC is available under `topic`/remote.
};
```

Import Notes
----

Publish Options

One needs to set either `publish_raw`, `publish_parsed` or `publish_cover` in the MQTT setup or no messages will be published.


Overall Active State of Stream

`active_start` and `active_end` represent a stable on/off flag for the current airplay session.  

`active_start` is plublished when any new airplay session begins 

`active_end` will fire after a configured timeout period unless the airplay stream is resumed.

```xml
sessioncontrol =
{
//	"active" state starts when play begins and ends when the active_state_timeout has elapsed after play ends, unless another play session starts before the timeout has fully elapsed.
	active_state_timeout = 30.0;
};
```

MetaData Parsing
----


Additional details regarding the metadata can be found at [https://github.com/mikebrady/shairport-sync-metadata-reader]

Meta data is generated by both the stream source (iOS, itunes, etc) and by shairport-sync itself.  This data is coded as two 4-character codes to identify each piece of data, the `type` and the `code`.

The first 4-character code, called the `type`, is either:
 * `core` for all the regular metadadata coming from iTunes, etc., or
 * `ssnc` (for 'shairport-sync') for all metadata coming from Shairport Sync itself, such as start/end delimiters, etc.

* For `core` metadata, the second 4-character code is the 4-character metadata code that comes from iTunes etc. See, for example, https://code.google.com/p/ytrack/wiki/DMAP for information about the significance of the codes. The original data supplied by the source, if any, follows, and is encoded in base64 format. The length of the data is also provided.
* For `ssnc` metadata, the second 4-character code is used to distinguish the messages. Cover art, coming from the source, is not tagged in the same way as other metadata, it seems, so is sent as an `ssnc` type metadata message with the code `PICT`. Progress information, similarly, is not tagged like other source-originated metadata, so it is sent as an `ssnc` type with the code `prgr`.

Here are some of the `core` codes commonly passed from the source:
 * `asar` -- "artist"
 * `asal` -- "album"
 * `minm` -- "title"
 * `asgn` -- "genre"
 * `asfm` -- "format"
 * `asal` -- "songalbum'
 * `pvol` -- "volume"
 * `clip` -- "client_ip"

Here are the 'ssnc' codes defined so far:
 * `PICT` -- the payload is a picture, either a JPEG or a PNG. Check the first few bytes to see which.
 * `clip` -- the payload is the IP number of the client, i.e. the sender of audio. Can be an IPv4 or an IPv6 number.
 * `pbeg` -- play stream begin. No arguments
 * `pend` -- play stream end. No arguments
 * `pfls` -- play stream flush. No arguments
 * `prsm` -- play stream resume. No arguments
 * `pvol` -- play volume. The volume is sent as a string -- "airplay_volume,volume,lowest_volume,highest_volume", where "volume", "lowest_volume" and "highest_volume" are given in dB. The "airplay_volume" is what's sent by the source (e.g. iTunes) to the player, and is from 0.00 down to -30.00, with -144.00 meaning "mute". This is linear on the volume control slider of iTunes or iOS AirPlay. If the volume setting is being ignored by Shairport Sync itself, the volume, lowest_volume and highest_volume values are zero.
 * `prgr` -- progress -- this is metadata from AirPlay consisting of RTP timestamps for the start of the current play sequence, the current play point and the end of the play sequence.
 * `mdst` -- a sequence of metadata is about to start. The RTP timestamp associated with the metadata sequence is included as data, if available.
 * `mden` -- a sequence of metadata has ended. The RTP timestamp associated with the metadata sequence is included as data, if available.
 * `pcst` -- a picture is about to be sent. The RTP timestamp associated with it is included as data, if available.
 * `pcen` -- a picture has been sent. The RTP timestamp associated with it is included as data, if available.
 * `snam` -- a device e.g. "Joe's iPhone" has started a play session. Specifically, it's the "X-Apple-Client-Name" string.
 * `snua` -- a "user agent" e.g. "iTunes/12..." has started a play session. Specifically, it's the "User-Agent" string.
 * `stal` -- this is an error message meaning that reception of a large piece of metadata, usually a large picture, has stalled; bad things may happen.


Parsed Messages
----

The MQTT service can parse the above raw messages into a subset of human-readable topics that include, 

* `artist` -- text of artist name 
* `album` -- text of album name
* `title` -- text of song title
* `genre` -- text of genre
* `format` -- ??
* `songalbum` -- 
* `volume` -- The volume is sent as a string -- "airplay_volume,volume,lowest_volume,highest_volume", where "volume", "lowest_volume" and "highest_volume" are given in dB. (see above)
* `client_ip` -- IP address of the connected client

and empty messages at the following topics are published.

* `play_start` -- fired at the begining of every song
* `play_end` -- fired at the end of every song
* `play_flush` -- fired when song is skipped or on positional change
* `play_resume` -- fired when song play resumes from pause
* `active_start` -- fired when a new active airplay session begins
* `active_end` -- fired after a configured timeout period after the stream ends (unless a new stream begins)



## Consuming MQTT Data

Users will find examples on how to consume the MQTT data in various home automation projects.  If a user has an interesting use please raise a new issue to suggest adding it to the guide, or simply fork the development branch and create a pull-request.

### Home Assistant Variable Templates

Examples of consuming "parsed" MQTT data in [Home Assistant](https://www.home-assistant.io/)
The `active_start` and `active_end` have good potential use as triggers to turn on and off various connect receivers/zones.  The messages published are empty and therefor no "payload_on" is set, "payload_off" however is set to prevent accidental triggering.

```yml
binary_sensor:

  - platform: mqtt
    name: "shairport active start"
    state_topic: "shairport/active_start"
    payload_on: ""
    payload_off: "OFF"
    off_delay: 300

  - platform: mqtt
    name: "shairport active end"
    state_topic: "shairport/active_end"
    payload_on: ""
    payload_off: "OFF"
    off_delay: 300
```

Below parsed data is saved into the Home Assistant database as sensor data.  Please not the conversion of the volume from dB to percentage.

```yml
sensor:
  - platform: mqtt
    name: "shairport album"
    state_topic: "shairport/album"
    expire_after: 600
  
  - platform: mqtt
    name: "shairport artist"
    state_topic: "shairport/artist"
    expire_after: 600
    
  - platform: mqtt
    name: "shairport title"
    state_topic: "shairport/title"
    expire_after: 600
    
  - platform: mqtt
    name: "shairport genre"
    state_topic: "shairport/genre" 
    expire_after: 600
    
  - platform: mqtt
    name: "shairport volume (dB)"
    state_topic: "shairport/volume"
    
  - platform: mqtt
    name: "shairport volume (PCT)"
    state_topic: "shairport/volume"
    value_template: "{{ value |  regex_findall_index(find='^(.+?),', index=0, ignorecase=False) | float / 30 + 1  }}"
    unit_of_measurement: 'percent'
```