New MCP23017 PCF8574 All-In-One node

After 14 month of work in my free (and work) time here I present my first AIO solution to handle 3 similar kind of Input-Output I2C chips with Node-Red:

I'm still searching a way to publish it to NPM.
(Do not know yet, how to "log in" to my NPM account on Rpi terminal to publish...)

Please tell your opinion, and report any errors you may find.

The main differences to the original 0.1 version:

  1. It supports INTERRUPTS
  2. read can be triggered -> you get a full JSON of all pins and read success
  3. Node-Red does not crash if any errors happening
  4. You can use multiple I2C buses!

kép

4 Likes

Successfully published:
(took me 50 minutes to figure out)

$ npm login
User: ****
Password: ***
$ cd
$ npm publish --access public

3 Likes

Added publishing quick example to docs:

1 Like

Help needed:

I've just noticed a very strange thing:

  • if I set an MCP23017 node to a bit between [0-7]
  • only the first 8 = [0-7] is turned on/off at the "All0" and "All1" command

But:

  • if I set an MCP23017 node to a bit between [8-15]
  • ALL is turning on/off just fine

Theoretically the code is not influenced by Bit number:

_aBus.writeByteSync(_addr, BNK1_OLAT_A, OnOff & 0xFF);	//Set output A
_aBus.writeByteSync(_addr, BNK1_OLAT_B, OnOff & 0xFF);	//Set output B

What is your oppinion?

I'd like to implement into this component a "direct-payload-control" method.
msg.payload would be a special character, like "d"
msg.Pin = 0-15
msg.State = true/false

This way you don't need to place 8-16 of mcp-pcf-Out nodes in your flow one by one, it's enough to set 1 or 2.

What should be the payload "letter" in this case? ("All0" and "All1" is for setting ALL.)

  • "Direct"
  • "D"
  • "d"
  • "A" or "B" depending on 0-7 or 8-15 (easiest to program!)
  • "Set"
  • -1
  • ... something else

0 voters

It is possible the A or B side needs to be pre-initialized at MCP23017, so accepting all (0-15) is not possible at one node only, if there is no other node in the upper / lower range!

Updated NPM.

New feature:

direct msg control for Out Node is finished.

Nobody voted. Choosed : msg.payload = -1

Example:

[
    {
        "id": "cdb554694af63c0b",
        "type": "inject",
        "z": "04823d5afca6d208",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 550,
        "y": 160,
        "wires": [
            [
                "c97d62672d3eb61e"
            ]
        ]
    },
    {
        "id": "83cfcef10524acd0",
        "type": "inject",
        "z": "04823d5afca6d208",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "false",
        "payloadType": "bool",
        "x": 550,
        "y": 200,
        "wires": [
            [
                "c97d62672d3eb61e"
            ]
        ]
    },
    {
        "id": "b29818dfe5fa6d8c",
        "type": "inject",
        "z": "04823d5afca6d208",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "All0",
        "payloadType": "str",
        "x": 550,
        "y": 60,
        "wires": [
            [
                "c97d62672d3eb61e"
            ]
        ]
    },
    {
        "id": "489cc4c35bb3839b",
        "type": "inject",
        "z": "04823d5afca6d208",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "All1",
        "payloadType": "str",
        "x": 550,
        "y": 100,
        "wires": [
            [
                "c97d62672d3eb61e"
            ]
        ]
    },
    {
        "id": "c97d62672d3eb61e",
        "type": "MCP PCF Out",
        "z": "04823d5afca6d208",
        "name": "MCP-23-5",
        "chip": "ad16f0140a10887d",
        "bitNum": "1",
        "invert": true,
        "x": 760,
        "y": 180,
        "wires": []
    },
    {
        "id": "997bc22c57525541",
        "type": "inject",
        "z": "04823d5afca6d208",
        "name": "Set-2-On",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "Pin",
                "v": "2",
                "vt": "num"
            },
            {
                "p": "State",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "-1",
        "payloadType": "str",
        "x": 500,
        "y": 260,
        "wires": [
            [
                "c97d62672d3eb61e"
            ]
        ]
    },
    {
        "id": "437dc37a9faf8f09",
        "type": "inject",
        "z": "04823d5afca6d208",
        "name": "Set-2-Off",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "Pin",
                "v": "2",
                "vt": "num"
            },
            {
                "p": "State",
                "v": "false",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "-1",
        "payloadType": "str",
        "x": 500,
        "y": 300,
        "wires": [
            [
                "c97d62672d3eb61e"
            ]
        ]
    },
    {
        "id": "ad16f0140a10887d",
        "type": "mcp_pcf_chip",
        "busNum": "22",
        "addr": "0x23",
        "interval": "0",
        "startAllHIGH": true
    }
]

Hi @PizzaProgram I don't use these but after a quick read through I would offer these suggestions...

  1. Don't use Sentence case names (stick with lowercase and camelCase)
  2. Instead of msg.Pin and msg.State, why not consider using topic and payload e.g. ...
    • topic: 1 payload: true = turn pin 1 on
    • topic: all, payload: true = turn all pins on
    • topic: 6 payload: false = turn pin 6 off
    • topic: "1,3,5" payload: true = turn pins 1, 3 & 5 on
    • topic: "set" payload: 0b10000001 = turn pins 7 & 0 on, 6 ~ 1 off

