[
    {
        "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"
        }
    }
]