-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathget-python-data.json
1 lines (1 loc) · 45.7 KB
/
get-python-data.json
1
[{"id":"c8d536e94f59d49d","type":"tab","label":"Run Python code","disabled":false,"info":"","env":[]},{"id":"1ce64dfc715f9858","type":"tab","label":"VISA Test","disabled":false,"info":"","env":[]},{"id":"ecf996dbcbeedbfd","type":"subflow","name":"Get Servers","info":"Simply run the `jupyter server list` command and parse the output as an array of objects containing server properties.","category":"Jupyter","in":[{"x":60,"y":80,"wires":[{"id":"4ea97c5b74114d39"}]}],"out":[{"x":580,"y":80,"wires":[{"id":"5e6abde9f34b8fc0","port":0}]}],"env":[],"meta":{"module":"node-red-jupyter-tools","version":"0.1","author":"Paulo Felipe Jarschel <[email protected]>","desc":"Get a list of running Jupyter servers","keywords":"jupyter, python","license":"GPL-3.0"},"color":"#D8BFD8","icon":"font-awesome/fa-list-ul"},{"id":"e8b1d6f8290a4e3b","type":"subflow","name":"Jupyter Manager","info":"Manage Jupyter servers available to the flow.\r\n\r\nIt allows one server/kernel/session to be running globally (within node-red).\r\nAt the moment, it does not allow a connection to an existing server, but it should be easy to implement.\r\n\r\nThe allowed inputs are:\r\n 1. \"start\": Simply start a server, kernel and session if not already started;\r\n 2. \"restart\": Restart kernel/session (useful if something is wrong, without the need of messing with the server);\r\n 3. \"stop\": Stop the running server. If for some reason a running server was \"lost\" to the flow (e.g.: after a crash), it **WILL NOT BE STOPPED**;\r\n 4. \"stop all\": Stop all running servers on the machine. **USE CAUTION WITH THIS ONE!**\r\n\r\nThere is a status indicator that runs at a 1 second interval. If the flow is connected to a server, it will be indicated.\r\n\r\nIt doesn't return anything useful.","category":"Jupyter","in":[{"x":60,"y":520,"wires":[{"id":"a93dad4d58c7544b"}]}],"out":[{"x":1280,"y":480,"wires":[{"id":"49419187d17c94fa","port":0},{"id":"f4fa13f4f5984f4a","port":0}]}],"env":[],"meta":{"module":"node-red-jupyter-tools","version":"0.1","author":"Paulo Felipe Jarschel <[email protected]>","desc":"Manage Jupyter servers available to the flow","keywords":"jupyter, python"},"color":"#D8BFD8","icon":"font-awesome/fa-server","status":{"x":300,"y":120,"wires":[{"id":"dac568d94b1d9143","port":0}]}},{"id":"0dcc892460200b20","type":"subflow","name":"Execute Python Code","info":"Takes a text input and attempt to run it at a Jupyter server.\r\nMultiline supported.\r\nEntire thousands-of-lines codes are supported.\r\n\r\nThe use of a template node as input is recommended, but anything goes.\r\n\r\nPython output is passed on as the msg.payload and logged (cropped) to the console.","category":"Jupyter","in":[{"x":60,"y":80,"wires":[{"id":"2c77f2ec0596b24f"}]}],"out":[{"x":340,"y":80,"wires":[{"id":"2c77f2ec0596b24f","port":0}]}],"env":[],"meta":{"module":"node-red-jupyter-tools","version":"0.1","author":"Paulo Felipe Jarschel <[email protected]>","desc":"Execute python code on a running Jupyter server","keywords":"jupyter, python","license":"GPL-3.0"},"color":"#D8BFD8","icon":"font-awesome/fa-cogs"},{"id":"30cc2af1b6f3f4e2","type":"subflow","name":"Get Data from Python","info":"Get data from a variable that exists in the Jupyter kernel.\r\n\r\nThe input payload is the variable name, or an array with the variable names (as strings).\r\nIf the requested variable(s) is(are) not defined, an empty string will be returned instead.\r\nAlso, if the requested variable is actually a non-serializable object, an empty string will be returned as well.\r\n\r\nCurrently, it returns a JSON containing the variables names and data as key/value pairs.\r\nSo far, this approach seems the most effective, as it can handle strings, numbers, arrays and etc. with ease.\r\n\r\nLists, tuples, dicts, numpy arrays and pandas dataframes are supported (nested or not).","category":"Jupyter","in":[{"x":80,"y":380,"wires":[{"id":"af3a7c35043180ad"}]}],"out":[{"x":1100,"y":380,"wires":[{"id":"04f1e343d60b2eb2","port":0},{"id":"7667d6b5b54a77c9","port":0}]}],"env":[],"meta":{"module":"node-red-jupyter-tools","version":"0.1","author":"Paulo Felipe Jarschel <[email protected]>","desc":"Get data from a variable that exists in the Jupyter kernel","keywords":"jupyter, python","license":"GPL-3.0"},"color":"#D8BFD8","icon":"font-awesome/fa-clipboard"},{"id":"f3413dd9cf7452e9","type":"subflow","name":"VISA Init","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"91e5a710db54f977"}]}],"out":[{"x":630,"y":80,"wires":[{"id":"9f7344f3a51f8676","port":0}]}],"env":[],"meta":{},"color":"#DDAA99","inputLabels":["Trigger"],"outputLabels":["Execution Output"]},{"id":"dfccab4af70a2e16","type":"subflow","name":"VISA Open","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"a7ba59e9cc7ad1b3"}]}],"out":[{"x":1010,"y":80,"wires":[{"id":"7fcac3ddc87881db","port":0}]},{"x":1010,"y":180,"wires":[{"id":"098e01a01f57e0da","port":0}]}],"env":[],"meta":{},"color":"#DDAA99","inputLabels":["Address"],"outputLabels":["Execution Output","Instrument ID"]},{"id":"6373cee7258498f1","type":"subflow","name":"VISA Query","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"8feab4879a2270ac"}]}],"out":[{"x":660,"y":80,"wires":[{"id":"4c0b52865ca07640","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"4bab381a44e24d4f","type":"subflow","name":"VISA Read","info":"","category":"","in":[{"x":100,"y":160,"wires":[{"id":"32de5b10a0978853"}]}],"out":[{"x":700,"y":160,"wires":[{"id":"1a87923532898bf0","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"0c2d06d40ba312db","type":"subflow","name":"VISA Write","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"dcc0edbcb3d2a46c"}]}],"out":[{"x":660,"y":80,"wires":[{"id":"6ef007474cd48661","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"0216f2f41feb6ed2","type":"junction","z":"1ce64dfc715f9858","x":560,"y":500,"wires":[["655374db8be282a1","836f08f41e0e3ec5"]]},{"id":"6ebd787ec6d49d91","type":"junction","z":"1ce64dfc715f9858","x":360,"y":500,"wires":[["580b1333e0011fbf","0216f2f41feb6ed2"]]},{"id":"7b54e181a52bc9ce","type":"junction","z":"1ce64dfc715f9858","x":400,"y":360,"wires":[["8ee174d72dcf7791","6ebd787ec6d49d91"]]},{"id":"836f08f41e0e3ec5","type":"junction","z":"1ce64dfc715f9858","x":820,"y":500,"wires":[["5f6bb7fd91b4e3fd"]]},{"id":"e508d1d9930d09ac","type":"junction","z":"e8b1d6f8290a4e3b","x":1300,"y":40,"wires":[["09a29d5ea529f1fd"]]},{"id":"09a29d5ea529f1fd","type":"junction","z":"e8b1d6f8290a4e3b","x":20,"y":20,"wires":[["268a1ab4144dc4d0"]]},{"id":"4ea97c5b74114d39","type":"exec","z":"ecf996dbcbeedbfd","command":"jupyter server list","addpay":"","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"","x":230,"y":80,"wires":[["5e6abde9f34b8fc0"],["5e6abde9f34b8fc0"],[]]},{"id":"5e6abde9f34b8fc0","type":"function","z":"ecf996dbcbeedbfd","name":"Get server list","func":"// Prepare output payload\nlet servers_info = [];\n\n// Check if payload is actually a string, and if it is the expected output\nif (typeof msg.payload === \"string\" || msg.payload instanceof String) {\n if (msg.payload.indexOf(\"Currently running servers:\") >= 0) {\n // Create array of servers \n let server_list = msg.payload.split(\"\\r\\n\").slice(1, -1);\n\n // Parse each server string to get server info\n server_list.forEach(function(item, index){\n let url_stub = item.split(\":\")[1];\n let server_info = {\n \"baseUrl\": \"http:\" + url_stub,\n \"wsUrl\": \"ws:\" + url_stub,\n \"port\": item.split(\":\")[2].split(\"/\")[0],\n \"token\": item.split(\"?token=\")[1].split(\" :: \")[0],\n \"dir\": item.split(\" :: \")[1],\n }\n servers_info.push(server_info);\n });\n }\n}\n\n// Set servers info as message payload\nmsg.payload = servers_info;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":80,"wires":[[]]},{"id":"a93dad4d58c7544b","type":"switch","z":"e8b1d6f8290a4e3b","name":"Start/Stop","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"start","vt":"str"},{"t":"eq","v":"reset","vt":"str"},{"t":"eq","v":"stop","vt":"str"},{"t":"eq","v":"stop all","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":220,"y":520,"wires":[["33577d1edcdb882a"],["75e5f62dfe062d31"],["e4676eb8a4fb9f64"],["ed5dad1289c76560"]]},{"id":"6788e19190e77d1b","type":"comment","z":"e8b1d6f8290a4e3b","name":"Commands are: start, reset, stop, stop all","info":"","x":240,"y":460,"wires":[]},{"id":"ed5dad1289c76560","type":"subflow:ecf996dbcbeedbfd","z":"e8b1d6f8290a4e3b","name":"","x":590,"y":700,"wires":[["5df34bd1a9b1df64"]]},{"id":"5df34bd1a9b1df64","type":"function","z":"e8b1d6f8290a4e3b","name":"Stop all","func":"// Check if message payload is actually an array\nif(Array.isArray(msg.payload)) {\n let servers = RED.util.cloneMessage(msg).payload;\n\n // Stop session\n if (global.get(\"jupyter_session\") != undefined) {\n global.get(\"jupyter_session\").shutdown();\n }\n\n // Stop all found servers\n servers.forEach(function(item) {\n if (typeof item.port === 'string' || item.port instanceof String) {\n msg.payload = item.port;\n node.send(msg);\n }\n });\n \n // Clear globals\n global.set(\"jupyter_port\", undefined);\n global.set(\"jupyter_token\", undefined);\n global.set(\"jupyter_wsUrl\", undefined);\n global.set(\"jupyter_baseUrl\", undefined);\n global.set(\"jupyter_session\", undefined);\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":700,"wires":[["a78a0fb4dc99bd11"]]},{"id":"a78a0fb4dc99bd11","type":"exec","z":"e8b1d6f8290a4e3b","command":"jupyter server stop","addpay":"payload","append":"","useSpawn":"true","timer":"0","winHide":true,"oldrc":false,"name":"","x":970,"y":660,"wires":[[],[],["49419187d17c94fa"]]},{"id":"057e23ae535722d6","type":"function","z":"e8b1d6f8290a4e3b","name":"Find invoked server","func":"// Check if message payload is actually an array\nif(Array.isArray(msg.payload)) {\n let servers = RED.util.cloneMessage(msg).payload;\n\n // Check if any of the running servers was invoked from here\n servers.forEach(function(item) {\n if (typeof item.port === 'string' || item.port instanceof String) {\n if (item.port == global.get(\"jupyter_port\")) {\n // If it was, stop session, the server, and clear globals\n if (global.get(\"jupyter_session\") != undefined) {\n global.get(\"jupyter_session\").shutdown();\n }\n global.set(\"jupyter_port\", undefined);\n global.set(\"jupyter_token\", undefined);\n global.set(\"jupyter_wsUrl\", undefined);\n global.set(\"jupyter_baseUrl\", undefined);\n global.set(\"jupyter_session\", undefined);\n \n msg.payload = item.port;\n node.send(msg);\n }\n }\n });\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":620,"wires":[["a78a0fb4dc99bd11"]]},{"id":"e4676eb8a4fb9f64","type":"subflow:ecf996dbcbeedbfd","z":"e8b1d6f8290a4e3b","name":"","x":530,"y":620,"wires":[["057e23ae535722d6"]]},{"id":"e36ce5fd3b39e4e4","type":"function","z":"e8b1d6f8290a4e3b","name":"Check existing servers","func":"let is_running = false;\n\n// Check if there is information of a running server\nif (global.get(\"jupyter_port\") != undefined) {\n // If so, check if it is actually running\n \n // Check if message payload is actually an array\n if(Array.isArray(msg.payload)) {\n // Check if global port corresponds to a running server\n msg.payload.forEach(function(item) {\n if (typeof item.port === 'string' || item.port instanceof String) {\n if (item.port == global.get(\"jupyter_port\")) {\n // If so, re-set globals and check session status\n is_running = true;\n global.set(\"jupyter_port\", item.port);\n global.set(\"jupyter_token\", item.token);\n global.set(\"jupyter_wsUrl\", item.wsUrl);\n global.set(\"jupyter_baseUrl\", item.baseUrl);\n \n if (global.get(\"jupyter_session\") == undefined) {\n msg.payload = \"start session\";\n } else {\n if (global.get(\"jupyter_session\").serverSettings.token != item.token) {\n global.get(\"jupyter_session\").shutdown();\n global.set(\"jupyter_session\", undefined);\n msg.payload = \"start session\";\n } else {\n msg.payload = \"\";\n }\n }\n }\n }\n });\n }\n}\n\n// If not, just go on starting a new one\nif (!is_running) {\n // Clear all globals and session info\n if (global.get(\"jupyter_session\") != undefined) {\n global.get(\"jupyter_session\").shutdown();\n }\n global.set(\"jupyter_port\", undefined);\n global.set(\"jupyter_token\", undefined);\n global.set(\"jupyter_wsUrl\", undefined);\n global.set(\"jupyter_baseUrl\", undefined);\n global.set(\"jupyter_session\", undefined);\n\n msg.payload = \"start server\";\n}\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":140,"wires":[["08afc66a86721576"]]},{"id":"33577d1edcdb882a","type":"subflow:ecf996dbcbeedbfd","z":"e8b1d6f8290a4e3b","name":"","x":430,"y":140,"wires":[["e36ce5fd3b39e4e4"]]},{"id":"08afc66a86721576","type":"switch","z":"e8b1d6f8290a4e3b","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"start server","vt":"str"},{"t":"eq","v":"start session","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":830,"y":140,"wires":[["28a8dd406840cde4"],["c13c555871daa215"]]},{"id":"28a8dd406840cde4","type":"exec","z":"e8b1d6f8290a4e3b","command":"jupyter server","addpay":"","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"","x":700,"y":260,"wires":[["d88a58f4ed2188a3"],["d88a58f4ed2188a3"],["d88a58f4ed2188a3"]]},{"id":"d88a58f4ed2188a3","type":"function","z":"e8b1d6f8290a4e3b","name":"Parse URL and token","func":"let main_identifier = \"copy and paste one of these URLs:\\r\\n\"\nif (typeof msg.payload === 'string' || msg.payload instanceof String) {\n if (msg.payload.indexOf(main_identifier) >= 0) {\n let full_url = msg.payload.split(main_identifier)[1].split(\"\\r\\n\")[0];\n let url_stub = full_url.split(\":\")[1];\n global.set(\"jupyter_port\", full_url.split(\":\")[2].split(\"/\")[0]);\n global.set(\"jupyter_token\", full_url.split(\"?token=\")[1].split(\" :: \")[0]);\n global.set(\"jupyter_wsUrl\", \"ws:\" + url_stub);\n global.set(\"jupyter_baseUrl\", \"http:\" + url_stub);\n\n msg.payload = \"start session\";\n return msg;\n }\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":960,"y":260,"wires":[["c13c555871daa215"]]},{"id":"c13c555871daa215","type":"function","z":"e8b1d6f8290a4e3b","name":"Session Manager","func":"// Import Jupyter Services\n// const services = require('@jupyterlab/services');\nconst services = global.get('jp_services');\n\nif (msg.payload == \"start session\") {\n // Check if session exists, and end it\n let resetting = false;\n if (global.get(\"jupyter_session\") != undefined) {\n resetting = true;\n console.log('Ending session…');\n global.get(\"jupyter_session\").shutdown().then(function () {\n global.set(\"jupyter_session\", undefined);\n new_session();\n });\n }\n\n // Start a new session.\n function new_session() {\n const options = {\n path: 'foo.ipynb',\n type: 'notebook',\n name: 'foo.ipynb',\n kernel: {\n name: 'python'\n }\n };\n\n let port = global.get(\"jupyter_port\");\n let token = global.get(\"jupyter_token\");\n let baseUrl = global.get(\"jupyter_baseUrl\") + \":\" + port + \"/\";\n let wsUrl = global.get(\"jupyter_wsUrl\") + \":\" + port + \"/\";\n console.log('Starting session…');\n\n const kernelManager = new services.KernelManager();\n kernelManager.serverSettings.baseUrl = baseUrl;\n kernelManager.serverSettings.wsUrl = wsUrl;\n kernelManager.serverSettings.token = token;\n\n const sessionManager = new services.SessionManager({ kernelManager });\n sessionManager.serverSettings.baseUrl = baseUrl;\n sessionManager.serverSettings.wsUrl = wsUrl;\n sessionManager.serverSettings.token = token;\n\n sessionManager.startNew(options).then(function (s) {\n global.set(\"jupyter_session\", s);\n node.send(msg);\n });\n }\n\n if (!resetting) {\n new_session();\n }\n}\n\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":400,"wires":[["82f96099b7551fdf"]]},{"id":"82f96099b7551fdf","type":"template","z":"e8b1d6f8290a4e3b","name":"Base imports","field":"payload","fieldType":"msg","format":"python","syntax":"plain","template":"import os\nimport sys\nimport json\nprint(\"Base imports ok\")","output":"str","x":910,"y":400,"wires":[["f4fa13f4f5984f4a"]]},{"id":"54771eacd975f1bb","type":"comment","z":"e8b1d6f8290a4e3b","name":"Manage stopping servers","info":"","x":690,"y":560,"wires":[]},{"id":"97a99757b0a0dc12","type":"comment","z":"e8b1d6f8290a4e3b","name":"Manage starting servers and resetting kernels","info":"","x":710,"y":80,"wires":[]},{"id":"49419187d17c94fa","type":"function","z":"e8b1d6f8290a4e3b","name":"Force code 0","func":"msg.payload.code = 0;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1100,"y":520,"wires":[["e508d1d9930d09ac"]]},{"id":"b57feb0361bc771b","type":"inject","z":"e8b1d6f8290a4e3b","name":"Check status","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":120,"y":80,"wires":[["268a1ab4144dc4d0"]]},{"id":"268a1ab4144dc4d0","type":"subflow:ecf996dbcbeedbfd","z":"e8b1d6f8290a4e3b","name":"","x":110,"y":120,"wires":[["dac568d94b1d9143"]]},{"id":"dac568d94b1d9143","type":"function","z":"e8b1d6f8290a4e3b","name":"Check existing servers","func":"let is_running = false;\n\n// Check if there is information of a running server\nif (global.get(\"jupyter_port\") != undefined) {\n // If so, check if it is actually running\n // Check if message payload is actually an array\n if(Array.isArray(msg.payload)) {\n // Check if global port corresponds to a running server\n msg.payload.forEach(function(item) {\n if (typeof item.port === 'string' || item.port instanceof String) {\n if (item.port == global.get(\"jupyter_port\")) {\n is_running = true;\n }\n }\n });\n }\n}\n\n// Set status\nif (is_running) {\n msg.payload = \"Active on port \" + global.get(\"jupyter_port\");\n} else {\n msg.payload = \"Stopped\";\n}\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":160,"y":180,"wires":[[]]},{"id":"f4fa13f4f5984f4a","type":"subflow:0dcc892460200b20","z":"e8b1d6f8290a4e3b","name":"","x":1120,"y":400,"wires":[["e508d1d9930d09ac"]]},{"id":"75e5f62dfe062d31","type":"subflow:ecf996dbcbeedbfd","z":"e8b1d6f8290a4e3b","name":"","x":390,"y":500,"wires":[["5fed117cbe362397"]]},{"id":"5fed117cbe362397","type":"function","z":"e8b1d6f8290a4e3b","name":"Check existing","func":"// Check if there is information of a running server\nif (global.get(\"jupyter_port\") != undefined) {\n // If so, check if it is actually running\n // Check if message payload is actually an array\n if(Array.isArray(msg.payload)) {\n // Check if global port corresponds to a running server\n msg.payload.forEach(function(item) {\n if (typeof item.port === 'string' || item.port instanceof String) {\n if (item.port == global.get(\"jupyter_port\")) {\n // If so, re-set globals and check session status\n global.set(\"jupyter_port\", item.port);\n global.set(\"jupyter_token\", item.token);\n global.set(\"jupyter_wsUrl\", item.wsUrl);\n global.set(\"jupyter_baseUrl\", item.baseUrl);\n \n msg.payload = \"start session\";\n }\n }\n });\n }\n} else {\n msg.payload = \"\"\n}\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":440,"wires":[["c13c555871daa215"]]},{"id":"2c77f2ec0596b24f","type":"function","z":"0dcc892460200b20","name":"Send to Jupyter","func":"let session = global.get(\"jupyter_session\");\n\nif (session != undefined) {\n const future = session.kernel.requestExecute({ code: msg.payload, silent: false });\n future.onIOPub = function(reply) {\n if (reply.header.msg_type == 'stream') {\n msg.payload = reply.content.text;\n while (msg.payload.slice(-1) == \"\\n\" || msg.payload.slice(-1) == \"\\r\") {\n msg.payload = msg.payload.slice(0, -1);\n }\n\n if (reply.content.text.length > 1000) {\n console.log(\n reply.content.text.substring(0, 499) +\n \"\\n...\\n\" +\n reply.content.text.substring(reply.content.text.length - 500)\n );\n } else {\n console.log(reply.content.text);\n }\n \n }\n };\n future.onReply = function(reply) {\n if (reply.content.status == 'ok') {\n msg.code = 0;\n // console.log('Python execution OK!');\n }\n else {\n console.log(\"Something went wrong with the python execution:\");\n console.log(reply.content.evalue);\n msg.code = 1;\n }\n };\n future.done.then(function(){\n node.send(msg);\n }).catch(function (err) {\n console.error(err);\n });\n\n msg.payload = \"\";\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":80,"wires":[[]]},{"id":"c5b4ae7248df176f","type":"template","z":"30cc2af1b6f3f4e2","name":"Request Variable","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"import json\n\nvar_name = \"{{{payload}}}\"\nvar = \"\"\n\n# Try importing numpy and pandas\nnpok = False\npdok = False\ntry:\n import numpy as np\n npok = True\nexcept:\n pass\ntry:\n import pandas as pd\n pdok = True\nexcept:\n pass\n \n\n# Functions\n# If it is a numpy array, convert it to list\ndef convert_np(var):\n # If numpy is not installed, it does nothing\n changed = False\n if npok:\n if isinstance(var, np.ndarray):\n var = var.tolist()\n changed = True\n return var, changed\n\n# If it is a pandas dataframe, convert it to a json string\ndef convert_df(var):\n # If pandas is not installed, it does nothing\n changed = False\n if pdok:\n if isinstance(var, pd.DataFrame):\n var = var.to_json()\n changed = True\n return var, changed\n\n# If it is a dict, list or tuple, recursively try to find numpy arrays and pandas dataframes to convert\ndef walk_list_convert(var):\n changed = False\n if isinstance(var, list) or isinstance(var, tuple):\n for i in range(len(var)):\n it = var[i]\n newit, it_changed = check_convert_all(it)\n if it_changed:\n var[i] = newit\n changed = True\n return var, changed\n \ndef walk_dict_convert(var):\n changed = False\n if isinstance(var, dict):\n for key in var:\n it = var[key]\n newit, it_changed = check_convert_all(it)\n if it_changed:\n var[key] = newit\n changed = True\n return var, changed\n\n# Function to check all conversion possibilities\ndef check_convert_all(var):\n changed = False \n var, changed = convert_np(var)\n if not changed:\n var, changed = convert_df(var)\n if not changed:\n var, changed = walk_list_convert(var)\n if not changed:\n var, changed = walk_dict_convert(var)\n \n return var, changed\n\n\n# Try to find variable\ntry:\n var = eval(var_name)\nexcept:\n pass\n\n# Check is object is numpy array or pandas dataframe\nvar, changed = check_convert_all(var)\n\n# Quietly drop non-serializable objects\ntry:\n print(json.dumps({var_name: var}))\nexcept:\n print(json.dumps({var_name: \"\"}))","output":"str","x":330,"y":500,"wires":[["8d8e840fa1598939"]]},{"id":"04f1e343d60b2eb2","type":"function","z":"30cc2af1b6f3f4e2","name":"Convert to JSON","func":"msg.payload = JSON.parse(msg.payload);\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":790,"y":500,"wires":[[]]},{"id":"8d8e840fa1598939","type":"subflow:0dcc892460200b20","z":"30cc2af1b6f3f4e2","name":"","x":560,"y":500,"wires":[["04f1e343d60b2eb2"]]},{"id":"878056838036a20a","type":"split","z":"30cc2af1b6f3f4e2","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":210,"y":160,"wires":[["2d1b21ca48c7e0ea"]]},{"id":"af3a7c35043180ad","type":"switch","z":"30cc2af1b6f3f4e2","name":"","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"array","vt":"array"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":190,"y":380,"wires":[["878056838036a20a"],["c5b4ae7248df176f"]]},{"id":"7667d6b5b54a77c9","type":"join","z":"30cc2af1b6f3f4e2","name":"","mode":"custom","build":"merged","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":970,"y":260,"wires":[[]]},{"id":"2d1b21ca48c7e0ea","type":"template","z":"30cc2af1b6f3f4e2","name":"Request Variable","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"import json\n\nvar_name = \"{{{payload}}}\"\nvar = \"\"\n\n# Try importing numpy and pandas\nnpok = False\npdok = False\ntry:\n import numpy as np\n npok = True\nexcept:\n pass\ntry:\n import pandas as pd\n pdok = True\nexcept:\n pass\n \n\n# Functions\n# If it is a numpy array, convert it to list\ndef convert_np(var):\n # If numpy is not installed, it does nothing\n changed = False\n if npok:\n if isinstance(var, np.ndarray):\n var = var.tolist()\n changed = True\n return var, changed\n\n# If it is a pandas dataframe, convert it to a json string\ndef convert_df(var):\n # If pandas is not installed, it does nothing\n changed = False\n if pdok:\n if isinstance(var, pd.DataFrame):\n var = var.to_json()\n changed = True\n return var, changed\n\n# If it is a dict, list or tuple, recursively try to find numpy arrays and pandas dataframes to convert\ndef walk_list_convert(var):\n changed = False\n if isinstance(var, list) or isinstance(var, tuple):\n for i in range(len(var)):\n it = var[i]\n newit, it_changed = check_convert_all(it)\n if it_changed:\n var[i] = newit\n changed = True\n return var, changed\n \ndef walk_dict_convert(var):\n changed = False\n if isinstance(var, dict):\n for key in var:\n it = var[key]\n newit, it_changed = check_convert_all(it)\n if it_changed:\n var[key] = newit\n changed = True\n return var, changed\n\n# Function to check all conversion possibilities\ndef check_convert_all(var):\n changed = False \n var, changed = convert_np(var)\n if not changed:\n var, changed = convert_df(var)\n if not changed:\n var, changed = walk_list_convert(var)\n if not changed:\n var, changed = walk_dict_convert(var)\n \n return var, changed\n\n\n# Try to find variable\ntry:\n var = eval(var_name)\nexcept:\n pass\n\n# Check is object is numpy array or pandas dataframe\nvar, changed = check_convert_all(var)\n\n# Quietly drop non-serializable objects\ntry:\n print(json.dumps({var_name: var}))\nexcept:\n print(json.dumps({var_name: \"\"}))","output":"str","x":330,"y":260,"wires":[["aaa84ec9833e67e1"]]},{"id":"53a6adacf88cb9db","type":"function","z":"30cc2af1b6f3f4e2","name":"Convert to JSON","func":"msg.payload = JSON.parse(msg.payload);\nif (msg.parts.index == msg.parts.count - 1) {\n msg.complete = true;\n}\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":790,"y":260,"wires":[["7667d6b5b54a77c9"]]},{"id":"aaa84ec9833e67e1","type":"subflow:0dcc892460200b20","z":"30cc2af1b6f3f4e2","name":"","x":560,"y":260,"wires":[["53a6adacf88cb9db"]]},{"id":"91e5a710db54f977","type":"template","z":"f3413dd9cf7452e9","name":"Initialize VISA","field":"payload","fieldType":"msg","format":"python","syntax":"plain","template":"# We begin with a safe and efficient VISA initialization routine\nvisa_import_ok = False\nvisa_rm_ok = False\ntry:\n visa\n visa_import_ok = True\nexcept:\n try:\n import pyvisa as visa\n visa_import_ok = True\n\n visa_open_devs = []\n\n # Function to aid in managing open instruments\n def FindOpenResource(res_name:str) -> visa.Resource:\n visa_rm_list = visa_rm.list_opened_resources()\n\n # Clear closed devices\n for res in visa_open_devs.copy():\n if res not in visa_rm_list:\n visa_open_devs.remove(res)\n \n # Find desired device\n for res in visa_rm_list:\n if res.resource_info.resource_name == res_name:\n return res\n raise Exception(f\"Error: No resource matching the name {res_name} found!\")\n\n except Exception as e:\n # print(e)\n print(\"Error importing pyvisa! Is it installed?\")\n\nif visa_import_ok:\n try:\n visa_rm\n visa_rm_ok = True\n except:\n try:\n visa_rm = visa.ResourceManager()\n visa_rm_ok = True\n except Exception as e:\n # print(e)\n print(\"Error initializing VISA Resource Manager. Is a VISA backend available? (E.g.: NI, Keysight)\")\n\nif visa_rm_ok:\n if visa_rm.list_resources:\n print(\"VISA initialization OK!\")","output":"str","x":190,"y":80,"wires":[["9f7344f3a51f8676"]]},{"id":"9f7344f3a51f8676","type":"subflow:0dcc892460200b20","z":"f3413dd9cf7452e9","name":"Execute Python Code","x":400,"y":80,"wires":[[]],"icon":"font-awesome/fa-file-text-o"},{"id":"d0b24ba974be5c0f","type":"template","z":"dfccab4af70a2e16","name":"Connect to instrument","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"# The code as shown here uses the message payload received by the node, via Mustache Template\ninst_addr = \"{{{payload}}}\"\ntry:\n if visa_rm_ok: \n try:\n # Check if open\n FindOpenResource(inst_addr)\n print(f\"Resource at {inst_addr} was already open!\")\n except:\n try:\n # Try opening device\n visa_open_devs.append(visa_rm.open_resource(inst_addr))\n\n # If communicating via socket, set termination to line end\n if \"::SOCKET\" in inst_addr:\n visa_open_devs[-1].read_termination = \"\\n\"\n \n print(f\"Successfully opened resource at {inst_addr}.\")\n \n except Exception as e:\n print(f\"Error opening device:\\n{e}\")\n else:\n print(\"VISA initialization not complete, check previous output!\")\nexcept Exception as e:\n print(\"VISA initialization not complete! Make sure the Initialize VISA node has been executed before!\")\n\n","output":"str","x":440,"y":80,"wires":[["7fcac3ddc87881db"]]},{"id":"7fcac3ddc87881db","type":"subflow:0dcc892460200b20","z":"dfccab4af70a2e16","name":"Execute Python Code","x":680,"y":80,"wires":[["e0eaa6cb25b0f4f2"]],"icon":"font-awesome/fa-file-text-o"},{"id":"a7ba59e9cc7ad1b3","type":"change","z":"dfccab4af70a2e16","name":"","rules":[{"t":"set","p":"inst_addr","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":210,"y":80,"wires":[["d0b24ba974be5c0f"]]},{"id":"aa2b8c2162c63d61","type":"template","z":"dfccab4af70a2e16","name":"Get resource name","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"# The code as shown here uses the message payload received by the node, via Mustache Template\ninst_addr = \"{{{payload}}}\"\ntry:\n print(FindOpenResource(inst_addr).resource_info.resource_name)\nexcept Exception as e:\n print(f\"Error getting device info:\\n{e}\")","output":"str","x":570,"y":180,"wires":[["098e01a01f57e0da"]]},{"id":"e0eaa6cb25b0f4f2","type":"switch","z":"dfccab4af70a2e16","name":"If execution was OK","property":"code","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":150,"y":180,"wires":[["8e2706a703c847ab"]]},{"id":"8e2706a703c847ab","type":"change","z":"dfccab4af70a2e16","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"inst_addr","tot":"flow"},{"t":"set","p":"topic","pt":"msg","to":"inst","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":360,"y":180,"wires":[["aa2b8c2162c63d61"]]},{"id":"098e01a01f57e0da","type":"subflow:0dcc892460200b20","z":"dfccab4af70a2e16","name":"Execute Python Code","x":800,"y":180,"wires":[[]],"icon":"font-awesome/fa-file-text-o"},{"id":"22790d02bd6d68b0","type":"template","z":"6373cee7258498f1","name":"query","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"# The code as shown here uses the message payload received by the node, via Mustache Template\ninst_addr = \"{{{payload.inst}}}\"\ntry:\n if visa_rm_ok: \n try:\n # Check if open\n inst = FindOpenResource(inst_addr)\n response = inst.query(\"{{{payload.cmd}}}\")\n print(response)\n except Exception as e:\n print(\"Error querying from device:\\n{e}\")\n else:\n print(\"VISA initialization not complete, check previous output!\")\nexcept Exception as e:\n print(\"VISA initialization not complete! Make sure the Initialize VISA node has been executed before!\")\n\n","output":"str","x":310,"y":80,"wires":[["4c0b52865ca07640"]]},{"id":"4c0b52865ca07640","type":"subflow:0dcc892460200b20","z":"6373cee7258498f1","name":"","x":500,"y":80,"wires":[[]]},{"id":"8feab4879a2270ac","type":"join","z":"6373cee7258498f1","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":170,"y":80,"wires":[["22790d02bd6d68b0"]]},{"id":"7b9e12623e2d2148","type":"template","z":"4bab381a44e24d4f","name":"read","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"# The code as shown here uses the message payload received by the node, via Mustache Template\ninst_addr = \"{{{payload.inst}}}\"\ntry:\n if visa_rm_ok: \n try:\n # Check if open\n inst = FindOpenResource(inst_addr)\n response = inst.read()\n print(response)\n except Exception as e:\n print(f\"Error reading from device\\n{e}\")\n else:\n print(\"VISA initialization not complete, check previous output!\")\nexcept Exception as e:\n print(\"VISA initialization not complete! Make sure the Initialize VISA node has been executed before!\")\n\n","output":"str","x":350,"y":160,"wires":[["1a87923532898bf0"]]},{"id":"1a87923532898bf0","type":"subflow:0dcc892460200b20","z":"4bab381a44e24d4f","name":"","x":540,"y":160,"wires":[[]]},{"id":"32de5b10a0978853","type":"join","z":"4bab381a44e24d4f","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":210,"y":160,"wires":[["7b9e12623e2d2148"]]},{"id":"5029c71fb52479dc","type":"template","z":"0c2d06d40ba312db","name":"write","field":"payload","fieldType":"msg","format":"python","syntax":"mustache","template":"# The code as shown here uses the message payload received by the node, via Mustache Template\ninst_addr = \"{{{payload.inst}}}\"\ntry:\n if visa_rm_ok: \n try:\n # Check if open\n inst = FindOpenResource(inst_addr)\n inst.write(\"{{{payload.cmd}}}\")\n except Exception as e:\n print(\"Error writing to device:\\n{e}\")\n else:\n print(\"VISA initialization not complete, check previous output!\")\nexcept Exception as e:\n print(\"VISA initialization not complete! Make sure the Initialize VISA node has been executed before!\")\n\n","output":"str","x":310,"y":80,"wires":[["6ef007474cd48661"]]},{"id":"6ef007474cd48661","type":"subflow:0dcc892460200b20","z":"0c2d06d40ba312db","name":"","x":500,"y":80,"wires":[[]]},{"id":"dcc0edbcb3d2a46c","type":"join","z":"0c2d06d40ba312db","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":170,"y":80,"wires":[["5029c71fb52479dc"]]},{"id":"dcf49513c37c4ddb","type":"inject","z":"c8d536e94f59d49d","name":"Run","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":250,"y":400,"wires":[["0ee359c162a15c3c"]]},{"id":"0ee359c162a15c3c","type":"template","z":"c8d536e94f59d49d","name":"Python Code","field":"payload","fieldType":"msg","format":"python","syntax":"plain","template":"print('running')\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nprint('import ok')\n\nn = 1000\nx = np.linspace(-10, 10, n)\ny = np.sin(x) + 0.4*(np.random.random(n) - 0.5)\nprint('vars ok')\n\nplt.plot(x, y)\nplt.savefig('foo.png', dpi=300)\nprint('plot done')\n\ntestvar = {\"x\": 45, \"lol\": \"test\", \"bbb\": (1,5,'oi'), \"vfr\": {\"g\": 5, \"l\": \"puco\", \"vik\": np.random.randint(0, 10, 10)}, \"kkkk\": [1,2,3,4,5], \"arai\": np.random.randint(0, 10, (3,3))}","output":"str","x":410,"y":400,"wires":[["9fe2d0c268f5819b"]]},{"id":"2d2be768ad57a7c7","type":"inject","z":"c8d536e94f59d49d","name":"Get var","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"['x', 'y', 'testvar']","payloadType":"jsonata","x":250,"y":520,"wires":[["5ef27751bd10911a"]]},{"id":"6f3517806310b255","type":"comment","z":"c8d536e94f59d49d","name":"Create data","info":"","x":250,"y":360,"wires":[]},{"id":"6b3aba92636caf35","type":"comment","z":"c8d536e94f59d49d","name":"Get data","info":"","x":240,"y":480,"wires":[]},{"id":"b2928b84d4584cf8","type":"debug","z":"c8d536e94f59d49d","name":"Var","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":630,"y":520,"wires":[]},{"id":"5217f37a5ad5ece8","type":"subflow:e8b1d6f8290a4e3b","z":"c8d536e94f59d49d","name":"","x":360,"y":140,"wires":[[]]},{"id":"4bd7fbb0073d0e52","type":"inject","z":"c8d536e94f59d49d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop all","payloadType":"str","x":110,"y":200,"wires":[["5217f37a5ad5ece8"]]},{"id":"77c61e0c36eec02c","type":"inject","z":"c8d536e94f59d49d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop","payloadType":"str","x":110,"y":160,"wires":[["5217f37a5ad5ece8"]]},{"id":"5320355b6831a8e5","type":"inject","z":"c8d536e94f59d49d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"reset","payloadType":"str","x":110,"y":120,"wires":[["5217f37a5ad5ece8"]]},{"id":"0339587784c035f8","type":"inject","z":"c8d536e94f59d49d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"start","payloadType":"str","x":110,"y":80,"wires":[["5217f37a5ad5ece8"]]},{"id":"33c4729ee4bb86cf","type":"comment","z":"c8d536e94f59d49d","name":"Manage Jupyter servers and kernels","info":"","x":360,"y":100,"wires":[]},{"id":"9fe2d0c268f5819b","type":"subflow:0dcc892460200b20","z":"c8d536e94f59d49d","name":"Execute Python Code","x":620,"y":400,"wires":[["0d610d0ac2d6f3c6"]],"icon":"font-awesome/fa-file-text-o"},{"id":"0d610d0ac2d6f3c6","type":"debug","z":"c8d536e94f59d49d","name":"Code output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":830,"y":400,"wires":[]},{"id":"5ef27751bd10911a","type":"subflow:30cc2af1b6f3f4e2","z":"c8d536e94f59d49d","name":"Get Data from Python","x":440,"y":520,"wires":[["b2928b84d4584cf8"]]},{"id":"506e09a7ea306572","type":"subflow:e8b1d6f8290a4e3b","z":"1ce64dfc715f9858","name":"","x":310,"y":120,"wires":[[]]},{"id":"0f115d25403fec56","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop all","payloadType":"str","x":90,"y":180,"wires":[["506e09a7ea306572"]]},{"id":"60bcc8407d9530f3","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop","payloadType":"str","x":90,"y":140,"wires":[["506e09a7ea306572"]]},{"id":"f0b1a8a3618bbf95","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"reset","payloadType":"str","x":90,"y":100,"wires":[["506e09a7ea306572"]]},{"id":"f1c089433089eb72","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"start","payloadType":"str","x":90,"y":60,"wires":[["506e09a7ea306572"]]},{"id":"bf0ef2948c835efe","type":"inject","z":"1ce64dfc715f9858","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":90,"y":300,"wires":[["ab4b9a49815e8d9c"]]},{"id":"66dfeb5d940c8b57","type":"comment","z":"1ce64dfc715f9858","name":"Initialization","info":"","x":190,"y":260,"wires":[]},{"id":"934ece249391d606","type":"debug","z":"1ce64dfc715f9858","name":"Init output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":500,"y":300,"wires":[]},{"id":"ab4b9a49815e8d9c","type":"subflow:f3413dd9cf7452e9","z":"1ce64dfc715f9858","name":"","x":240,"y":300,"wires":[["934ece249391d606"]]},{"id":"f6eaf96f902f9bc3","type":"inject","z":"1ce64dfc715f9858","name":"Set inst. addr.","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"TCPIP0::127.0.0.1::51235::SOCKET","payloadType":"str","x":110,"y":360,"wires":[["42aefc098bd07997"]]},{"id":"42aefc098bd07997","type":"subflow:dfccab4af70a2e16","z":"1ce64dfc715f9858","name":"","x":290,"y":360,"wires":[["934ece249391d606"],["7b54e181a52bc9ce"]]},{"id":"fb017618d5cec56a","type":"comment","z":"1ce64dfc715f9858","name":"Get IDN with a query","info":"","x":950,"y":320,"wires":[]},{"id":"1f2bd591b361946a","type":"debug","z":"1ce64dfc715f9858","name":"Tests output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1130,"y":360,"wires":[]},{"id":"8ee174d72dcf7791","type":"subflow:6373cee7258498f1","z":"1ce64dfc715f9858","name":"","x":910,"y":360,"wires":[["1f2bd591b361946a"]]},{"id":"358f19f9d3864cad","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"cmd","payload":"*IDN?","payloadType":"str","x":920,"y":400,"wires":[["8ee174d72dcf7791"]]},{"id":"e0f0c847dea72ad2","type":"comment","z":"1ce64dfc715f9858","name":"Set Frequency and get it by writing/reading","info":"","x":650,"y":480,"wires":[]},{"id":"525f95a98884158e","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"cmd","payload":"freq:freq 22345.9876","payloadType":"str","x":410,"y":580,"wires":[["580b1333e0011fbf"]]},{"id":"580b1333e0011fbf","type":"subflow:0c2d06d40ba312db","z":"1ce64dfc715f9858","name":"","x":460,"y":540,"wires":[[]]},{"id":"5f6bb7fd91b4e3fd","type":"subflow:4bab381a44e24d4f","z":"1ce64dfc715f9858","name":"","x":940,"y":540,"wires":[["1f2bd591b361946a"]]},{"id":"655374db8be282a1","type":"subflow:0c2d06d40ba312db","z":"1ce64dfc715f9858","name":"","x":720,"y":540,"wires":[["5f6bb7fd91b4e3fd"]]},{"id":"9b19276d5d204197","type":"inject","z":"1ce64dfc715f9858","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"cmd","payload":"freq:freq?","payloadType":"str","x":700,"y":580,"wires":[["655374db8be282a1"]]},{"id":"23b275929ccaea85","type":"comment","z":"1ce64dfc715f9858","name":"Jupyter session","info":"","x":280,"y":60,"wires":[]}]