3.2.1 • Public • Published


Node-RED nodes to configure and control MCP23008, MCP23017, PCF8574(A) and PCF8575 i2c port expanders.


To install use the Menu - Manage palette - Install option and search for @joe-ab1do/mcp-pcf-aio, or run the following command in your Node-RED user directory, typically ~/.node-red

npm i @joe-ab1do/mcp-pcf-aio


Provides two nodes, one to use a pin as an input and one to use a pin as an output. Also includes a configuration node to setup the i2c port expander chip. Pins already in use by one of the nodes cannot be reselected in another node. A node will show 4 states: On=green, Off=gray, Uninitialized=yellow, Error=red.

Requires i2c-bus module. Should get automatically installed.

Input: mcp pcf in

Defines a chip’s pin as an input port and reads its value. mcp pcf in needs to be associated with a configured port expander chip. Select a pre-configured chip or configure a new chip by clicking on the pencil icon. Outputs msg.payload=true/false, depending on the input value.

  • 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.

Output: mcp pcf out

Defines a chip’s pin as an output port and sets its value. mcp pcf out needs to be associated with a configured port expander chip. Select a pre-configured chip or configure a new chip by clicking on the pencil icon. Either use:

  • A single output node to set all non-input pins to 1/0 using msg.payload=true/false and msg.topic="all". Works best if all pins on a chip are output ports.
  • An output node to control one or more different output pins using msg.payload=true/false, msg.topic="any" and msg.pin=pin# or pin# array. As an example if a mcp pcf out node connected to pin 1 receives a msg with msg.payload=true, msg.topic="any", msg.pin=7 then pin 7 will be set to 1. If msg.pin=[0,2,3,7], then pins 0, 2, 3 and 7 will be set to 1.
  • An output node to control the output port of the pin it is connected to using msg.payload=true/false (msg.topicis ignored if not equal to "all" or "any").


This example shows the use of a mcp pcf out to set the output of another pin on the same chip. The debug node shows the message object sent to pin6 of a MCP23008 to switch the output pin3 of that same chip.

In this second, more elaborate example a mcp pcf out node is set to pin6 of a MCP23008 (i2c-1 @ 0x20) to drive a relay connected to pin6 (via a relay driver) that, when activated, switches pin 15 of a MCP23017 (i2c-3 @ 0X20) from 1 to 0. The change of pin15 of the MCP23017 results in an interrupt occurring (active when 0). The MCP23017's interrupt pin is connected to one of the Raspberry Pi's GPIO ports with pull-up resistor activated. The output of this GPIO-in node (node IRQ MCP23017) is wired to a mcp pcf in node set to pin 15 of the MCP23017. The output of this mcp pcf in node is wired to 2 mcp pcf out nodes: one set to pin10 of the same MCP23017 chip and one set to pin1 of a PCF8574 chip (i2c-3 @ 0X21). The image shows the state with the relay activated. The debug nodes show interrupt going to 0, a msg.payload=true being sent and interrupt reset to 1



I am idebted to László Szakmári who expanded Mike Wilson's original code and wrote the first few versions of mcp-pcf-aio. Thanks to our many fruitful discussions I was able to greatly expand and streamline his code. Thanks to Mike Wilson for the original v0.1 node: MCP23017chip

Change Logs

Change Log 2023-10-31 (YMD) Version: 3.2.1

by Joe de Groot (ab1do@optonline.net)

  • Removed obsolete input field to the right of i2c bus search button on mcp pcf chip config panel
  • Corrected release date of version 3.2.0

Change Log 2023-10-22 (YMD) Version: 3.2.0

by Joe de Groot (ab1do@optonline.net)

  • Expanded functionality of msg.topic="any": msg.pin can now also be equal to an array of pins, e.g. msg.pin=[0,2,5,7]. Backwards compatibility is ensured by allowing msg.pin to equal a single number instead of requiring a 1 element array.
  • Updated output node help file accordingly

Change Log 2023-10-03 (YMD) Version: 3.1.2

