Dualshock 4 receiver

Create a seamless gaming experience with the Node-RED DualShock 4 Receiver flow, powered by the dualshock-controller npm module. This versatile flow allows you to effortlessly connect and interact with your DualShock 4 controller in Node-RED, opening up a world of possibilities for gaming, automation, and control applications.

With this intuitive Node-RED flow, you can:

Establish a secure and reliable connection to your DualShock 4 controller. Access a wide range of controller data, including button presses, analog stick movements, and accelerometer readings. Customize actions and responses based on controller input, enabling you to design interactive applications or automate tasks. Seamlessly integrate your DualShock 4 controller with other IoT devices and services in your Node-RED projects.

Whether you're a gaming enthusiast looking to enhance your gaming experience or a developer seeking to incorporate gaming controllers into your projects, the DualShock 4 Receiver flow for Node-RED simplifies the process and offers flexibility for creative exploration. Start building your next gaming or automation project with ease using this powerful Node-RED flow and the dualshock-controller npm module today!

[{"id":"62264c9ebd5f8815","type":"tab","label":"Dualshock 4","disabled":false,"info":"","env":[]},{"id":"99a814c605cf657a","type":"group","z":"62264c9ebd5f8815","name":"Dualshock 4 controller sender","style":{"label":true,"stroke":"#003F97"},"nodes":["12de082f6683ba15","b81edf27eef4765d","bb8d491eda1c033b","ff83174dd3248d15","714fc480901f0a0e","1b43646e66f1f04b","ce7a6805e3036fea","1da39337104e7934","370ccf5402f43958","9d91efe76e72ee80","446259cbc3a7bd10","bd23ef4805d7c191","9f63aa2e202ef23a","0c48a8e47e101bcf","81f0956b165be29f","7d7222b409ffa70f","dd4dbac9a2848498"],"x":34,"y":39,"w":892,"h":282},{"id":"12de082f6683ba15","type":"function","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"Dualshock","func":"function filterDeadZone(data, side) {\n    if (data.x >= 145 || data.x <= 115 || data.y >= 145 || data.y <= 115) {\n        node.send({ \"payload\": `${side}Stick move: (${data.x},${data.y})`, \"controller\": controller, \"topic\": `${side}Stick`});\n    } else {\n        return;\n    };\n};\n\n// controls to turn on the listener\nif (msg.payload === \"on\") {\n    // pass options to create the controller.\n    var controller = dualShock({\n        // you can use a ds4 by uncommenting this line.\n        config: \"dualshock4-generic-driver\",\n\n        // if the above configuration doesn\"t work for you,\n        // try uncommenting the following line instead.\n        //config: \"dualshock4-alternate-driver\",\n\n        // if using ds4 comment this line.\n        //config: \"dualShock3\",\n\n        // smooths the output from the acelerometers (moving averages) defaults to true\n        accelerometerSmoothing: true,\n\n        // smooths the output from the analog sticks (moving averages) defaults to false\n        analogStickSmoothing: false,\n    });\n\n    // set the maximum number of listeners\n    controller._maxListeners = 50;\n\n    // make sure you add an error event handler\n    controller.on(\"error\", err => node.error({ \"error\": err }));\n\n    // analog stick handlers:\n    controller.on(\"left:move\", data => filterDeadZone(data, \"left\"));\n    controller.on(\"right:move\", data => filterDeadZone(data, \"right\"));\n    //controller.on(\"left:move\", data => node.send({ \"payload\": `leftStick move: (${data.x},${data.y})`, \"controller\": controller}));\n    //controller.on(\"right:move\", data => node.send({ \"payload\": `rightStick move: (${data.x},${data.y})`, \"controller\": controller}));\n\n    // square, triangle, circle, and cross event handlers:\n    controller.on(\"square:press\", () => node.send({ \"payload\": \"square press\", \"controller\": controller }));\n    controller.on(\"square:release\", () => node.send({ \"payload\": \"square release\", \"controller\": controller }));\n    controller.on(\"triangle:press\", () => node.send({ \"payload\": \"triangle press\", \"controller\": controller }));\n    controller.on(\"triangle:release\", () => node.send({ \"payload\": \"triangle release\", \"controller\": controller }));\n    controller.on(\"circle:press\", () => node.send({ \"payload\": \"circle press\", \"controller\": controller }));\n    controller.on(\"circle:release\", () => node.send({ \"payload\": \"circle release\", \"controller\": controller }));\n    controller.on(\"x:press\", () => node.send({ \"payload\": \"cross press\", \"controller\": controller }));\n    controller.on(\"x:release\", () => node.send({ \"payload\": \"cross release\", \"controller\": controller }));\n\n    // dpad event handlers:\n    controller.on(\"dpadUp:press\", () => node.send({ \"payload\": \"dpadUp press\", \"controller\": controller }));\n    controller.on(\"dpadUp:release\", () => node.send({ \"payload\": \"dpadUp release\", \"controller\": controller }));\n    controller.on(\"dpadUpRight:press\", () => node.send({ \"payload\": \"dpadUpRight press\", \"controller\": controller }));\n    controller.on(\"dpadUpRight:release\", () => node.send({ \"payload\": \"dpadUpRight release\", \"controller\": controller }));\n    controller.on(\"dpadRight:press\", () => node.send({ \"payload\": \"dpadRight press\", \"controller\": controller }));\n    controller.on(\"dpadRight:release\", () => node.send({ \"payload\": \"dpadRight release\", \"controller\": controller }));\n    controller.on(\"dpadDownRight:press\", () => node.send({ \"payload\": \"dpadDownRight press\", \"controller\": controller }));\n    controller.on(\"dpadDownRight:release\", () => node.send({ \"payload\": \"dpadDownRight release\", \"controller\": controller }));\n    controller.on(\"dpadDown:press\", () => node.send({ \"payload\": \"dpadDown press\", \"controller\": controller }));\n    controller.on(\"dpadDown:release\", () => node.send({ \"payload\": \"dpadDown release\", \"controller\": controller }));\n    controller.on(\"dpadDownLeft:press\", () => node.send({ \"payload\": \"dpadDownLeft press\", \"controller\": controller }));\n    controller.on(\"dpadDownLeft:release\", () => node.send({ \"payload\": \"dpadDownLeft release\", \"controller\": controller }));\n    controller.on(\"dpadLeft:press\", () => node.send({ \"payload\": \"dpadLeft press\", \"controller\": controller }));\n    controller.on(\"dpadLeft:release\", () => node.send({ \"payload\": \"dpadLeft release\", \"controller\": controller }));\n    controller.on(\"dpadUpLeft:press\", () => node.send({ \"payload\": \"dpadUpLeft press\", \"controller\": controller }));\n    controller.on(\"dpadUpLeft:release\", () => node.send({ \"payload\": \"dpadUpLeft release\", \"controller\": controller }));\n    \n    // share, options, and PS Button handlers:\n    controller.on(\"share:press\", () => node.send({ \"payload\": \"share press\", \"controller\": controller }));\n    controller.on(\"share:release\", () => node.send({ \"payload\": \"share release\", \"controller\": controller }));\n    controller.on(\"options:press\", () => node.send({ \"payload\": \"options press\", \"controller\": controller }));\n    controller.on(\"options:release\", () => node.send({ \"payload\": \"options release\", \"controller\": controller }));\n    controller.on(\"psxButton:press\", () => node.send({ \"payload\": \"PS Button press\", \"controller\": controller }));\n    controller.on(\"psxButton:release\", () => node.send({ \"payload\": \"PS Button release\", \"controller\": controller }));\n    \n    // L/R handlers:\n    controller.on(\"l1:press\", () => node.send({ \"payload\": \"L1 press\", \"controller\": controller }));\n    controller.on(\"l1:release\", () => node.send({ \"payload\": \"L1 release\", \"controller\": controller }));\n    controller.on(\"r1:press\", () => node.send({ \"payload\": \"R1 press\", \"controller\": controller }));\n    controller.on(\"r1:release\", () => node.send({ \"payload\": \"R1 release\", \"controller\": controller }));\n    controller.on(\"l2:press\", () => node.send({ \"payload\": \"L2 press\", \"controller\": controller }));\n    controller.on(\"l2:release\", () => node.send({ \"payload\": \"L2 release\", \"controller\": controller }));\n    //controller.on(\"l2:analog\", () => node.send({ \"payload\": \"L2 analog\", \"controller\": controller }));\n    controller.on(\"r2:press\", () => node.send({ \"payload\": \"R2 press\", \"controller\": controller }));\n    controller.on(\"r2:release\", () => node.send({ \"payload\": \"R2 release\", \"controller\": controller }));\n    //controller.on(\"r2:analog\", () => node.send({ \"payload\": \"R2 analog\", \"controller\": controller }));\n    //controller.on(\"leftAnalogBump:press\", () => node.send({ \"payload\": \"L2 press\", \"controller\": controller }));\n    //controller.on(\"leftAnalogBump:release\", () => node.send({ \"payload\": \"L2 release\", \"controller\": controller }));\n    //controller.on(\"rightAnalogBump:press\", () => node.send({ \"payload\": \"R2 press\", \"controller\": controller }));\n    //controller.on(\"rightAnalogBump:release\", () => node.send({ \"payload\": \"R2 release\", \"controller\": controller }));\n    controller.on(\"leftStick:press\", () => node.send({ \"payload\": \"L3 press\", \"controller\": controller }));\n    controller.on(\"leftStick:release\", () => node.send({ \"payload\": \"L3 release\", \"controller\": controller }));\n    controller.on(\"rightStick:press\", () => node.send({ \"payload\": \"R3 press\", \"controller\": controller }));\n    controller.on(\"rightStick:release\", () => node.send({ \"payload\": \"R3 release\", \"controller\": controller }));\n\n    // touchpad handlers:\n    controller.on(\"touchpad:press\", () => node.send({ \"payload\": \"touchpad press\", \"controller\": controller }));\n    controller.on(\"touchpad:release\", () => node.send({ \"payload\": \"touchpad release\", \"controller\": controller }));\n    //finger 1 is x1 finger 2 is x2\n    //controller.on(\"touchpad:x1:active\", () => node.send({ \"payload\": \"touchpad one finger active\" }));\n    //controller.on(\"touchpad:x2:active\", () => node.send({ \"payload\": \"touchpad two fingers active\" }));\n    //controller.on(\"touchpad:x2:inactive\", () => node.send({ \"payload\": \"touchpad back to single finger\" }));\n    //controller.on(\"touchpad:x1\", data => node.send({ \"payload\": `touchpad x1: ${data.x}, ${data.y}`, \"controller\": controller, \"topic\": \"touchpad\" }));\n    //controller.on(\"touchpad:x2\", data => node.send({ \"payload\": `touchpad x2: ${data.x}, ${data.y}`, \"controller\": controller, \"topic\": \"touchpad\" }));\n\n    // motion control handlers:\n    //controller.on(\"rightLeft:motion\", data => node.send({ \"payload\": data, \"topic\": \"motion\", \"controller\": controller }))\n    //controller.on(\"forwardBackward:motion\", data => node.send({ \"payload\": data, \"topic\": \"motion\", \"controller\": controller }))\n    //controller.on(\"upDown:motion\", data => node.send({ \"payload\": data, \"topic\": \"motion\", \"controller\": controller }))\n\n    // status handlers:\n    //controller.on(\"connected\", () => node.send({ \"payload\": \"connected\", \"topic\": \"status\", \"controller\": controller }));\n    //controller.on(\"battery:change\", data => node.send({ \"payload\": data, \"topic\": \"status\", \"controller\": controller }));\n    //controller.on(\"connection:change\", data => node.send({ \"payload\": data, \"topic\": \"status\", \"controller\": controller }));\n    //controller.on(\"charging:change\", data => node.send({ \"payload\": data, \"topic\": \"status\", \"controller\": controller }));\n\n    // send startup message\n    node.send({ \"payload\": \"Listeners turned on\", \"controller\": controller });\n\n    // save controller\n    flow.set(\"controller\", controller);\n    \n    // status output for function node\n    node.status({ fill: \"green\", shape: \"dot\", text: \"ON\" });\n};\n\n// controls to turn off the listener\nif (msg.payload === \"off\") {\n    // get our saved controller\n    let controller = flow.get(\"controller\");\n\n    // set the maximum number of listeners\n    controller._maxListeners = 0;\n\n    // clear event listeners\n    controller._events[\"error\"] = [];\n    controller._events[\"left:move\"] = [];\n    controller._events[\"right:move\"] = [];\n    controller._events[\"square:press\"] = [];\n    controller._events[\"square:release\"] = [];\n    controller._events[\"triangle:press\"] = [];\n    controller._events[\"triangle:release\"] = [];\n    controller._events[\"circle:press\"] = [];\n    controller._events[\"circle:release\"] = [];\n    controller._events[\"x:press\"] = [];\n    controller._events[\"x:release\"] = [];\n    controller._events[\"dpadUp:press\"] = [];\n    controller._events[\"dpadUp:release\"] = [];\n    controller._events[\"dpadUpRight:press\"] = [];\n    controller._events[\"dpadUpRight:release\"] = [];\n    controller._events[\"dpadRight:press\"] = [];\n    controller._events[\"dpadRight:release\"] = [];\n    controller._events[\"dpadDownRight:press\"] = [];\n    controller._events[\"dpadDownRight:release\"] = [];\n    controller._events[\"dpadDown:press\"] = [];\n    controller._events[\"dpadDown:release\"] = [];\n    controller._events[\"dpadDownLeft:press\"] = [];\n    controller._events[\"dpadDownLeft:release\"] = [];\n    controller._events[\"dpadLeft:press\"] = [];\n    controller._events[\"dpadLeft:release\"] = [];\n    controller._events[\"dpadUpLeft:press\"] = [];\n    controller._events[\"dpadUpLeft:release\"] = [];\n    controller._events[\"options:press\"] = [];\n    controller._events[\"options:release\"] = [];\n    controller._events[\"share:press\"] = [];\n    controller._events[\"share:release\"] = [];\n    controller._events[\"psxButton:press\"] = [];\n    controller._events[\"psxButton:release\"] = [];\n    controller._events[\"l1:press\"] = [];\n    controller._events[\"l1:release\"] = [];\n    controller._events[\"r1:press\"] = [];\n    controller._events[\"r1:release\"] = [];\n    controller._events[\"l2:press\"] = [];\n    controller._events[\"l2:release\"] = [];\n    controller._events[\"r2:press\"] = [];\n    controller._events[\"r2:release\"] = [];\n    controller._events[\"leftStick:press\"] = [];\n    controller._events[\"leftStick:release\"] = [];\n    controller._events[\"rightStick:press\"] = [];\n    controller._events[\"rightStick:release\"] = [];\n    controller._events[\"touchpad:press\"] = [];\n    controller._events[\"touchpad:release\"] = [];\n\n    // send final closing message\n    node.send({ \"payload\": \"Listeners turned off\", \"controller\": controller });\n\n    // save controller\n    flow.set(\"controller\", controller);\n\n    // status output for function node\n    node.status({ fill: \"red\", shape: \"dot\", text: \"OFF\" });\n};","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"dualShock","module":"node-dualshock-controller"}],"x":290,"y":180,"wires":[["ce7a6805e3036fea"]]},{"id":"b81edf27eef4765d","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"rightStick(x,y)","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":800,"y":160,"wires":[]},{"id":"bb8d491eda1c033b","type":"inject","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":130,"y":160,"wires":[["12de082f6683ba15"]]},{"id":"ff83174dd3248d15","type":"catch","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"","scope":["12de082f6683ba15"],"uncaught":false,"x":130,"y":260,"wires":[["1b43646e66f1f04b"]]},{"id":"714fc480901f0a0e","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"errors","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":430,"y":260,"wires":[]},{"id":"1b43646e66f1f04b","type":"function","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"warn","func":"if (msg.error) {\n    node.warn(\"Don't forget to check that the controller hasn't lost connection first.\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":260,"wires":[["714fc480901f0a0e"]]},{"id":"ce7a6805e3036fea","type":"switch","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"hold","vt":"str"},{"t":"eq","v":"leftStick","vt":"str"},{"t":"eq","v":"rightStick","vt":"str"},{"t":"eq","v":"motion","vt":"str"},{"t":"eq","v":"status","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":6,"x":430,"y":180,"wires":[["0c48a8e47e101bcf"],["9d91efe76e72ee80"],["446259cbc3a7bd10"],["9f63aa2e202ef23a"],["bd23ef4805d7c191"],["370ccf5402f43958"]]},{"id":"1da39337104e7934","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"leftStick(x,y)","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":120,"wires":[]},{"id":"370ccf5402f43958","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"other","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":280,"wires":[]},{"id":"9d91efe76e72ee80","type":"delay","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"5","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":630,"y":120,"wires":[["1da39337104e7934"]]},{"id":"446259cbc3a7bd10","type":"delay","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"5","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":630,"y":160,"wires":[["b81edf27eef4765d"]]},{"id":"bd23ef4805d7c191","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"controller status","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":640,"y":240,"wires":[]},{"id":"9f63aa2e202ef23a","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"motion","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":200,"wires":[]},{"id":"0c48a8e47e101bcf","type":"debug","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"hold","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":80,"wires":[]},{"id":"81f0956b165be29f","type":"comment","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"Sender controls","info":"","x":140,"y":120,"wires":[]},{"id":"7d7222b409ffa70f","type":"comment","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"Output here","info":"","x":430,"y":100,"wires":[]},{"id":"dd4dbac9a2848498","type":"inject","z":"62264c9ebd5f8815","g":"99a814c605cf657a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":130,"y":200,"wires":[["12de082f6683ba15"]]}]

Flow Info

Created 1 year, 5 months ago
Rating: 5 1

Actions

Rate:

Node Types

Core
  • catch (x1)
  • comment (x2)
  • debug (x7)
  • delay (x2)
  • function (x2)
  • inject (x2)
  • switch (x1)
Other

Tags

  • Playstation
  • dualshock
  • controller
  • iot
  • buttons
  • analog-sticks
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option