Concatenate numbers since digits from keyboard

I'm so sorry ! two error messages:

node: object
msg.payload: array [250]
[object, object, object, object, object, object, object, object, object, object…]

node: send
msg.lookup: undefined
undefined

Yours

[{"id":"4ecd6c21.39aee4","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"16b4bcb7.538223","type":"debug","z":"4ecd6c21.39aee4","name":"Receive","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1440,"y":320,"wires":[]},{"id":"9c12e589.3a1f58","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"79","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":480,"wires":[["103e38ef.a48d37"]]},{"id":"8a029001.bf16","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"85","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":560,"wires":[["103e38ef.a48d37"]]},{"id":"95c31108.111c3","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"81","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":520,"wires":[["103e38ef.a48d37"]]},{"id":"f2a77fda.db3ab","type":"function","z":"4ecd6c21.39aee4","name":"send the number string with 1sec timeout","func":"input = msg.payload;\ninput = String(input);                          //just in case\nstorage = context.get(\"storage\");               // recall your storage\ntimer = context.get(\"timer\")||null;             // recall last timer if exists\nclearTimeout(timer);                            // clear the last timer\ncontext.set(\"timer\",timer);                     // set it to be empty\nif (storage === undefined){\n    storage = [];\n}\n\n//recall the lastout and make a number out of it\nlastOut = context.get(\"lastOut\")||\"1\";\nlastOut = parseInt(lastOut);\n\nif (input == \"PU\"){\n    lastOut++;\n    context.set(\"lastOut\",String(lastOut));\n    return {payload: lastOut};\n}else if (input == \"PD\"){\n     lastOut--;\n    context.set(\"lastOut\",String(lastOut));\n    return {payload: lastOut};\n}\n\n//________________________________________________________________this is only called when sending the code\nrun = function mytimer(){                             //define a function that does all the stuff when you want to send the code\n\n    output = storage.join()                     //put all array indices together in one string\n    output = output.replace(/,/gi,\"\")          // get rid of the commas e.g. replace them by an empty string\n//store the output to a contextvariable \"lastOut\"\ncontext.set(\"lastOut\",output)\n    msg = {payload:output}                   \n    node.send(msg)\n    context.set(\"storage\",[]);\n    return null;\n}\n\n//________________________________________________________________\n\n\ntimer = setTimeout(run,1000);               // set your new timer (1sec is 1000 milliseconds)\nstorage.push(input);                        // append them to the end of your storage array\ncontext.set(\"storage\",storage);             // set your new array back to storage\ncontext.set(\"timer\",timer);                 // store your new timer\nreturn null;","outputs":1,"noerr":0,"x":700,"y":380,"wires":[["bb056c77.72a3a","9dd13afe.f247c8"]]},{"id":"103e38ef.a48d37","type":"function","z":"4ecd6c21.39aee4","name":"replace keyboard input with numbers","func":"input = msg.payload;\ninput = String(input);                  //here are the variables whe need for the function to work\ntable = flow.get(\"corrtable\");\n//----------------------------------------------------------\n// here we do the stuff we actually want to do\n\nindexOfMyValue = table.keyboard.indexOf(input);\nnumberIWant = table.output[indexOfMyValue];\n\n//----------------------------------------------------------\n// now that you got the \"numberIWant\"\n\n//set the payload to it\nmsg.payload = numberIWant;\n\n// and send it out\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":380,"wires":[["f2a77fda.db3ab","7790398e.5fe8f8"]]},{"id":"9dd13afe.f247c8","type":"file in","z":"4ecd6c21.39aee4","name":"","filename":"/home/pi/Desktop/collecteweb.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":1040,"y":380,"wires":[["c3b23a9c.f74a78"]]},{"id":"c3b23a9c.f74a78","type":"csv","z":"4ecd6c21.39aee4","name":"","sep":",","hdrin":false,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":false,"x":1270,"y":380,"wires":[["4321c23b.42b8ec","cf3d5a6e.63d2d8"]]},{"id":"4321c23b.42b8ec","type":"function","z":"4ecd6c21.39aee4","name":"your lookup func","func":"lookup = msg.lookup;\nvar output;\ndata = msg.payload;\n\nfor (i=0;i<data.length;i++){\n    if (data[i].col1 == lookup){\n        output = data[i].col2;\n        context.set(\"lookup\",null);\n        msg = {payload:output};\n        node.send(msg);\n    }\n}\n\nreturn null;","outputs":1,"noerr":0,"x":1440,"y":380,"wires":[["16b4bcb7.538223","def8e270.a643e"]]},{"id":"bb056c77.72a3a","type":"debug","z":"4ecd6c21.39aee4","name":"send","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"lookup","targetType":"msg","x":670,"y":320,"wires":[]},{"id":"cf3d5a6e.63d2d8","type":"debug","z":"4ecd6c21.39aee4","name":"object","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1250,"y":320,"wires":[]},{"id":"58d4b65a.80a018","type":"comment","z":"4ecd6c21.39aee4","name":"","info":"the seperator has to be semikolon (;)\nwhenn using miltiple columns, not commas\nthats an excel-thing","x":960,"y":420,"wires":[]},{"id":"def8e270.a643e","type":"exec","z":"4ecd6c21.39aee4","d":true,"command":"DISPLAY=:0 chromium-browser","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":1390,"y":580,"wires":[[],[],[]]},{"id":"581279c2.f86a48","type":"rpi-keyboard","z":"4ecd6c21.39aee4","name":"","x":350,"y":120,"wires":[["45370388.767f9c"]]},{"id":"45370388.767f9c","type":"calculate","z":"4ecd6c21.39aee4","name":"","pauseType":"rate","calculation":"max","timeout":"500","timeoutUnits":"milliseconds","rate":"1","x":350,"y":180,"wires":[["103e38ef.a48d37"]]},{"id":"286877bd.f63a58","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"onceDelay":"1","x":90,"y":40,"wires":[["58046171.80949"]]},{"id":"58046171.80949","type":"function","z":"4ecd6c21.39aee4","name":"set your correspondence table to flow","func":"corrtable = {};   //this is now an object, no array\n\n                    \ninput = [\"53\",\"71\",\"72\",\"73\",\"75\",\"76\",\"77\",\"79\",\"80\",\"81\",\"82\",\"104\",\"109\"];                       //this\noutput = [\"!\",\"7\",\"8\",\"9\",\"4\",\"5\",\"6\",\"1\",\"2\",\"3\",\"0\",\"pu\",\"pd\"];                          //and this are now arrays which we will put into the object\n\ncorrtable = \n{\"keyboard\":input,\"output\":output};\n\nflow.set(\"corrtable\",corrtable);\n\nreturn null;","outputs":0,"noerr":0,"x":350,"y":40,"wires":[]},{"id":"7790398e.5fe8f8","type":"debug","z":"4ecd6c21.39aee4","name":"replace","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":380,"y":320,"wires":[]},{"id":"5521cb26.f9e004","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"!","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":70,"y":440,"wires":[["103e38ef.a48d37"]]}]

yes yes,
as i did that out of my head w/o Node Red, i did not think about, taht we called our message
msg.lookup
and not msg.payload

necessary! because msg.lookup is the code, while msg.payload is the array to lookup from

i tried it at the computer now an for me this works!

input = msg.payload;
input = String(input);                          //just in case
storage = context.get("storage");               // recall your storage
timer = context.get("timer")||null;             // recall last timer if exists
clearTimeout(timer);                            // clear the last timer
context.set("timer",timer);                     // set it to be empty
if (storage === undefined){
    storage = [];
}

//recall the lastout and make a number out of it
lastOut = context.get("lastOut")||"1";
lastOut = parseInt(lastOut);

if (input == "PU"){
    lastOut++;
    context.set("lastOut",String(lastOut));
    return {lookup: String(lastOut)};
}else if (input == "PD"){
     lastOut--;
    context.set("lastOut",String(lastOut));
    return {lookup: String(lastOut)};
}

//________________________________________________________________this is only called when sending the code
run = function mytimer(){                             //define a function that does all the stuff when you want to send the code

    output = storage.join()                     //put all array indices together in one string
    output = output.replace(/,/gi,"")          // get rid of the commas e.g. replace them by an empty string
//store the output to a contextvariable "lastOut"
context.set("lastOut",String(output));
    msg = {lookup:output}                   
    node.send(msg)
    context.set("storage",[]);
    return null;
}

//________________________________________________________________


timer = setTimeout(run,1000);               // set your new timer (1sec is 1000 milliseconds)
storage.push(input);                        // append them to the end of your storage array
context.set("storage",storage);             // set your new array back to storage
context.set("timer",timer);                 // store your new timer
return null;

we simply have tor replace payload with lookup here

aand we defined the code for pd and pu
to be "PD" and "PU" not "pd" and "pu" strings are case sensitive!

that means in the correspondance table replace these to major letters.
"PD" "PU"

and you can remove the interval from the corrtable inject

please leave it once
not every second

if you change sth and want it to reload simply press the blue square at the inject node once

I modified the corrtable (PU, PD) and its timestamps, then the code of the "Send ..." node. It's great, it works very well !!
Definitely the code is a very subtle exercise.
Unfortunately, the up and down arrows do not produce the expected effect.
Yours

I edited the code above 20 minutes ago. please copy it again
it counts up and down as expected

Maybe it's a problem with my browser or my keyboard?
Below are the debug messages.
Yours

17/04/2020 à 19:15:24node: replacepi/key : msg.payload : string[2]

"PU"

17/04/2020 à 19:15:24node: sendmsg.lookup : string[3]

"NaN"

17/04/2020 à 19:15:24node: objectmsg.payload : array[250]

[ object, object, object, object, object, object, object, object, object, object … ]

reessaye s*il te plai

input = msg.payload;
input = String(input);                          //just in case
storage = context.get("storage");               // recall your storage
timer = context.get("timer")||null;             // recall last timer if exists
clearTimeout(timer);                            // clear the last timer
context.set("timer",timer);                     // set it to be empty
if (storage === undefined){
    storage = [];
}

//recall the lastout and make a number out of it
lastOut = context.get("lastOut")||"1";
lastOut = parseInt(lastOut);

if (input == "PU"){
    lastOut++;
    context.set("lastOut",String(lastOut));
    return {lookup: String(lastOut)};
}else if (input == "PD"){
     lastOut--;
    context.set("lastOut",String(lastOut));
    return {lookup: String(lastOut)};
}

//________________________________________________________________this is only called when sending the code
run = function mytimer(){                             //define a function that does all the stuff when you want to send the code

    output = storage.join()                     //put all array indices together in one string
    output = output.replace(/,/gi,"")          // get rid of the commas e.g. replace them by an empty string
//store the output to a contextvariable "lastOut"
context.set("lastOut",output);
    msg = {lookup:output}                   
    node.send(msg)
    context.set("storage",[]);
    return null;
}

//________________________________________________________________


timer = setTimeout(run,1000);               // set your new timer (1sec is 1000 milliseconds)
storage.push(input);                        // append them to the end of your storage array
context.set("storage",storage);             // set your new array back to storage
context.set("timer",timer);                 // store your new timer
return null;

well it works here, i dont really know what the problem is
if its not working with the new code please change to screenshots.

did you reactivate the exec node? that was inactive in the last flow you sent me

Thank you for these elements.
I have just tried again and the url is displayed well after the entry, but Page Up and Down do not allow to change url.
It may be a problem with my browser or my keyboard or with "!" ?
Below are the debug messages.
04/17/2020 at 20: 18: 13node: replace
pi / key: msg.payload: string [2]
"COULD"
04/17/2020 at 20: 18: 14node: send
msg.lookup: string [3]
"Nope"
04/17/2020 at 20: 18: 15node: object
msg.payload: array [250]
[object, object, object, object, object, object, object, object, object, object…]
04/17/2020 at 20: 18: 40node: replace
pi / key: msg.payload: undefined
undefined

Unfortunately I have to join my family by skype. I will do tests again tomorrow at the first hour.
Good night,
Yours

No more results this mornig.
Yours

PS : ye,s the exec node is reactivated

After having repeated the flow several times today, I still arrive at the same result: "Nan" at the exit of the "Send ..." node when I press Page Up or Page Down.
Maybe it is related to my hardware configuration if on your side it works? (raspberry pi3 +, raspbian buster, chromium, nodered V1.0.3, keyboard and mouse on usb)
I'm a little desperate! In any case everything else works perfectly !
Yours

hey there,

i think its not a problem with you software. the way you choose with the "!" will not work as you may expect.

there are more than one option as always...

  1. you can append the exclamation mark to EVERY of you input codes,+
    as a result you would have to type !1!2!3 when you like to open domain 123
    and !PD for page down.
    i think that is not very convenient...

  2. start a dashboard and type the number for the url you want to access in an numerical input node in your dashboard.
    more convenient bau still not elegant

  3. set up a "initiation word" to tell the flow it should hear to what you're typing and a stop word to make the flow stop listening to your keypad inputs.
    thats probably the most convenient way that is thinkable for me, when this should stay simple
    and I help you programming it :wink:

3.a.
there are different options of what to use as start and stop code.
depending on if it is numerical or in characters you would need to add some keys to your corr table

lets say starting the flow by "999876"
stopping it by "666789"
--> no additional entrys needed
it should be something you would in other cases never type...
i think 999876 is easy but uncommon.

you could use "startdegaulle" "stopdegaulle"
or "jarvislisten" "jarvisstop"
--> you would need to add the used characters to the corrtable.

just tell me and then we'll work it out
sincerly

Thank you so much for your tenacity and your encouragement.
After reading your last message, it seems to me that 2 things are necessary:
-1- check conformity of the flow that I use / the flow that you have and that works.
-2- If the two flows are identical, I will have to choose from the 3 approaches that you have listed. At first glance, the first seems to me the most suited to my way of using the keyboard.
I attach my feed to verify compliance ; Could you import it and test it on your computer?
Thank you for your help.
Yours

[{"id":"4ecd6c21.39aee4","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"16b4bcb7.538223","type":"debug","z":"4ecd6c21.39aee4","name":"Receive","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1480,"y":320,"wires":[]},{"id":"9c12e589.3a1f58","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"79","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":460,"wires":[["103e38ef.a48d37"]]},{"id":"8a029001.bf16","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"85","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":540,"wires":[["103e38ef.a48d37"]]},{"id":"95c31108.111c3","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"81","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":500,"wires":[["103e38ef.a48d37"]]},{"id":"f2a77fda.db3ab","type":"function","z":"4ecd6c21.39aee4","name":"send the number string with 1sec timeout","func":"input = msg.payload;\ninput = String(input);                          //just in case\nstorage = context.get(\"storage\");               // recall your storage\ntimer = context.get(\"timer\")||null;             // recall last timer if exists\nclearTimeout(timer);                            // clear the last timer\ncontext.set(\"timer\",timer);                     // set it to be empty\nif (storage === undefined){\n    storage = [];\n}\n\n//recall the lastout and make a number out of it\nlastOut = context.get(\"lastOut\")||\"1\";\nlastOut = parseInt(lastOut);\n\nif (input == \"PU\"){\n    lastOut++;\n    context.set(\"lastOut\",String(lastOut));\n    return {lookup: String(lastOut)};\n}else if (input == \"PD\"){\n     lastOut--;\n    context.set(\"lastOut\",String(lastOut));\n    return {lookup: String(lastOut)};\n}\n\n//________________________________________________________________this is only called when sending the code\nrun = function mytimer(){                             //define a function that does all the stuff when you want to send the code\n\n    output = storage.join()                     //put all array indices together in one string\n    output = output.replace(/,/gi,\"\")          // get rid of the commas e.g. replace them by an empty string\n//store the output to a contextvariable \"lastOut\"\ncontext.set(\"lastOut\",output);\n    msg = {lookup:output}                   \n    node.send(msg)\n    context.set(\"storage\",[]);\n    return null;\n}\n\n//________________________________________________________________\n\n\ntimer = setTimeout(run,1000);               // set your new timer (1sec is 1000 milliseconds)\nstorage.push(input);                        // append them to the end of your storage array\ncontext.set(\"storage\",storage);             // set your new array back to storage\ncontext.set(\"timer\",timer);                 // store your new timer\nreturn null;","outputs":1,"noerr":0,"x":740,"y":380,"wires":[["bb056c77.72a3a","9dd13afe.f247c8"]]},{"id":"103e38ef.a48d37","type":"function","z":"4ecd6c21.39aee4","name":"replace keyboard input with numbers","func":"input = msg.payload;\ninput = String(input);                  //here are the variables whe need for the function to work\ntable = flow.get(\"corrtable\");\n//----------------------------------------------------------\n// here we do the stuff we actually want to do\n\nindexOfMyValue = table.keyboard.indexOf(input);\nnumberIWant = table.output[indexOfMyValue];\n\n//----------------------------------------------------------\n// now that you got the \"numberIWant\"\n\n//set the payload to it\nmsg.payload = numberIWant;\n\n// and send it out\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":380,"wires":[["f2a77fda.db3ab","7790398e.5fe8f8","b5bb40af.7a2d4"]]},{"id":"9dd13afe.f247c8","type":"file in","z":"4ecd6c21.39aee4","name":"","filename":"/home/pi/Desktop/collecteweb.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":1080,"y":380,"wires":[["c3b23a9c.f74a78"]]},{"id":"c3b23a9c.f74a78","type":"csv","z":"4ecd6c21.39aee4","name":"","sep":",","hdrin":false,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":false,"x":1310,"y":380,"wires":[["4321c23b.42b8ec","cf3d5a6e.63d2d8"]]},{"id":"4321c23b.42b8ec","type":"function","z":"4ecd6c21.39aee4","name":"your lookup func","func":"lookup = msg.lookup;\nvar output;\ndata = msg.payload;\n\nfor (i=0;i<data.length;i++){\n    if (data[i].col1 == lookup){\n        output = data[i].col2;\n        context.set(\"lookup\",null);\n        msg = {payload:output};\n        node.send(msg);\n    }\n}\n\nreturn null;","outputs":1,"noerr":0,"x":1480,"y":380,"wires":[["16b4bcb7.538223","def8e270.a643e"]]},{"id":"bb056c77.72a3a","type":"debug","z":"4ecd6c21.39aee4","name":"send","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"lookup","targetType":"msg","x":690,"y":320,"wires":[]},{"id":"cf3d5a6e.63d2d8","type":"debug","z":"4ecd6c21.39aee4","name":"object","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1290,"y":320,"wires":[]},{"id":"58d4b65a.80a018","type":"comment","z":"4ecd6c21.39aee4","name":"","info":"the seperator has to be semikolon (;)\nwhenn using miltiple columns, not commas\nthats an excel-thing","x":1000,"y":320,"wires":[]},{"id":"def8e270.a643e","type":"exec","z":"4ecd6c21.39aee4","command":"DISPLAY=:0 chromium-browser","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":1070,"y":500,"wires":[[],[],[]]},{"id":"581279c2.f86a48","type":"rpi-keyboard","z":"4ecd6c21.39aee4","name":"","x":110,"y":280,"wires":[["45370388.767f9c"]]},{"id":"45370388.767f9c","type":"calculate","z":"4ecd6c21.39aee4","name":"","pauseType":"rate","calculation":"max","timeout":"500","timeoutUnits":"milliseconds","rate":"1","x":110,"y":340,"wires":[["103e38ef.a48d37"]]},{"id":"286877bd.f63a58","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"1","payloadType":"str","repeat":"1","crontab":"","once":false,"onceDelay":"1","x":490,"y":80,"wires":[["58046171.80949"]]},{"id":"58046171.80949","type":"function","z":"4ecd6c21.39aee4","name":"set your correspondence table to flow","func":"corrtable = {};   //this is now an object, no array\n\n                    \ninput = [\"53\",\"71\",\"72\",\"73\",\"75\",\"76\",\"77\",\"79\",\"80\",\"81\",\"82\",\"104\",\"109\"];                       //this\noutput = [\"!\",\"7\",\"8\",\"9\",\"4\",\"5\",\"6\",\"1\",\"2\",\"3\",\"0\",\"PU\",\"PD\"];                          //and this are now arrays which we will put into the object\n\ncorrtable = \n{\"keyboard\":input,\"output\":output};\n\nflow.set(\"corrtable\",corrtable);\n\nreturn null;","outputs":0,"noerr":0,"x":770,"y":100,"wires":[]},{"id":"7790398e.5fe8f8","type":"debug","z":"4ecd6c21.39aee4","name":"replace","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":380,"y":320,"wires":[]},{"id":"5521cb26.f9e004","type":"inject","z":"4ecd6c21.39aee4","name":"","topic":"","payload":"!","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":420,"wires":[["103e38ef.a48d37"]]},{"id":"b5bb40af.7a2d4","type":"switch","z":"4ecd6c21.39aee4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":460,"y":640,"wires":[[]]}]```

okay here it is:
FLOW:

[{"id":"e2251fa9.aba62","type":"debug","z":"7f34182f.097b98","name":"Receive","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1480,"y":320,"wires":[]},{"id":"b7f73c4.79ee5c","type":"function","z":"7f34182f.097b98","name":"your lookup func","func":"lookup = msg.lookup;\nvar output;\ndata = msg.payload;\n\nfor (i=0;i<data.length;i++){\n    if (data[i].col1 == lookup){\n        output = data[i].col2;\n        context.set(\"lookup\",null);\n        msg = {payload:output};\n        node.send(msg);\n    }\n}\n\nreturn null;","outputs":1,"noerr":0,"x":1480,"y":380,"wires":[["e2251fa9.aba62","c581d4b4.614ab8"]]},{"id":"254ad571.91edaa","type":"inject","z":"7f34182f.097b98","name":"","topic":"","payload":"79","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":460,"wires":[["9fcb4740.919098"]]},{"id":"24aa13c8.66cb2c","type":"inject","z":"7f34182f.097b98","name":"","topic":"","payload":"85","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":540,"wires":[["9fcb4740.919098"]]},{"id":"a7cb714c.afa29","type":"inject","z":"7f34182f.097b98","name":"","topic":"","payload":"81","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":500,"wires":[["9fcb4740.919098"]]},{"id":"98188437.5b35b8","type":"function","z":"7f34182f.097b98","name":"send the number string with 1sec timeout","func":"input = msg.payload;\ninput = String(input);                          //just in case\nstorage = context.get(\"storage\");               // recall your storage\ntimer = context.get(\"timer\")||null;             // recall last timer if exists\nclearTimeout(timer);                            // clear the last timer\ncontext.set(\"timer\",timer);                     // set it to be empty\nif (storage === undefined){\n    storage = [];\n}\n\n//recall the lastout and make a number out of it\nlastOut = context.get(\"lastOut\")||\"1\";\nlastOut = parseInt(lastOut);\n\nif (input == \"PU\"){\n    lastOut++;\n    context.set(\"lastOut\",String(lastOut));\n    return {lookup: String(lastOut)};\n}else if (input == \"PD\"){\n     lastOut--;\n    context.set(\"lastOut\",String(lastOut));\n    return {lookup: String(lastOut)};\n}\n\n//________________________________________________________________this is only called when sending the code\nrun = function mytimer(){                             //define a function that does all the stuff when you want to send the code\n\n    output = storage.join()                     //put all array indices together in one string\n    output = output.replace(/,/gi,\"\")          // get rid of the commas e.g. replace them by an empty string\n//store the output to a contextvariable \"lastOut\"\ncontext.set(\"lastOut\",output);\n    msg = {lookup:output}                   \n    node.send(msg)\n    context.set(\"storage\",[]);\n    return null;\n}\n\n//________________________________________________________________\n\n\ntimer = setTimeout(run,1000);               // set your new timer (1sec is 1000 milliseconds)\nstorage.push(input);                        // append them to the end of your storage array\ncontext.set(\"storage\",storage);             // set your new array back to storage\ncontext.set(\"timer\",timer);                 // store your new timer\nreturn null;","outputs":1,"noerr":0,"x":740,"y":380,"wires":[["d36b4adf.5b4bc8","5d3e8cb6.7d5984"]]},{"id":"9fcb4740.919098","type":"function","z":"7f34182f.097b98","name":"replace keyboard input with numbers","func":"input = msg.payload;\ninput = String(input);                  //here are the variables whe need for the function to work\ntable = flow.get(\"corrtable\");\nblock = context.get(\"block\");\ntimer = context.get(\"timer\")||null;\n\nif(input == \"53\"){  //which is the code of the \"!\"\n    context.set(\"block\",false); //store in context that messages may pass\n    block = false; // for the rest of the func msg may pass as well\ntimer = setTimeout(function(){context.set(\"block\",true);node.status({text:\"Node is in blocking mode\"})},5000); //stor in context a 5sec timer and after that msg will be blocked\ncontext.set(\"timer\",timer);\nnode.status({text:\"Node lets msg pass\"});\n}\n\nif (block === true){ // if block is true the messages should be blocked, and the rest of the scope is aborted\n    return null;\n}\n\n//----------------------------------------------------------\n// here we do the stuff we actually want to do\n\nif(input != \"53\"){ // if input it not a ! than pass the numbers\nindexOfMyValue = table.keyboard.indexOf(input);\nnumberIWant = table.output[indexOfMyValue];\n\n//----------------------------------------------------------\n// now that you got the \"numberIWant\"\n\n//set the payload to it\nmsg.payload = numberIWant;\nreturn msg;\n}\n// and send it out\n","outputs":1,"noerr":0,"x":390,"y":380,"wires":[["98188437.5b35b8","c5f41792.a78958"]]},{"id":"5d3e8cb6.7d5984","type":"file in","z":"7f34182f.097b98","name":"","filename":"/home/pi/Desktop/collecteweb.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":1080,"y":380,"wires":[["b7833ceb.35a9a"]]},{"id":"b7833ceb.35a9a","type":"csv","z":"7f34182f.097b98","name":"","sep":",","hdrin":false,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":false,"x":1310,"y":380,"wires":[["b7f73c4.79ee5c","1d28d98b.5bf076"]]},{"id":"d36b4adf.5b4bc8","type":"debug","z":"7f34182f.097b98","name":"send","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"lookup","targetType":"msg","x":690,"y":320,"wires":[]},{"id":"1d28d98b.5bf076","type":"debug","z":"7f34182f.097b98","name":"object","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1290,"y":320,"wires":[]},{"id":"82ba249a.70e7a8","type":"comment","z":"7f34182f.097b98","name":"","info":"the seperator has to be semikolon (;)\nwhenn using miltiple columns, not commas\nthats an excel-thing","x":1000,"y":320,"wires":[]},{"id":"c581d4b4.614ab8","type":"exec","z":"7f34182f.097b98","command":"DISPLAY=:0 chromium-browser","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":950,"y":480,"wires":[["4a3c3041.b881c"],["4a3c3041.b881c"],["4a3c3041.b881c"]]},{"id":"b56b3fe4.ec6d8","type":"rpi-keyboard","z":"7f34182f.097b98","name":"","x":110,"y":280,"wires":[["9a27cf3.87bd73"]]},{"id":"1eb34d45.d5ed13","type":"inject","z":"7f34182f.097b98","name":"","topic":"","payload":"1","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"1","x":410,"y":160,"wires":[["1271e20b.af3e7e"]]},{"id":"1271e20b.af3e7e","type":"function","z":"7f34182f.097b98","name":"set your correspondence table to flow","func":"corrtable = {};   //this is now an object, no array\n\ninput = [\"53\",\"71\",\"72\",\"73\",\"75\",\"76\",\"77\",\"79\",\"80\",\"81\",\"82\",\"104\",\"109\"];                       //this\noutput = [\"!\",\"7\",\"8\",\"9\",\"4\",\"5\",\"6\",\"1\",\"2\",\"3\",\"0\",\"PU\",\"PD\"];                          //and this are now arrays which we will put into the object\n\ncorrtable = \n{\"keyboard\":input,\"output\":output};\n\nflow.set(\"corrtable\",corrtable);\n\nreturn null;","outputs":0,"noerr":0,"x":670,"y":160,"wires":[]},{"id":"c5f41792.a78958","type":"debug","z":"7f34182f.097b98","name":"replace","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":380,"y":320,"wires":[]},{"id":"bdf120d5.2b8c5","type":"inject","z":"7f34182f.097b98","name":"","topic":"","payload":"53","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":420,"wires":[["9fcb4740.919098"]]},{"id":"9a27cf3.87bd73","type":"calculate","z":"7f34182f.097b98","name":"","pauseType":"rate","calculation":"max","timeout":"500","timeoutUnits":"milliseconds","rate":"1","x":110,"y":340,"wires":[["9fcb4740.919098"]]},{"id":"4a3c3041.b881c","type":"debug","z":"7f34182f.097b98","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1240,"y":480,"wires":[]}]

its done and works.
please do me the favor of trying to understand the new code in the replace node.
you dont have to do anything in the corr table
and your may now input
!123
!137
!250

to load your domain.

i repeat myself:
please don't inject the corr table every second, thats nonsense
once at startup is totally enough!
like i did in the new configuration it is already done

there is one thing that you have to do now by yourself,
i cant test your pi keyboard node for you.
you have to look at what exactly comes out of this node and what to do with it.
i can only test with the inject nodes on your flow with these three numbers and the "!"
with this it works!

and I understand what this calculation node ist doing...
as a suggestion:
replace it with this:
node-red-contrib-throttle
and set it up to "by time" and the time to 150 milliseconds.
that is more what you are lookin for i think.
this will let one msg pass every 150ms...or whenever you like

and as this is a programming forum i have a sweet or you:

you dont need this node either...
a throttle is very easy to do by yourself:
but of course you can install and use the throttle node.
it is fast and reliable and useful

now = Date.now();
then = context.get("then")||0;

if (now-then < 150){
return null;
}else{
context.set("then",now);
return msg;
}

Hello ! i'm writing you an answer / calculation node :

Thanks, thanks, thanks! it works !!!
I guess I have trouble putting the codes you sent me successively into the nodes, sorry.
For what comes out of the Pikeyboard node:
I get the following from the Debug nodes of the Pi Keyboard node and the Calculation node:
04/19/2020 at 10: 12: 01node: Pi keyboard pi / key: msg.payload: number 53
04/19/2020 at 10: 12: 01node: Pi keyboard pi / key: msg.payload: number 53
04/19/2020 at 10: 12: 01node: calculation pi / key: msg.payload: number 53
04/19/2020 at 10: 12: 01node: keyboard pi / key: msg.payload: number 79
04/19/2020 at 10: 12: 01node: keyboard pi / key: msg.payload: number 79
04/19/2020 at 10: 12: 01node: calculation pi / key: msg.payload: number 79
04/19/2020 at 10: 12: 01node: keyboard pi / key: msg.payload: number 80
04/19/2020 at 10: 12: 02node: keyboard pi / key: msg.payload: number 80
04/19/2020 at 10: 12: 02node: calculation pi / key: msg.payload: number 80
04/19/2020 at 10: 12: 02node: keyboard pi / key: msg.payload: number 81
04/19/2020 at 10: 12: 02node: keyboard pi / key: msg.payload: number 81
04/19/2020 at 10: 12: 02node: calculation pi / key: msg.payload: number 81
04/19/2020 at 10: 12: 50node: keyboard pi / key: msg.payload: number 29
04/19/2020 at 10: 12: 50node: keyboard pi / key: msg.payload: number 29
04/19/2020 at 10: 12: 50node: calculation pi / key: msg.payload: number 29
04/19/2020 at 10: 12: 50node: keyboard pi / key: msg.payload: number 29
04/19/2020 at 10: 12: 50node: keyboard pi / key: msg.payload: number 29
04/19/2020 at 10: 12: 51node: calculation pi / key: msg.payload: number 29
04/19/2020 at 10: 12: 51node: keyboard
pi / key: msg.payload: number 29
In fact,

  • Each character entered on the keyboard comes out twice from the Pi Keyboard node (keydown + keyup from what I read).
  • The "calculation" node is intended to remove this duplicate

I actually have a problem on this node because it should have been set to "2" and not to "1"
I immediately look at what you sent me
Yours

I created a function node with your code to de-duplicate at the exit of the keyboard, and it works very well with the value 150. I will see in use if it is necessary to refine this setting.
I now start to understand the code of the node "replace ..."
Yours

What I understand from the code, after its first part which poses the correspondence table, the blocking function and its timer:
1: if the input is not 53, the process is blocked
2: if the input is 53, the process is unlocked for 5 seconds
3: during these 5 seconds all entries will be replaced by the corresponding output from the correspondence table
4: each output is sent to the next node (for concatenation if delay <1 second)
5: after 5 seconds the process is again blocked
I hope I understand !!!!
Yours

1 Like

Hello,
I wanted to thank you because my workflow works very well now even if I still have to deepen my understanding of the code. It's my job now.
Then, I will open a new search: how to activate / deactivate FLOWS from the keyboard.
Thank you again and "au plaisir !".
Yours,
Laurent

2 Likes