by Joe de Groot (ab1do@optonline.net)

  • Bugfix: when editing a chip, chip address no longer jumps to first unused address on bus, but instead remains as is until a new address is selected
  • Cleaned up and streamlined code even more
  • After extensive testing removed all code relating to checking if i2c read/write is in progress (was commented out)
  • Added MCP23017 example flow

Change Log 2023-09-06 (Y-M-D) Version: 3.0

by Joe de Groot (ab1do@optonline.net)

  • Removed i2c address doubling mechanism to distinguish between chips: chip types are now directly selected.
  • Expanded chip types to also include MCP23008 and PCF8575.
  • I2C bus number can either be entered directly or available buses can be searched and selected.
  • I2C addresses in use by a node cannot be reselected. Selected address also displays which of the chip's address pins should be high/low.
  • I2C address selection list complies with selected chip type.
  • PCF chip configuration defaults to start all high to comply with datasheet: “The I/Os should be high before being used as inputs”; MCP chips do not have this restriction and default to start all low.
  • PCF chips output node's All High/All Low no longer affects input nodes
  • PCF chips initialization when using only interrupts now does a one time read at the end of initialization to set the input nodes according to their actual input values.
  • Per the latest datasheet (rev D), MCP chips cannot use pin 7 (pins 7 & 15) as inputs. This is now reflected in the input node setup. This limitation can be overridden by the user, as issues only seem to occur in very rare, exceptional cases. See the Microchip Forum for more details on this issue.
  • An input or output node can only be connected to an unused pin of the associated chip – used pins cannot be reselected.
  • Interrupts for MCP chips have been changed to occur when input value changes from previous value, similar to PCF chips.
  • Interrupts for MCP chips are set to open drain (ODR), active when 0 (similar to PCF chips). Connect to a GPIO port and use its internal pull-up resistor or use an external pull-up resistor.
  • Added Diagnostics option to input node: if unchecked (default) only sends msg.payload reflecting the state of the chip's input port; if checked sends second message with read diagnostics;
  • An output node's invert setting has now been incorporated for control of a different pin: if the output node being controlled is not present on the configuration pane, then the invert setting of the node receiving the message determines whether the value of the pin being controlled is inverted or not; if the output node being controlled is present, then its invert setting determines whether the pin value is inverted or not.
  • An output node's message structure now uses msg.topic to distinguish between the various chip-wide control modes and pin-control mode.
  • Output node's configuration screen includes a legacy option, that when checked reverts to the previous message structure using msg.payload=true(false)/all1/all0/-1.
  • All help screens as well as this README file have been extensively edited.
  • Configuration screens now include relevant tips/notes.
  • Changed various icons, including the node icons.
  • If name is left blank, node label now includes chip type, i2c bus number and i2c address as well as pin it is connected to.
  • mcp pcf in and mcp pcf out nodes now bundled together in the palette under the category gpio expansion
  • Removed (commented out) code relating to checking if i2c read/write is in progress, including the creation of the related global context variable; i2c controllers already manage this process. Besides, other nodes that use the same i2c bus have no awareness of such a global context variable.

Change Log 2022-09-08 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • Changed Interrupt initialization of the MCP chips again: (EXPERIMENTAL! Testing needed.)
    IOC=1 << If any of A or B input IO-bank pin changed, both INTA and INTB is triggered

Change Log 2022-09-07 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • Changed Interrupt initialization of the MCP chips: (EXPERIMENTAL! Testing needed.)
    MIRROR=1 << If any of A or B input IO-bank pin changed, both INTA and INTB is triggered
    ODR=1 << Not only "Active-Low" state, but both "High/Low" input changes are triggered

Change Log 2022-06-07 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • WARNING! Naming of commands and msg values changed !!! (No more Capital beginnings.) "All0" -> "all0" "All1" -> "all1" msg.AllStatesRaw -> msg.allStatesRaw ... also fixed name convention at source code, like OnOFF -> on_off Read more here

  • If read-interval is set to 0 it will clear any running timer.

