Node-red-contrib-mcp23017chip

Thanks for the info!

I have also seen, you have this:

I also have some of those chips too.
I guess, many of us, trying to put together a smarthome system with many IO ports buy those boards together with this one.

I think it would be a good idea to put both together in a Mega-pack library, so they can work on the same i2c BUS.

  • Also easy to add a Bus-scanner to help find available buses and device addresses.
  • And a name-reader to identify the devices.
  • Plus, as a bonus, a chip-processor node, that can accept Bus/address/etc via Msg, and process those asyncronouosly. So we won't need to place 16 nodes for each chip.

Finally:

  • Interrupt support (if possible)
  • better help / descriptions
  • some examples bounded to the installation

You'll see, there are many things I've already fixed.

... but first the error-handling is the most important thing to start with.

You can download the current release 1.3 from here...

Mike, most of us here are not programmers, and we all, like you, do the best we can with the knowledge that we have, so don't let a few unwitting comments dishearten you.

If others think that they can improve your code, it's a great learning experience to get a PR, and see why and what changes have been suggested. :+1:

2 Likes

Yes - I second that - I am constant amazed at the new and interesting ways people manage to break what I think is perfectly functional code :slight_smile: and while moaning doesn't inspire me to fix things more rapidly - any good pull request always does.

1 Like

< OFF >

I have to say:

SORRY !

I didn't wanted to write a post toooo long, left this part out of it and because of that, a big misunderstanding occurred:

  • I wasn't talking about you. If I've red the prev. topic well, there was someone before you, who wrote the original code. You just took that old code from him and fixed it so it can be installed. Right?
  • I'm VERY VERY thankful, that you have posted this node! :smiling_face_with_three_hearts:

Without your help it would have been impossible for me to do it myself all alone, building up full from bottom. Enhancing something is much easier :wink:

Great Job! :+1:

2 Likes

While we are talking about this node and have the author pop up here, I would like to use the opportunity to encourage the movement of putting the code on GitHub.
I'm using this node to monitor all my doors and windows in the house and found two areas for improvement:

  1. there is no input so I can't force to read the value - so there is no way to refresh the data - I need to open/close all my windows to have the current status if NR for some reason loose that info (like when deploying new changes)
  2. it only supports polling so there is huge amount of traffic between RPi and MCP23017 over and over - and the chip allow to use interrupt - I have working Python script just waiting for the interrupt - if no windows is opened, there is no unnecessary traffic on i2c line

So having the code officially available on github will make community fixes and changes easier.
Anyway, thanks for the great work so far!
Cheers

I still not fully understand this. Where can I find more help/info about it?

Here are the docs for npm versions About semantic versioning | npm Docs

1 Like

I've just learned I can combine version number and date:
1.3.0+20201228

Feel free to do so and add us to the project.

We did not made any GitHub projects so far.
But currently I'm still not fully convinced it would be safe to install a program that has full access to my hdd and can upload files to the cloud.

What program are you referring to?

Also I've realized this code is not safe yet to publish officially.
So changing the version number to 1.3 was not a good idea.
Should be 0.3.0.

That's interesting, because theoretically it SHOULD read it too, not just pushing outputs. But I could not test it yet.

I do not know enough about this chip programming itself to understand how interrupt could be used. It seems to be a risky thing, because it can happen, that you reset the interrupt, and while you are reading the values, a new data comes in...
So you'll miss the new change this way. (Concurrent race condition/ semaphoring problem...)

an other problem:

Currently, if I turn on 1 relay at the first time after attaching the board, ALL the other relays turn ON. That very very bad this way.

I think it has to do with lack of proper initialization.

  1. it should read current state of all pins first,
  2. store pins in the array
  3. set to output
  4. execute pin change.

OR

maybe just the implementation of inverse / pullup is bad ?

I'll have to dig into the code more deeply, but it's already showing this work will be 5x more difficult and time consuming, than I've hoped.

Well, that risk is actually when polling. If you read input every 500ms, then any state change shorter than that will be missed so I would say interrupt surpasses polling that even super short change will be noticed. And when int is rised, the copy of inputs is stored aside so you can read value at the moment of the interrupt (with exact info which input caused int) and also you could read current value if you wish, so no data is lost.

