-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mcu_code 1st #122
mcu_code 1st #122
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an interesting idea. As I understand it, mcu_code
is a version of the function
node with two differences:
- The functions are only executed on the MCU. This is for functions with code that is "MCU-only" and would generate an exception running under Node-RED on computers.
- There is an optional Moddable SDK manifest
This all seems convenient for developers building flows.
It might be more clear if the name of the node type included the word "function" so that developers understand it is a kind of function node. Maybe "MCU Function" or "Function - MCU"?
FWIW – sometimes it is useful to have a Function node that runs on both MCU and computers but has different behaviors. For example, the computer implementation might be a simulator for testing / development. To do that, you can check RED.mcu
:
if (RED.mcu) {
// running on MCU
}
else {
// running on computer
}
Using that approach, a separate function node is less necessary. Of course, that doesn't provide the manifest feature.
@ralphwetzel – I vaguely recall you've thought about this kind of situation before. Do you have any input?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a copy of the Function node's HTML with some changes to add the manifest. It will be difficult to keep this in sync with future changes to the Function node. I don't know if there is a good way to achieve that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree too.
If you are running only on the MCU, you may not need to synchronize. There may also be possibilities to add other features.
If I could write a simple Moddable code (function), I would be fine with just that function, but it was difficult for me, so I created it by changing the Function node.
Thank you for your response. I'm not good at English, so I use Google Translate. I'm sorry if I didn't convey the nuance. The idea was to execute Moddable code using Node-RED.
For example, you can save the following code (which causes an interrupt on an M5Button) to a node using Node-RED import/export to take advantage of the Node-RED ecosystem.
I didn't know about the RED.mcu function. Thanks, |
No problem. JavaScript is a universal language.
They should be. You can access the M5Stack buttons, for example. I modified your "mcu_code" node, fixing the start-up script and making it a "function" node. It seems to work with M5Stack buttons. {
"id": "1017cc0e2a06da55",
"type": "function",
"z": "8c60c58949866055",
"name": "M5StackButton",
"func": "\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "button.a.onChanged = function () {\n const up = this.read()\n if (up === 0) {\n node.send({payload: \"BtnA\"});\n }\n}\nbutton.b.onChanged = function () {\n const up = this.read()\n if (up === 0) {\n node.send({payload: \"BtnB\"});\n }\n}\nbutton.c.onChanged = function () {\n const up = this.read()\n if (up === 0) {\n node.send({payload: \"BtnC\"});\n }\n}",
"finalize": "",
"libs": [],
"_mcu": {
"mcu": false
},
"x": 460,
"y": 180,
"wires": [
[
"c274399f02e409b4"
]
]
},
I understand these problems need to be solved in some way. Maybe your solution is good. I'm just not sure yet. I'd like to think about it. Also, I'm curious if @ralphwetzel has any ideas, since he knows the plug-in best. |
@NW-Lab – would you confirm that the modified node above allows you to access the M5 buttons? Thank you. |
@phoddie It would be nice if there was a way to stop sandbox execution of a function and a node where you could freely write manifest.json. Since manifest.json is a driver specification, I think it accompanies the code. Therefore, it may be better to use it as a comment node in the flow rather than specifying it in the Plugin. Thank you. |
Excellent. Thank you.
I want to confirm. You want to prevent the code of the Function node from running in Node-RED, but allow it to run on Node-RED MCU?
A Comment node is a nice idea. It could eventually be a "manifest" node. But, your original idea to have the manifest with the Function/MCU-Code node is nice. As an experiment, I using the Description field of the Function node to hold the manifest. It is a small hack, but an easy one. Here's a test flow that uses the qrCode module. The function scripts test flows.json[
{
"id": "8c60c58949866055",
"type": "tab",
"label": "Flow 7",
"disabled": false,
"info": "",
"env": [],
"_mcu": {
"mcu": false
}
},
{
"id": "1017cc0e2a06da55",
"type": "function",
"z": "8c60c58949866055",
"name": "M5StackButton",
"func": "if (!RED.mcu) return;\n\nlet qr = qrCode({input: msg.payload});\nlet size = qr.size;\nqr = new Uint8Array(qr);\n\nmsg.payload = \"\";\nfor (let y = 0; y < size; y++) {\n\tfor (let x = 0; x < size; x++) {\n\t\tif (qr[(y * size) + x])\n\t\t\tmsg.payload += \"X\";\n\t\telse\n\t\t\tmsg.payload += \".\";\n\t}\n\tmsg.payload += \"\\n\";\n}\n\n\nreturn msg;\n",
"outputs": 1,
"noerr": 0,
"initialize": "if (!RED.mcu) return;\n\nbutton.a.onChanged = function () {\n const up = this.read()\n if (up === 0) {\n node.send({payload: \"BtnA\"});\n }\n}\nbutton.b.onChanged = function () {\n const up = this.read()\n if (up === 0) {\n node.send({payload: \"BtnB\"});\n }\n}\nbutton.c.onChanged = function () {\n const up = this.read()\n if (up === 0) {\n node.send({payload: \"BtnC\"});\n }\n}",
"finalize": "",
"libs": [
{
"var": "qrCode",
"module": "qrcode"
}
],
"_mcu": {
"mcu": false
},
"x": 460,
"y": 160,
"wires": [
[
"c274399f02e409b4"
]
],
"info": "{\n \"include\": [\n \"$(MODULES)/data/qrcode/manifest.json\"\n ]\n}\n"
},
{
"id": "c274399f02e409b4",
"type": "debug",
"z": "8c60c58949866055",
"name": "debug 90",
"active": true,
"tosidebar": false,
"console": true,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"_mcu": {
"mcu": false
},
"x": 690,
"y": 160,
"wires": []
},
{
"id": "e68d8b42704484e3",
"type": "inject",
"z": "8c60c58949866055",
"name": "",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "one two",
"payloadType": "str",
"_mcu": {
"mcu": false
},
"x": 220,
"y": 120,
"wires": [
[
"1017cc0e2a06da55"
]
]
},
{
"id": "1ee20679e607da19",
"type": "inject",
"z": "8c60c58949866055",
"name": "",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "",
"payload": "three four",
"payloadType": "str",
"_mcu": {
"mcu": false
},
"x": 220,
"y": 180,
"wires": [
[
"1017cc0e2a06da55"
]
]
}
] To use the manifest from the Description requires change mcmanifest.json. This is similar to the change in your PR. flows.forEach((node, i) => {
let manifest;
if (("function" === node.type) && node.info?.startsWith("{"))
manifest = JSON.parse(node.info);
else if (node.moddable_manifest)
... This approach works. It is a little strange. But... it requires no new nodes, so it is a convenient way to experiment further. What do you think? |
I thought it was a good idea, but it seems like there might be an error in the sandbox. The message "The flow has been stopped because an unknown module exists. aw3641-404" will be displayed and the Plugin BUILD button will be disabled. flows.json
mcmanifest.js
It's not going well. Thank you. |
I confirmed that node-red-mcu works well. If possible, I think it would be better to take measures so that the Plugin's "BUILD" button does not become disabled. . Thank you. |
Hi!
|
hello @ralphwetzel, thank you for all the information. For example, if the comment node is named "moddable_import", it seems like incorporating a mechanism to add imports would help organize the current request. Thank you |
@ralphwetzel – thank you for your extensive notes.
My experience is that this is inconsistent. Some module specifiers do not generate an error, but others do. That makes it an impediment to using the standard Function module, as you note. Your node-red-mcu-gate is an elegant solution to part of this challenge. We could achieve something similar with the The most developer-friendly approach is what both you and @NW-Lab have experimented with – a single node:
That's a maintenance headache, unfortunately. (FWIW – based on what we've seen with @NW-Lab's work, this should only require minor changes to
That would be interesting input into this discussion. I'm sure @NW-Lab would be interested to compare. Would you consider sharing a prerelease of that? |
hello I've published the revised version on Moddable. This PR is no longer needed. Thank you. |
Hello I think there may be more than one way to create a manifest. At the moment, I'm satisfied with the method of creating comments nodes, and it seems like it's not a good idea to increase the number of nodes as @phoddie wrote. For now, I will close this pull request. Thank you |
For developers, the best solution is to have a single Function Node. The alternative, creating an MCU Function node, is possible as @NW-Lab and @ralphwetzel have independently shown, but harder to maintain and more for developers to think about. It seems like the Function Node could be a little more expressive in Node-RED. If it was, it would also be better for Node-RED MCU. I am sure proposing any changes to the Function Node would be tough, since it is so widely used. Still, let's discuss what's might be interesting.
|
Hello
I wanted to run Moddable code on Node-Red.
Removed sandbox from Node-Red core's function and made it possible to write moddable_manifest.
As an example, the following Flows can be executed.(This is the same code as moddable/examples/drivers/aw3641.)
Thank you.