Change Log 2022-06-06 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • BUG Fix: Too long read time caused a (.warning) error instead of increasing the timer interval x2.

  • Enh.: If the last read time is shorter than interval, it resumes the timer at original interval.

Change Log 2022-03-26 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • PCF chips show now correct Address -at Main-Chip setup. Fixed.

  • Fixed "interval too short" auto-increase happaning if "interrupt-triggered" read occures

  • Added examples

Change Log 2022-03-25 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • Changed msg.pin and msg.state to lower case.

Change Log 2022-03-22 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • you can set 1-1 node only pro 0-7 or 8-15 and control via msg.Pin= and msg.State= if msg.Payload=-1

  • fixed consol.warning bug if Timer set = 0ms.

Change Log 2022-03-21 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • Fixed bug: on input change payload was always "true".

Change Log 2022-03-19 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)


  • Enhanced html help of the node

  • fixed bugs (like: partial Deploy did not clear prev. instances from context)

Change Log 2022-03-03 (Y-M-D) Version:

by László Szakmári (www.pizzaprogram.hu)

  • Added PCF8574 + PCF8574A chip support. Both In + Out.

  • Fixed Naming of PFC... to PCF... (the original code was spelled wrong).

  • Detailed Logging to consol can be turned on/off with const log2consol = False; and timerLog = false;

  • Fixed Input Bugs. Now stable.

  • Fixed bug if same chip had both in+out pins mixed.

  • Fixed crashing of Node-red if chip or I2C bus was suddenly removed from system.

  • Inject (Interrupt) trigger adds extra values to msg. [] ... see help

  • New Github upload. (PFC false-named one got deleted)

Change Log 2021-01-11 (Y-M-D)

by László Szakmári (www.pizzaprogram.hu)

  • !!! IMPORTANT CHANGE: -- [ x ] Inverse is now affecting Output too ! (Some relay boards are functioning "the opposite way", turning ON if pin is Low.)

  • Changed Bus open/close behaviour. Separate open before/after each read/write operation block. (This way no more non-stop opened bus > no more NodeRed crash if unexpected disconnect.)

  • Fixed other NR crashes: Added Error handling (try - catch) for each i2c bus operation. Each operation has it's own value to report proper error text. (Like: "Bus opening failed", ... etc) (But execution time increased from 8ms to 12ms on Raspberri 4)

  • Fixed 16pin array initialization (16x null)

  • Added multiple/same pin initialization error handling. (Highlander: "There Can Be Only One" :-D )

  • Added lots of comments and constants to JS file (like IOCON, IODIR_A, etc...)

  • Changed icon to a chip-like one. (font-awesome/fa-ticket)

  • Faster initialisation: if set to output >> skips pullup & invert writes.

  • Prevents the input-timer to run if the previous function is still running.

  • +2 states of a node and color change of Off: On=green Off=grey Uninitialised=yellow Error=red

  • Does not starting input-timer, if there are no input nodes available.

  • Auto-increasing read-interval if < 15ms or if reading took too long.

  • If error occured during read-timer >> changing interval to 5 sec >> if normal again >> changing back

  • Dokument + Code changes: -- Pretty print of JS code (inline) -- All local variables start now with _underline -- Many comments + constants + references added to code -- Fixed help in mcp_pcf_chip.html file

Change Log 2021-09-12 (Y-M-D)

  • Fixed input

  • Add input trigger to handle interrupts. If msg.payload = True >> and succesfully read

    msg.immediateReadSuccess = true. If any error:Result = false

  • Limit debounce timeing to max = interval - 20ms

  • debounce is not starting if =0

Change Log 2021-11-11 (Y-M-D)

  • Node name changed from MCP23017chip to current ,mcp_pfc_aio v2.1.0 ( AIO = All in One IO = Input Output )

Package Sidebar


npm i @joe-ab1do/mcp-pcf-aio

Weekly Downloads






Unpacked Size

320 kB

Total Files


Last publish


  • joe-ab1do