Spotify Notify Now Playing
Node-RED

Spotify Notify Now Playing

Sends a notification with artist and song title to your display when Spotify plays a song.
A flow by rogote

Download flow

Flow Details

This flow polls the Spotify Web API every 20 seconds and sends a notification to your display when a new song is played.

You can customize the look of the notification easily. Also there is an option to exclude certain devices (e.g. show notifications from your desktop computer and the media station, but not your mobile).

Unfortunately, podcasts or audio books do not work. I have tried to include this, but the Node-RED wrapper for the Spotify WebAPI does not seem to pass the required data.

Requirements

  • Node node-red-contrib-spotify. Install via Manage Palette (not npm)
  • Icon 18207 of the lametric icons. Install it via Icons tab in Awtrix WebUI.
  • Spotify account and a registration for Spotify Web API for authentication using a Client id and a Client secret

Using Spotify WebAPI

  • Go to https://developer.spotify.com, login with your account
  • To create an app, go to your Dashboard, click on the Create an app button and enter the following information:
    • App Name: My Node-RED
    • App Description: My Node-RED integration
    • Redirect URI: any URL, e.g. http://localhost
    • Check that you want to use Web API
    • Finally, check the Developer Terms of Service checkbox and tap on the Create button.
  • Click on the Settings button for you app
  • The Client ID can be found here. The Client Secret can be found behind the View client secret link.
  • Insert this this client id and secret in the Spotify OAuth config
