New MCP23017 PCF8574 All-In-One node

For JavaScript, it is more that you shouldn't start with an upper case letter because common convention uses that for Class names.

I used to use type prefixes but it can get in the way, especially when needing to refactor. These days I make better use of JSDoc comments and VScode's clever capabilities for using those along with tslint to make sense of object types.

New version is available on NPM.
(Interrupt problems were reported, so changed initialization.)
Interrupt is still experimental, testing needed.

If anyone interested on testing an upgraded version (because I don't have time currently)
Joe has made an extended AIO to support even more chip types + reworked the whole html part of the node to prevent choosing same port for other chips:
Github link...

I do not know, if it has an NPM or not yet,
but I think it is necessary to download and install it from Github directly.

Important discovery is that:

MCP23017 chip has a construction error, which makes it unsafe to use the last 2 ports for inputs!
(maybe it was 7. + 15. ports ? ) please check the new upgraded manual for the chip!

1 Like

Thanks to the patience and many fruitful discussions this past year with @PizzaProgram I have been able to significantly enhance and streamline his code. What set me on this path is:

  • I have a relay board with two MCP23008 chips that I needed to drive. Most if not all nodes that I found for this chip use a compiled library to set up and communicate with the chip itself. Although this works it theory, I found many to no longer work, or compiled on a 32 bit operating system. Without access to the source code it is impossible to change anything.

  • This code uses a config node, which makes it easily accessible and as such an integrated part of NR. Whereas the compiled libraries were all setup to poll inputs, the config node allowed for polling only, interrupts only, or a combination of both.

  • By directly selecting the chip type I was able to expand the node to use MCP23008, MCP23017, PCF8574(A) and PCF8575 i2c port expanders. Further details on the many changes and enhancements can be found in the change log section of the README.md file.

I have now published the node to npm. It does not show up in the palette manager yet, but in the mean time can be found here. The node has been extensively tested on all chip types using polling and/or interrupts. Interrupts are rock solid - tested on each chip type with a combination of input and output pins on a chip.

Finally I'd like to thank all on this forum who helped me along the way, without whom I would have still been fumbling in the dark. It's been quite the learning experience!

3 Likes
  • Read values by regularly polling them.
  • Read values when an interrupt occurs. Interrupts will occur when an input value changes from its previous value.
  • Read values using a combination of both polling and interrupts.

To me at least the middle option seems to be the obvious choice, what is the use case for the other two please ?

I agree and I like using interrupts only as well. Depending on the use case (and I certainly don't profess awareness of all use cases) polling might be preferable, e.g. saves you having to run an extra wire to a GPIO port. Or all GPIO ports may already be in use, or you want to make absolutely sure an input change was indeed captured, or....

Also, when using interrupts you cannot software debounce a switch/relay contact. This does not seem to be an issue and if it is you can add a trigger node to the output of the mcp pcf in node connected to the pin the switch is connected to.

The key is the user has the option to choose the best scenario for their situation.

2 Likes

^ totally agree with @Joe-AB1DO

Also it is wise to use a timer with "long period" (for example every 1000ms) as safety next to interrupt, so if anything is wrong with:

  • the interrupt system
  • the wiring (no dampener resistors present)
  • sparking, lightning, etc.

There is still a "delayed correction" to read the final state of the pin.

1 Like

GPA7 and GPB7 are for output only

https://www.microchip.com/mymicrochip/filehandler.aspx?documentid=390b641b-9f77-4421-80f7-7b13266491de

Well that was Microchip's way of dealing with the issue that was raised by a customer of theirs, but it turns out that the specific issue occurred in pretty rare situations only. See the discussion on their forum for the details. Anyway, Microchip's response was to modify the specsheet (rev D) by adding a note to that effect on page 18. Earlier versions of the specsheet do not have this note.

However, that being said, it turns out that in most cases GPA7 and GPB7 can actually be used successfully as inputs without issue. Either way, the node's chip configuration panel defaults to not allowing these ports as inputs to comply with the specsheet, but at the same time gives the user the option to override this restriction. So again, it is up to you. A quick search shows that over the years the ports have been used successfully as inputs without fail.

Good day, fellow members. I am seeking assistance with a particular node testing scenario. It appears that I can only activate one output at a time for the node. If I activate another output, the previous one turns off. I am using the MCP23017. Is this behavior intended as a feature, or could it be a potential bug?

It is certainly not intended and in all my testing of this node I have never come across that kind of behavior. Can you describe in some more detail how you have set everything up? Specifically:

  • What hardware are you running the node on, version of nodejs, version of node-red, version of npm, etc.

  • Ideally send a json export of your flow. I still have my test bench set up here, so could import and double check. FYI, I am using a Raspberry Pi.

  • Otherwise images of the flow, the configuration panels of the output nodes as well as the configuration panel of the chip. Are you polling or using interrupts?

I'm running the node on a Banana Pi M64 with the following system specifications:

  • Operating System: Ubuntu 22.04.3 LTS
  • Kernel Version: 4.4.89
  • Node.js Version: v20.6.1
  • npm Version: 10.1.0
  • Node-RED Version: 3.1.0

Regarding the node, I can confirm that the "node-red-contrib-mcp23017chip" from WillHey is working perfectly for my setup. If you have any further questions or need more details, please feel free to ask.

[
    {
        "id": "8be4f97c44d81f4c",
        "type": "tab",
        "label": "test",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "4b2f28abdf25c766",
        "type": "mcp pcf chip",
        "chipType": "MCP23017",
        "busNum": "1",
        "addr": "0X20",
        "mcpInputOverride": true,
        "interval": "100",
        "startAllHIGH": false
    },
    {
        "id": "ffc5d87038a814b5",
        "type": "mcp pcf out",
        "z": "8be4f97c44d81f4c",
        "name": "relay_00",
        "chip": "4b2f28abdf25c766",
        "bitNum": "0",
        "invert": false,
        "legacy": false,
        "x": 440,
        "y": 80,
        "wires": []
    },
    {
        "id": "2aafa068b494d3e8",
        "type": "mcp pcf out",
        "z": "8be4f97c44d81f4c",
        "name": "relay_01",
        "chip": "4b2f28abdf25c766",
        "bitNum": "1",
        "invert": false,
        "legacy": false,
        "x": 440,
        "y": 120,
        "wires": []
    },
    {
        "id": "896f2b37003e192e",
        "type": "inject",
        "z": "8be4f97c44d81f4c",
        "name": "on_relay_00",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 150,
        "y": 80,
        "wires": [
            [
                "77f0a5fe2e7e547e"
            ]
        ]
    },
    {
        "id": "f5f152ce9b21d8f1",
        "type": "inject",
        "z": "8be4f97c44d81f4c",
        "name": "off_relay_00",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "false",
        "payloadType": "bool",
        "x": 150,
        "y": 120,
        "wires": [
            [
                "68a8b15105aed91e"
            ]
        ]
    },
    {
        "id": "68a545d60ab4f464",
        "type": "inject",
        "z": "8be4f97c44d81f4c",
        "name": "on_relay_01",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 150,
        "y": 180,
        "wires": [
            [
                "f79d083d88911e7d"
            ]
        ]
    },
    {
        "id": "0d39391d1c479958",
        "type": "inject",
        "z": "8be4f97c44d81f4c",
        "name": "off_relay_01",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "false",
        "payloadType": "bool",
        "x": 150,
        "y": 220,
        "wires": [
            [
                "44b01d0b0392d001"
            ]
        ]
    },
    {
        "id": "77f0a5fe2e7e547e",
        "type": "link out",
        "z": "8be4f97c44d81f4c",
        "name": "relay_00",
        "mode": "link",
        "links": [
            "9068ab90c322961f"
        ],
        "x": 255,
        "y": 80,
        "wires": []
    },
    {
        "id": "9068ab90c322961f",
        "type": "link in",
        "z": "8be4f97c44d81f4c",
        "name": "relay_01",
        "links": [
            "68a8b15105aed91e",
            "77f0a5fe2e7e547e"
        ],
        "x": 345,
        "y": 80,
        "wires": [
            [
                "ffc5d87038a814b5"
            ]
        ]
    },
    {
        "id": "68a8b15105aed91e",
        "type": "link out",
        "z": "8be4f97c44d81f4c",
        "name": "relay_00",
        "mode": "link",
        "links": [
            "9068ab90c322961f"
        ],
        "x": 255,
        "y": 120,
        "wires": []
    },
    {
        "id": "f79d083d88911e7d",
        "type": "link out",
        "z": "8be4f97c44d81f4c",
        "name": "relay_01",
        "mode": "link",
        "links": [
            "01bea90b9fa4d014"
        ],
        "x": 255,
        "y": 180,
        "wires": []
    },
    {
        "id": "01bea90b9fa4d014",
        "type": "link in",
        "z": "8be4f97c44d81f4c",
        "name": "relay_01",
        "links": [
            "f79d083d88911e7d",
            "44b01d0b0392d001"
        ],
        "x": 345,
        "y": 120,
        "wires": [
            [
                "2aafa068b494d3e8"
            ]
        ]
    },
    {
        "id": "44b01d0b0392d001",
        "type": "link out",
        "z": "8be4f97c44d81f4c",
        "name": "relay_01",
        "mode": "link",
        "links": [
            "01bea90b9fa4d014"
        ],
        "x": 255,
        "y": 220,
        "wires": []
    }
]

I imported your flow (thanks for sending) and it works as intended. My MCP23017 is on i2c-3, so all I did was change the bus number and it works perfectly:

If I click on on_relay_00 inject node and then on on_relay_01 inject node, both relay_00 and relay_01 output nodes are on, as indicated by the status indicator:

So you are saying if you first turn relay_00 on, then relay_01, relay_00 turns off? If so, that's not what I'm seeing here. As mentioned, I am running RPi 4B:

  • OS: raspios Bullseye 64-bit
  • Node.js version: v18.17.1
  • npm version: v9.6.7
  • node-RED Version: 3.1.0

So other than the actual hardware and linux version, not too different. One other thing you could try:

  • Open a terminal, go to the directory where you have node-red installed (usually ~/.node-red) and enter node-red-restart to restart the server. Then refresh the browser window.
  • In the same node-red directory enter node-red-log : this is where the nodes output a detailed log. Starting with both output nodes off, when you click on the 2 inject nodes to turn the two output nodes on you should see something like this:

This shows that the two LSBs of ip16 (pins 0 and 1) go from 00 to 01 to 11. Do you see anything different? If so, what?

BTW, in the terminal enter ^c to exit the log.

One more thing: you mentioned you were using "node-red-contrib-mcp23017chip" from WillHey
before. Did you first remove that node (including the config node), node-red-restart and refresh the browser before installing @joe-ab1do/mcp_pcf_aio? If not, they might be interfering with each other. Just a thought...

If everything is working, can you please let me know and what you changed?

Just published an updated version 3.1.2. See change log in ReadMe file for details.

If you experience an problem, please open an issue on github.

2 Likes

Updated to version 3.2.0, which expands functionality of msg.topic="any" by allowing msg.pin to equal either a number identifying which port to set, or an array of numbers to set several ports simultaneously.

Includes updated help files and ReadMe file describing this increased functionality.

See change log in ReadMe file for more details.

1 Like