Dear @Marooned,
I understand what you are saying, no need to re-explain.
But I'm afraid you are not.

  • Are you aware of terms like race condition, atomic operation, etc. ?
    Please read this...
    especially Page 25.
    "The value in INTCAP can be lost if GPIOis read before INTCAP while another IOCis pending."

That means, it can happen, that if 2 buttons are "pushed" (input change) within a few millisec, you may not get notification of the 2th. EVER.

I've just tested speed, and it turned out:

  • To read all 8+8 values from bank A+B takes avg. 8 millisec from a Raspberry Pi 4!

So it's not a question of "if ..." but "when it happens".


But you gave me 2 ideas:

  1. I could combine the two methods!
    After an interrupt-read, some time later, (like 20ms) a 2th read should be runned and compared to the last read.
  2. I should measure the elapsed time of readout, and if it's too long compared to the interval-period the user has set, the period should be auto-incremented. (min. 1.5x-2.0x of minimum-time.)

The first idea can be accomplished only, if I figure out, how NodeRed can "listen" for interrupts on I2C bus.

1 Like

The code has always been on GitHub. But no link from NPM, as I am not sure how to add the link

I will happily accept any Pull Requests

Other random thoughts

  1. Whilst I have 9 of these chips connected to 5 different PIs. All my new projects involve Shellies (MQTT) , as it is quicker and easier to get working.
  2. I accept the polling is intensive but not sure of any downside (even with many other chips on the same bus)
  3. The initialisation is an issue, so on my heatpump controller (starting and stopping many pumps) I have an Arduinio watchdog that checks a hardwired heartbeat and enables the outputs with a 5v signal to relay & SSR boards. For PIs controlling lights, the family have got used to much flashing of LED lights
  4. Again I agree that short pulses will inevitably be missed, but have no real life issues with it
  5. The inverse is just setting a register on the chip - I agree it is not intuitive but does accurately reflect the chip functionality
  6. I don't disagree at all with the changes suggested
3 Likes

I've sent you a PR to add the repo url to the npm description - Add repo url to package by Paul-Reed · Pull Request #9 · willhey/mcp23017chip · GitHub

2 Likes

Well, I'm almost finished...

Change log:

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

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

  • 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 16pin array initialization (16x null)

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

  • Added lots of comments and constants to mcp23017chip.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.

  • 4 states of a node: On=green Off=grey Uninitialised=yellow Error=red

Error:

Still having problem how to push error messages from a non-visible node.

 [red] Uncaught Exception:
3 Jan 19:33:29 - TypeError: node.done is not a function

Handling errors help page did not help.

module.exports = function(RED) { ...

function myTimer(theChip) { ...
var node = this; 
try {
...
}
catch (err) {
	err.discription = _processState + " failed.";
	err.busNumber   = this.busNum;
...
	console.error(err);
	node.done(err);  // also tried without node.  ... just: done(err);
	return false;
};

is myTimer the main class of your node?

Are you using an IDE that you can step debug?

If so, put a stop on the line (or enable break on exception) and inspect the value of node it should look like this...

VSCode debugger

Isn't that the usual way relay boards work? Using the active pulldown on the output to drive an opto-isolator.

I'm using cheap relay boards, normally the 5V is active and waiting for GND to pull=close=turn on.
I have already resistors between all ports, but still, when NR started >> ALL relays turned on!
(That would kill all my 8 roller-shutter tube engines if I would attach them in this state.)

The built-in pullups are useless for outputs. See chip PDF:

  • 3.5.7 PULL-UP RESISTOR CONFIGURATION REGISTER
    The GPPU register controls the pull-up resistors for the port pins. If a bit is set and the corresponding pin is configured as an input, the corresponding port pin is internally pulled up with a 100 kQ resistor.

Also, I had exactly the same problem with "node-red-contrib-gpio" / Firmata using Arduino Nano boards.
That's why I've started to modify this node and realised how many other errors are present in the code.