[ { "id": "98eecb7bb5dbbaf0", "type": "tab", "label": "AwtrixSpotifyNowPlayingNotify release", "disabled": true, "info": "", "env": [] }, { "id": "102a7c3090fc21bc", "type": "group", "z": "98eecb7bb5dbbaf0", "name": "AwtrixSpotifyNowPlaying", "style": { "label": true }, "nodes": [ "f07bc970d1ba1d34", "cc39161e9f07b9e7", "0d7b7ef06966888c", "9637b1fa56ac50be", "0f3340104ade2060", "c586b27248de35e3", "192cbe59ce8d1b8f", "a37cb524eb2e81b7", "4f88debd9b96161f", "73b3f79623812ba6", "dc255cbcd49bf14c", "27ea2881cadb1f92", "2d9face2a87e72d7", "fe6a16cb0b96ec69", "691c9f88f16bd888", "c1f765fa96cfabc4", "eae4632e012e7ddb", "bdd49c32127e509f", "593fdc2b0ff0d6a2", "eb64fc82df1b4f28", "918ace7ed1bffb3a", "c3f8ccea36f7ec8f", "6d40d23e58c88456", "bf4c58920c2e72b8", "2c5334769f24b80c", "911d011a95bc459c", "c07faab9894a65cb", "71d68eeaed474950", "3d1e8e19487546e6", "80e257fffa8df888", "25c3b1d127d029a1", "f5e36a35068d3417", "e43d0a770e75346d", "de5520fd34e592f9", "5896383e6831434d" ], "x": 14, "y": 19, "w": 1332, "h": 782 }, { "id": "f07bc970d1ba1d34", "type": "inject", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Initialise", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 140, "y": 100, "wires": [ [ "0d7b7ef06966888c" ] ] }, { "id": "cc39161e9f07b9e7", "type": "change", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Initialise Now Playing Data", "rules": [ { "t": "set", "p": "image", "pt": "flow", "to": "payload.items[0].track.album.images[0].url", "tot": "msg" }, { "t": "set", "p": "trackname", "pt": "flow", "to": "payload.items[0].track.name", "tot": "msg" }, { "t": "set", "p": "artistname", "pt": "flow", "to": "payload.items[0].track.artists[0].name", "tot": "msg" }, { "t": "set", "p": "albumname", "pt": "flow", "to": "payload.items[0].track.album.name", "tot": "msg" }, { "t": "set", "p": "favicon", "pt": "flow", "to": "payload.items[0].track.album.images[2].url", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 640, "y": 100, "wires": [ [ "9637b1fa56ac50be", "c586b27248de35e3" ] ] }, { "id": "0d7b7ef06966888c", "type": "spotify", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Get Recent Tracks", "auth": "034f07b3451cce16", "api": "getMyRecentlyPlayedTracks", "x": 330, "y": 100, "wires": [ [ "cc39161e9f07b9e7" ] ] }, { "id": "9637b1fa56ac50be", "type": "spotify", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Get Me", "auth": "034f07b3451cce16", "api": "getMe", "x": 840, "y": 100, "wires": [ [ "0f3340104ade2060" ] ] }, { "id": "0f3340104ade2060", "type": "change", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Initialise Name", "rules": [ { "t": "set", "p": "username", "pt": "flow", "to": "payload.display_name", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1000, "y": 100, "wires": [ [] ] }, { "id": "c586b27248de35e3", "type": "spotify", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Get if playing", "auth": "034f07b3451cce16", "api": "getMyCurrentPlaybackState", "x": 210, "y": 200, "wires": [ [ "de5520fd34e592f9" ] ] }, { "id": "192cbe59ce8d1b8f", "type": "switch", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "", "property": "payload.is_playing", "propertyType": "msg", "rules": [ { "t": "cont", "v": "true", "vt": "str" }, { "t": "else" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 550, "y": 200, "wires": [ [ "a37cb524eb2e81b7" ], [ "eb64fc82df1b4f28" ] ] }, { "id": "a37cb524eb2e81b7", "type": "spotify", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Get Current Track", "auth": "034f07b3451cce16", "api": "getMyCurrentPlayingTrack", "x": 750, "y": 200, "wires": [ [ "c07faab9894a65cb" ] ] }, { "id": "4f88debd9b96161f", "type": "change", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Update Now Playing Data", "rules": [ { "t": "set", "p": "duration", "pt": "msg", "to": "payload.item.duration_ms", "tot": "msg" }, { "t": "set", "p": "position", "pt": "msg", "to": "payload.progress_ms", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1170, "y": 200, "wires": [ [ "27ea2881cadb1f92" ] ] }, { "id": "73b3f79623812ba6", "type": "function", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Calc remaining seconds", "func": "msg.delay = 1 + ( msg.duration - msg.position ) / 1000;\n\nif (msg.delay > 20) {\n msg.delay = 20;\n}\n \nmsg.delay = msg.delay * 1000;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 530, "y": 540, "wires": [ [ "2d9face2a87e72d7" ] ] }, { "id": "dc255cbcd49bf14c", "type": "http request", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "AwtrixUlanzi/Notify", "method": "POST", "ret": "txt", "paytoqs": "ignore", "url": "http://192.168.178.165/api/notify", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [ { "keyType": "Content-Type", "keyValue": "", "valueType": "other", "valueValue": "application/json" } ], "x": 770, "y": 640, "wires": [ [] ], "icon": "font-awesome/fa-align-left" }, { "id": "27ea2881cadb1f92", "type": "function", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "PrepareNotification", "func": "msg.firstArtistString = msg.payload.item.artists[0].name;\nmsg.artistsString = \"\";\nfor (var i = 0; i < msg.payload.item.artists.length; i++) {\n if(i>0){\n msg.artistsString = msg.artistsString + \", \";\n }\n msg.artistsString = msg.artistsString + msg.payload.item.artists[i].name;\n}\nmsg.trackString = msg.payload.item.name;\nmsg.albumString = msg.payload.item.album.name;\nmsg.albumTrimmedString = msg.albumString.split('(')[0];\nmsg.playedTrack = msg.artistsString + \" - \" + msg.trackString;\n\n\n// Change here for your personal style\n// Please check\n// https://blueforcer.github.io/awtrix3/#/api?id=json-properties\n// what is possible\n// these strings are avilable\n// msg.artistsString with all artists seperated by ,\n// msg.firstArtistString first listed artist only\n// msg.albumString album name\n// msg.albumTrimmedString album name without things in brackets like \"(super extra edition with three live songs and audio comments)\"\n// msg.playedTrack track name\n//\nmsg.payload = {\n \"text\": [\n {\n \"t\": msg.artistsString, // use msg.artistsString for all Artists or msg.firstArtistString for first artist only \n \"c\": \"81B71A\" // color of artist\n },\n {\n \"t\": \" \" + msg.trackString,\n \"c\": \"FFFFFF\" // color of track title\n },\n {\n \"t\": \" \" + msg.albumTrimmedString,\n \"c\": \"CCCCCC\" // color of album title\n }\n ],\n \"repeat\": 1,\n \"scrollSpeed\": 80,\n \"icon\": 18207,\n \"pushIcon\": 1,\n \"textCase\": 0,\n \"textOffset\": 0,\n \"wakeup\": 1,\n};\n\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 210, "y": 540, "wires": [ [ "c1f765fa96cfabc4", "73b3f79623812ba6" ] ] }, { "id": "2d9face2a87e72d7", "type": "delay", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "", "pauseType": "delayv", "timeout": "5", "timeoutUnits": "seconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "second", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": false, "allowrate": false, "outputs": 1, "x": 1180, "y": 480, "wires": [ [ "691c9f88f16bd888" ] ] }, { "id": "fe6a16cb0b96ec69", "type": "link in", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "link in 1", "links": [ "691c9f88f16bd888" ], "x": 75, "y": 200, "wires": [ [ "c586b27248de35e3" ] ] }, { "id": "691c9f88f16bd888", "type": "link out", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "link out 2", "mode": "link", "links": [ "fe6a16cb0b96ec69" ], "x": 1275, "y": 480, "wires": [] }, { "id": "c1f765fa96cfabc4", "type": "rbe", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "", "func": "rbe", "gap": "", "start": "", "inout": "out", "septopics": false, "property": "playedTrack", "topi": "topic", "x": 470, "y": 640, "wires": [ [ "dc255cbcd49bf14c" ] ] }, { "id": "eae4632e012e7ddb", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Init", "info": "", "x": 110, "y": 60, "wires": [] }, { "id": "bdd49c32127e509f", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Check Status", "info": "Call SpotifyWebApi and check whether we are playing", "x": 130, "y": 160, "wires": [] }, { "id": "593fdc2b0ff0d6a2", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Song changed? Notify!", "info": "Send notification to Awtrix when song changed", "x": 520, "y": 600, "wires": [] }, { "id": "eb64fc82df1b4f28", "type": "function", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Check again in 20 seconds", "func": "msg.delay = 20 * 1000;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 780, "y": 300, "wires": [ [ "2d9face2a87e72d7" ] ] }, { "id": "918ace7ed1bffb3a", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Change notification style here", "info": "", "x": 240, "y": 500, "wires": [] }, { "id": "c3f8ccea36f7ec8f", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Case: playing", "info": "", "x": 730, "y": 160, "wires": [] }, { "id": "6d40d23e58c88456", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Case: not playing", "info": "", "x": 740, "y": 260, "wires": [] }, { "id": "bf4c58920c2e72b8", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Change URL of Awtrix here", "info": "", "x": 790, "y": 600, "wires": [] }, { "id": "2c5334769f24b80c", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Wait. Then start again", "info": "", "x": 1220, "y": 440, "wires": [] }, { "id": "911d011a95bc459c", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Insert your Spotify API data here in config node", "info": "", "x": 420, "y": 60, "wires": [] }, { "id": "c07faab9894a65cb", "type": "switch", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "", "property": "payload.currently_playing_type", "propertyType": "msg", "rules": [ { "t": "eq", "v": "track", "vt": "str" }, { "t": "else" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 950, "y": 200, "wires": [ [ "4f88debd9b96161f" ], [ "eb64fc82df1b4f28" ] ] }, { "id": "71d68eeaed474950", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Case: track", "info": "", "x": 1130, "y": 160, "wires": [] }, { "id": "3d1e8e19487546e6", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Case: other (not supported)", "info": "All other cases like Podcast shows or audio books are not working in Node-REDs API wrapper node-red-contrib-spotify", "x": 1000, "y": 240, "wires": [] }, { "id": "25c3b1d127d029a1", "type": "inject", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Manual Start", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 130, "y": 760, "wires": [ [ "f5e36a35068d3417" ] ] }, { "id": "f5e36a35068d3417", "type": "spotify", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Get if playing", "auth": "034f07b3451cce16", "api": "getMyCurrentPlaybackState", "x": 310, "y": 760, "wires": [ [ "e43d0a770e75346d" ] ] }, { "id": "e43d0a770e75346d", "type": "debug", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "device ID", "active": true, "tosidebar": true, "console": true, "tostatus": false, "complete": "payload.device.id", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 490, "y": 760, "wires": [] }, { "id": "80e257fffa8df888", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Use this to exclude devices: Start playback on a device, then start this flow to get a device id in log and debug view.", "info": "", "x": 450, "y": 720, "wires": [] }, { "id": "de5520fd34e592f9", "type": "switch", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Check device", "property": "payload.device.id", "propertyType": "msg", "rules": [ { "t": "eq", "v": "insert Device ID for devices you dont want to be shown", "vt": "str" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 380, "y": 200, "wires": [ [ "eb64fc82df1b4f28" ], [ "192cbe59ce8d1b8f" ] ] }, { "id": "5896383e6831434d", "type": "comment", "z": "98eecb7bb5dbbaf0", "g": "102a7c3090fc21bc", "name": "Insert device ids to exclude here", "info": "", "x": 430, "y": 160, "wires": [] }, { "id": "034f07b3451cce16", "type": "spotify-auth", "name": "Spotify OAuth", "scope": "user-read-playback-state\nuser-read-private\nuser-follow-read\nuser-library-read\nuser-read-playback-position\nplaylist-read-private\nuser-top-read\nuser-read-currently-playing\nuser-read-recently-played" } ]
-- Flow first published on June 30, 2024, last updated on July 7, 2024 at 06:55.