[
    {
        "id": "1a0aea5a9ec739d4",
        "type": "subflow",
        "name": "Pause / resume media players",
        "info": "This node allows you to pause and resume\nmedia players.  If the message contains\na property \"action\" set to \"pause\", it\nwill pause your media players.  If the\naction contains \"resume\", it will\nresume the media players that were\npaused by this flow before.  The output\nwill contain a property \"action\"\n(\"paused\" / \"resumed\") if any action\nwas taken.  If no action is in the\nmessage, this will toggle between pausing\nall media players and resuming all\nmedia players.\n\nList property `ignore_media_players` in the\n`msg` will cause all listed media players to be\nignored by this node.  Those media\nplayers will never be considered for\npause / resume functionality.\n\nMode can be \"all\" (pause all media players\nthen unpause all that were paused) or\n\"last\" (pause the most recently playing\nmedia player and unpause the most\nrecently paused media player).  The first\nmode is useful when you go away / return\nand the second mode is useful with a\nremote control.",
        "category": "",
        "in": [
            {
                "x": 60,
                "y": 1000,
                "wires": [
                    {
                        "id": "f89ab83cf667f16b"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 1900,
                "y": 980,
                "wires": [
                    {
                        "id": "eb1f47efc8f86bb2",
                        "port": 0
                    },
                    {
                        "id": "0f04933c58b7cb39",
                        "port": 0
                    },
                    {
                        "id": "0f921359e4c58ab6",
                        "port": 0
                    },
                    {
                        "id": "40a17022ca5326cc",
                        "port": 0
                    }
                ]
            }
        ],
        "env": [
            {
                "name": "mode",
                "type": "str",
                "value": "all"
            }
        ],
        "meta": {},
        "color": "#DDAA99",
        "status": {
            "x": 1000,
            "y": 1080,
            "wires": [
                {
                    "id": "bf63dd0acc724f51",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "4c30f22b71d5afea",
        "type": "ha-get-entities",
        "z": "1a0aea5a9ec739d4",
        "name": "Get all playing media players",
        "server": "47fda6e5630a2a77",
        "version": 0,
        "rules": [
            {
                "property": "entity_id",
                "logic": "starts_with",
                "value": "media_player",
                "valueType": "str"
            },
            {
                "property": "state",
                "logic": "is",
                "value": "playing",
                "valueType": "str"
            },
            {
                "property": "entity_id",
                "logic": "does_not_include",
                "value": "msg.ignore_media_players ? msg.ignore_media_players : []",
                "valueType": "jsonata"
            }
        ],
        "output_type": "array",
        "output_empty_results": true,
        "output_location_type": "msg",
        "output_location": "payload",
        "output_results_count": 1,
        "x": 960,
        "y": 520,
        "wires": [
            [
                "e15dc12f3d16eac5"
            ]
        ]
    },
    {
        "id": "e15dc12f3d16eac5",
        "type": "change",
        "z": "1a0aea5a9ec739d4",
        "name": "Reset paused media players",
        "rules": [
            {
                "t": "set",
                "p": "paused_media_players",
                "pt": "flow",
                "to": "[]",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 960,
        "y": 600,
        "wires": [
            [
                "f3625c938279c676"
            ]
        ]
    },
    {
        "id": "ceecb503f94968d3",
        "type": "api-call-service",
        "z": "1a0aea5a9ec739d4",
        "name": "Pause this player",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_pause",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 850,
        "y": 840,
        "wires": [
            [
                "3b46b3f58af3abb8"
            ]
        ]
    },
    {
        "id": "667042427207e63c",
        "type": "split",
        "z": "1a0aea5a9ec739d4",
        "name": "For each",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 880,
        "y": 760,
        "wires": [
            [
                "ceecb503f94968d3"
            ]
        ]
    },
    {
        "id": "3b46b3f58af3abb8",
        "type": "join",
        "z": "1a0aea5a9ec739d4",
        "name": "Rejoin",
        "mode": "auto",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": true,
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 890,
        "y": 920,
        "wires": [
            [
                "fc8b59c7e4b787a5"
            ]
        ]
    },
    {
        "id": "fc8b59c7e4b787a5",
        "type": "change",
        "z": "1a0aea5a9ec739d4",
        "name": "Remember paused media players",
        "rules": [
            {
                "t": "set",
                "p": "paused_media_players",
                "pt": "flow",
                "to": "payload",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1200,
        "y": 920,
        "wires": [
            [
                "0f921359e4c58ab6"
            ]
        ]
    },
    {
        "id": "d8cb6dc6e49fe445",
        "type": "change",
        "z": "1a0aea5a9ec739d4",
        "name": "Reset paused media players",
        "rules": [
            {
                "t": "set",
                "p": "paused_media_players",
                "pt": "flow",
                "to": "[]",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 960,
        "y": 300,
        "wires": [
            [
                "6914ba0f44f01d12"
            ]
        ]
    },
    {
        "id": "ade4baa0c3b1eed5",
        "type": "change",
        "z": "1a0aea5a9ec739d4",
        "name": "Recall paused media players",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "paused_media_players",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 960,
        "y": 380,
        "wires": [
            [
                "d8cb6dc6e49fe445"
            ]
        ]
    },
    {
        "id": "63de03f98dcac1b9",
        "type": "split",
        "z": "1a0aea5a9ec739d4",
        "name": "For each",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 900,
        "y": 220,
        "wires": [
            [
                "ca9e6a5c25410bc8"
            ]
        ]
    },
    {
        "id": "ca9e6a5c25410bc8",
        "type": "api-call-service",
        "z": "1a0aea5a9ec739d4",
        "name": "Resume this player",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_play",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 930,
        "y": 140,
        "wires": [
            [
                "bb433ed5613a444d"
            ]
        ]
    },
    {
        "id": "bb433ed5613a444d",
        "type": "join",
        "z": "1a0aea5a9ec739d4",
        "name": "Rejoin",
        "mode": "auto",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": true,
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 890,
        "y": 60,
        "wires": [
            [
                "36f7c4925d5ea1b0"
            ]
        ]
    },
    {
        "id": "29ffef81af4d5733",
        "type": "switch",
        "z": "1a0aea5a9ec739d4",
        "name": "Pause or resume?",
        "property": "action",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "resume",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "pause",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 3,
        "x": 450,
        "y": 440,
        "wires": [
            [
                "ade4baa0c3b1eed5"
            ],
            [
                "4c30f22b71d5afea"
            ],
            [
                "9a1ec1a2ab3ae4a3"
            ]
        ]
    },
    {
        "id": "36f7c4925d5ea1b0",
        "type": "change",
        "z": "1a0aea5a9ec739d4",
        "name": "Resumed",
        "rules": [
            {
                "t": "set",
                "p": "action",
                "pt": "msg",
                "to": "resumed",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1200,
        "y": 60,
        "wires": [
            [
                "40a17022ca5326cc"
            ]
        ]
    },
    {
        "id": "9a1ec1a2ab3ae4a3",
        "type": "switch",
        "z": "1a0aea5a9ec739d4",
        "name": "Are there any media players paused?",
        "property": "paused_media_players",
        "propertyType": "flow",
        "rules": [
            {
                "t": "nempty"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 530,
        "y": 600,
        "wires": [
            [
                "ade4baa0c3b1eed5"
            ],
            [
                "4c30f22b71d5afea"
            ]
        ]
    },
    {
        "id": "0f921359e4c58ab6",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "paused status",
        "func": "var l = msg.payload.length !== 0 ? msg.payload.length : 0;\nnode.status({ fill: \"yellow\", text: \"paused \" + l + \" players\" + \" : \" + new Date().toLocaleString() })\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1560,
        "y": 920,
        "wires": [
            []
        ]
    },
    {
        "id": "40a17022ca5326cc",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "playing status",
        "func": "var l = msg.payload.length !== 0 ? msg.payload.length : 0;\nnode.status({ fill: \"green\", text: \"playing \" + l + \" players\" + \" : \" + new Date().toLocaleString() })\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1560,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "bf63dd0acc724f51",
        "type": "status",
        "z": "1a0aea5a9ec739d4",
        "name": "",
        "scope": [
            "0f921359e4c58ab6",
            "40a17022ca5326cc",
            "d4ecc61c74e6d1f2",
            "eb1f47efc8f86bb2",
            "0f04933c58b7cb39",
            "980334b08b5c1b04"
        ],
        "x": 900,
        "y": 1080,
        "wires": [
            []
        ]
    },
    {
        "id": "f89ab83cf667f16b",
        "type": "switch",
        "z": "1a0aea5a9ec739d4",
        "name": "All or last?",
        "property": "mode",
        "propertyType": "env",
        "rules": [
            {
                "t": "eq",
                "v": "all",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "last",
                "vt": "str"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 190,
        "y": 1000,
        "wires": [
            [
                "29ffef81af4d5733"
            ],
            [
                "1d35139373e27de3"
            ]
        ]
    },
    {
        "id": "1d35139373e27de3",
        "type": "switch",
        "z": "1a0aea5a9ec739d4",
        "name": "Pause or resume?",
        "property": "action",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "resume",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "pause",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 3,
        "x": 470,
        "y": 1520,
        "wires": [
            [
                "14337c043208cc64"
            ],
            [
                "631b71be23c94109"
            ],
            [
                "3279597110fbaffd"
            ]
        ]
    },
    {
        "id": "631b71be23c94109",
        "type": "ha-get-entities",
        "z": "1a0aea5a9ec739d4",
        "name": "Get all media players",
        "server": "47fda6e5630a2a77",
        "version": 0,
        "rules": [
            {
                "property": "entity_id",
                "logic": "starts_with",
                "value": "media_player",
                "valueType": "str"
            },
            {
                "property": "entity_id",
                "logic": "does_not_include",
                "value": "msg.ignore_media_players ? msg.ignore_media_players : []",
                "valueType": "jsonata"
            }
        ],
        "output_type": "array",
        "output_empty_results": false,
        "output_location_type": "msg",
        "output_location": "payload",
        "output_results_count": 1,
        "x": 840,
        "y": 1900,
        "wires": [
            [
                "d4ecc61c74e6d1f2"
            ]
        ]
    },
    {
        "id": "d4ecc61c74e6d1f2",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "filter last playing",
        "func": "var any = null;\nfor (var state of [\"playing\"]) {\n    for (var player of msg.payload) {\n        if (player.state != state) {\n            continue;\n        }\n        if (any === null) {\n            any = player;\n            continue;\n        }\n        if (any.last_changed < player.last_changed) {\n            any = player;\n            continue;\n        }\n        if (any.last_updated < player.last_updated) {\n            any = player;\n            continue;\n        }\n    }\n}\nif (any === null) {\n    node.status({ fill: \"blue\", text: \"No player to pause\" + \" : \" + new Date().toLocaleString() })\n    msg.payload = {};\n    return [null, msg];\n}\n\nmsg.payload = any;\nnode.status({ fill: \"blue\", text: msg.payload.entity_id + \" : \" + new Date().toLocaleString() })\nreturn [msg, null];",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1080,
        "y": 1900,
        "wires": [
            [
                "6ec8885c8b88799d"
            ],
            [
                "eb1f47efc8f86bb2"
            ]
        ]
    },
    {
        "id": "6ec8885c8b88799d",
        "type": "api-call-service",
        "z": "1a0aea5a9ec739d4",
        "name": "Pause player",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_pause",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 1330,
        "y": 1900,
        "wires": [
            [
                "eb1f47efc8f86bb2"
            ]
        ]
    },
    {
        "id": "14337c043208cc64",
        "type": "ha-get-entities",
        "z": "1a0aea5a9ec739d4",
        "name": "Get all media players",
        "server": "47fda6e5630a2a77",
        "version": 0,
        "rules": [
            {
                "property": "entity_id",
                "logic": "starts_with",
                "value": "media_player",
                "valueType": "str"
            },
            {
                "property": "entity_id",
                "logic": "does_not_include",
                "value": "msg.ignore_media_players ? msg.ignore_media_players : []",
                "valueType": "jsonata"
            }
        ],
        "output_type": "array",
        "output_empty_results": true,
        "output_location_type": "msg",
        "output_location": "payload",
        "output_results_count": 1,
        "x": 840,
        "y": 1180,
        "wires": [
            [
                "980334b08b5c1b04"
            ]
        ]
    },
    {
        "id": "980334b08b5c1b04",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "filter last paused or stopped",
        "func": "var any = null;\nfor (var state of [\"paused\"]) {\n    for (var player of msg.payload) {\n        if (player.state != state) {\n            continue;\n        }\n        if (any === null) {\n            any = player;\n            continue;\n        }\n        if (any.last_changed < player.last_changed) {\n            any = player;\n            continue;\n        }\n        if (any.last_updated < player.last_updated) {\n            any = player;\n            continue;\n        }\n    }\n}\nif (any === null) {\n    for (var state of [\"idle\"]) {\n        for (var player of msg.payload) {\n            if (player.state != state) {\n                continue;\n            }\n            if (any === null) {\n                any = player;\n                continue;\n            }\n            if (any.last_changed < player.last_changed) {\n                any = player;\n                continue;\n            }\n            if (any.last_updated < player.last_updated) {\n                any = player;\n                continue;\n            }\n        }\n    }\n    node.status({ fill: \"blue\", text: \"No player to resume\" + \" : \" + new Date().toLocaleString() })\n    msg.payload = {};\n    return [null, msg];\n}\n\nmsg.payload = any;\nnode.status({ fill: \"blue\", text: msg.payload.entity_id + \" : \" + new Date().toLocaleString() })\nreturn [msg, null];",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1120,
        "y": 1180,
        "wires": [
            [
                "14a9dfdf0ce7f515"
            ],
            [
                "0f04933c58b7cb39"
            ]
        ]
    },
    {
        "id": "eb1f47efc8f86bb2",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "paused status",
        "func": "var e = msg.payload.entity_id ? msg.payload.entity_id : \"no player\";\nnode.status({ fill: \"yellow\", text: \"paused \" + e + \": \" + new Date().toLocaleString() })\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1560,
        "y": 1500,
        "wires": [
            []
        ]
    },
    {
        "id": "14a9dfdf0ce7f515",
        "type": "api-call-service",
        "z": "1a0aea5a9ec739d4",
        "name": "Resume player",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_play",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 1380,
        "y": 1180,
        "wires": [
            [
                "0f04933c58b7cb39"
            ]
        ]
    },
    {
        "id": "0f04933c58b7cb39",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "playing status",
        "func": "var e = msg.payload.entity_id ? msg.payload.entity_id : \"no player\";\nnode.status({ fill: \"yellow\", text: \"playing \" + e + \": \" + new Date().toLocaleString() })\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1560,
        "y": 1040,
        "wires": [
            []
        ]
    },
    {
        "id": "3279597110fbaffd",
        "type": "ha-get-entities",
        "z": "1a0aea5a9ec739d4",
        "name": "Get all playing media players",
        "server": "47fda6e5630a2a77",
        "version": 0,
        "rules": [
            {
                "property": "entity_id",
                "logic": "starts_with",
                "value": "media_player",
                "valueType": "str"
            },
            {
                "property": "state",
                "logic": "is",
                "value": "playing",
                "valueType": "str"
            },
            {
                "property": "entity_id",
                "logic": "does_not_include",
                "value": "msg.ignore_media_players ? msg.ignore_media_players : []",
                "valueType": "jsonata"
            }
        ],
        "output_type": "array",
        "output_empty_results": true,
        "output_location_type": "msg",
        "output_location": "payload",
        "output_results_count": 1,
        "x": 440,
        "y": 1640,
        "wires": [
            [
                "20e1aaecdbd0c7a0"
            ]
        ]
    },
    {
        "id": "20e1aaecdbd0c7a0",
        "type": "function",
        "z": "1a0aea5a9ec739d4",
        "name": "any playing?",
        "func": "var any = null;\nfor (var player of msg.payload) {\n    any = player;\n    break;\n}\nif (any === null) {\n    msg.action = \"resume\";\n    return [msg, null];\n} else {\n    msg.action = \"pause\";\n    return [null, msg];\n}",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 730,
        "y": 1520,
        "wires": [
            [
                "14337c043208cc64"
            ],
            [
                "631b71be23c94109"
            ]
        ],
        "outputLabels": [
            "paused, resume",
            "playing, pause"
        ]
    },
    {
        "id": "378c24380530a0ca",
        "type": "catch",
        "z": "1a0aea5a9ec739d4",
        "name": "",
        "scope": [
            "ceecb503f94968d3"
        ],
        "uncaught": false,
        "x": 1130,
        "y": 840,
        "wires": [
            [
                "3b46b3f58af3abb8"
            ]
        ]
    },
    {
        "id": "4727ac024b6ef90c",
        "type": "catch",
        "z": "1a0aea5a9ec739d4",
        "name": "",
        "scope": [
            "ca9e6a5c25410bc8"
        ],
        "uncaught": false,
        "x": 710,
        "y": 140,
        "wires": [
            [
                "bb433ed5613a444d"
            ]
        ]
    },
    {
        "id": "f3625c938279c676",
        "type": "switch",
        "z": "1a0aea5a9ec739d4",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "nempty"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 890,
        "y": 680,
        "wires": [
            [
                "667042427207e63c"
            ],
            [
                "fc8b59c7e4b787a5"
            ]
        ]
    },
    {
        "id": "6914ba0f44f01d12",
        "type": "switch",
        "z": "1a0aea5a9ec739d4",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "nempty"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 1190,
        "y": 300,
        "wires": [
            [
                "63de03f98dcac1b9"
            ],
            [
                "40a17022ca5326cc"
            ]
        ]
    },
    {
        "id": "b778c74473856912",
        "type": "subflow",
        "name": "Next / prev in media player",
        "info": "List property `ignore_media_players` in the\n`msg` will cause all listed media players to be\nignored by this node.",
        "category": "",
        "in": [
            {
                "x": 50,
                "y": 30,
                "wires": [
                    {
                        "id": "47c6a660ba23c358"
                    }
                ]
            }
        ],
        "out": [],
        "env": [],
        "meta": {},
        "color": "#DDAA99",
        "status": {
            "x": 820,
            "y": 160,
            "wires": [
                {
                    "id": "9101c7eb8af60222",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "42e410c97ecc7b95",
        "type": "subflow:82ceaca1c306b6aa",
        "z": "b778c74473856912",
        "name": "Current media player",
        "x": 520,
        "y": 220,
        "wires": [
            [
                "e741665d6a5ef3f5"
            ]
        ]
    },
    {
        "id": "e741665d6a5ef3f5",
        "type": "api-call-service",
        "z": "b778c74473856912",
        "name": "Next",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_next_track",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 790,
        "y": 220,
        "wires": [
            []
        ]
    },
    {
        "id": "5a06c1cefbcdde26",
        "type": "api-call-service",
        "z": "b778c74473856912",
        "name": "Previous",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_previous_track",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 780,
        "y": 100,
        "wires": [
            []
        ]
    },
    {
        "id": "025bd4842d45b1a6",
        "type": "subflow:82ceaca1c306b6aa",
        "z": "b778c74473856912",
        "name": "Current media player",
        "x": 520,
        "y": 100,
        "wires": [
            [
                "5a06c1cefbcdde26"
            ]
        ]
    },
    {
        "id": "9101c7eb8af60222",
        "type": "status",
        "z": "b778c74473856912",
        "name": "",
        "scope": [
            "e741665d6a5ef3f5",
            "5a06c1cefbcdde26"
        ],
        "x": 620,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "47c6a660ba23c358",
        "type": "switch",
        "z": "b778c74473856912",
        "name": "Command",
        "property": "payload.command",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "down",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "up",
                "vt": "str"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 250,
        "y": 160,
        "wires": [
            [
                "025bd4842d45b1a6"
            ],
            [
                "42e410c97ecc7b95"
            ]
        ]
    },
    {
        "id": "82ceaca1c306b6aa",
        "type": "subflow",
        "name": "Get paused / playing media player",
        "info": "List property `ignore_media_players` in the\n`msg` will cause all listed media players to be\nignored by this node.",
        "category": "",
        "in": [
            {
                "x": 60,
                "y": 80,
                "wires": [
                    {
                        "id": "a55fecd7304ee010"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 840,
                "y": 80,
                "wires": [
                    {
                        "id": "eb026cd54c8ef197",
                        "port": 0
                    }
                ]
            }
        ],
        "env": [],
        "meta": {},
        "color": "#C0DEED",
        "icon": "font-awesome/fa-info-circle",
        "status": {
            "x": 840,
            "y": 160,
            "wires": [
                {
                    "id": "2010f5eb34110337",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "a55fecd7304ee010",
        "type": "ha-get-entities",
        "z": "82ceaca1c306b6aa",
        "name": "Get all playing or paused players",
        "server": "47fda6e5630a2a77",
        "version": 0,
        "rules": [
            {
                "property": "entity_id",
                "logic": "starts_with",
                "value": "media_player",
                "valueType": "str"
            },
            {
                "property": "state",
                "logic": "includes",
                "value": "[\"playing\", \"paused\"]",
                "valueType": "jsonata"
            },
            {
                "property": "entity_id",
                "logic": "does_not_include",
                "value": "msg.ignore_media_players ? msg.ignore_media_players : []",
                "valueType": "jsonata"
            }
        ],
        "output_type": "array",
        "output_empty_results": false,
        "output_location_type": "msg",
        "output_location": "payload",
        "output_results_count": 1,
        "x": 340,
        "y": 80,
        "wires": [
            [
                "eb026cd54c8ef197"
            ]
        ]
    },
    {
        "id": "eb026cd54c8ef197",
        "type": "function",
        "z": "82ceaca1c306b6aa",
        "name": "get latest player",
        "func": "var last_changed = \"\";\nvar player = null;\nfor (var p of msg.payload) {\n    if (p.last_changed > last_changed) {\n        player = p;\n        last_changed = p.last_changed;\n        continue;\n    }\n    if (p.last_updated > last_changed) {\n        player = p;\n        last_changed = p.last_updated;\n        continue;\n    }\n}\nif (player !== null) {\n    node.status({ text: player.entity_id + \" (\" + player.state + \")\", fill: \"green\" });\n    msg.payload = player;\n    return msg;\n} else {\n    node.status({text: \"No player\", fill: \"yellow\"});\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 640,
        "y": 80,
        "wires": [
            []
        ]
    },
    {
        "id": "2010f5eb34110337",
        "type": "status",
        "z": "82ceaca1c306b6aa",
        "name": "",
        "scope": [
            "eb026cd54c8ef197"
        ],
        "x": 660,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "fdadee349978682f",
        "type": "subflow",
        "name": "Fast-forward / rewind media player discrete",
        "info": "Seek length factor is how many\nseconds per minimal step to seek.\n\nList property `ignore_media_players` in the\n`msg` will cause all listed media players to be\nignored by this node.",
        "category": "",
        "in": [
            {
                "x": 40,
                "y": 160,
                "wires": [
                    {
                        "id": "0942f58306645859"
                    }
                ]
            }
        ],
        "out": [],
        "env": [
            {
                "name": "seek_length_factor",
                "type": "num",
                "value": "5"
            }
        ],
        "meta": {},
        "color": "#DDAA99",
        "status": {
            "x": 1120,
            "y": 620,
            "wires": [
                {
                    "id": "9b7ebd2ba9e02881",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "fd93e497989e6d74",
        "type": "subflow:82ceaca1c306b6aa",
        "z": "fdadee349978682f",
        "name": "Current media player",
        "x": 760,
        "y": 480,
        "wires": [
            [
                "2e80f9125f8edac0"
            ]
        ]
    },
    {
        "id": "1ee1d5534283cb20",
        "type": "change",
        "z": "fdadee349978682f",
        "name": "Direction forward",
        "rules": [
            {
                "t": "set",
                "p": "scrub.direction",
                "pt": "msg",
                "to": "$env(\"seek_length_factor\") * msg.payload.step_size",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 490,
        "y": 420,
        "wires": [
            [
                "fd93e497989e6d74"
            ]
        ]
    },
    {
        "id": "9741a4801074f54d",
        "type": "change",
        "z": "fdadee349978682f",
        "name": "Direction backward",
        "rules": [
            {
                "t": "set",
                "p": "scrub.direction",
                "pt": "msg",
                "to": "-$env(\"seek_length_factor\") * msg.payload.step_size",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 490,
        "y": 480,
        "wires": [
            [
                "fd93e497989e6d74"
            ]
        ]
    },
    {
        "id": "2a82ad36bdf1e489",
        "type": "function",
        "z": "fdadee349978682f",
        "name": "inc/dec",
        "func": "var seek_position = msg.scrub.seek_position;\nvar scrub_direction = msg.scrub.direction;\nvar max_seek_step = msg.scrub.max_seek_step;\nif (scrub_direction >= 0) {\n    var fac = 1;\n} else {\n    var fac = -1;\n}\nscrub_direction = Math.min(max_seek_step, Math.abs(scrub_direction)) * fac;\nseek_position = seek_position + scrub_direction;\nseek_position = Math.max(0, seek_position);\nmsg.scrub.seek_position = seek_position;\nnode.status({\n    fill: \"green\",\n    text: \"Scrubbed \" + msg.payload.entity_id + \" \" + scrub_direction + \" to \" + msg.scrub.seek_position.toFixed(1) + \": \" + new Date().toLocaleString()\n})\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1240,
        "y": 480,
        "wires": [
            [
                "3dab7b192eb16673"
            ]
        ]
    },
    {
        "id": "2e80f9125f8edac0",
        "type": "function",
        "z": "fdadee349978682f",
        "name": "Position / max seek step",
        "func": "var difference = 0;\nif (msg.payload.state == \"playing\") {\n    var last_updated = Date.parse(msg.payload.attributes.media_position_updated_at);\n    var now = Date.now();\n    difference = (now - last_updated) / 1000;\n    if (isNaN(difference)) {\n        difference = 0;\n    } else {\n        node.warn(\"Compensating due to ongoing playback with \" + difference);\n    }\n}\n\nvar seek_position = msg.payload.attributes.media_position;\nif (seek_position === null) {\n    // No seek position.\n    return null;\n}\n\nvar max_seek_step = 0;\nif (msg.payload.attributes.media_duration === undefined) {\n    msg.scrub.max_seek_step = 30;\n} else {\n    msg.scrub.max_seek_step = msg.payload.attributes.media_duration * 0.1;\n}\nmsg.scrub.seek_position = seek_position + difference;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1030,
        "y": 480,
        "wires": [
            [
                "2a82ad36bdf1e489"
            ]
        ]
    },
    {
        "id": "0942f58306645859",
        "type": "switch",
        "z": "fdadee349978682f",
        "name": "Command",
        "property": "payload.command",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "up",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "down",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 3,
        "x": 190,
        "y": 480,
        "wires": [
            [
                "1ee1d5534283cb20"
            ],
            [
                "9741a4801074f54d"
            ],
            []
        ]
    },
    {
        "id": "3dab7b192eb16673",
        "type": "api-call-service",
        "z": "fdadee349978682f",
        "name": "Scrub in player",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "media_seek",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": payload.entity_id, \"seek_position\": scrub.seek_position}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 1580,
        "y": 480,
        "wires": [
            []
        ]
    },
    {
        "id": "9b7ebd2ba9e02881",
        "type": "status",
        "z": "fdadee349978682f",
        "name": "",
        "scope": [
            "2a82ad36bdf1e489"
        ],
        "x": 920,
        "y": 620,
        "wires": [
            []
        ]
    },
    {
        "id": "d7483652324db060",
        "type": "subflow",
        "name": "Media player discrete volume control",
        "info": "",
        "category": "",
        "in": [
            {
                "x": 180,
                "y": 100,
                "wires": [
                    {
                        "id": "06f9536d8642d44a"
                    }
                ]
            }
        ],
        "out": [],
        "env": [
            {
                "name": "entity_id",
                "type": "str",
                "value": ""
            }
        ],
        "meta": {},
        "color": "#C0DEED",
        "inputLabels": [
            "Hue tap knob"
        ],
        "icon": "font-awesome/fa-volume-up",
        "status": {
            "x": 1240,
            "y": 420,
            "wires": [
                {
                    "id": "89ea32966710747d",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "06f9536d8642d44a",
        "type": "switch",
        "z": "d7483652324db060",
        "name": "Command",
        "property": "payload.command",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "up",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "down",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 3,
        "x": 450,
        "y": 100,
        "wires": [
            [
                "580ea751eccb8e10"
            ],
            [
                "e1cbe84a7cfe36f7"
            ],
            []
        ]
    },
    {
        "id": "580ea751eccb8e10",
        "type": "change",
        "z": "d7483652324db060",
        "name": "Volume up",
        "rules": [
            {
                "t": "set",
                "p": "volume_direction",
                "pt": "msg",
                "to": "0.015 * msg.payload.step_size",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 210,
        "y": 280,
        "wires": [
            [
                "04675de25d1f8c98"
            ]
        ]
    },
    {
        "id": "e1cbe84a7cfe36f7",
        "type": "change",
        "z": "d7483652324db060",
        "name": "Volume down",
        "rules": [
            {
                "t": "set",
                "p": "volume_direction",
                "pt": "msg",
                "to": "-0.015 * msg.payload.step_size",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 220,
        "y": 340,
        "wires": [
            [
                "04675de25d1f8c98"
            ]
        ]
    },
    {
        "id": "73c8f3dcdc40fbef",
        "type": "api-current-state",
        "z": "d7483652324db060",
        "name": "Current volume",
        "server": "47fda6e5630a2a77",
        "version": 3,
        "outputs": 1,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "{{ entity_id }}",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "volume_level",
                "propertyType": "msg",
                "value": "$entity().attributes.volume_level",
                "valueType": "jsonata"
            },
            {
                "property": "entity_id",
                "propertyType": "msg",
                "value": "",
                "valueType": "triggerId"
            }
        ],
        "for": "0",
        "forType": "num",
        "forUnits": "minutes",
        "override_topic": false,
        "state_location": "payload",
        "override_payload": "msg",
        "entity_location": "data",
        "override_data": "msg",
        "x": 620,
        "y": 300,
        "wires": [
            [
                "d46abc13d492dcc2"
            ]
        ]
    },
    {
        "id": "d46abc13d492dcc2",
        "type": "function",
        "z": "d7483652324db060",
        "name": "inc/dec",
        "func": "var now = Date.now();\nvar last_volume_level = flow.get(\"last_volume_level\");\nvar last_volume_level_time = flow.get(\"last_volume_level_time\");\n\nif (last_volume_level_time !== undefined && now - last_volume_level_time < 5000) {\n    var volume_level = last_volume_level;\n} else {\n    var volume_level = msg.volume_level;\n    if (volume_level === undefined) {\n        node.status({ fill: \"yellow\", text: \"receiver off / cannot get volume: \" + new Date().toLocaleString() });\n        return;\n    }\n}\nvar volume_direction = msg.volume_direction;\nvolume_level = volume_level + volume_direction;\nvolume_level = Math.min(Math.max(0, volume_level), 1);\nmsg.payload = volume_level;\nflow.set(\"last_volume_level\", volume_level);\nflow.set(\"last_volume_level_time\", now);\nnode.status({fill: \"green\", text: volume_level.toFixed(3) + \": \" + new Date().toLocaleString()})\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 860,
        "y": 300,
        "wires": [
            [
                "51747b0d74d82161"
            ]
        ]
    },
    {
        "id": "51747b0d74d82161",
        "type": "api-call-service",
        "z": "d7483652324db060",
        "name": "Set volume",
        "server": "47fda6e5630a2a77",
        "version": 5,
        "debugenabled": false,
        "domain": "media_player",
        "service": "volume_set",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\"entity_id\": entity_id, \"volume_level\": payload}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "x": 1210,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "04675de25d1f8c98",
        "type": "change",
        "z": "d7483652324db060",
        "name": "Set entity",
        "rules": [
            {
                "t": "set",
                "p": "entity_id",
                "pt": "msg",
                "to": "entity_id",
                "tot": "env"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 440,
        "y": 300,
        "wires": [
            [
                "73c8f3dcdc40fbef"
            ]
        ]
    },
    {
        "id": "89ea32966710747d",
        "type": "status",
        "z": "d7483652324db060",
        "name": "",
        "scope": [
            "d46abc13d492dcc2"
        ],
        "x": 1060,
        "y": 420,
        "wires": [
            []
        ]
    },
    {
        "id": "010236e9a60895ec",
        "type": "subflow",
        "name": "Hue Tap dial",
        "info": "This node takes the output of a Home Assistant\n*Events: all* node, set to capture events of\nthe `zha_event` kind, and if the device' IEEE\naddress matches the property `device_ieee` set\non this node's instance, then the events are\ntreated as Philips Hue Tap dial events, and\nthey are processed and routed to the respective\noutputs.  The `msg.payload` coming through the\noutput will have at least a `command` property\nwhich will be used to route to each output\nas denoted below.  It may also have a property\n`last_clicked_button` which contains an integer\nnumber between 1 and 4 representing the button\nyou last clicked; you can use this value to make\ndecisions on what to do with the outputs of\nthis node.\n\nThere are six outputs in this node:\n\n1. `command=up`: the dial was turned\n   clockwise; the `step_size` property\n   will contain by how much (in an arbitrary\n   unit-less value)\n2. `command=down`: the dial was turned\n   counterclockwise; rotation angle works\n   as for `command=up`\n3. `command=click`: a button was clicked;\n   the property `button` contains the button\n   number (1 through 4)\n4. `command=doubleclick`: a button was double-\n   clicked (> 250 ms between taps)\n5. `command=tripleclick`: a button was triple-\n   clicked\n6. the event does not correspond to any known\n   device events",
        "category": "",
        "in": [
            {
                "x": 60,
                "y": 60,
                "wires": [
                    {
                        "id": "7aed7e25bc733f53"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 2020,
                "y": 380,
                "wires": [
                    {
                        "id": "0331ddd634c616b5",
                        "port": 3
                    }
                ]
            },
            {
                "x": 2030,
                "y": 420,
                "wires": [
                    {
                        "id": "0331ddd634c616b5",
                        "port": 4
                    }
                ]
            },
            {
                "x": 2030,
                "y": 260,
                "wires": [
                    {
                        "id": "0331ddd634c616b5",
                        "port": 0
                    }
                ]
            },
            {
                "x": 2050,
                "y": 300,
                "wires": [
                    {
                        "id": "0331ddd634c616b5",
                        "port": 1
                    }
                ]
            },
            {
                "x": 2040,
                "y": 340,
                "wires": [
                    {
                        "id": "0331ddd634c616b5",
                        "port": 2
                    }
                ]
            },
            {
                "x": 970,
                "y": 480,
                "wires": [
                    {
                        "id": "4d4511de07701ace",
                        "port": 6
                    }
                ]
            }
        ],
        "env": [],
        "meta": {},
        "color": "#C0DEED",
        "inputLabels": [
            "ZHA event"
        ],
        "outputLabels": [
            "up",
            "down",
            "click",
            "doubleclick",
            "tripleclick",
            "else"
        ],
        "icon": "font-awesome/fa-volume-up",
        "status": {
            "x": 1720,
            "y": 540,
            "wires": [
                {
                    "id": "b126369ffdd94aec",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "7aed7e25bc733f53",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat data",
        "func": "Object.keys(msg.payload.event).forEach((key, index) => {\n    msg.payload[key] = msg.payload.event[key];\n})\ndelete msg.payload[\"event\"];\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 420,
        "y": 300,
        "wires": [
            [
                "4d4511de07701ace"
            ]
        ]
    },
    {
        "id": "4d4511de07701ace",
        "type": "switch",
        "z": "010236e9a60895ec",
        "name": "Knob action",
        "property": "msg",
        "propertyType": "jsonata",
        "rules": [
            {
                "t": "jsonata_exp",
                "v": "payload.command = \"step_with_on_off\" and payload.params.step_mode = 0",
                "vt": "jsonata"
            },
            {
                "t": "jsonata_exp",
                "v": "payload.command = \"step_with_on_off\" and payload.params.step_mode = 1",
                "vt": "jsonata"
            },
            {
                "t": "jsonata_exp",
                "v": "payload.command = \"recall\" and payload.params.scene_id = 1",
                "vt": "jsonata"
            },
            {
                "t": "jsonata_exp",
                "v": "payload.command = \"recall\" and payload.params.scene_id = 0",
                "vt": "jsonata"
            },
            {
                "t": "jsonata_exp",
                "v": "payload.command = \"recall\" and payload.params.scene_id = 5",
                "vt": "jsonata"
            },
            {
                "t": "jsonata_exp",
                "v": "payload.command = \"recall\" and payload.params.scene_id = 4",
                "vt": "jsonata"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 7,
        "x": 650,
        "y": 300,
        "wires": [
            [
                "31411023cfe3c8a7"
            ],
            [
                "8245352d72f9e3db"
            ],
            [
                "a6137d78a4c9acca"
            ],
            [
                "9f93ed61d019b64d"
            ],
            [
                "a25b391629e1124f"
            ],
            [
                "39fbbb6d16cdfad7"
            ],
            []
        ],
        "outputLabels": [
            "up",
            "down",
            "scene1",
            "scene2",
            "scene3",
            "scene4",
            "else"
        ]
    },
    {
        "id": "31411023cfe3c8a7",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat",
        "func": "msg.payload = {\n    \"command\": \"up\",\n    \"step_size\": msg.payload.params.step_size / 8,\n    \"transition_time\": msg.payload.params.transition_time,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 160,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "8245352d72f9e3db",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat",
        "func": "msg.payload = {\n    \"command\": \"down\",\n    \"step_size\": msg.payload.params.step_size / 8,\n    \"transition_time\": msg.payload.params.transition_time,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 200,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "a6137d78a4c9acca",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat",
        "func": "msg.payload = {\n    \"command\": \"click\",\n    \"button\": msg.payload.params.scene_id,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 240,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "9f93ed61d019b64d",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat",
        "func": "msg.payload = {\n    \"command\": \"click\",\n    \"button\": 2,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 280,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "a25b391629e1124f",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat",
        "func": "msg.payload = {\n    \"command\": \"click\",\n    \"button\": 3,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 320,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "39fbbb6d16cdfad7",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Reformat",
        "func": "msg.payload = {\n    \"command\": \"click\",\n    \"button\": msg.payload.params.scene_id,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 360,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "b3e89396cb073ca2",
        "type": "trigger",
        "z": "010236e9a60895ec",
        "name": "",
        "op1": "",
        "op2": "",
        "op1type": "nul",
        "op2type": "payl",
        "duration": "250",
        "extend": true,
        "overrideDelay": true,
        "units": "ms",
        "reset": "",
        "bytopic": "all",
        "topic": "topic",
        "outputs": 1,
        "x": 1380,
        "y": 400,
        "wires": [
            [
                "f16aa7ea93e905dd"
            ]
        ]
    },
    {
        "id": "f16aa7ea93e905dd",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Process delayed taps",
        "func": "var last = context.get(\"last_active\")\nvar current = {\n    time: Date.now(),\n    msg: msg\n};\n\nfunction fmt(msg) {\n    if (msg.payload.command == \"click\" || msg.payload.command == \"doubleclick\" || msg.payload.command == \"tripleclick\") {\n        return \"\" + msg.payload.command + \" of button \" + msg.payload.button + (msg.selection ? \" (mode \" + msg.selection + \")\" : \"\");\n    }\n    else if (msg.payload.command == \"up\" || msg.payload.command == \"down\") {\n        return \"\" + msg.payload.command + \" of step size \" + msg.payload.step_size + (msg.selection ? \" (mode \" + msg.selection + \")\" : \"\");\n    }\n    return JSON.stringify(msg);\n}\n\nfunction status(msg, buffering) {\n    node.status({ text: msg, fill: \"blue\", shape: buffering ? \"ring\" : \"dot\"});\n}\n\nif (current.msg.flush) {\n    if (last !== undefined && last !== null) {\n        context.set(\"last_active\", null);\n        status(\"flushing  \" + fmt(last.msg), false);\n        return [[last.msg], null];\n    }\n}\nelse if (current.msg.payload.command == \"click\") {\n    if (last === undefined || last === null) {\n        context.set(\"last_active\", current);\n        status(\"buffering \" + fmt(current.msg), true);\n        return [null, { flush: true }];\n    } else {\n        if (\n            current.msg.payload.button == last.msg.payload.button\n        ) {\n            if (\n                last.msg.payload.command == \"click\"\n            ) {\n                // Instead of queueing the current message,\n                // update the last message.\n                last.msg.payload.command = \"doubleclick\";\n                status(\"rebuffering \" + fmt(last.msg), true);\n                return [null, { flush: true }];\n            }\n            else if (\n                last.msg.payload.command == \"doubleclick\"\n            ) {\n                last.msg.payload.command = \"tripleclick\";\n                context.set(\"last_active\", null);\n                status(\"flushing \" + fmt(last.msg), false);\n                return [[last.msg], null];\n            }\n            else {\n                // This is an error\n                node.error({msg:\"Cannot be\", current: current, last: last})\n            }\n        } else { /* buttons don't match */\n            context.set(\"last_active\", current);\n            status(\"flushing \" + fmt(last.msg) + \" and buffering \" + fmt(current.msg), true);\n            return [[last.msg], { flush: true }];\n        }\n    }\n}\nelse {\n    if (last === undefined || last === null) {\n        status(\"relaying \" + fmt(current.msg), false);\n        return [current.msg];\n    }\n    else {\n        context.set(\"last_active\", null);\n        status(\"relaying previous \" + fmt(last.msg) + \" and current \" + fmt(current.msg), false);\n        return [[last.msg, current.msg], null];\n    }\n}\n",
        "outputs": 2,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1380,
        "y": 300,
        "wires": [
            [
                "9ae5e1b2605722fd"
            ],
            [
                "b3e89396cb073ca2"
            ]
        ],
        "outputLabels": [
            "output",
            "flush request"
        ]
    },
    {
        "id": "0331ddd634c616b5",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "switch",
        "func": "if (msg.payload.command == \"click\") {\n    return [msg, null, null, null, null];\n}\nif (msg.payload.command == \"doubleclick\") {\n    return [null, msg, null, null, null];\n}\nif (msg.payload.command == \"tripleclick\") {\n    return [null, null, msg, null, null];\n}\nif (msg.payload.command == \"up\") {\n    return [null, null, null, msg, null];\n}\nif (msg.payload.command == \"down\") {\n    return [null, null, null, null, msg];\n}\n",
        "outputs": 5,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1810,
        "y": 300,
        "wires": [
            [],
            [],
            [],
            [],
            []
        ]
    },
    {
        "id": "b126369ffdd94aec",
        "type": "status",
        "z": "010236e9a60895ec",
        "name": "",
        "scope": [
            "f16aa7ea93e905dd"
        ],
        "x": 1330,
        "y": 540,
        "wires": [
            []
        ]
    },
    {
        "id": "9ae5e1b2605722fd",
        "type": "function",
        "z": "010236e9a60895ec",
        "name": "Selection func",
        "func": "function getSelection() {\n    return context.get(\"selection\");\n}\n\nfunction cloneWithSelection(oldm) {\n    var m = RED.util.cloneMessage(oldm);\n    var g = getSelection();\n    if (g !== null && g !== undefined) {\n        m.payload.last_clicked_button = g;\n    }\n    return m;\n}\n\nfunction setSelection(sel) {\n    context.set(\"selection\", sel);\n}\n\nmsg = cloneWithSelection(msg);\n\nif (msg.payload.command == \"click\") {\n    setSelection(msg.payload.button);\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1620,
        "y": 300,
        "wires": [
            [
                "0331ddd634c616b5"
            ]
        ]
    },
    {
        "id": "843cbeb1697357cc",
        "type": "server-events",
        "z": "34a6d2328609f4f7",
        "name": "Dial events",
        "server": "47fda6e5630a2a77",
        "version": 2,
        "eventType": "zha_event",
        "exposeToHomeAssistant": false,
        "eventData": "{\"device_ieee\": \"00:17:88:01:0d:13:5b:28\"}",
        "haConfig": [
            {
                "property": "name",
                "value": ""
            },
            {
                "property": "icon",
                "value": ""
            }
        ],
        "waitForRunning": true,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "eventData"
            },
            {
                "property": "topic",
                "propertyType": "msg",
                "value": "$outputData(\"eventData\").event_type",
                "valueType": "jsonata"
            }
        ],
        "x": 360,
        "y": 2640,
        "wires": [
            []
        ]
    },
    {
        "id": "3f14dead6da795cd",
        "type": "subflow:010236e9a60895ec",
        "z": "34a6d2328609f4f7",
        "name": "",
        "env": [
            {
                "name": "device_ieee",
                "value": "00:17:88:01:0d:13:5b:28",
                "type": "str"
            }
        ],
        "x": 550,
        "y": 2640,
        "wires": [
            [
                "aaaa54b2b90218a3"
            ],
            [
                "aaaa54b2b90218a3"
            ],
            [],
            [
                "f6abbc75d6419514"
            ],
            [],
            []
        ]
    },
    {
        "id": "c02ecdf56a6d2aff",
        "type": "subflow:d7483652324db060",
        "z": "34a6d2328609f4f7",
        "name": "Marantz volume control discrete",
        "env": [
            {
                "name": "entity_id",
                "value": "media_player.marantz_av7702mkii",
                "type": "str"
            }
        ],
        "x": 1090,
        "y": 2540,
        "wires": []
    },
    {
        "id": "aec8efeda8255a83",
        "type": "subflow:fdadee349978682f",
        "z": "34a6d2328609f4f7",
        "name": "",
        "x": 1130,
        "y": 2600,
        "wires": []
    },
    {
        "id": "782694450b6c7611",
        "type": "subflow:b778c74473856912",
        "z": "34a6d2328609f4f7",
        "name": "",
        "x": 1080,
        "y": 2660,
        "wires": []
    },
    {
        "id": "aaaa54b2b90218a3",
        "type": "switch",
        "z": "34a6d2328609f4f7",
        "name": "vol / scrub / skip",
        "property": "payload.last_clicked_button",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "1",
                "vt": "num"
            },
            {
                "t": "eq",
                "v": "2",
                "vt": "num"
            },
            {
                "t": "eq",
                "v": "3",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 3,
        "x": 800,
        "y": 2600,
        "wires": [
            [
                "c02ecdf56a6d2aff"
            ],
            [
                "aec8efeda8255a83"
            ],
            [
                "782694450b6c7611"
            ]
        ],
        "outputLabels": [
            "volume",
            "scrub",
            "nextprev"
        ]
    },
    {
        "id": "f6abbc75d6419514",
        "type": "switch",
        "z": "34a6d2328609f4f7",
        "name": "button = 2?",
        "property": "payload.button",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "2",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 790,
        "y": 2680,
        "wires": [
            [
                "a2d89645036ba857"
            ]
        ],
        "outputLabels": [
            "pause/play"
        ]
    },
    {
        "id": "a2d89645036ba857",
        "type": "subflow:1a0aea5a9ec739d4",
        "z": "34a6d2328609f4f7",
        "name": "Pause / resume last media player",
        "env": [
            {
                "name": "mode",
                "value": "last",
                "type": "str"
            }
        ],
        "x": 1100,
        "y": 2720,
        "wires": [
            []
        ]
    },
    {
        "id": "47fda6e5630a2a77",
        "type": "server",
        "name": "Home Assistant",
        "version": 5,
        "addon": false,
        "rejectUnauthorizedCerts": false,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30",
        "areaSelector": "friendlyName",
        "deviceSelector": "friendlyName",
        "entitySelector": "friendlyName",
        "statusSeparator": ": ",
        "statusYear": "hidden",
        "statusMonth": "short",
        "statusDay": "numeric",
        "statusHourCycle": "default",
        "statusTimeFormat": "h:m:s.ms",
        "enableGlobalContextStore": true
    }
]