So, have a PCF8574 breakout board and want to use it via NR? Have I got a deal, [cough], a flow for you!
I could not seem to find an easy, straight forward way to use an PCF8574 based GPIO expansion breakout board in NR.
There are examples via Google, there are various modules, etc. But for one reason or another some I could not use or get working. I wanted to use the i2c-bus nodes (module) https://flows.nodered.org/node/node-red-contrib-i2c as basic start to a flow, but that specific solution is 'command' driven for i2c in/out, read/write, or at least I could not figure out how to use said nodes to do simple i2c byte write/read calls.
I did use the i2c scan node for NR, to make sure the PC8574 device is on the i2c bus before any attempt to use... Any i2c device can drop off the i2c bus, which can happen at times, rather than have the flows crash and burn. Usually I send a pop window to the dashboard as alert if that happens.
Fortunately, the i2c-bus module (node.js not NR variant) https://www.npmjs.com/package/i2c-bus can do simple direct byte read/write calls. Hence, you can set and get the 'register' state of the PCF8574 chip. Below is a few flows that illustrate driving a PCF8574 chip (breakout board variant) via NR. There is a bit of scripting to do the actual i2c byte read and write calls, but other than that, NR flow based. I did add a flow context variable to save and restore the 'register' state as well.
One key requirement is that in the settings.js file, make sure the global function includes the i2c:require('i2c-bus') support.
[{"id":"cddd57a4.af7698","type":"tab","label":"PCF8574","disabled":false,"info":""},{"id":"373eb13.0be93ce","type":"comment","z":"cddd57a4.af7698","name":"Ensure Global Function (Settings.js) Includes i2c:require('i2c-bus')","info":"https://tech.scargill.net/i2c-for-everyone/","x":260,"y":40,"wires":[]},{"id":"f59be8f9.076c7","type":"inject","z":"cddd57a4.af7698","name":"Automatic","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":100,"wires":[["f401a9b9.336e"]]},{"id":"f401a9b9.336e","type":"i2c scan","z":"cddd57a4.af7698","name":"Scan","busno":"1","x":270,"y":100,"wires":[[],["dc9fb2bd.9fb36"]]},{"id":"dc9fb2bd.9fb36","type":"switch","z":"cddd57a4.af7698","name":"PCF8574 (Address 0x38 | 56)?","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"56","vt":"num"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":490,"y":120,"wires":[["8e93378d.f151f8"],["9f61bcbb.0d41"]]},{"id":"450aa5ce.661834","type":"debug","z":"cddd57a4.af7698","name":"Message","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":940,"y":220,"wires":[]},{"id":"1e41e1ad.3f24e6","type":"function","z":"cddd57a4.af7698","name":"Write PCF8574","func":"const i2c = global.get('i2c');\n\nvar PCF8574 = flow.get('pcf8574');\n\nconst theAddress = PCF8574.address;\nconst theBus = PCF8574.bus;\nconst theRegister = msg.register;\n\nvar theDevice = i2c.openSync(theBus);\ntheDevice.sendByteSync(theAddress, theRegister);\ntheDevice.closeSync();\n\nmsg.register = theRegister;\nmsg.bus = theBus;\nmsg.address = theAddress;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":760,"y":240,"wires":[["450aa5ce.661834"]]},{"id":"ecc3b10a.e3b7","type":"function","z":"cddd57a4.af7698","name":"Read PCF8574","func":"const i2c = global.get('i2c');\n\nvar PCF8574 = flow.get('pcf8574');\n\nconst theAddress = PCF8574.address;\nconst theBus = PCF8574.bus;\n\nvar theDevice = i2c.openSync(theBus);\ntheRegister = theDevice.receiveByteSync(theAddress);\ntheDevice.closeSync();\n\nPCF8574.register = theRegister;\nflow.set('pcf8574', PCF8574);\n\nmsg.register = theRegister;\nmsg.bus = theBus;\nmsg.address = theAddress;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":760,"y":200,"wires":[["450aa5ce.661834"]]},{"id":"ec2fcdfe.6d29f","type":"inject","z":"cddd57a4.af7698","name":"P7 (Bit 7) On","props":[{"p":"payload"},{"p":"bit","v":"7","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":960,"wires":[["2bcbd6ee.cbf3ca"]]},{"id":"d8b00c75.60a3d","type":"inject","z":"cddd57a4.af7698","name":"P7 (Bit 7) Off","props":[{"p":"payload"},{"p":"bit","v":"7","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":920,"wires":[["2bcbd6ee.cbf3ca"]]},{"id":"8e93378d.f151f8","type":"change","z":"cddd57a4.af7698","name":"Exist","rules":[{"t":"set","p":"exist","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":730,"y":100,"wires":[["79e60788.67f0d"]]},{"id":"9f61bcbb.0d41","type":"change","z":"cddd57a4.af7698","name":"!Exist","rules":[{"t":"set","p":"exist","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":730,"y":140,"wires":[["79e60788.67f0d"]]},{"id":"76c4ad08.6b1db4","type":"inject","z":"cddd57a4.af7698","name":"Direct Read","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":200,"wires":[["f684642f.c762f8"]]},{"id":"e1756b6a.63c8e8","type":"link out","z":"cddd57a4.af7698","name":"","links":["171eaafb.49cfb5"],"x":375,"y":200,"wires":[]},{"id":"171eaafb.49cfb5","type":"link in","z":"cddd57a4.af7698","name":"","links":["e1756b6a.63c8e8"],"x":615,"y":200,"wires":[["ecc3b10a.e3b7"]]},{"id":"79e60788.67f0d","type":"function","z":"cddd57a4.af7698","name":"Set","func":"const PCF8574 = { 'address': 56, 'bus': 1, 'register': 0, 'exist': msg.exist};\n\nflow.set('pcf8574', PCF8574);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":870,"y":120,"wires":[[]]},{"id":"f684642f.c762f8","type":"switch","z":"cddd57a4.af7698","name":"Exist?","property":"pcf8574.exist","propertyType":"flow","rules":[{"t":"true"}],"checkall":"false","repair":false,"outputs":1,"x":270,"y":200,"wires":[["e1756b6a.63c8e8"]]},{"id":"6d3e4216.84fe74","type":"link in","z":"cddd57a4.af7698","name":"","links":["7ca065db.d30034","8e63e800.6645d","f297373a.b84258","a247b0ec.570dd","553280b0.1569d","a3d445fd.a36818","a8e0aa3e.c2eb1","f5361233.9003f","1c69bc01.1fa1f4"],"x":615,"y":240,"wires":[["1e41e1ad.3f24e6"]]},{"id":"f4612b87.5aa588","type":"inject","z":"cddd57a4.af7698","name":"Direct All Off","props":[{"p":"payload"},{"p":"register","v":"0","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":240,"wires":[["32aaf175.7181ce"]]},{"id":"32aaf175.7181ce","type":"switch","z":"cddd57a4.af7698","name":"Exist?","property":"pcf8574.exist","propertyType":"flow","rules":[{"t":"true"}],"checkall":"false","repair":false,"outputs":1,"x":270,"y":260,"wires":[["7ca065db.d30034"]]},{"id":"7ca065db.d30034","type":"link out","z":"cddd57a4.af7698","name":"","links":["6d3e4216.84fe74"],"x":375,"y":260,"wires":[]},{"id":"9f27abce.14aea","type":"inject","z":"cddd57a4.af7698","name":"Direct All On","props":[{"p":"payload"},{"p":"register","v":"255","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":280,"wires":[["32aaf175.7181ce"]]},{"id":"49e4b515.703a5c","type":"inject","z":"cddd57a4.af7698","name":"P6 (Bit 6) On","props":[{"p":"payload"},{"p":"bit","v":"6","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":880,"wires":[["bda2b3ff.ce25b8"]]},{"id":"c1474945.86ab48","type":"inject","z":"cddd57a4.af7698","name":"P6 (Bit 6) Off","props":[{"p":"payload"},{"p":"bit","v":"6","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":840,"wires":[["bda2b3ff.ce25b8"]]},{"id":"544da9d6.9dff18","type":"inject","z":"cddd57a4.af7698","name":"P0 (Bit 0) On","props":[{"p":"payload"},{"p":"bit","v":"0","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":400,"wires":[["b48b6f02.abe7c8"]]},{"id":"8c813931.0f55a8","type":"inject","z":"cddd57a4.af7698","name":"P0 (Bit 0) Off","props":[{"p":"payload"},{"p":"bit","v":"0","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":360,"wires":[["b48b6f02.abe7c8"]]},{"id":"a247b0ec.570dd","type":"link out","z":"cddd57a4.af7698","name":"","links":["5a62665b.10c488","6d3e4216.84fe74"],"x":975,"y":360,"wires":[]},{"id":"acd2a521.692eb8","type":"switch","z":"cddd57a4.af7698","name":"Exist?","property":"pcf8574.exist","propertyType":"flow","rules":[{"t":"true"}],"checkall":"false","repair":false,"outputs":1,"x":730,"y":360,"wires":[["93e2b586.cf38e"]]},{"id":"93e2b586.cf38e","type":"function","z":"cddd57a4.af7698","name":"Set","func":"const MASK = 1 << msg.bit;\n\nvar PCF8574 = flow.get('pcf8574');\nvar theRegister = PCF8574.register;\n\nif (msg.payload) {\n theRegister |= MASK;\n} else {\n theRegister &= ~MASK;\n}\n\n//node.warn(`Get Register ${PCF8574.register}, Bit ${msg.bit}, Mask ${MASK}, Set Register ${theRegister}`);\n\nPCF8574.register = theRegister;\nflow.set('pcf8574', PCF8574);\n\nmsg.register = theRegister;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":870,"y":360,"wires":[["a247b0ec.570dd"]]},{"id":"47927b0d.5d564c","type":"inject","z":"cddd57a4.af7698","name":"P1 (Bit 1) On","props":[{"p":"payload"},{"p":"bit","v":"1","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":480,"wires":[["891cde91.fcdf28"]]},{"id":"df331cb0.5817f8","type":"inject","z":"cddd57a4.af7698","name":"P1 (Bit 1) Off","props":[{"p":"payload"},{"p":"bit","v":"1","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":440,"wires":[["891cde91.fcdf28"]]},{"id":"e8bb9031.313a98","type":"inject","z":"cddd57a4.af7698","name":"P2 (Bit 2) On","props":[{"p":"payload"},{"p":"bit","v":"2","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":560,"wires":[["cc8d45aa.93a2f"]]},{"id":"a1f9923a.78322","type":"inject","z":"cddd57a4.af7698","name":"P2 (Bit 2) Off","props":[{"p":"payload"},{"p":"bit","v":"2","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":520,"wires":[["cc8d45aa.93a2f"]]},{"id":"508dab5a.f78ddc","type":"inject","z":"cddd57a4.af7698","name":"P3 (Bit 3) On","props":[{"p":"payload"},{"p":"bit","v":"3","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":640,"wires":[["5c8b4184.98d448"]]},{"id":"9f1da49c.b17bf8","type":"inject","z":"cddd57a4.af7698","name":"P3 (Bit 3) Off","props":[{"p":"payload"},{"p":"bit","v":"3","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":600,"wires":[["5c8b4184.98d448"]]},{"id":"a0bd41e8.496fd8","type":"inject","z":"cddd57a4.af7698","name":"P4 (Bit 4) On","props":[{"p":"payload"},{"p":"bit","v":"4","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":720,"wires":[["848c8ca4.7d0e2"]]},{"id":"681cd30a.16293c","type":"inject","z":"cddd57a4.af7698","name":"P4 (Bit 4) Off","props":[{"p":"payload"},{"p":"bit","v":"4","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":680,"wires":[["848c8ca4.7d0e2"]]},{"id":"ca7ceb18.528d","type":"inject","z":"cddd57a4.af7698","name":"P5 (Bit 5) On","props":[{"p":"payload"},{"p":"bit","v":"5","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":110,"y":800,"wires":[["68113d53.be9af4"]]},{"id":"8471d999.6b0c5","type":"inject","z":"cddd57a4.af7698","name":"P5 (Bit 5) Off","props":[{"p":"payload"},{"p":"bit","v":"5","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":760,"wires":[["68113d53.be9af4"]]},{"id":"dd6050de.db985","type":"link in","z":"cddd57a4.af7698","name":"","links":["b48b6f02.abe7c8","891cde91.fcdf28","cc8d45aa.93a2f","5c8b4184.98d448","848c8ca4.7d0e2","68113d53.be9af4","bda2b3ff.ce25b8","2bcbd6ee.cbf3ca"],"x":615,"y":360,"wires":[["acd2a521.692eb8"]]},{"id":"b48b6f02.abe7c8","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":380,"wires":[]},{"id":"891cde91.fcdf28","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":460,"wires":[]},{"id":"cc8d45aa.93a2f","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":540,"wires":[]},{"id":"5c8b4184.98d448","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":620,"wires":[]},{"id":"848c8ca4.7d0e2","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":700,"wires":[]},{"id":"68113d53.be9af4","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":780,"wires":[]},{"id":"bda2b3ff.ce25b8","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":860,"wires":[]},{"id":"2bcbd6ee.cbf3ca","type":"link out","z":"cddd57a4.af7698","name":"","links":["dd6050de.db985"],"x":235,"y":940,"wires":[]}]
Also, this solution does not save the 'register' state between NR stops and starts, but that can be done via anyone of the different context save methods for NR. Such is beyond the scope of this forum post for now.
Oh, if anyone knows of away to use the i2c-bus NR module and do direct byte read/write calls, via the defined i2c-in and i2c-out nodes, without the command specification requirement, let me know. Enjoy!