After upgrade failed to install node-red-contrib-mcp23017chip

Hi there

I have RPi B rev 2 and it was running old Raspbian. I decided to upgrade the whole stack and put the latest RPi OS to fresh SD card. I was trying to get IOTstack docker to handle it all but there was so many errors that after few days I gave up. The reason is probably that my RPi is ARMv6 and most of modern docker containers target is ARMv7.

Anyway, I went the traditional way of installing everything directly on OS. After installing Node-RED I copied the whole folder ~/.node-red from previous instance but it failed to load mentioned MCP23017 node and serial-port. So I got rid of node_modules and do npm install from scratch. While serial-port is fine now, MCP node is not and it's crucial to my flows as it handles all windows/doors switches.

Palette manager in NR shows such error:

Error: The module '/home/pi/.node-red/node_modules/i2c-bus/build/Release/i2c.node' was compiled against a different Node.js version using NODE_MODULE_VERSION 64. This version of Node.js requires NODE_MODULE_VERSION 72. Please try re-compiling or re-installing the module (for instance, using `npm rebuild` or `npm install`). (line:3)

npm rebuild did not fix the issue

npm install shows dozens of screens of errors, the final excerpt looks like this:

/home/pi/.cache/node-gyp/12.19.0/include/node/v8.h:2709:40: note:   candidate expects 1 argument, 0 provided
In file included from ../src/i2c.cc:107:
../src/./writequick.cc: In function ‘Nan::NAN_METHOD_RETURN_TYPE WriteQuickSync(Nan::NAN_METHOD_ARGS_TYPE)’:
../src/./writequick.cc:60:32: error: no matching function for call to ‘v8::Value::Int32Value()’
   int fd = info[0]->Int32Value();
                                ^
In file included from /home/pi/.cache/node-gyp/12.19.0/include/node/node.h:67,
                 from ../src/i2c.cc:1:
/home/pi/.cache/node-gyp/12.19.0/include/node/v8.h:2709:40: note: candidate: ‘v8::Maybe<int> v8::Value::Int32Value(v8::Local<v8::Context>) const’
   V8_WARN_UNUSED_RESULT Maybe<int32_t> Int32Value(Local<Context> context) const;
                                        ^~~~~~~~~~
/home/pi/.cache/node-gyp/12.19.0/include/node/v8.h:2709:40: note:   candidate expects 1 argument, 0 provided
In file included from ../src/i2c.cc:107:
../src/./writequick.cc:61:34: error: no matching function for call to ‘v8::Value::Int32Value()’
   __u8 bit = info[1]->Int32Value();
                                  ^
In file included from /home/pi/.cache/node-gyp/12.19.0/include/node/node.h:67,
                 from ../src/i2c.cc:1:
/home/pi/.cache/node-gyp/12.19.0/include/node/v8.h:2709:40: note: candidate: ‘v8::Maybe<int> v8::Value::Int32Value(v8::Local<v8::Context>) const’
   V8_WARN_UNUSED_RESULT Maybe<int32_t> Int32Value(Local<Context> context) const;
                                        ^~~~~~~~~~
/home/pi/.cache/node-gyp/12.19.0/include/node/v8.h:2709:40: note:   candidate expects 1 argument, 0 provided
make: *** [i2c.target.mk:111: Release/obj.target/i2c/src/i2c.o] Error 1
make: Leaving directory '/home/pi/.node-red/node_modules/i2c-bus/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/usr/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack     at ChildProcess.emit (events.js:314:20)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
gyp ERR! System Linux 5.4.72+
gyp ERR! command "/usr/bin/node" "/usr/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/pi/.node-red/node_modules/i2c-bus
gyp ERR! node -v v12.19.0
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not ok
npm WARN node-red-project@0.0.1 No repository field.
npm WARN node-red-project@0.0.1 No license field.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! i2c-bus@1.2.5 install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the i2c-bus@1.2.5 install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/pi/.npm/_logs/2020-11-07T10_47_57_518Z-debug.log

As the upgrade was made to have the latest version of all possible pieces I would like not to be forced to downgrade nodejs but I'm not sure that's the issue. Any hints on that?

node v12.19.0
npm 6.14.8

Thanks

It seems that node is not compatible with nodejs12. The node has not been updated in 5 years so it is not particularly surprising. There is an outstanding issue on the node's github page which has not been answered so I think you can assume the node is dead. You could downgrade to nodejs 8, but since is long out of support that is not desirable. Alternatively you could fork the node and fix it (which might just be a matter of updating package.json to use the latest version of the i2c node). Finally you could try and solve the problem without using that node.

1 Like

