Next revision | Previous revision |
fuss:node-red [2020/05/24 11:16] – created office | fuss:node-red [2025/06/11 17:47] (current) – [Maintain Fixed Number of Files in a Folder using Default Nodes] office |
---|
</code> | </code> |
| |
The map at the top is responsible for conditionally proxying requests based on the user agents: by default, all requests to the server ''mynoderedserver.tld'' are passed to node-red on port ''1880'' and requests that match the regular expression ''~AEO[A-Z]{2,3} Build\/[A-Z0-9]+'' are delivered to port ''8080'' on which the Amazon Alexa Philips Hue Emulation bridge (provided by ''node-red-contrib-amazon-echo') is listening. | The map at the top is responsible for conditionally proxying requests based on the user agents: by default, all requests to the server ''mynoderedserver.tld'' are passed to node-red on port ''1880'' and requests that match the regular expression ''~AEO[A-Z]{2,3} Build\/[A-Z0-9]+'' are delivered to port ''8080'' on which the Amazon Alexa Philips Hue Emulation bridge (provided by ''node-red-contrib-amazon-echo'') is listening. |
| |
The result is that a request via a browser to ''<nowiki>http://mynoderedserver.tld</nowiki>'' will open up the node-red flow design interface. Similarly, requests to: ''<nowiki>http://mynoderedserver.tld/ui</nowiki>'' will open the dashboard provided by ''node-red-dashboard'' package. This removes the need to memorize ports and/or IP addresses. | The result is that a request via a browser to ''<nowiki>http://mynoderedserver.tld</nowiki>'' will open up the node-red flow design interface. Similarly, requests to: ''<nowiki>http://mynoderedserver.tld/ui</nowiki>'' will open the dashboard provided by ''node-red-dashboard'' package. This removes the need to memorize ports and/or IP addresses. |
| |
| ====== Creating an Elegant Multiple Algorithm Random Number Engine in Node Red ====== |
| |
| One problem with Node Red is that function nodes are meant to execute JavaScript code but there is no persistence using the function node such that if the JavaScript code is a class then the class within the function node will have to be instantiated each and every time a message is passed to the input of the function node. |
| |
| It would be nice if Node Red flow would allow for easily adding classes by instantiating the classes when the Node Red flow is deployed (or started) and then re-using the instantiated object every time. There is a way to reuse classes instantiated on startup by using dynamic object instantiation and invocation whilst additionally only using built-in nodes in order to not require any third-party modules. |
| |
| As an example, the following is an implementation as a Node Red flow of a multiple-algorithm random number engine. The flow can be used by using link in and out nodes after specifying the algorithm to be used. |
| |
| ===== Creating the Engine on Startup ===== |
| |
| {{fuss:fuss_iot_node_red_flow_rng_engine.png?512}} |
| |
| The following nodes are used to dynamically instantiate the classes that will generate the random numbers: |
| * the ''Begin'' node is used just to jump start the entire flow when the flow is deployed or node-red is restarted, |
| * each ''Class Definition'' node contains a class that will generate a random number with the only requirement that the class implements at least a ''random()'' method call (perhaps there is a way to create an interface in node red such that each class node is supposed to implement the ''random()'' function (?)), |
| * the ''Instantiation'' class uses the JavaScript ''eval'' function to dynamically create an instance of the random number generating class, |
| * the ''Storage'' node defines the storage where an instance of the random number generating class will be stored, |
| * ''Store'' uses ''flow.set()'' method call internal to Node Red in order to store the instantiated object in memory. |
| |
| ===== Selecting the Algorithm and Calling the Engine ===== |
| |
| After an instance of each class is created and stored, the following flow is used to generate random numbers whenever other flows link using the link-in node and will output the random numbers via the link-out node to be processed. |
| |
| {{fuss:fuss_iot_node_red_flow_invoking.png?512}} |
| |
| The nodes within this flow have the following use: |
| * ''Method Invoker'' is responsible for retrieving a stored instance of the engine and then generating a random number; the node calls ''.random()'' on a dynamically constructed object such that the requirement is that the classes define a ''random()'' method, |
| * ''Normalize [0,1]'' is responsible for fitting the value generated by the clases within the $[0, 1]$ interval (perhps this could be parametrized further on), |
| * the two link-in and link-out nodes should be linked to from other flows in order to process incoming requests for a random number, |
| * ''timestamp'' and ''msg'' are meant just for testing |
| |
| ===== Export ===== |
| |
| <file json rng.json> |
| [{"id":"bf051c9.452f96","type":"tab","label":"Random Number Generators","disabled":false,"info":""},{"id":"3f5cdd9f.a44f52","type":"debug","z":"bf051c9.452f96","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":970,"y":560,"wires":[]},{"id":"4dffce72.2bcd48","type":"inject","z":"bf051c9.452f96","name":"Begin","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":"1","x":310,"y":160,"wires":[["986c2654.33466","f79a2199.e417e"]]},{"id":"9f9325d1.023298","type":"function","z":"bf051c9.452f96","name":"Store","func":"/* Push the object instance onto the pool of global variables. */\nflow.set(msg.topic, msg.payload, msg.store);\n","outputs":0,"noerr":0,"x":990,"y":160,"wires":[]},{"id":"986c2654.33466","type":"template","z":"bf051c9.452f96","name":"Class Definition","field":"payload","fieldType":"msg","format":"javascript","syntax":"plain","template":"/* \n Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,\n All rights reserved. \n \n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n \n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n \n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n \n 3. The names of its contributors may not be used to endorse or promote \n products derived from this software without specific prior written \n permission.\n \n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n \n Any feedback is very welcome.\n http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html\n email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)\n\n Wrapped by Sean McCullough (banksean@gmail.com) into JavaScript,\n Altered by Wizardry and Steamworks (grimore.org) into a JavaScript class-based variation.\n*/\n\nclass MersenneTwister {\n // class methods\n constructor(seed) {\n if (seed === undefined) {\n seed = new Date().getTime();\n }\n /* Period parameters */\n this.N = 624;\n this.M = 397;\n this.MATRIX_A = 0x9908b0df; /* constant vector a */\n this.UPPER_MASK = 0x80000000; /* most significant w-r bits */\n this.LOWER_MASK = 0x7fffffff; /* least significant r bits */\n\n this.mt = new Array(this.N); /* the array for the state vector */\n this.mti = this.N + 1; /* mti==N+1 means mt[N] is not initialized */\n\n this.init_genrand(seed);\n }\n\n /* initializes mt[N] with a seed */\n init_genrand() {\n this.mt[0] = s >>> 0;\n for (this.mti = 1; this.mti < this.N; this.mti++) {\n var s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30);\n this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253)\n + this.mti;\n /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */\n /* In the previous versions, MSBs of the seed affect */\n /* only MSBs of the array mt[]. */\n /* 2002/01/09 modified by Makoto Matsumoto */\n this.mt[this.mti] >>>= 0;\n /* for >32 bit machines */\n }\n }\n\n /* initialize by an array with array-length */\n /* init_key is the array for initializing keys */\n /* key_length is its length */\n /* slight change for C++, 2004/2/26 */\n init_by_array(init_key, key_length) {\n var i, j, k;\n this.init_genrand(19650218);\n i = 1; j = 0;\n k = (this.N > key_length ? this.N : key_length);\n for (; k; k--) {\n var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)\n this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525)))\n + init_key[j] + j; /* non linear */\n this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */\n i++; j++;\n if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; }\n if (j >= key_length) j = 0;\n }\n for (k = this.N - 1; k; k--) {\n var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);\n this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941))\n - i; /* non linear */\n this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */\n i++;\n if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; }\n }\n\n this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */\n }\n\n /* generates a random number on [0,0xffffffff]-interval */\n genrand_int32() {\n var y;\n var mag01 = new Array(0x0, this.MATRIX_A);\n /* mag01[x] = x * MATRIX_A for x=0,1 */\n\n if (this.mti >= this.N) { /* generate N words at one time */\n var kk;\n\n if (this.mti == this.N + 1) /* if init_genrand() has not been called, */\n this.init_genrand(5489); /* a default initial seed is used */\n\n for (kk = 0; kk < this.N - this.M; kk++) {\n y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);\n this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n for (; kk < this.N - 1; kk++) {\n y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);\n this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK);\n this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];\n\n this.mti = 0;\n }\n\n y = this.mt[this.mti++];\n\n /* Tempering */\n y ^= (y >>> 11);\n y ^= (y << 7) & 0x9d2c5680;\n y ^= (y << 15) & 0xefc60000;\n y ^= (y >>> 18);\n\n return y >>> 0;\n }\n\n /* generates a random number on [0,0x7fffffff]-interval */\n genrand_int31() {\n return (this.genrand_int32() >>> |