Better still, use typedInput widgets to let the user decide where the pin and value come from. (Saves user having to use change nodes to shift values around in the msg)

Just some thoughts off the top of my head. If I'm way off or misunderstanding something, my apologies.

Hi,

  1. OK, changing to pin + state lowercase now.
  • This is not how this node concept is working. Each pin has to be / can be set differently. Payload is used normally for normal control of 1 pin. (Boolean). Backward compatible.

  • state + pin is a SPECIAL case I've added, an extra feature to make it work similar to your 'topic' ider. So it has to be different.

  • I don't like to use topic. It is usually used for different things at a house control. The direct pin number of a relay is never == of the topic.

  • 1,3,5 >> too complicated, would mess up the current code, would exclude error control.

  • 0b110100 >> good idea, let me think about it, how to implement.
    How about if (msg.payload = "b") msg.binary ...
    But it's lot of work.

    And if you are controlling Relays, it's NEVER a good idea to switch multiple at the same time. Too high Voltage needed, 16x stronger sparkles, failing. Leaving 20ms between 1-1 relay switch is better!

I have no idea, what that is. Link please!

Sure you do (but you possibly just dont know the name :stuck_out_tongue: )

image
docs/api/ui/typedInput/

It permits a user to specify where the interesting value comes from (meaning they dont have to use a change node to set msg.pin for example)


You could easily add a checkbox called "lagacy mode" (set by default) then when it is unticked, use whatever msg inputs you wish - that make more sense. I.e. dont let compatibility force you to write something awkward to use - just work around it :slight_smile:

Again, if you have 2 modes (i.e. " legacy mode") this is not necessary & would permit you to use topic & payload


What is to stop someone putting 16 OUT nodes in parallel?
at least if you offer the ability to set 16 via one OUT node, you can internally control this.




Another suggestion (if you dont mind?)
IMO, the output node would have an output port to permit chaining. When wires are branched, under the hood, node-red clones the msg. 16 parallel outputs would make 16 clones. Also, it would be a reasonable feature to NOT send the msg through if the operation failed. e.g. consider these 2 flows...
inject 👉 set pin 1 👉 set pin 2 👉 reset pin 3 👉 send a success email
catch node watching for errors in "set pin 1", "set pin 2" & "reset pin 3" nodes 👉 send a FAIL email

Again, this "output port" can be optional if need be.

For control relay, maybe something simple (only msg.payload) as:

Single output contol:

A10

where:

  • A is corresponding to the 1st 8 outputs (1-8);or B for 2nd 8 outputs (9-16) of chip

  • 1 is first port in A or B;or 2-8 for others outputs

  • 0 is output state;or 1 for opposite state

All outputs control:

AA0

where:

  • A is 1st eight ports;or B for 2nd eight ports
  • A is all ports in A or B;no other option
  • 0 is output state, or 1 for opposite state

All the help, readme, changelog, default setup is using and mentioning: 0-7 + 8-15.
Using 1-16 would be VERY confusing.

You can make a script-node that converts/splits your desired A/B 1-16 coding to msg.pin=0-15 easily.

First I had the same idea!
So I did it.
Realised how much extra work would it be, so I've disabled it.
A [Catch] node can handle this "error-safe" method.
Not so easily, as your pin1 > pin2 > email thing, but still possible.

Maybe next year I start over and do that, but currently I'm happy it's working after 14 month. Still need to plug in all the wires, order some more chips, etc. to make my house work again after 2 years of "dark ages".

1 Like

That is a GREAT idea!

But I need help to do that.

  1. Last time I've changed something at the HTML code it took me TWO WEEKS to find the error, the whole node-red did not start.

  2. I've looked into the examples, but did not find any multi-complex case similar to mine.
    TypedInput Widget : Node-RED

msg.payload can be:
true/false Bool
or
"All0", "All1" as string selectable
or
-1 as number

if payload= -1
msg.pin
msg.state
should appear, otherwise hidden.

If I get a chance tomorrow I'll post something for you. In the mean time, look at nodes like buffer-parser, Cron+ and even the http-response node. They have working examples.

1 Like

Help needed:

  • How do I publish a bundled example to this project?
  • I've saved the flow.json file I've made
  • created a "./examples" subdir and copied inside there

Now what's next? How do I make a NR example from it, that would be auto-installed when someone is installing from palette manager ?

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.

There is a new version of this node, check the Readme . :wink:
Open an issue at Github, if you find any problem. (See top link #1 )

Haha, yes not terribly obvious.

Well, now go turn on 2FA to prevent account takeover, do the same on GitHub as well.

hmm... I've always endeavored to apply Redicks VB Naming Conventions and Coding Conventions and applied them to any other language I learn where appropriate. (I even apply it to database objects, tblSales, viewMonthlySales, procPublishSales, rptRegionalSales, etc.. However, I don't do the same for column names in tables/views, but that's more or less to try to maintain compatability with allot of stuff that's out in the wild
.)
An example of a variable for a last name might look like this strLastName . He recommends prefacing the variable name with it's type and then continuing on with TitleCase for the rest of the name.

To each his own.