Thanks for the input.
Yeah, downgrading 4 versions down does not sound like a good idea.
I'll see if I can try to adjust the code to be usable with the newest nodejs.

As for not using the node.. this is quite distant plan as this node can only poll the sensor so I have like 12 nodes polling every 500ms, not so nice. I did Python script to use interrupt feature of that chip so it informs me after any change so would be nice to have interrupt node for that chip but that would require me to master creating nodes and using js to access the hardware.. something I would need to find the time to learn that (I create frontend in JS/TS/Angular as my work, so there is some base already).

I'll post an update in case of a success.
Thanks

If you have a python script that accesses it you could modify that to publish to MQTT and pick it up from MQTT in node-red.

1 Like

I have solved this using a function node and functionGlobalContext

in setting.js add the line as follows
functionGlobalContext: {
i2c:require('i2c-bus')
// os:require('os'),
// jfive:require("johnny-five"),
// j5board:require("johnny-five").Board({repl:false})
},

Then use the following flow

[{"id":"58ec3cd7.0e9d94","type":"function","z":"2d841d75.69d8b2","name":"MFC23017 Controller","func":"const i2c = global.get('i2c');\nthisChip = \"chip\" + msg.address\nthisPin = msg.pin\nchip = context.get(thisChip)\n\nif (msg.topic == 'init'){\n    if (chip == undefined){\n        chip = {\"isInputs\":0x00, \"pullUps\":0x00, \"inverts\":0x00, \"bus\":1, \"address\":msg.address, \"lastWrite\":0x00, \"lastRead\":0x00 }\n    }\n    const i2c1 = i2c.openSync(chip.bus);\n    if (msg.isInput) {chip.isInputs = chip.isInputs | (1<<thisPin)} else {chip.isInputs = chip.isInputs & ~(1<<thisPin)}\n\tif (msg.pullUp) {chip.pullUps = chip.pullUps | (1<<thisPin)} else {chip.pullUps = chip.pullUps & ~(1<<thisPin)}\n\tif (msg.invert) {chip.inverts = chip.inverts | (1<<thisPin)} else {chip.inverts = chip.inverts & ~(1<<thisPin)}\n\n    i2c1.writeByteSync(chip.address, 0x0A, 0x00);\n\ti2c1.writeByteSync(chip.address, 0x00, chip.isInputs & 0xFF);//update in out mode A\n\ti2c1.writeByteSync(chip.address, 0x01, (chip.isInputs >> 8) & 0xFF);//update in out mode B\n\ti2c1.writeByteSync(chip.address, 0x0C, chip.pullUps & 0xFF);\t//update pull up A\n\ti2c1.writeByteSync(chip.address, 0x0D, (chip.pullUps >> 8) & 0xFF);\t//update pull up B\n\ti2c1.writeByteSync(chip.address, 0x02, chip.inverts & 0xFF);\t//update pull up A\n\ti2c1.writeByteSync(chip.address, 0x03, (chip.inverts >> 8) & 0xFF);\t//update pull up B\n    i2c1.closeSync()\n}\nif (msg.topic == 'set'){\n    if (msg.payload){\n\t\tchip.lastWrite = chip.lastWrite | 1 << thisPin;\n\t} else {\n\t\tchip.lastWrite = chip.lastWrite & ~ (1 << thisPin);\n\t}\n\tconst i2c1 = i2c.openSync(chip.bus);\n\tif (thisPin < 8) {\n\t\ti2c1.writeByteSync(chip.address, 0x14, chip.lastWrite & 0xFF);\t//Set output A\n\t} else {\n\t\ti2c1.writeByteSync(chip.address, 0x15, (chip.lastWrite >> 8) & 0xFF);\t//Set output B\n\t}\n}\nif  (msg.topic == 'get'){\n    const i2c1 = i2c.openSync(chip.bus);\n    const ipA = i2c1.readByteSync(chip.address, 0x12);\n    const ipB = i2c1.readByteSync(chip.address, 0x13);\n    var ipAll = ipA + (ipB << 8);\n\tif (ipAll != chip.lastRead){\n\t\tvar diffWord = ipAll ^ chip.lastRead;\n\t\tfor (var i=0; i < 16; i++){\n\t\t\tif (diffWord & (1 << i)){\n\t\t\t\tvar newState =  (((ipAll & (1 << i)) == 0) ? false : true) \n\t\t\t\tmsg1 = {\"payload\":newState, \"address\":chip.address, \"pin\":i }\n\t\t\t\tnode.send(msg1);\n\t\t\t}\n\t\t}\n\t\tchip.lastRead = ipAll;\n\t}\n}\n\ncontext.set(thisChip, chip)","outputs":1,"noerr":0,"initialize":"","finalize":"","x":840,"y":760,"wires":[["dfaa627a.76ccf","3a4c1a0a.9edca6"]],"info":"pullup - only for outputs\ninvert - only what it shows the register as - does not effect actual ouput state"},{"id":"38bdbd9.26c6342","type":"inject","z":"2d841d75.69d8b2","name":"","props":[{"p":"topic","vt":"str"},{"p":"address","v":"34","vt":"num"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"get","x":630,"y":840,"wires":[["58ec3cd7.0e9d94"]]},{"id":"e10af374.f968a","type":"comment","z":"2d841d75.69d8b2","name":"MCP23017","info":"","x":620,"y":600,"wires":[]},{"id":"dfaa627a.76ccf","type":"debug","z":"2d841d75.69d8b2","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1010,"y":760,"wires":[]},{"id":"3a4c1a0a.9edca6","type":"switch","z":"2d841d75.69d8b2","name":"chip 34","property":"address","propertyType":"msg","rules":[{"t":"eq","v":"34","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":1020,"y":660,"wires":[["260c8588.af118a","fe07c207.718e"]]},{"id":"260c8588.af118a","type":"switch","z":"2d841d75.69d8b2","name":"","property":"pin","propertyType":"msg","rules":[{"t":"eq","v":"9","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":1170,"y":660,"wires":[["dbbcf390.1d076"]]},{"id":"dbbcf390.1d076","type":"link out","z":"2d841d75.69d8b2","name":"MCP23017 chip 34 pin 9","links":["dacba421.ad1ab8"],"x":1255,"y":660,"wires":[]},{"id":"fe07c207.718e","type":"switch","z":"2d841d75.69d8b2","name":"","property":"pin","propertyType":"msg","rules":[{"t":"eq","v":"10","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":1170,"y":700,"wires":[["84a7e942.b4ec68"]]},{"id":"84a7e942.b4ec68","type":"link out","z":"2d841d75.69d8b2","name":"MCP23017 chip 34 pin 10","links":["dacba421.ad1ab8","e57a3f6d.d1735"],"x":1255,"y":700,"wires":[]},{"id":"1eae26c8.fdb3c9","type":"inject","z":"2d841d75.69d8b2","name":"","props":[{"p":"topic","vt":"str"},{"p":"address","v":"34","vt":"num"},{"p":"pin","v":"1","vt":"str"},{"p":"isInput","v":"false","vt":"bool"},{"p":"pullUp","v":"true","vt":"bool"},{"p":"invert","v":"false","vt":"bool"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"init","payloadType":"str","x":650,"y":640,"wires":[["58ec3cd7.0e9d94"]]},{"id":"f1a3ded7.6314d","type":"inject","z":"2d841d75.69d8b2","name":"","props":[{"p":"topic","vt":"str"},{"p":"address","v":"34","vt":"num"},{"p":"pin","v":"14","vt":"str"},{"p":"isInput","v":"true","vt":"bool"},{"p":"pullUp","v":"false","vt":"bool"},{"p":"invert","v":"false","vt":"bool"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"init","x":630,"y":800,"wires":[["58ec3cd7.0e9d94"]]},{"id":"3d4d31a5.442ece","type":"inject","z":"2d841d75.69d8b2","name":"","props":[{"p":"topic","vt":"str"},{"p":"address","v":"34","vt":"num"},{"p":"pin","v":"1","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"set","payload":"true","payloadType":"bool","x":630,"y":680,"wires":[["58ec3cd7.0e9d94"]]},{"id":"4b88f91.a754a08","type":"inject","z":"2d841d75.69d8b2","name":"","props":[{"p":"topic","vt":"str"},{"p":"address","v":"34","vt":"num"},{"p":"pin","v":"1","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"set","payload":"false","payloadType":"bool","x":640,"y":720,"wires":[["58ec3cd7.0e9d94"]]}]

The "init" is used to initialise the chip (per pin)
The "get" polls the chip for change (input & output)
The "set" turns pins on / off
The output of the function sends changes

I have tested most of it and have just started using it for controlling heating / lighting etc so most bugs should be fixed

ToDo - have an array to initialise the chip (instead of per pin)

2 Likes

Quick update.
Yeah, downloading mcp23017chip, changing "i2c-bus": "~1.2.2" to "i2c-bus": "~5.2.1" and installing it locally via npm i /path/to/mcp23017chip did the thing. All is working good now :slight_smile:

Also, I'll check the Python script pushing updates to MQTT way. No polling sounds more sense here.

Thanks

1 Like

Could you add a comment to the issue I linked to, for anyone else finding this please.

1 Like

node-red-contrib-mcp23017chip is now updated

3 Likes

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