[
{
"id": "1985ea40c1c7a8f6",
"type": "tab",
"label": "Player - WiiM",
"disabled": false,
"info": "WiiM Pro Plus Control via HTTP API\nPolling every 5s for artist/title/volume/state\nCommands: prev, play/resume, pause, next, vol:<0-100>\nNo artwork/cover"
},
{
"id": "95a4155f5eb7883e",
"type": "comment",
"z": "1985ea40c1c7a8f6",
"name": "WiiM Pro Plus",
"info": "Base URL: https://{wiim_ip}/httpapi.asp?command=\nStatus: getPlayerStatus (JSON)\nMetadata: getMetaInfo (JSON)\nCommands: setPlayerCmd:prev / pause / resume / next / vol:<0-100>\n\nMore api information: https://www.wiimhome.com/pdf/HTTP%20API%20for%20WiiM%20Products.pdf\n\nIP address is configurable via the 'Config WiiM IP' node.\n\n📱 Quick Setup:\n1. Find WiiM IP in your network (e.g., via WiiM app).\n2. Edit \"Config WiiM IP\" node → On Start: global.set('wiim_ip', '192.168.x.x');\n3. Deploy → Done! Works with WiiM Pro/Pro Plus.\n\nWiim Player V1.0 - 01.02.2026 - Run",
"x": 130,
"y": 40,
"wires": []
},
{
"id": "6f931c0d16d8ef05",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Config WiiM IP",
"func": "global.set('wiim_ip', '192.168.1.44');",
"outputs": 0,
"timeout": "",
"noerr": 0,
"initialize": "global.set('wiim_ip', '192.168.1.44');",
"finalize": "",
"libs": [],
"x": 140,
"y": 100,
"wires": []
},
{
"id": "4eadc4c3841cf2ca",
"type": "ui_button",
"z": "1985ea40c1c7a8f6",
"name": "Previous",
"group": "f9be0acd304ba0c2",
"order": 1,
"width": "1",
"height": "1",
"passthru": false,
"label": "",
"tooltip": "Previous",
"color": "#ffffff",
"bgcolor": "#3ececd",
"className": "",
"icon": "skip_previous",
"payload": "prev",
"payloadType": "str",
"topic": "wiim/command",
"topicType": "str",
"x": 1200,
"y": 60,
"wires": [
[
"85af84ac2c3cc02f"
]
]
},
{
"id": "a980e5c0b2185d91",
"type": "ui_button",
"z": "1985ea40c1c7a8f6",
"name": "Play",
"group": "f9be0acd304ba0c2",
"order": 2,
"width": "2",
"height": "1",
"passthru": false,
"label": "",
"tooltip": "Play",
"color": "#ffffff",
"bgcolor": "#3ececd",
"className": "",
"icon": "play_arrow",
"payload": "resume",
"payloadType": "str",
"topic": "wiim/command",
"topicType": "str",
"x": 1210,
"y": 120,
"wires": [
[
"85af84ac2c3cc02f"
]
]
},
{
"id": "d840a1130a8e78b6",
"type": "ui_button",
"z": "1985ea40c1c7a8f6",
"name": "Pause",
"group": "f9be0acd304ba0c2",
"order": 3,
"width": "2",
"height": "1",
"passthru": false,
"label": "",
"tooltip": "Pause",
"color": "#ffffff",
"bgcolor": "#3ececd",
"className": "",
"icon": "pause",
"payload": "pause",
"payloadType": "str",
"topic": "wiim/command",
"topicType": "str",
"x": 1210,
"y": 180,
"wires": [
[
"85af84ac2c3cc02f"
]
]
},
{
"id": "50c442f711a7aaba",
"type": "ui_button",
"z": "1985ea40c1c7a8f6",
"name": "Next",
"group": "f9be0acd304ba0c2",
"order": 4,
"width": "1",
"height": "1",
"passthru": false,
"label": "",
"tooltip": "Next",
"color": "#ffffff",
"bgcolor": "#3ececd",
"className": "",
"icon": "skip_next",
"payload": "next",
"payloadType": "str",
"topic": "wiim/command",
"topicType": "str",
"x": 1210,
"y": 240,
"wires": [
[
"85af84ac2c3cc02f"
]
]
},
{
"id": "e305d64b4dbccc78",
"type": "ui_slider",
"z": "1985ea40c1c7a8f6",
"name": "Volume",
"label": "Volume",
"tooltip": "",
"group": "f9be0acd304ba0c2",
"order": 5,
"width": 0,
"height": 0,
"passthru": true,
"outs": "all",
"topic": "wiim/volume",
"topicType": "str",
"min": 0,
"max": 100,
"step": 1,
"className": "",
"x": 1200,
"y": 300,
"wires": [
[
"74dec51c9138c2e2"
]
]
},
{
"id": "662fff739f796ada",
"type": "ui_text",
"z": "1985ea40c1c7a8f6",
"group": "f9be0acd304ba0c2",
"order": 6,
"width": 0,
"height": 0,
"name": "Artist",
"label": "Artist",
"format": "{{msg.payload.artist || '–'}}",
"layout": "row-spread",
"className": "",
"style": false,
"font": "",
"fontSize": "",
"color": "#000000",
"x": 1210,
"y": 420,
"wires": []
},
{
"id": "9eb5c7cf506f74f7",
"type": "ui_text",
"z": "1985ea40c1c7a8f6",
"group": "f9be0acd304ba0c2",
"order": 7,
"width": 0,
"height": 0,
"name": "Song Title",
"label": "Song",
"format": "{{msg.payload.title || '–'}}",
"layout": "row-spread",
"className": "",
"style": false,
"font": "",
"fontSize": "",
"color": "#000000",
"x": 1200,
"y": 480,
"wires": []
},
{
"id": "85af84ac2c3cc02f",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Build WiiM Command",
"func": "let cmd = '';\n\nswitch (msg.payload) {\n case 'prev':\n cmd = 'setPlayerCmd:prev';\n break;\n case 'resume':\n cmd = 'setPlayerCmd:resume';\n break;\n case 'pause':\n cmd = 'setPlayerCmd:pause';\n break;\n case 'next':\n cmd = 'setPlayerCmd:next';\n break;\n}\n\nif (cmd) {\n msg.url = 'https://' + global.get('wiim_ip') + '/httpapi.asp?command=' + cmd;\n msg.method = 'GET';\n}\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1460,
"y": 160,
"wires": [
[
"f3473ee8facb06ea"
]
]
},
{
"id": "74dec51c9138c2e2",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Build Volume Command",
"func": "let vol = Math.round(msg.payload);\n\n// Send volume to WiiM\nmsg.url = 'https://' + global.get('wiim_ip') + '/httpapi.asp?command=setPlayerCmd:vol:' + vol;\nmsg.method = 'GET';\n\n// Mark the time of last user change (debounce flag)\nglobal.set('wiim_last_vol_change', Date.now());\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1450,
"y": 300,
"wires": [
[
"f3473ee8facb06ea"
]
]
},
{
"id": "f3473ee8facb06ea",
"type": "http request",
"z": "1985ea40c1c7a8f6",
"name": "WiiM API Call",
"method": "GET",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "wiim_tls_config",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 1720,
"y": 300,
"wires": [
[]
]
},
{
"id": "81dea50b7152fedc",
"type": "inject",
"z": "1985ea40c1c7a8f6",
"name": "Poll every 5s",
"props": [
{
"p": "payload"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": 0.5,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 140,
"y": 360,
"wires": [
[
"da321590d20aab72",
"cff59d37f7dcdf07"
]
]
},
{
"id": "e4ac843a6f7d99f6",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Update Status (Volume)",
"func": "let vol = msg.payload.volume || 20;\nlet state = msg.payload.state || 'stopped';\n\n// Ignore poll if user changed volume <15s ago\nif (global.get('wiim_last_vol_change') > Date.now() - 15000) {\n return [null, msg]; // No slider update, but keep other logic\n}\n\n// Sync WiiM → slider\nlet sliderMsg = { payload: vol };\n\nglobal.set('wiim_volume', vol);\nglobal.set('wiim_state', state);\n\nreturn [sliderMsg, msg];",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 930,
"y": 300,
"wires": [
[
"e305d64b4dbccc78"
]
]
},
{
"id": "74a5bb1213ae8608",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Update Artist & Song",
"func": "let artist = msg.payload.metaData.artist || '–';\nlet title = msg.payload.metaData.title || '–';\n\nmsg.payload = { artist: artist, title: title };\n\nreturn [msg, msg]; // first to Artist text, second to Song Title text",
"outputs": 2,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 920,
"y": 420,
"wires": [
[
"662fff739f796ada"
],
[
"9eb5c7cf506f74f7"
]
]
},
{
"id": "b219fe2c9c4e993c",
"type": "http request",
"z": "1985ea40c1c7a8f6",
"name": "Get Player Status",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "wiim_tls_config",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 630,
"y": 360,
"wires": [
[
"e4ac843a6f7d99f6",
"e6428184121f1cc0"
]
]
},
{
"id": "a9aa0ffe297fda80",
"type": "http request",
"z": "1985ea40c1c7a8f6",
"name": "Get Meta Info",
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "wiim_tls_config",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 640,
"y": 420,
"wires": [
[
"74a5bb1213ae8608"
]
]
},
{
"id": "da321590d20aab72",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Build Status URL",
"func": "msg.url = 'https://' + global.get('wiim_ip') + '/httpapi.asp?command=getPlayerStatus';\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 360,
"wires": [
[
"b219fe2c9c4e993c"
]
]
},
{
"id": "cff59d37f7dcdf07",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Build Metadata URL",
"func": "msg.url = 'https://' + global.get('wiim_ip') + '/httpapi.asp?command=getMetaInfo';\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 420,
"wires": [
[
"a9aa0ffe297fda80"
]
]
},
{
"id": "e6428184121f1cc0",
"type": "function",
"z": "1985ea40c1c7a8f6",
"name": "Map Current Input",
"func": "let mode = parseInt(msg.payload.mode || 0);\nlet activeInput = 'Unbekannt';\n\nswitch (mode) {\n case 0:\n activeInput = 'Network / Streaming';\n break;\n case 1:\n activeInput = 'Optical In';\n break;\n case 2:\n activeInput = 'Line In / Coaxial';\n break;\n case 3:\n activeInput = 'Bluetooth';\n break;\n case 31:\n activeInput = 'Ethernet / Network';\n break;\n case 40:\n activeInput = 'Line In';\n break;\n case 41:\n activeInput = 'Bluetooth';\n break;\n case 43:\n activeInput = 'Optical In';\n break;\n default:\n activeInput = 'Unbekannt (Mode ' + mode + ')';\n}\n\nglobal.set('wiim_active_input', activeInput);\n\nmsg.payload = { currentInput: activeInput };\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 910,
"y": 360,
"wires": [
[
"d4334a88d3030ead"
]
]
},
{
"id": "d4334a88d3030ead",
"type": "ui_text",
"z": "1985ea40c1c7a8f6",
"group": "f9be0acd304ba0c2",
"order": 11,
"width": "6",
"height": "1",
"name": "Current Input",
"label": "Current Input",
"format": "{{msg.payload.currentInput || 'Unbekannt'}}",
"layout": "row-spread",
"className": "",
"style": false,
"font": "",
"fontSize": 16,
"color": "#000000",
"x": 1190,
"y": 360,
"wires": []
},
{
"id": "f9be0acd304ba0c2",
"type": "ui_group",
"name": "Wiim",
"tab": "2c8e194fe4fc498b",
"order": 1,
"disp": true,
"width": 6,
"collapse": false,
"className": ""
},
{
"id": "wiim_tls_config",
"type": "tls-config",
"name": "WiiM Ignore Self-Signed",
"cert": "",
"key": "",
"ca": "",
"certname": "",
"keyname": "",
"caname": "",
"servername": "",
"verifyservercert": false,
"alpnprotocol": ""
},
{
"id": "2c8e194fe4fc498b",
"type": "ui_tab",
"name": "Player",
"icon": "my_library_music",
"disabled": false,
"hidden": false
},
{
"id": "f8a167f87891f9f3",
"type": "global-config",
"env": [],
"modules": {
"node-red-dashboard": "3.6.6"
}
}
]