Behringer x32 to Home Assistant

Adds the Behringer x32 mixer to Home Assistant

[{"id":"5e89dcaa06413f09","type":"subflow","name":"HASS Event","info":"","category":"","in":[],"out":[{"x":860,"y":140,"wires":[{"id":"7c798a8f61be78ab","port":0}]}],"env":[{"name":"Event","type":"str","value":"","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"Loaded"},"v":"loaded"},{"l":{"en-US":"Script Update"},"v":"scriptUpdate"}]}}}],"meta":{},"color":"#DDAA99"},{"id":"2306a1c4ae9bd0d7","type":"function","z":"5e89dcaa06413f09","name":"function 18","func":"switch (env.get(\"Event\")) {\n    case \"loaded\": {\n        if (msg.topic == \"home_assistant_client:ready\" && msg.payload == \"ready\") {\n            msg.delay = 1;\n            return msg;\n        }\n        break;\n    }\n    case \"scriptUpdate\": {\n        if (msg.topic == \"call_service\" && msg.payload.event.domain == \"script\" && msg.payload.event.service == \"reload\") {\n            return msg;\n        }\n        break;\n    }\n    case \"disconnected\": {\n        if (msg.topic == \"home_assistant_client\" && msg.payload == \"disconnected\") {\n            return msg;\n        }\n        break;\n    }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":140,"wires":[["7c798a8f61be78ab"]]},{"id":"0bbb1a7f6689f423","type":"server-events","z":"5e89dcaa06413f09","name":"","server":"","version":1,"event_type":"home_assistant_client","exposeToHomeAssistant":false,"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":320,"y":140,"wires":[["2306a1c4ae9bd0d7"]]},{"id":"7c798a8f61be78ab","type":"delay","z":"5e89dcaa06413f09","name":"","pauseType":"delayv","timeout":"0","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":720,"y":140,"wires":[[]]},{"id":"4efbf8f6c335d350","type":"server-events","z":"5e89dcaa06413f09","name":"","server":"","version":1,"event_type":"call_service","exposeToHomeAssistant":false,"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":350,"y":180,"wires":[["2306a1c4ae9bd0d7"]]},{"id":"a139c1176fb91368","type":"comment","z":"a49785d74e501672","name":"x32","info":"","x":250,"y":700,"wires":[]},{"id":"78cc2d578fdb6fdf","type":"udp in","z":"a49785d74e501672","name":"x32In","iface":"","port":"10025","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":250,"y":900,"wires":[["4c0c5d47dc8cb69a"]]},{"id":"6a69af6e90e25094","type":"osc","z":"a49785d74e501672","name":"","path":"","metadata":false,"x":550,"y":860,"wires":[["a0d73c3e891687af"]]},{"id":"f4cc69e670da42d0","type":"function","z":"a49785d74e501672","name":"Subscribe to updates","func":"var msgs = [];\nfor(var i in flow.get(\"x32Devices\")) {\n    msgs.push({\n        \"topic\": \"/xremote\",\n        \"ip\": flow.get(\"x32Devices\")[i].ip\n    });\n}\nreturn [msgs];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":860,"wires":[["6a69af6e90e25094"]]},{"id":"a0d73c3e891687af","type":"udp out","z":"a49785d74e501672","name":"","addr":"","iface":"","port":"10023","ipv":"udp4","outport":"10025","base64":false,"multicast":"false","x":690,"y":860,"wires":[]},{"id":"b994656caae77cbf","type":"inject","z":"a49785d74e501672","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"10","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":235,"y":860,"wires":[["f4cc69e670da42d0"]],"l":false},{"id":"31eba5fd1fd772d8","type":"function","z":"a49785d74e501672","name":"Get information","func":"var msgs = [];\nvar devices = flow.get(\"x32Devices\");\nfor(var i in devices) {\n    //Channels\n    for(var j in devices[i].channels) {\n        var channel = devices[i].channels[j];\n        \n        //If there are multiple channels set id to be the first channel\n        if(Array.isArray(channel)) {\n            channel = channel[0];\n        }\n        \n        //Master\n        msgs.push({\n            \"topic\": `/ch/${('0' + channel).slice(-2)}/mix/fader`,\n            \"ip\": devices[i].ip\n        });\n        msgs.push({\n            \"topic\": `/ch/${('0' + channel).slice(-2)}/mix/on`,\n            \"ip\": devices[i].ip\n        });\n        \n        //Buses\n        for(var k in devices[i].buses) {\n            var bus = devices[i].buses[k];\n            \n            msgs.push({\n                \"topic\": `/ch/${('0' + channel).slice(-2)}/mix/${('0' + bus).slice(-2)}/level`,\n                \"ip\": devices[i].ip\n            });\n            msgs.push({\n                \"topic\": `/ch/${('0' + channel).slice(-2)}/mix/${('0' + bus).slice(-2)}/on`,\n                \"ip\": devices[i].ip\n            });\n        }\n    }\n}\nreturn [msgs];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":820,"wires":[["6a69af6e90e25094"]]},{"id":"755012ef4d6274b5","type":"function","z":"a49785d74e501672","name":"Set x32 Devices","func":"flow.set(\"x32Devices\", {\n    //Example device 1\n    \"Example 1\": {\n        \"ip\": \"192.16.0.1\",\n        \"buses\": {\n            \"Bus 1\": 1,\n            \"Bus 2\": 2\n        },\n        \"channels\": {\n            \"Channel 1\": 1,\n            \"Channel 2\": [25, 26]\n        }\n    },\n    //Example device 2\n    \"Example 2\": {\n        \"ip\": \"192.16.0.1\",\n        \"buses\": {\n            \"Bus 1\": 1,\n            \"Bus 2\": 2\n        },\n        \"channels\": {\n            \"Channel 1\": 1,\n            \"Channel 2\": [25, 26]\n        }\n    }\n});\n\n///////////////////////////////////////////////////////\n///////////////////////////////////////////////////////\n\n//Setup our stores for information\nfor(var i in flow.get(\"x32Devices\")) {\n    flow.get(\"x32Devices\")[i][\"busValues\"] = {\n        \"master\": {\n            \"levels\": {},\n            \"mutes\": {}\n        }\n    }\n    \n    for(var j in flow.get(\"x32Devices\")[i].buses) {\n        flow.get(\"x32Devices\")[i][\"busValues\"][j] = {\n            \"levels\": {},\n            \"mutes\": {}\n        }\n    }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":740,"wires":[[]]},{"id":"77288f011112c51c","type":"inject","z":"a49785d74e501672","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":235,"y":740,"wires":[["755012ef4d6274b5"]],"l":false},{"id":"043d2f8d72425c8c","type":"server-events","z":"a49785d74e501672","name":"","server":"","version":1,"event_type":"call_service","exposeToHomeAssistant":false,"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":290,"y":780,"wires":[["652d666e21c1fb01"]]},{"id":"d7786aa24bf0c753","type":"function","z":"a49785d74e501672","name":"Action","func":"var entity_id = msg.entity_id || msg.data.entity_id;\nvar entityIdSplits = entity_id.split(\".\")[1].split(\"_\");\nvar devices = flow.get(\"x32Devices\");\nif(!devices){return;}\nvar service = msg.event.service;\nvar serviceData = msg.event.service_data;\n\nvar device;\nvar bus;\nvar ids;\n\n//Find the device\nfor(var i in devices) {\n    if (i.replace(/[^A-Za-z0-9]/g, '').toLowerCase() == entityIdSplits[1]) {\n        device = devices[i];\n        break;\n    }\n}\n\n//Find the bus\nfor (var i in device.buses) {\n    if (i.replace(/[^A-Za-z0-9]/g, '').toLowerCase() == entityIdSplits[2]) {\n        bus = device.buses[i];\n        break;\n    }\n}\n\n//Find the channel\nfor (var i in device.channels) {\n    if (i.replace(/[^A-Za-z0-9]/g, '').toLowerCase() == entityIdSplits[3]) {\n        ids = device.channels[i];\n        break;\n    }\n}\n\nif (!Array.isArray(ids)) { ids = [ids]; }\nif(!device || !bus || !ids){return;}\n\nvar msgs = [];\nswitch (msg.event.domain) {\n    //Volume\n    case \"number\": {\n        switch (service) {\n            case \"set_value\": {\n                if (bus == \"master\") {\n                    for (var i in ids) {\n                        var value = parseInt(serviceData.value) / 100;\n                        msg.push({\n                            \"topic\": `/ch/${('0' + ids[i]).slice(-2)}/mix/fader`,\n                            \"payload\": value,\n                            \"ip\": device.ip,\n                        });\n                    }\n                }\n                else {\n                    for (var i in ids) {\n                        var value = parseInt(serviceData.value) / 100;\n                        msgs.push({\n                            \"topic\": `/ch/${('0' + ids[i]).slice(-2)}/mix/${('0' + bus).slice(-2)}/level`,\n                            \"payload\": value,\n                            \"ip\": device.ip,\n                        });\n                    }\n                }\n                break;\n            }\n        }\n        break;\n    }\n    //Mute\n    case \"input_boolean\": {\n        var value = 0;\n        switch (service) {\n            case \"turn_on\": {\n                value = 0;\n                break;\n            }\n            case \"turn_off\": {\n                value = 1;\n                break;\n            }\n            case \"toggle\": {\n                value = device[\"busValues\"][bus].mutes[ids[i]] ? 0 : 1\n                break;\n            }\n        }\n\n        if (bus == \"master\") {\n            for (var i in ids) {\n                msgs.push({\n                    \"topic\": `/ch/${('0' + ids[i]).slice(-2)}/mix/on`,\n                    \"payload\": value,\n                    \"ip\": device.ip\n                });\n            }\n        }\n        else {\n            for (var i in ids) {\n                msgs.push({\n                    \"topic\": `/ch/${('0' + ids[i]).slice(-2)}/mix/${('0' + bus).slice(-2)}/on`,\n                    \"payload\": value,\n                    \"ip\": device.ip\n                });\n            }\n        }\n        break;\n    }\n}\nreturn [msgs];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":780,"wires":[["ee3df45e42b854ea"]]},{"id":"90553d545ba4742f","type":"osc","z":"a49785d74e501672","name":"","path":"","metadata":false,"x":550,"y":900,"wires":[["f701fcd927c877ac"]]},{"id":"f701fcd927c877ac","type":"function","z":"a49785d74e501672","name":"Create entity","func":"var devices = flow.get(\"x32Devices\");\nvar msgs = [];\n\n//Find the channel\nfunction findChannel(device, id) {\n    for (var i in device.channels) {\n        var check = device.channels[i];\n        if (!Array.isArray(check)) { check = [check]; }\n\n        for (var j in check) {\n            if (check[j] == id) {\n                return i;\n            }\n        }\n    }\n}\n\n//Find the bus\nfunction findBus(device, id) {\n    for (var i in device.buses) {\n        var check = device.buses[i];\n        if (!Array.isArray(check)) { check = [check]; }\n\n        for (var j in check) {\n            if (check[j] == id) {\n                return i;\n            }\n        }\n    }\n}\n\nif (msg.device) {\n    if (msg.topic.includes(\"/ch/\") && msg.topic.includes(\"/mix/fader\")) {\n        var id = findChannel(msg.device, parseInt(msg.topic.split(\"/\")[2]));\n\n        if (id) {\n            flow.get(\"x32Devices\")[msg.deviceId][\"busValues\"][\"master\"].levels[id] = msg.payload;\n            return {\n                \"entity_id\": `number.x32_${msg.deviceId.toLowerCase()}_master_${id.replace(/[^A-Za-z0-9]/g, '').toLowerCase()}_volume`,\n                \"payload\": {\n                    \"data\": {\n                        \"state\": Math.ceil(msg.payload * 100).toString(),\n                        \"attributes\": {\n                            \"friendly_name\": `${id} Volume`,\n                            \"device\": msg.deviceId,\n                            \"bus\": \"master\",\n                            \"id\": id,\n                            \"editable\": true,\n                            \"min\": 0,\n                            \"max\": 100,\n                            \"step\": 1,\n                            \"unit_of_measurement\": \"%\"\n                        }\n                    }\n                },\n                \"channels\": flow.get(\"x32Devices\")[msg.deviceId][\"busValues\"]\n            }\n        }\n    }\n    else if (msg.topic.includes(\"/ch/\") && msg.topic.includes(\"/mix/on\")) {\n        var id = findChannel(msg.device, parseInt(msg.topic.split(\"/\")[2]));\n\n        if (id) {\n            flow.get(\"x32Devices\")[msg.deviceId][\"busValues\"][\"master\"].mutes[id] = msg.payload;\n            return {\n                \"entity_id\": `input_boolean.x32_${msg.deviceId.toLowerCase()}_master_${id.replace(/[^A-Za-z0-9]/g, '').toLowerCase()}_mute`,\n                \"payload\": {\n                    \"data\": {\n                        \"state\": msg.payload ? \"off\" : \"on\",\n                        \"attributes\": {\n                            \"friendly_name\": `${id} Mute`,\n                            \"bus\": \"master\",\n                            \"id\": id,\n                            \"device\": msg.deviceId,\n                            \"editable\": true\n                        }\n                    }\n                }\n            }\n        }\n    }\n    else if (msg.topic.includes(\"/ch/\") && msg.topic.includes(\"/mix/\") && msg.topic.includes(\"/level\")) {\n        var id = findChannel(msg.device, parseInt(msg.topic.split(\"/\")[2]));\n        var bus = findBus(msg.device, parseInt(msg.topic.split(\"/\")[4]));\n\n        if (id && bus) {\n            flow.get(\"x32Devices\")[msg.deviceId][\"busValues\"][bus].levels[id] = msg.payload;\n            return {\n                \"entity_id\": `number.x32_${msg.deviceId.toLowerCase()}_${bus.replace(/[^A-Za-z0-9]/g, '').toLowerCase()}_${id.replace(/[^A-Za-z0-9]/g, '').toLowerCase()}_volume`,\n                \"payload\": {\n                    \"data\": {\n                        \"state\": Math.ceil(msg.payload * 100).toString(),\n                        \"attributes\": {\n                            \"friendly_name\": `${bus} ${id} Volume`,\n                            \"device\": msg.deviceId,\n                            \"bus\": bus,\n                            \"id\": id,\n                            \"editable\": true,\n                            \"min\": 0,\n                            \"max\": 100,\n                            \"step\": 1,\n                            \"unit_of_measurement\": \"%\"\n                        }\n                    }\n                }, \n                \"channels\": flow.get(\"x32Devices\")[msg.deviceId][\"busValues\"]\n            }\n        }\n    }\n    else if (msg.topic.includes(\"/ch/\") && msg.topic.includes(\"/mix/\") && msg.topic.includes(\"/on\")) {\n        var id = findChannel(msg.device, parseInt(msg.topic.split(\"/\")[2]));\n        var bus = findBus(msg.device, parseInt(msg.topic.split(\"/\")[4]));\n\n        if (id && bus) {\n            flow.get(\"x32Devices\")[msg.deviceId][\"busValues\"][bus].mutes[id] = msg.payload;\n            return {\n                \"entity_id\": `input_boolean.x32_${msg.deviceId.toLowerCase()}_${bus.replace(/[^A-Za-z0-9]/g, '').toLowerCase()}_${id.replace(/[^A-Za-z0-9]/g, '').toLowerCase()}_mute`,\n                \"payload\": {\n                    \"data\": {\n                        \"state\": msg.payload ? \"off\" : \"on\",\n                        \"attributes\": {\n                            \"friendly_name\": `${bus} ${id} Mute`,\n                            \"bus\": bus,\n                            \"id\": id,\n                            \"device\": msg.deviceId,\n                            \"editable\": true\n                        }\n                    }\n                }\n            }\n        }\n    }\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nif(!flow.get(\"ampStates\")) {\n    flow.set(\"ampStates\", {});\n}","finalize":"","libs":[],"x":690,"y":900,"wires":[["1756accb1dac8ea0"]]},{"id":"4c0c5d47dc8cb69a","type":"function","z":"a49785d74e501672","name":"Get device","func":"var devices = flow.get(\"x32Devices\");\nfor(var i in devices) {\n    if(msg.ip == devices[i].ip) {\n        msg.deviceId = i;\n        msg.device = devices[i];\n        return msg;\n    }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":900,"wires":[["90553d545ba4742f"]]},{"id":"1756accb1dac8ea0","type":"trigger","z":"a49785d74e501672","name":"","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"100","extend":true,"overrideDelay":false,"units":"ms","reset":"","bytopic":"topic","topic":"entity_id","outputs":1,"x":860,"y":900,"wires":[["ed9657ad1e983a10"]]},{"id":"ed9657ad1e983a10","type":"ha-api","z":"a49785d74e501672","name":"","server":"","version":1,"debugenabled":false,"protocol":"http","method":"post","path":"/api/states/{{entity_id}}","data":"","dataType":"json","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":1010,"y":900,"wires":[[]]},{"id":"85a519946809d4bb","type":"trigger","z":"a49785d74e501672","name":"","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"1","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":900,"y":780,"wires":[["31eba5fd1fd772d8"]]},{"id":"ee3df45e42b854ea","type":"osc","z":"a49785d74e501672","name":"","path":"","metadata":false,"x":750,"y":780,"wires":[["a0d73c3e891687af","4c0c5d47dc8cb69a","85a519946809d4bb"]]},{"id":"652d666e21c1fb01","type":"function","z":"a49785d74e501672","name":"Prepare","func":"if (typeof msg.payload.event.service_data.entity_id == \"string\") {\n    msg.payload.event.service_data.entity_id = [msg.payload.event.service_data.entity_id];\n}\n\nvar msgs = [];\nfor (var i in msg.payload.event.service_data.entity_id) {\n    if (msg.payload.event.service_data.entity_id[i].includes(\"x32_\")) {\n        msgs.push({\n            \"topic\": msg.topic,\n            \"entity_id\": msg.payload.event.service_data.entity_id[i],\n            \"event\": msg.payload.event,\n            \"data\": msg.payload.event.service_data\n        });\n    }\n}\nreturn [msgs];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":780,"wires":[["d7786aa24bf0c753"]]},{"id":"28b657a52c29f2a9","type":"subflow:5e89dcaa06413f09","z":"a49785d74e501672","name":"Loaded","env":[{"name":"Event","value":"loaded","type":"str"}],"x":250,"y":820,"wires":[["31eba5fd1fd772d8"]]}]

Flow Info

Created 2 years, 9 months ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • comment (x1)
  • delay (x1)
  • function (x8)
  • inject (x2)
  • trigger (x2)
  • udp in (x1)
  • udp out (x1)
Other
  • ha-api (x1)
  • osc (x3)
  • server-events (x3)
  • subflow (x1)
  • subflow:5e89dcaa06413f09 (x1)

Tags

  • behringer
  • x32
  • mixer
  • homeassistant
  • home
  • assistant
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option