Skip to content
Snippets Groups Projects
Commit 9ac6089e authored by Nikolaus Wirtz's avatar Nikolaus Wirtz
Browse files

Merge branch 'finalize' into 'master'

Finalize

See merge request !9
parents 5fdd369a 015283e8
Branches master
No related tags found
1 merge request!9Finalize
...@@ -18,7 +18,7 @@ The project requires: ...@@ -18,7 +18,7 @@ The project requires:
Install the latest version of **_Python 3_** from https://www.python.org/downloads/. Verify that the path to the python executeable got added to the PATH system variable. For that open up the command prompt and use the command `python --version`. It should output the just installed python version. Install the latest version of **_Python 3_** from https://www.python.org/downloads/. Verify that the path to the python executeable got added to the PATH system variable. For that open up the command prompt and use the command `python --version`. It should output the just installed python version.
To install the required software the repository contains a bash script *pi-setup.sh*. To run the script use `sh pi-setup.sh` in the command line from the root directory of the project repository. The script updates the apt-package manager and installs **_Node.js_**, **_Node-RED_**, **_npm_** and **_PostgreSQL_**. To install the required software the repository contains a bash script *pi-setup.sh*. The script upgrades the apt-package manager and installs **_Node.js_**, **_Node-RED_**, **_npm_** and **_PostgreSQL_**. To run the script use `sh pi-setup.sh` in the command line from the root directory of the project repository. In case there are no execute permissions set for the files *pi-setup.sh* and *pi-setup-code.py* you have to manually set them first with `chmod +x pi-setup.sh` and `chmod +x pi-setup-code.py`.
Additionally it installs the **_Node-RED-packages_** used by the project: Additionally it installs the **_Node-RED-packages_** used by the project:
- *node-red-contrib-buffer-parser* - *node-red-contrib-buffer-parser*
......
No preview for this file type
...@@ -4,5 +4,5 @@ ...@@ -4,5 +4,5 @@
devices = 6 devices = 6
# Set hostnames # Set hostnames
address_prefix = "example-prefix-" address_prefix = "prefix-example-"
address_suffix = ".example-suffix" address_suffix = ".suffix-example"
\ No newline at end of file \ No newline at end of file
[{"id":"e8034ec0.182578","type":"tab","label":"dv am","disabled":false,"info":""},{"id":"c206ac56.ec99c8","type":"tab","label":"data","disabled":false,"info":""},{"id":"f825e8a0.9d51f","type":"tab","label":"dv asset","disabled":false,"info":""},{"id":"6d95b6d3.106588","type":"tab","label":"Create data","disabled":false,"info":""},{"id":"3d5ce28770ed0d20","type":"postgresdb","hostname":"localhost","port":"5432","db":"vpp","ssl":false},{"id":"6a6c8a2.ae75774","type":"inject","z":"e8034ec0.182578","name":"Start","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"start","x":130,"y":260,"wires":[["2dc3a3fb.e32ef4"]]},{"id":"43189a12.ffbcf4","type":"inject","z":"e8034ec0.182578","name":"show params","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"device1","payloadType":"global","x":150,"y":80,"wires":[["6b714eca.075eb"]]},{"id":"6b714eca.075eb","type":"debug","z":"e8034ec0.182578","name":"show params","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":310,"y":80,"wires":[]},{"id":"2dc3a3fb.e32ef4","type":"file in","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","format":"lines","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":330,"y":260,"wires":[["f35585cc.e58b68"]]},{"id":"1d979cd2.bd172b","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":650,"y":260,"wires":[["10ffb8a7.ba3487"]]},{"id":"f35585cc.e58b68","type":"function","z":"e8034ec0.182578","name":"convert","func":"var newMsg;\nnewMsg = {\n payload: \"[\" + msg.payload + \"]\"\n}\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":260,"wires":[["1d979cd2.bd172b"]]},{"id":"8cfc218d.653c98","type":"function","z":"e8034ec0.182578","name":"Init. params","func":"// hardcoded device ID\nglobal.set(\"device1.id\",100001);\nglobal.set(\"device1.hostname_prefix\",\"tmp\");\nglobal.set(\"device1.hostname_suffix\",\"tmp\");\n\nglobal.set(\"device1.hostname\",global.get(\"device1.hostname_prefix\")+(global.get(\"device1.id\") - 100000)+ global.get(\"device1.hostname_suffix\"))\n\n// set initial state to follower\nglobal.set(\"device1.state\", \"follower\");\nvar randomWait = Math.ceil(Math.random()*5)+1;\nglobal.set(\"device1.randomWait\", randomWait);\n// indices and thresholds\nglobal.set(\"device1.sysCommitIndex\",1);\nglobal.set(\"device1.dataCommitIndex\",1);\nglobal.set(\"device1.sysSnapshotTH\",5);\nglobal.set(\"device1.dataSnapshotTH\",30);\nglobal.set(\"device1.sysLastApplied\",0);\nglobal.set(\"device1.dataLastApplied\",0);\nglobal.set(\"device1.timestamp\",0);\nglobal.set(\"device1.leaderId\", null);\n\n// hardcoded number of devices\nglobal.set(\"device1.nodesNum\",6);\nvar len = global.get(\"device1.nodesNum\");\n\n// hardcoded functions\nglobal.set(\"device1.virtualFuncs[0].name\", \"FaultLoc\"); \nglobal.set(\"device1.virtualFuncs[0].device\", null); // value device id\nglobal.set(\"device1.virtualFuncs[1].name\", \"ServiceRes\"); \nglobal.set(\"device1.virtualFuncs[1].device\", null); \n\n// Device 0\nglobal.set(\"device1.devices[0].id\", null);\nglobal.set(\"device1.devices[0].online\", null);\nglobal.set(\"device1.devices[0].ip\", null);\nglobal.set(\"device1.devices[0].port\", null);\nglobal.set(\"device1.devices[0].nextSysLogIndex\", null);\nglobal.set(\"device1.devices[0].nextDataLogIndex\", null);\nglobal.set(\"device1.devices[0].matchSysLogIndex\", null);\nglobal.set(\"device1.devices[0].matchDataLogIndex\", null);\n\n// hardcoded devices\n\nfor (i= 1; i<len+1;i++) {\n \n global.set(\"device1.devices[\"+i+\"].id\", 100000+i);\n global.set(\"device1.devices[\"+i+\"].online\", null);\n global.set(\"device1.devices[\"+i+\"].ip\", \"127.0.0.1\");\n global.set(\"device1.devices[\"+i+\"].port\", 10000+i);\n global.set(\"device1.devices[\"+i+\"].nextSysLogIndex\", null);\n global.set(\"device1.devices[\"+i+\"].nextDataLogIndex\", null);\n global.set(\"device1.devices[\"+i+\"].matchSysLogIndex\", null);\n global.set(\"device1.devices[\"+i+\"].matchDataLogIndex\", null);\n\n}\n\nmsg = {\n topic: \"start\"\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1050,"y":260,"wires":[["c8e8e64b.60ec28"]]},{"id":"c8e8e64b.60ec28","type":"function","z":"e8034ec0.182578","name":"timeout","func":"var myTerm = global.get(\"device1.currentTerm\");\nvar myId = global.get(\"device1.id\");\n\nif(msg.topic.includes(\"start\") || msg.topic.includes(\"myRequestVoteRPC\")){ // start timer\n context.set('count',0);\n msg.payload = { \n \"payload\": \"on\", \n \"warning\": 0,\n \"timeout\": global.get('device1.randomWait')\n };\n return msg;\n} \nelse if(msg.topic.includes(\"RPC\") && msg.payload.term >= myTerm){ //RPC from leader or candidate, to reactivate\n msg.payload = { \n \"payload\": \"on\", \n \"warning\": 0,\n \"timeout\": global.get('device1.randomWait')\n };\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":380,"wires":[["9f80a15f.bb2a98"]]},{"id":"5b97fc86.32033c","type":"function","z":"e8034ec0.182578","name":"updateParams","func":"if(msg.payload === \"off\"){\n // random wait\n var randomWait = Math.ceil(Math.random()*5)+1;\n flow.set(\"voteCount\", 1); // vote for self, count ++\n global.set(\"device1.randomWait\", randomWait);\n global.set(\"device1.state\", \"candidate\");\n global.set(\"device1.currentTerm\", global.get(\"device1.currentTerm\")+1);\n global.set(\"device1.voteFor\", global.get(\"device1.id\"));\n msg = {\n topic:\"myRequestVoteRPC\"\n }\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":460,"wires":[["473f8dd.9f0d274","c8e8e64b.60ec28"]]},{"id":"2677e779.36a628","type":"function","z":"e8034ec0.182578","name":"leaderInit","func":"var nextSysLogIndex = global.get(\"device1.systemLog\").length;\nvar nextDataLogIndex = global.get(\"device1.dataLog\").length;\nvar myId = global.get(\"device1.id\");\nvar len = global.get(\"device1.nodesNum\");\n\nfor(var i=1; i<=len; i++){\n if(i != (myId-100000)){\n global.set(\"device1.devices[\"+i+\"].nextSysLogIndex\",nextSysLogIndex);\n global.set(\"device1.devices[\"+i+\"].nextDataLogIndex\",nextDataLogIndex);\n global.set(\"device1.devices[\"+i+\"].matchSysLogIndex\",0);\n global.set(\"device1.devices[\"+i+\"].matchDataLogIndex\",0);\n global.set(\"device1.devices[\"+i+\"].online\",false);\n } else {\n global.set(\"device1.devices[\"+i+\"].online\",true);\n }\n}\n \n \n// set leader\nglobal.set(\"device1.state\", \"leader\");\nglobal.set(\"device1.leaderId\", myId);\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1680,"y":400,"wires":[[]]},{"id":"7ee6d5c.ae9d22c","type":"function","z":"e8034ec0.182578","name":"isVote","func":"var sysLogLen = global.get(\"device1.systemLog\").length-1;\nvar dataLogLen = global.get(\"device1.dataLog\").length-1;\nvar mySysLogTerm = global.get(\"device1.systemLog[\"+sysLogLen+\"].term\");\nvar mySysLogIndex = global.get(\"device1.systemLog[\"+sysLogLen+\"].index\");\nvar myDataLogTerm = global.get(\"device1.dataLog[\"+dataLogLen+\"].term\");\nvar myDataLogIndex = global.get(\"device1.dataLog[\"+dataLogLen+\"].index\");\nvar myTerm = global.get(\"device1.currentTerm\");\nvar myVote = global.get(\"device1.voteFor\");\nvar myId = global.get(\"device1.id\");\nvar candidateId = msg.payload.candidateId;\nvar lastSysLogTerm = msg.payload.lastSysLogTerm;\nvar lastSysLogIndex = msg.payload.lastSysLogIndex;\nvar lastDataLogTerm = msg.payload.lastDataLogTerm;\nvar lastDataLogIndex = msg.payload.lastDataLogIndex;\nvar term = msg.payload.term;\nvar isVote = false;\n\n// safety 5.4.1\nif(lastSysLogTerm > mySysLogTerm && lastDataLogTerm > myDataLogTerm) {\n isVote = true;\n} else if (lastSysLogTerm >= mySysLogTerm && lastDataLogTerm >= myDataLogTerm){\n if(lastSysLogIndex >= mySysLogIndex && lastDataLogIndex >= myDataLogIndex) {\n isVote = true;\n }\n}\n\nif(myTerm < term) {\n myTerm = term;\n global.set(\"device1.state\", \"follower\");\n global.set(\"device1.voteFor\", null);\n myVote = null;\n global.set(\"device1.currentTerm\", myTerm);\n} else if(myTerm > term) {\n isVote = false;\n}\n\nif(isVote && (myVote === null || myVote == candidateId)) {\n newMsg = {\n payload: {\n id: myId,\n term: myTerm,\n voteGranted: true\n }\n }\n global.set(\"device1.voteFor\", candidateId);\n \n} else {\n newMsg = {\n payload: {\n id: myId,\n term: myTerm,\n voteGranted: false\n }\n }\n}\n\nmsg.payload = newMsg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":800,"wires":[["5703d621e5907de8"]]},{"id":"17745a55.895cfe","type":"function","z":"e8034ec0.182578","name":"replyToLeader","func":"if (msg.payload.term > global.get(\"device1.currentTerm\")){// discover higher term\n\n node.warn(\"ReplyToLeader: Back to follower\");\n\n global.set(\"device1.currentTerm\", msg.payload.term);\n global.set(\"device1.voteFor\", null);\n global.set(\"device1.state\", \"follower\"); // back to follower\n \n} else if (global.get(\"device1.state\") == \"candidate\" && msg.payload.term == global.get(\"device1.currentTerm\")) { \n global.set(\"device1.state\", \"follower\"); ////candidate discovers current leader, back to follower\n \n node.warn(\"ReplyToLeader: Candidate to follower\"); \n\n} else if (msg.payload.term < global.get(\"device1.currentTerm\")) {\n\n node.warn(\"ReplyToLeader: MSG.TERM smaller than current TERM\");\n\n let newPayload = {\n id: global.get(\"device1.id\"),\n term: global.get(\"device1.currentTerm\"),\n sysSuccess: false,\n dataSuccess: false,\n sysEntriesLen: msg.payload.sysEntries.length,\n dataEntriesLen: msg.payload.dataEntries.length\n }\n\n msg.payload = newPayload;\n return msg;\n}\n\nif(global.get(\"device1.state\") == \"follower\"){\n global.set(\"device1.leaderId\", msg.payload.leaderId); \n var myId = global.get(\"device1.id\");\n var myTerm = global.get(\"device1.currentTerm\");\n var mySystemLog = global.get(\"device1.systemLog\");\n var myDataLog = global.get(\"device1.dataLog\");\n var sysSuccess = false;\n var dataSuccess = false;\n var sysCommitIndex = Math.min(msg.payload.leaderSysCommit, mySystemLog[mySystemLog.length-1].index);\n var dataCommitIndex = Math.min(msg.payload.leaderDataCommit, myDataLog[myDataLog.length-1].index)\n global.set(\"device1.sysCommitIndex\", sysCommitIndex);\n global.set(\"device1.dataCommitIndex\", dataCommitIndex);\n var newSysLog = [];\n var newDataLog = [];\n \n // snapshot here\n var sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n var sysLastApplied = global.get(\"device1.sysLastApplied\");\n var currvirtualFuncs0 = global.get(\"device1.virtualFuncs[0].device\");\n var currvirtualFuncs1 = global.get(\"device1.virtualFuncs[1].device\");\n var sysSnapshotTH = global.get(\"device1.sysSnapshotTH\");\n if(sysLastApplied - sysSnapshotIndex > sysSnapshotTH) {\n let logAfterSnapshot = [];\n let newSysSnapshotTerm = -1;\n for(let log of mySystemLog) {\n if(log.index == sysLastApplied){\n newSysSnapshotTerm = log.term;\n let newFirstLog = {\n index: sysLastApplied,\n term: newSysSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n } else if(log.index > sysLastApplied) {\n logAfterSnapshot.push(log);\n }\n }\n global.set(\"device1.sysSnapshot.index\",sysLastApplied);\n global.set(\"device1.sysSnapshot.term\",newSysSnapshotTerm);\n global.set(\"device1.sysSnapshot.virtualFuncs[0].device\",currvirtualFuncs0);\n global.set(\"device1.sysSnapshot.virtualFuncs[1].device\",currvirtualFuncs1);\n mySystemLog = logAfterSnapshot;\n global.set(\"device1.systemLog\",mySystemLog);\n \n }\n \n var dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\n var dataLastApplied = global.get(\"device1.dataLastApplied\");\n var currTs = global.get(\"device1.timestamp\");\n var dataSnapshotTH = global.get(\"device1.dataSnapshotTH\");\n if(dataLastApplied - dataSnapshotIndex > dataSnapshotTH) {\n let logAfterSnapshot = [];\n let newDataSnapshotTerm = -1;\n for(let log of myDataLog) {\n if(log.index == dataLastApplied){\n newDataSnapshotTerm = log.term;\n let newFirstLog = {\n index: dataLastApplied,\n term: newDataSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n node.warn(\"Pushing empty log\");\n } else if(log.index > dataLastApplied) {\n logAfterSnapshot.push(log);\n node.warn(\"Pushing non-empty log\");\n }\n }\n global.set(\"device1.dataSnapshot.index\",dataLastApplied);\n global.set(\"device1.dataSnapshot.term\",newDataSnapshotTerm);\n global.set(\"device1.dataSnapshot.timestamp\",currTs);\n myDataLog = logAfterSnapshot;\n global.set(\"device1.dataLog\",myDataLog);\n \n }\n \n \n \n for (let log of mySystemLog){\n newSysLog.push(log);\n if(log.index == msg.payload.prevSysLogIndex) {\n if(log.term == msg.payload.prevSysLogTerm) {\n // mySysLog until prevSysLogIndex(newSysLog) + sysEntries in AppendEntries RPC\n if(msg.payload.sysEntries.length > 1) { // sysEntriesNotNull\n global.set(\"device1.systemLog\", newSysLog.concat(msg.payload.sysEntries.slice(1, msg.payload.sysEntries.length)));\n }\n sysSuccess = true;\n }\n break;\n } \n }\n\n for (let log of myDataLog){\n newDataLog.push(log);\n if(log.index == msg.payload.prevDataLogIndex) {\n if(log.term == msg.payload.prevDataLogTerm) {\n if(msg.payload.dataEntries.length > 1) { // dataEntriesNotNull\n global.set(\"device1.dataLog\", newDataLog.concat(msg.payload.dataEntries.slice(1, msg.payload.dataEntries.length)));\n }\n dataSuccess = true;\n }\n break;\n } \n }\n \n let newPayload = {\n id: global.get(\"device1.id\"),\n term: global.get(\"device1.currentTerm\"),\n sysSuccess: sysSuccess,\n dataSuccess: dataSuccess,\n sysEntriesLen: msg.payload.sysEntries.length,\n dataEntriesLen: msg.payload.dataEntries.length\n }\n\n msg.payload = newPayload;\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":760,"wires":[["626db20f.d92afc","5703d621e5907de8"]]},{"id":"626db20f.d92afc","type":"function","z":"e8034ec0.182578","name":"persistent storage","func":"msg.payload = {\n currentTerm: global.get(\"device1.currentTerm\"),\n voteFor: global.get(\"device1.voteFor\"),\n systemLog: global.get(\"device1.systemLog\"),\n dataLog: global.get(\"device1.dataLog\"),\n sysSnapshot: global.get(\"device1.sysSnapshot\"),\n dataSnapshot: global.get(\"device1.dataSnapshot\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":760,"wires":[["9d92fc1d.4fbb2"]]},{"id":"9d92fc1d.4fbb2","type":"file","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":1170,"y":760,"wires":[[]]},{"id":"473f8dd.9f0d274","type":"function","z":"e8034ec0.182578","name":"RequestVoteRPC","func":"var sysLogLen = global.get(\"device1.systemLog\").length-1;\nvar dataLogLen = global.get(\"device1.dataLog\").length-1;\n\nvar newMsg = {\n payload:{\n term: global.get(\"device1.currentTerm\"),\n candidateId: global.get(\"device1.id\"),\n lastSysLogIndex: global.get(\"device1.systemLog[\"+sysLogLen+\"].index\"),\n lastSysLogTerm: global.get(\"device1.systemLog[\"+sysLogLen+\"].term\"),\n lastDataLogIndex: global.get(\"device1.dataLog[\"+dataLogLen+\"].index\"),\n lastDataLogTerm: global.get(\"device1.dataLog[\"+dataLogLen+\"].term\")\n }\n};\n\nreturn newMsg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":520,"wires":[["5f8746972ea09559"]]},{"id":"3e3a97b7.c7f7b","type":"function","z":"e8034ec0.182578","name":"results recv","func":"var myTerm = global.get(\"device1.currentTerm\");\nvar voteCount = flow.get(\"voteCount\");\nvar nodesNum = global.get(\"device1.nodesNum\");\n\nif (typeof msg.payload != \"undefined\") {\n if(msg.payload.voteGranted && msg.payload.term == myTerm) {\n voteCount += 1;\n flow.set(\"voteCount\", voteCount);\n } else if (msg.payload.term > myTerm) {\n flow.set(\"voteCount\", 0);\n }\n}\n\nif(voteCount >= (nodesNum+1)/2 ) {\n flow.set(\"voteCount\", 0);\n msg.payload = { \n \"payload\": \"cancel\" // cancel timer\n };\n return msg; // leader Init\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1390,"y":520,"wires":[["2677e779.36a628","9f80a15f.bb2a98","82ba0c9b.becd58"]]},{"id":"507503c7.60aaa4","type":"inject","z":"e8034ec0.182578","name":"heartbeats","props":[{"p":"payload.heartbeat","vt":"bool","v":"true"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":"0.1","topic":"","x":110,"y":1220,"wires":[["878781ba.aef818","7a15a110.bac49","4cebd161.848db8","9a1bba8b.93412","454e8a3cfd7fdbd8"]]},{"id":"878781ba.aef818","type":"function","z":"e8034ec0.182578","name":"isLeader & AppendEntries","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar newMsg = new Array(len-1);\nvar mySystemLog = global.get(\"device1.systemLog\");\nvar myDataLog = global.get(\"device1.dataLog\");\nvar myId = global.get(\"device1.id\");\nvar myState = global.get(\"device1.state\");\nvar j = 0;\n\nif(myState == \"leader\"){ //I'm leader\n for(var i=1; i<=len; i++){\n var sendId=100000 + i;\n if(sendId != myId){\n var dataEntries = [];\n var sysEntries = [];\n var entry = {\n index: -1,\n term: -1,\n command: \" \"\n };\n sysEntries.push(entry); // add this for protobuf encode/decode\n dataEntries.push(entry);\n var prevSysLogIndex = global.get(\"device1.devices[\"+i+\"].nextSysLogIndex\")-1;\n var prevSysLogTerm = -1; // after iter. still -1? -> in snapshot\n var prevDataLogIndex = global.get(\"device1.devices[\"+i+\"].nextDataLogIndex\")-1;\n var prevDataLogTerm = -1; // after iter. still -1? -> in snapshot\n \n\n for (let log of mySystemLog){\n if(log.index == prevSysLogIndex) {\n prevSysLogTerm = log.term;\n } else if (log.index > prevSysLogIndex){\n entry = {\n index: log.index,\n term: log.term,\n command: log.command\n };\n sysEntries.push(entry);\n }\n }\n for (let log of myDataLog) {\n if(log.index == prevDataLogIndex) {\n prevDataLogTerm = log.term;\n } else if (log.index > prevDataLogIndex){\n entry = {\n index: log.index,\n term: log.term,\n command: log.command\n };\n dataEntries.push(entry);\n }\n }\n \n newMsg[j] = {\n payload:{\n term: global.get(\"device1.currentTerm\"),\n leaderId: myId,\n sendId: sendId,\n prevSysLogIndex: prevSysLogIndex,\n prevSysLogTerm: prevSysLogTerm,\n prevDataLogIndex: prevDataLogIndex,\n prevDataLogTerm: prevDataLogTerm,\n leaderSysCommit: global.get(\"device1.sysCommitIndex\"),\n leaderDataCommit: global.get(\"device1.dataCommitIndex\"),\n sysEntries: sysEntries,\n dataEntries: dataEntries\n }\n };\n j++;\n }\n }\n return [newMsg];\n \n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":1220,"wires":[["6f9c0baf10f8bc91"]]},{"id":"a102604a.fe65c8","type":"function","z":"e8034ec0.182578","name":"isUpdateTerm","func":"var myTerm = global.get(\"device1.currentTerm\");\nif(typeof msg.payload !== 'undefined'){\n if(msg.payload.term > myTerm){\n global.set(\"device1.currentTerm\", msg.payload.term);\n global.set(\"device1.voteFor\", null);\n global.set(\"device1.state\", \"follower\");\n }\n else{\n return msg;\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1020,"y":1220,"wires":[["9fca9662.48c49","5c376bdf.4bc82c","cadd8a3.2140778","ff9f0847.173b48"]]},{"id":"9fca9662.48c49","type":"function","z":"e8034ec0.182578","name":"isSuccess","func":"var serverId = msg.payload.id;\nvar nextSysLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\");\nvar nextDataLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\");\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\nvar dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\n\nif(msg.payload.sysSuccess === false){\n\n if(nextSysLogIndex - 1 > sysSnapshotIndex) {\n nextSysLogIndex -= 1;\n } else if (nextSysLogIndex <= sysSnapshotIndex) {\n nextSysLogIndex = sysSnapshotIndex + 1;\n }\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\", nextSysLogIndex);\n}\nelse{\n\n if(msg.payload.sysEntriesLen > 1) {// not heartbeat message \n nextSysLogIndex = nextSysLogIndex + msg.payload.sysEntriesLen - 1;\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\", nextSysLogIndex);\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].matchSysLogIndex\", nextSysLogIndex-1);\n }\n}\n\n\nif(msg.payload.dataSuccess === false){\n\n if(nextDataLogIndex - 1 > dataSnapshotIndex) {\n nextDataLogIndex -= 1;\n } else if (nextDataLogIndex <= dataSnapshotIndex) {\n nextDataLogIndex = dataSnapshotIndex + 1;\n }\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\", nextDataLogIndex);\n}\nelse{\n\n if(msg.payload.dataEntriesLen > 1) {\n nextDataLogIndex = nextDataLogIndex + msg.payload.dataEntriesLen - 1;\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\", nextDataLogIndex);\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].matchDataLogIndex\", nextDataLogIndex-1);\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1260,"y":1240,"wires":[["1a3a2f43.16ff89"]]},{"id":"1a3a2f43.16ff89","type":"function","z":"e8034ec0.182578","name":"commitIndex++","func":"var devices = global.get(\"device1.devices\");\nvar nodesNum = global.get(\"device1.nodesNum\");\nvar majority = Math.round((nodesNum-1)/2);\nvar myId = global.get(\"device1.id\");\nvar myTerm = global.get(\"device1.currentTerm\");\nvar matchSysLogIndexArr = [];\nvar matchDataLogIndexArr = [];\nvar sysCommitIndex = global.get(\"device1.sysCommitIndex\");\nvar dataCommitIndex = global.get(\"device1.dataCommitIndex\");\nvar systemLog = global.get(\"device1.systemLog\");\nvar dataLog = global.get(\"device1.dataLog\");\nfor(let device of devices) {\n if(device.id !== null && device.id != myId) {\n matchSysLogIndexArr.push(device.matchSysLogIndex);\n matchDataLogIndexArr.push(device.matchDataLogIndex);\n }\n \n}\n\nmatchSysLogIndexArr.sort((a, b) => a - b);\nmatchDataLogIndexArr.sort((a, b) => a - b);\n\nfor(let i=majority; i>=0; i--) {\n if(matchSysLogIndexArr[i] > sysCommitIndex) {\n for(let log of systemLog) {\n if(log.index == matchSysLogIndexArr[i]) {\n if(log.term == myTerm) {\n sysCommitIndex = matchSysLogIndexArr[i];\n }\n break;\n }\n }\n }\n if(matchDataLogIndexArr[i] > dataCommitIndex) {\n for(let log of dataLog) {\n if(log.index == matchDataLogIndexArr[i]) {\n if(log.term == myTerm) {\n dataCommitIndex = matchDataLogIndexArr[i];\n }\n break;\n }\n }\n }\n}\nglobal.set(\"device1.sysCommitIndex\", sysCommitIndex);\nglobal.set(\"device1.dataCommitIndex\", dataCommitIndex);\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1420,"y":1240,"wires":[[]]},{"id":"14b1e89c.463d47","type":"function","z":"e8034ec0.182578","name":"RPC","func":"msg.topic = \"RPC\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":380,"wires":[["c8e8e64b.60ec28"]]},{"id":"5c376bdf.4bc82c","type":"function","z":"e8034ec0.182578","name":"change topic","func":"msg.topic = msg.payload.id;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":1300,"wires":[["5f0d35de.012b5c"]]},{"id":"96868548.e8294","type":"function","z":"e8034ec0.182578","name":"isDeviceOn","func":"if(msg.payload == \"timeout\") {\n \n global.set(\"device1.devices[\" + (msg.topic - 100000) + \"].online\", false);\n} else {\n \n global.set(\"device1.devices[\" + (msg.topic - 100000) + \"].online\", true); \n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1650,"y":1300,"wires":[["683575de.cc64fc","e44b25dd.175e5"]]},{"id":"683575de.cc64fc","type":"function","z":"e8034ec0.182578","name":"assignDVAssetRequest","func":"//virtualFunc\nvar virtualFuncs = global.get(\"device1.virtualFuncs\");\n//get online devices\nvar devices = global.get(\"device1.devices\");\nvar leaderId = global.get(\"device1.leaderId\");\nvar onlineDeviceIds = {};\nvar systemLog = global.get(\"device1.systemLog\");\nvar prevLogIndex = systemLog[systemLog.length-1].index;\nvar term = global.get(\"device1.currentTerm\");\n\n\n// snapshot here\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n\n// hardcoded functions (number)\nvar currvirtualFuncs0 = global.get(\"device1.virtualFuncs[0].device\");\nvar currvirtualFuncs1 = global.get(\"device1.virtualFuncs[1].device\");\n\nvar sysLastApplied = global.get(\"device1.sysLastApplied\");\nvar sysSnapshotTH = global.get(\"device1.sysSnapshotTH\");\nif(sysLastApplied - sysSnapshotIndex > sysSnapshotTH) {\n var logAfterSnapshot = [];\n var newSysSnapshotTerm = -1;\n for(let log of systemLog) {\n if(log.index == sysLastApplied){\n newSysSnapshotTerm = log.term;\n let newFirstLog = {\n index: sysLastApplied,\n term: newSysSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n } else if(log.index > sysLastApplied) {\n logAfterSnapshot.push(log);\n }\n }\n global.set(\"device1.sysSnapshot.index\",sysLastApplied);\n global.set(\"device1.sysSnapshot.term\",newSysSnapshotTerm);\n global.set(\"device1.sysSnapshot.virtualFuncs[0].device\",currvirtualFuncs0);\n global.set(\"device1.sysSnapshot.virtualFuncs[1].device\",currvirtualFuncs1);\n systemLog = logAfterSnapshot;\n \n}\n\n// check for online devices\nfor(let device of devices) {\n if(device.online === true) {\n onlineDeviceIds[\"\"+device.id] = 0;\n }\n}\n\n// identify current workload\n// for loops tauschen, leader +1 nur beim loopen durch devices\nfor(let deviceId in onlineDeviceIds) {\n \n if (deviceId == leaderId) {\n onlineDeviceIds[\"\"+deviceId] += 1;\n }\n \n for(let virtualFunc of virtualFuncs) {\n if(deviceId == virtualFunc.device) {\n onlineDeviceIds[\"\"+deviceId] += 1;\n }\n } \n}\n\n// reassign functions\nvar j = 0;\nfor(let virtualFunc of virtualFuncs) {\n let isWorking = false;\n // own id and workload\n let relativeFreeDeviceId = global.get(\"device1.id\");\n let workload = onlineDeviceIds[\"\"+relativeFreeDeviceId];//\n for(let deviceId in onlineDeviceIds) {\n if(deviceId == virtualFunc.device) {\n isWorking = true;\n }\n }\n // if function is not assigned/working\n if(!isWorking) {\n for(let deviceId in onlineDeviceIds) {\n // check if other devices have a smaller workload than self\n if(onlineDeviceIds[deviceId] < workload) {\n workload = onlineDeviceIds[deviceId];\n relativeFreeDeviceId = parseInt(deviceId); // get min\n }\n }\n onlineDeviceIds[\"\"+relativeFreeDeviceId] += 1;\n \n //node.warn(relativeFreeDeviceId);\n \n let command = \"d\" + (relativeFreeDeviceId-100000) + \"vf\" + j;\n let entry = {\n index: prevLogIndex + 1,\n term: term,\n command: command\n }\n systemLog.push(entry);\n prevLogIndex += 1;\n }\n j++;\n}\n\nglobal.set(\"device1.systemLog\", systemLog);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1690,"y":1380,"wires":[["d8f7d54a.783cf8"]]},{"id":"7a15a110.bac49","type":"function","z":"e8034ec0.182578","name":"state machine","func":"var sysCommitIndex = global.get(\"device1.sysCommitIndex\");\nvar sysLastApplied = global.get(\"device1.sysLastApplied\");\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\nif (sysCommitIndex > sysLastApplied) { // execute command //how about roll back\n if(sysLastApplied < sysSnapshotIndex) { // execute snapshot\n var sysSnapshotVirtualFuncs = global.get(\"device1.sysSnapshot.virtualFuncs\");\n global.set(\"device1.virtualFuncs\", sysSnapshotVirtualFuncs);\n global.set(\"device1.sysLastApplied\", sysSnapshotIndex);\n } else {\n var systemLog = global.get(\"device1.systemLog\");\n var command = null;\n \n for(let log of systemLog) {\n if(log.index == sysLastApplied+1) {\n command = log.command;\n //node.warn(\"command:\");\n //node.warn(log.command);\n break;\n }\n }\n \n if(command !== null) {\n var pattern = \"(?:d)([0-9]*)(?:vf)([0-9]*)\";\n var deviceId = parseInt(command.match(pattern)[1])+100000;\n var vfId = parseInt(command.match(pattern)[2]);\n global.set(\"device1.virtualFuncs[\"+vfId+\"].device\", deviceId);\n sysLastApplied += 1;\n global.set(\"device1.sysLastApplied\", sysLastApplied);\n //node.warn(\"DeviceID: \" + deviceId);\n //node.warn(\"vfId: \" + vfId);\n //var test = command.match(pattern);\n }\n }\n\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":1380,"wires":[["cd125a54.98e9"]]},{"id":"220404b7.2bf64c","type":"function","z":"e8034ec0.182578","name":"assignDVAsset","func":"msg = {\n payload: {\n id: global.get(\"device1.id\"),\n virtualFunctions: global.get(\"device1.virtualFuncs\")\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":1380,"wires":[["f7de9d89.d7bbb8","954c09e32251cddd"]]},{"id":"cd125a54.98e9","type":"function","z":"e8034ec0.182578","name":"isLeader","func":"if(global.get(\"device1.state\") == \"leader\"){ \n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":1380,"wires":[["220404b7.2bf64c"]]},{"id":"4cebd161.848db8","type":"function","z":"e8034ec0.182578","name":"data processor","func":"\nvar dataCommitIndex = global.get(\"device1.dataCommitIndex\");\nvar dataLastApplied = global.get(\"device1.dataLastApplied\");\nvar dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\nif (dataCommitIndex > dataLastApplied) { // execute command //how about roll back\n if(dataLastApplied < dataSnapshotIndex) {\n // no need to set payload, since leader have send it to control device\n // TODO: delete current database and duplicate leader's database\n global.set(\"device1.dataLastApplied\", dataSnapshotIndex);\n \n }\n else {\n var dataLog = global.get(\"device1.dataLog\");\n var command = null;\n for(let log of dataLog) {\n if(log.index == dataLastApplied + 1) {\n command = log.command;\n break;\n }\n }\n if(command !== null) {\n // hardcoded data command pattern\n //var pattern = \"(?:s)([0-9]*)(?:m1)([0-9]*)(?:m2)([0-9]*)(?:ts)([0-9]*)\";\n //var s = command.match(pattern)[1];\n //var m1 = command.match(pattern)[2];\n //var m2 = command.match(pattern)[3];\n //var ts = command.match(pattern)[4];\n //global.set(\"device1.timestamp\", ts);\n // hardcoded sql statement to store results in DB\n //msg.topic = \"INSERT IGNORE INTO states (states, measurement1, measurement2, time) VALUES (\" + s + \",\" + m1 + \", \" + m2 + \", \" + ts + \");\";\n msg.payload = {\n command\n }\n //node.warn(command);\n //node.warn(command.split(',').map(Number));\n \n dataLastApplied += 1;\n global.set(\"device1.dataLastApplied\", dataLastApplied); \n return msg;\n }\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":1560,"wires":[["e85be469.ba8498","3eb17029.4cd0d8"]]},{"id":"d8f7d54a.783cf8","type":"function","z":"e8034ec0.182578","name":"persistent storage","func":"msg.payload = {\n currentTerm: global.get(\"device1.currentTerm\"),\n voteFor: global.get(\"device1.voteFor\"),\n systemLog: global.get(\"device1.systemLog\"),\n dataLog: global.get(\"device1.dataLog\"),\n sysSnapshot: global.get(\"device1.sysSnapshot\"),\n dataSnapshot: global.get(\"device1.dataSnapshot\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1910,"y":1380,"wires":[["7ffbb6e1.7a9dd8"]]},{"id":"7ffbb6e1.7a9dd8","type":"file","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":2130,"y":1380,"wires":[[]]},{"id":"ff9f0847.173b48","type":"function","z":"e8034ec0.182578","name":"SendSysSnapshot","func":"var serverId = msg.payload.id;\nvar nextSysLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\");\n\n//var sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n\n// snapshot here\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n\nvar syscount = flow.get(\"syscount\") || 1;\n\nif (syscount < 5) {\n node.warn(\"SendSysSnapshotNode:\");\n node.warn(msg.payload.sysSuccess);\n node.warn(nextSysLogIndex);\n node.warn(sysSnapshotIndex);\n}\n\nsyscount++;\n\nflow.set(\"syscount\",syscount);\n\n\n//if(msg.payload.sysSuccess === false && nextSysLogIndex - 1 == sysSnapshotIndex) {\nif(nextSysLogIndex - 1 == sysSnapshotIndex) {\n msg.payload = {\n leaderId: global.get(\"device1.id\"),\n sendId: serverId,\n term: global.get(\"device1.currentTerm\"),\n lastIncludedIndex: global.get(\"device1.sysSnapshot.index\"),\n lastIncludedTerm: global.get(\"device1.sysSnapshot.term\"),\n virtualFunctions: global.get(\"device1.sysSnapshot.virtualFuncs\")\n \n }\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1270,"y":1140,"wires":[["1506bd50e6d17b03"]]},{"id":"cadd8a3.2140778","type":"function","z":"e8034ec0.182578","name":"SendDataSnapshotCheck","func":"var serverId = msg.payload.id;\nvar nextDataLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\");\nvar dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\nif(msg.payload.dataSuccess === false && nextDataLogIndex - 1 == dataSnapshotIndex) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1290,"y":1000,"wires":[["e6876b38.23ad6"]]},{"id":"90cc26d4.0b84b","type":"function","z":"e8034ec0.182578","name":"UpdateSysSnapshot","func":"var myTerm = global.get(\"device1.currentTerm\");\n\nif(msg.payload.term < myTerm) {\n msg.payload = {\n term: myTerm\n }\n} else {\n var systemLog = global.get(\"device1.systemLog\");\n var lastLogIndex = systemLog[systemLog.length-1].index;\n var newSystemLog = [];\n var firstLog = {\n index:msg.payload.lastIncludedIndex,\n term: msg.payload.lastIncludedTerm,\n command: null\n }; \n newSystemLog.push(firstLog);\n global.set(\"device1.sysSnapshot.index\", msg.payload.lastIncludedIndex);\n global.set(\"device1.sysSnapshot.term\", msg.payload.lastIncludedTerm);\n global.set(\"device1.sysSnapshot.virtualFuncs\", msg.payload.virtualFunctions);\n if(lastLogIndex > msg.payload.lastIncludedIndex) {\n for(let log of systemLog) {\n if(log.index > msg.payload.lastIncludedIndex) {\n newSystemLog.push(log);\n }\n }\n }\n \n global.set(\"device1.systemLog\", newSystemLog);\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":840,"wires":[["5703d621e5907de8"]]},{"id":"619d09e2.17e938","type":"function","z":"e8034ec0.182578","name":"UpdateDataSnapshot","func":"var myTerm = global.get(\"device1.currentTerm\");\nif(msg.payload.term < myTerm) {\n msg.payload = {\n term: myTerm\n }\n} else {\n var dataLog = global.get(\"device1.dataLog\");\n var lastLogIndex = dataLog[dataLog.length-1].index;\n var newDataLog = [];\n var firstLog = {\n index:msg.payload.lastIncludedIndex,\n term: msg.payload.lastIncludedTerm,\n command: null\n }; \n newDataLog.push(firstLog);\n global.set(\"device1.dataSnapshot.index\", msg.payload.lastIncludedIndex);\n global.set(\"device1.dataSnapshot.term\", msg.payload.lastIncludedTerm);\n global.set(\"device1.dataSnapshot.timestamp\", msg.payload.ts);\n if(lastLogIndex > msg.payload.lastIncludedIndex) {\n for(let log of dataLog) {\n if(log.index > msg.payload.lastIncludedIndex) {\n newDataLog.push(log);\n }\n }\n }\n \n global.set(\"device1.dataLog\", newDataLog);\n \n msg.payload = {\n term: myTerm\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":880,"wires":[["5703d621e5907de8"]]},{"id":"658fc2f4.1026bc","type":"function","z":"e8034ec0.182578","name":"UpdateTerm","func":"var myTerm = global.get(\"device1.currentTerm\");\nif(msg.payload.term > myTerm) {\n global.set(\"device1.currentTerm\", myTerm);\n global.set(\"device1.state\", \"follower\");\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2650,"y":1060,"wires":[[]]},{"id":"110fab30.51d07d","type":"function","z":"e8034ec0.182578","name":"add data command","func":"var lastTimestamp = flow.get(\"lastTimestamp\") || 0;\nnow = parseInt(Date.now());\nif(now > lastTimestamp) {\n // hardcoded structure of data command\n var command = msg.payload;\n var dataLog = global.get(\"device1.dataLog\");\n var prevLogIndex = dataLog[dataLog.length-1].index;\n var term = global.get(\"device1.currentTerm\");\n \n // snapshot here\n var dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\n \n var dataLastApplied = global.get(\"device1.dataLastApplied\");\n var dataSnapshotTH = global.get(\"device1.dataSnapshotTH\");\n if(dataLastApplied - dataSnapshotIndex > dataSnapshotTH) {\n var logAfterSnapshot = [];\n var newDataSnapshotTerm = -1;\n for(let log of dataLog) {\n if(log.index == dataLastApplied){\n newDataSnapshotTerm = log.term;\n let newFirstLog = {\n index: dataLastApplied,\n term: newDataSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n } else if(log.index > dataLastApplied) {\n logAfterSnapshot.push(log);\n }\n }\n global.set(\"device1.dataSnapshot.index\",dataLastApplied);\n global.set(\"device1.dataSnapshot.term\",newDataSnapshotTerm);\n global.set(\"device1.dataSnapshot.command\",command);\n dataLog = logAfterSnapshot;\n \n }\n \n var entry = {\n index: prevLogIndex + 1,\n term: term,\n command: command\n }\n dataLog.push(entry);\n global.set(\"device1.dataLog\", dataLog);\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":1840,"wires":[["20db4fdb.0a2318","6f37cb10.82e28c","19ab3a15.aa5d8e"]]},{"id":"20db4fdb.0a2318","type":"function","z":"e8034ec0.182578","name":"persistent storage","func":"msg.payload = {\n currentTerm: global.get(\"device1.currentTerm\"),\n voteFor: global.get(\"device1.voteFor\"),\n systemLog: global.get(\"device1.systemLog\"),\n dataLog: global.get(\"device1.dataLog\"),\n sysSnapshot: global.get(\"device1.sysSnapshot\"),\n dataSnapshot: global.get(\"device1.dataSnapshot\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":810,"y":1840,"wires":[["479d48c8.9f7a7"]]},{"id":"479d48c8.9f7a7","type":"file","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":1070,"y":1840,"wires":[[]]},{"id":"5f0d35de.012b5c","type":"trigger","z":"e8034ec0.182578","name":"","op1":"","op2":"timeout","op1type":"pay","op2type":"str","duration":"2","extend":true,"overrideDelay":false,"units":"s","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":1410,"y":1300,"wires":[["96868548.e8294"]]},{"id":"63672d6f.8a13e4","type":"inject","z":"e8034ec0.182578","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1240,"y":1380,"wires":[["13f0d3b8.350424"]]},{"id":"13f0d3b8.350424","type":"function","z":"e8034ec0.182578","name":"reassign virtualFuncs","func":"var virtualFuncs = global.get(\"device1.virtualFuncs\");\nvar i = 0;\nfor(let virtualFunc of virtualFuncs) {\n virtualFuncs[i].device = null;\n i += 1;\n}\nglobal.set(\"device1.virtualFuncs\", virtualFuncs);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1440,"y":1380,"wires":[["683575de.cc64fc"]]},{"id":"e6876b38.23ad6","type":"function","z":"e8034ec0.182578","name":"SendDataSnapshot","func":"var serverId = msg.serverId;\nvar dataSnapshot = global.get(\"device1.dataSnapshot\");\nmsg.payload = {\n leaderId: global.get(\"device1.id\"),\n sendId: serverId,\n term: global.get(\"device1.currentTerm\"),\n lastIncludedIndex: parseInt(dataSnapshot.index),\n lastIncludedTerm: parseInt(dataSnapshot.term),\n ts: parseInt(dataSnapshot.timestamp),\n savedData: global.get(\"device1.dataSnapshot.command\")\n \n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1510,"y":1000,"wires":[["5d04d981016bc6d7"]]},{"id":"c5aace1d.804398","type":"debug","z":"e8034ec0.182578","name":"old leader failed","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1240,"y":360,"wires":[]},{"id":"d3aab986.98d398","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":360,"wires":[["c5aace1d.804398"]]},{"id":"182141de.c0edc6","type":"debug","z":"e8034ec0.182578","name":"new leader elected","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1250,"y":400,"wires":[]},{"id":"82ba0c9b.becd58","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":400,"wires":[["182141de.c0edc6"]]},{"id":"6441d6b8.f19c3","type":"debug","z":"e8034ec0.182578","name":"device failed","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":2090,"y":1300,"wires":[]},{"id":"e44b25dd.175e5","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1880,"y":1300,"wires":[["6441d6b8.f19c3"]]},{"id":"ea733857.b50658","type":"debug","z":"e8034ec0.182578","name":"vf re-allocated","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1040,"y":1380,"wires":[]},{"id":"f7de9d89.d7bbb8","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":880,"y":1380,"wires":[["ea733857.b50658"]]},{"id":"df0c7fde.e70108","type":"comment","z":"e8034ec0.182578","name":"candidate","info":"","x":140,"y":220,"wires":[]},{"id":"a3c4c508.5be348","type":"comment","z":"e8034ec0.182578","name":"follower","info":"","x":130,"y":760,"wires":[]},{"id":"16eb0377.f5d345","type":"comment","z":"e8034ec0.182578","name":"leader","info":"","x":70,"y":1180,"wires":[]},{"id":"8aedaf86.888ad8","type":"comment","z":"e8034ec0.182578","name":"Number of devices and own ID hardcoded here","info":"","x":1160,"y":220,"wires":[]},{"id":"ec050daf.aafe28","type":"comment","z":"e8034ec0.182578","name":"output only if there is another device","info":"","x":320,"y":1180,"wires":[]},{"id":"a2826e04.96ba1","type":"comment","z":"e8034ec0.182578","name":"message other devices","info":"","x":600,"y":1140,"wires":[]},{"id":"5322b28f.4e3fec","type":"split","z":"e8034ec0.182578","name":"split","splt":"10","spltType":"len","arraySplt":"10","arraySpltType":"len","stream":false,"addname":"","x":670,"y":1560,"wires":[["040c7202e8ec3d38"]]},{"id":"b1e30b63.7bc448","type":"comment","z":"e8034ec0.182578","name":"also makes sys snapshot","info":"","x":1690,"y":1420,"wires":[]},{"id":"32925675.b64caa","type":"comment","z":"e8034ec0.182578","name":"all devices: update vf allocation","info":"","x":370,"y":1340,"wires":[]},{"id":"32535587.8d31d2","type":"comment","z":"e8034ec0.182578","name":"also makes data snapshot","info":"","x":490,"y":1880,"wires":[]},{"id":"3a1d71ba.6cd56e","type":"function","z":"e8034ec0.182578","name":"Update - unit failure","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar failed = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET FAILED = C.FAILED FROM ( VALUES ( '\" + names[0] + \"', \" + failed[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + failed[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, FAILED) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":1600,"wires":[["85cba6bd.c0f18"]]},{"id":"a3481321.eff9d","type":"function","z":"e8034ec0.182578","name":"Update - unit activation","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar status = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET ACTIVE = C.ACTIVE FROM ( VALUES ( '\" + names[0] + \"', \" + status[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + status[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, ACTIVE) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":1560,"wires":[["85cba6bd.c0f18"]]},{"id":"85cba6bd.c0f18","type":"postgres","z":"e8034ec0.182578","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":false,"outputs":0,"x":1370,"y":1600,"wires":[]},{"id":"10ffb8a7.ba3487","type":"function","z":"e8034ec0.182578","name":"load from persistent storage","func":"global.set(\"device1\",undefined); // clear history\n\nif(msg.payload.length===1){ // if exists\n global.set(\"device1.currentTerm\", msg.payload[0].currentTerm);\n global.set(\"device1.voteFor\", msg.payload[0].voteFor);\n global.set(\"device1.systemLog\",msg.payload[0].systemLog);\n global.set(\"device1.dataLog\",msg.payload[0].dataLog);\n global.set(\"device1.sysSnapshot\", msg.payload[0].sysSnapshot);\n global.set(\"device1.dataSnapshot\", msg.payload[0].dataSnapshot);\n \n} else {\n global.set(\"device1.currentTerm\", 0);\n global.set(\"device1.voteFor\", null);\n global.set(\"device1.systemLog[0].index\",0);\n global.set(\"device1.systemLog[0].term\",0);\n global.set(\"device1.systemLog[0].command\",null);\n global.set(\"device1.dataLog[0].index\",0);\n global.set(\"device1.dataLog[0].term\",0);\n global.set(\"device1.dataLog[0].command\",null);\n global.set(\"device1.sysSnapshot.index\", 0);\n global.set(\"device1.sysSnapshot.term\", 0);\n global.set(\"device1.sysSnapshot.virtualFuncs[0].name\", \"FaultLoc\");\n global.set(\"device1.sysSnapshot.virtualFuncs[0].device\", null);\n global.set(\"device1.sysSnapshot.virtualFuncs[1].name\", \"ServiceRes\");\n global.set(\"device1.sysSnapshot.virtualFuncs[1].device\", null);\n global.set(\"device1.dataSnapshot.index\", 0);\n global.set(\"device1.dataSnapshot.term\", 0);\n global.set(\"device1.dataSnapshot.timestamp\", null);\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":260,"wires":[["8cfc218d.653c98"]]},{"id":"e85be469.ba8498","type":"function","z":"e8034ec0.182578","name":"","func":"var command = msg.payload.command;\nif(command) {\n msg.payload = command.split(',').map(Number);\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":1560,"wires":[["5322b28f.4e3fec"]]},{"id":"9a1bba8b.93412","type":"function","z":"e8034ec0.182578","name":"isLeader & dataCommand","func":"var dataLastApplied = global.get(\"device1.dataLastApplied\");\nvar command = null;\nif(global.get(\"device1.state\") == \"leader\"){ \n var dataLog = global.get(\"device1.dataLog\");\n for(let log of dataLog) {\n if(log.index == dataLastApplied) {\n command = log.command;\n break;\n }\n }\n if(command) {\n msg.payload = command.split(',').map(Number);\n return msg;\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":1720,"wires":[[]]},{"id":"3603e552.3536ea","type":"split","z":"e8034ec0.182578","name":"split","splt":"10","spltType":"len","arraySplt":"10","arraySpltType":"len","stream":false,"addname":"","x":930,"y":1880,"wires":[["a0fa6158.213458"]]},{"id":"a0fa6158.213458","type":"switch","z":"e8034ec0.182578","name":"","property":"payload","propertyType":"msg","rules":[{"t":"index","v":"0","vt":"num","v2":"0","v2t":"num"},{"t":"index","v":"1","vt":"num","v2":"1","v2t":"num"},{"t":"index","v":"2","vt":"num","v2":"2","v2t":"num"}],"checkall":"true","repair":false,"outputs":3,"x":1090,"y":1880,"wires":[["8491bef5.a35f98"],["7198942e.f5b2c4"],["c40085a686a1f474"]]},{"id":"b07e41ef.2a8b58","type":"postgres","z":"e8034ec0.182578","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":false,"outputs":0,"x":1630,"y":1920,"wires":[]},{"id":"6f37cb10.82e28c","type":"function","z":"e8034ec0.182578","name":"","func":"var dataLog = global.get(\"device1.dataLog\");\nvar dataLastApplied = global.get(\"device1.dataLastApplied\");\nfor(let log of dataLog) {\n if(log.index == dataLastApplied) {\n command = log.command;\n break;\n }\n}\nif(command) {\n msg.payload = command.split(',').map(Number);\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":780,"y":1880,"wires":[["3603e552.3536ea"]]},{"id":"9f80a15f.bb2a98","type":"mytimeout","z":"e8034ec0.182578","name":"","outtopic":"","outsafe":"","outwarning":"Warning","outunsafe":"off","warning":"5","timer":"30","debug":false,"ndebug":false,"ignoreCase":false,"repeat":false,"again":false,"x":730,"y":380,"wires":[["5b97fc86.32033c","d3aab986.98d398"],[]]},{"id":"3eb17029.4cd0d8","type":"function","z":"e8034ec0.182578","name":"take time","func":"var myState = global.get(\"device1.state\");\nif(myState == \"follower\"){\n msg.date = parseInt(Date.now());\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":1600,"wires":[["bf99977b.1dc21"]]},{"id":"bf99977b.1dc21","type":"debug","z":"e8034ec0.182578","name":"data command received","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":730,"y":1600,"wires":[]},{"id":"19ab3a15.aa5d8e","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":780,"y":1800,"wires":[["ba61460f.c3cea"]]},{"id":"ba61460f.c3cea","type":"debug","z":"e8034ec0.182578","name":"data command added","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":980,"y":1800,"wires":[]},{"id":"7198942e.f5b2c4","type":"function","z":"e8034ec0.182578","name":"Update - unit failure","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar failed = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET FAILED = C.FAILED FROM ( VALUES ( '\" + names[0] + \"', \" + failed[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + failed[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, FAILED) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1360,"y":1920,"wires":[["b07e41ef.2a8b58"]]},{"id":"8491bef5.a35f98","type":"function","z":"e8034ec0.182578","name":"Update - unit activation","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar status = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET ACTIVE = C.ACTIVE FROM ( VALUES ( '\" + names[0] + \"', \" + status[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + status[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, ACTIVE) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1370,"y":1880,"wires":[["b07e41ef.2a8b58"]]},{"id":"b2cde435ac09a8c8","type":"comment","z":"e8034ec0.182578","name":"Read persistent storage","info":"","x":320,"y":220,"wires":[]},{"id":"bf2b6e298f3a8e0e","type":"comment","z":"e8034ec0.182578","name":"Init Term / Logs / Snapshot","info":"","x":830,"y":220,"wires":[]},{"id":"c385cce04ce02b57","type":"comment","z":"e8034ec0.182578","name":"Init parameters","info":"","x":1060,"y":180,"wires":[]},{"id":"f5e15eec8e459022","type":"comment","z":"e8034ec0.182578","name":"Loop","info":"","x":710,"y":340,"wires":[]},{"id":"1cfb607e7b3c5378","type":"comment","z":"e8034ec0.182578","name":"Request Votes from other devices","info":"","x":590,"y":480,"wires":[]},{"id":"5581712efefb15d0","type":"comment","z":"e8034ec0.182578","name":"Init leader and set next / match indices","info":"","x":1770,"y":360,"wires":[]},{"id":"65d1529c825035d1","type":"comment","z":"e8034ec0.182578","name":"Write persistens storage","info":"","x":970,"y":720,"wires":[]},{"id":"7b140ddc3b3bebda","type":"comment","z":"e8034ec0.182578","name":"Append Entries","info":"","x":800,"y":1140,"wires":[]},{"id":"d3e424a412dd5eba","type":"comment","z":"e8034ec0.182578","name":"DataSnapshot","info":"","x":1250,"y":960,"wires":[]},{"id":"5219faa00c283942","type":"comment","z":"e8034ec0.182578","name":"SysSnapshot","info":"","x":1250,"y":1100,"wires":[]},{"id":"095f38e191be1d09","type":"comment","z":"e8034ec0.182578","name":"make dataCommand","info":"","x":330,"y":1680,"wires":[]},{"id":"454e8a3cfd7fdbd8","type":"function","z":"e8034ec0.182578","name":"Check virtual assignment","func":"msg = {\n payload: {\n id: global.get(\"device1.id\"),\n virtualFunctions: global.get(\"device1.virtualFuncs\")\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":1480,"wires":[[]]},{"id":"c40085a686a1f474","type":"function","z":"e8034ec0.182578","name":"Update - unit available flexibility","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar av_flex = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET AVAILABLE_FLEXIBILITY = C.AVAILABLE_FLEXIBILITY FROM ( VALUES ( '\" + names[0] + \"', \" + av_flex[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + av_flex[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, AVAILABLE_FLEXIBILITY) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1390,"y":1960,"wires":[["b07e41ef.2a8b58"]]},{"id":"88800c24c8448a17","type":"function","z":"e8034ec0.182578","name":"Update - unit available flexibility","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar av_flex = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET AVAILABLE_FLEXIBILITY = C.AVAILABLE_FLEXIBILITY FROM ( VALUES ( '\" + names[0] + \"', \" + av_flex[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + av_flex[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, AVAILABLE_FLEXIBILITY) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1090,"y":1640,"wires":[["85cba6bd.c0f18"]]},{"id":"040c7202e8ec3d38","type":"switch","z":"e8034ec0.182578","name":"","property":"payload","propertyType":"msg","rules":[{"t":"index","v":"0","vt":"num","v2":"0","v2t":"num"},{"t":"index","v":"1","vt":"num","v2":"1","v2t":"num"},{"t":"index","v":"2","vt":"num","v2":"2","v2t":"num"}],"checkall":"true","repair":false,"outputs":3,"x":850,"y":1560,"wires":[["a3481321.eff9d"],["3a1d71ba.6cd56e"],["88800c24c8448a17"]]},{"id":"5f8746972ea09559","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9054\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nflow.set(\"voteCount\", 1);\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":520,"wires":[["8bbadb902812373d"]]},{"id":"cc3ee8e61e7e014f","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":1130,"y":520,"wires":[["f77426521f69308d"]]},{"id":"b5c5283949b29bd5","type":"tcp in","z":"e8034ec0.182578","name":"","server":"server","host":"","port":9054,"datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":120,"y":800,"wires":[["22d97f5b4bf69158"]]},{"id":"9e8f5a354ad3eb90","type":"tcp out","z":"e8034ec0.182578","name":"","host":"","port":"","beserver":"reply","base64":false,"end":false,"tls":"","x":1030,"y":840,"wires":[]},{"id":"36bdd2368f037954","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1010,"y":520,"wires":[["cc3ee8e61e7e014f"]]},{"id":"f77426521f69308d","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":1250,"y":520,"wires":[["3e3a97b7.c7f7b"]]},{"id":"22d97f5b4bf69158","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":250,"y":800,"wires":[["4759aa603ba068a3","5aed97c5bedd1905","4538c7f3cb0a8cb1","3b925a2d83cb3541","96f53eeb1fc07946"]]},{"id":"5703d621e5907de8","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":910,"y":840,"wires":[["9e8f5a354ad3eb90"]]},{"id":"8bbadb902812373d","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":880,"y":520,"wires":[["36bdd2368f037954"]]},{"id":"4759aa603ba068a3","type":"function","z":"e8034ec0.182578","name":"RequestVote","func":"if (msg.payload.func == \"RequestVote\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":800,"wires":[["7ee6d5c.ae9d22c","14b1e89c.463d47"]]},{"id":"5aed97c5bedd1905","type":"function","z":"e8034ec0.182578","name":"AppendEntries","func":"if (msg.payload.func == \"AppendEntries\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":760,"wires":[["17745a55.895cfe","14b1e89c.463d47"]]},{"id":"4538c7f3cb0a8cb1","type":"function","z":"e8034ec0.182578","name":"SendSysSnapshot","func":"if (msg.payload.func == \"SendSysSnapshot\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":840,"wires":[["90cc26d4.0b84b"]]},{"id":"3b925a2d83cb3541","type":"function","z":"e8034ec0.182578","name":"SendDataSnapshot","func":"if (msg.payload.func == \"SendDataSnapshot\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":880,"wires":[["619d09e2.17e938"]]},{"id":"2e283c9da7afbc58","type":"comment","z":"e8034ec0.182578","name":"response","info":"","x":920,"y":800,"wires":[]},{"id":"6f9c0baf10f8bc91","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar ident = msg.payload.sendId - 100000;\n\nmsg.host = prefix + ident + suffix;\nmsg.port = \"9054\";\nmsg.sendId = 100000+ident;\nmsg.payload.func = \"AppendEntries\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":1220,"wires":[["e3075d272d368e0e"]]},{"id":"e3075d272d368e0e","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":1220,"wires":[["ea1916f3768498a2"]]},{"id":"de6c75391121cb2c","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":830,"y":1220,"wires":[["86e3f9cfc8f6cae0"]]},{"id":"86e3f9cfc8f6cae0","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":990,"y":1180,"wires":[["a102604a.fe65c8"]]},{"id":"5d04d981016bc6d7","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9054\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"SendDataSnapshot\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1690,"y":1000,"wires":[["d91029af30d9e993"]]},{"id":"d91029af30d9e993","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1840,"y":1000,"wires":[["6c96aa710feb750e"]]},{"id":"6c96aa710feb750e","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1970,"y":1000,"wires":[["b836828fc215281b"]]},{"id":"b836828fc215281b","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":2090,"y":1000,"wires":[["6bf2228941ab98ad"]]},{"id":"6bf2228941ab98ad","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":2390,"y":1000,"wires":[["658fc2f4.1026bc"]]},{"id":"1506bd50e6d17b03","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\nvar sendId = msg.payload.sendId;\nvar digit = String(sendId).slice(-1);\n\nvar newMsg;\n\n//for (i= 0; i<len;i++) {\nlet clone = JSON.parse(JSON.stringify(msg));\nnewMsg = clone;\nnewMsg.host = prefix + digit + suffix;\nnewMsg.port = \"9054\"\nnewMsg.payload.func = \"SendSysSnapshot\"\n//}\n\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1690,"y":1140,"wires":[["35dfc499ac9e60b2"]]},{"id":"35dfc499ac9e60b2","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1840,"y":1140,"wires":[["029af64f3c4b5ea3"]]},{"id":"029af64f3c4b5ea3","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1970,"y":1140,"wires":[["3cbdf438b0bc8cbe"]]},{"id":"3cbdf438b0bc8cbe","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":2090,"y":1140,"wires":[["c4fe538d3b3c831b"]]},{"id":"c4fe538d3b3c831b","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":2390,"y":1140,"wires":[["658fc2f4.1026bc"]]},{"id":"954c09e32251cddd","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9054\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"AssignVirtualFunctions\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":890,"y":1420,"wires":[["d8e7fae1232d045c"]]},{"id":"d8e7fae1232d045c","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1030,"y":1420,"wires":[["91c0b7872256d6ed"]]},{"id":"91c0b7872256d6ed","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":1150,"y":1420,"wires":[[]]},{"id":"ea1916f3768498a2","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":830,"y":1180,"wires":[["de6c75391121cb2c"]]},{"id":"96f53eeb1fc07946","type":"function","z":"e8034ec0.182578","name":"AssignVirtualFunctions","func":"if (msg.payload.func == \"AssignVirtualFunctions\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":920,"wires":[["0011097be96ce17b"]]},{"id":"0011097be96ce17b","type":"link out","z":"e8034ec0.182578","name":"","mode":"link","links":["eff75d391a641181"],"x":615,"y":920,"wires":[]},{"id":"4f267f9ff6ead2a1","type":"comment","z":"e8034ec0.182578","name":"Reset / Restart Devices","info":"","x":1500,"y":40,"wires":[]},{"id":"047bb659641db7b3","type":"inject","z":"e8034ec0.182578","name":"Reset","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1450,"y":80,"wires":[["2f0a2d9a6a5ae277"]]},{"id":"abc7f37fcb86b2c1","type":"inject","z":"e8034ec0.182578","name":"Restart","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1450,"y":120,"wires":[["b8f1030f757eaeae"]]},{"id":"31c9e50922f4356b","type":"udp out","z":"e8034ec0.182578","name":"","addr":"","iface":"","port":"","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":1730,"y":80,"wires":[]},{"id":"cec0f2e3bc81a7a5","type":"udp out","z":"e8034ec0.182578","name":"","addr":"","iface":"","port":"","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":1730,"y":120,"wires":[]},{"id":"2f0a2d9a6a5ae277","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].ip = \"dv-raspi-\" + (i+1) + \".acs-lab.eonerc.rwth-aachen.de\"\n newMsg[i].port = \"9055\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1590,"y":80,"wires":[["31c9e50922f4356b"]]},{"id":"b8f1030f757eaeae","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].ip = \"dv-raspi-\" + (i+1) + \".acs-lab.eonerc.rwth-aachen.de\"\n newMsg[i].port = \"9056\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1590,"y":120,"wires":[["cec0f2e3bc81a7a5"]]},{"id":"bdfbcb5df0b6488b","type":"udp in","z":"e8034ec0.182578","name":"","iface":"","port":"9056","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":140,"y":300,"wires":[["2dc3a3fb.e32ef4"]]},{"id":"b77c725d549754fc","type":"tcp in","z":"e8034ec0.182578","name":"","server":"server","host":"","port":"9055","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":140,"y":1840,"wires":[["bccc8582091ccdaf"]]},{"id":"67bd8c3368fe93ac","type":"comment","z":"e8034ec0.182578","name":"delay oder isSuccess vorziehen?","info":"","x":1030,"y":1100,"wires":[]},{"id":"b7c83a94a8062d1f","type":"comment","z":"e8034ec0.182578","name":"hier kommen gleichzeitig mehrere antworten zurück","info":"","x":2350,"y":1180,"wires":[]},{"id":"bccc8582091ccdaf","type":"function","z":"e8034ec0.182578","name":"parseData","func":"var command = msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":1840,"wires":[["110fab30.51d07d"]]},{"id":"db1b91c55349dd57","type":"comment","z":"e8034ec0.182578","name":"Show params","info":"","x":150,"y":40,"wires":[]},{"id":"5ae8f5f7.cf75a4","type":"debug","z":"c206ac56.ec99c8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":730,"y":360,"wires":[]},{"id":"cde710a9.b993a8","type":"file","z":"c206ac56.ec99c8","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":590,"y":80,"wires":[[]]},{"id":"5ef2ff32.208ae","type":"inject","z":"c206ac56.ec99c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":140,"y":80,"wires":[["fe2f2f69.538e6","58ab7f46.b59168"]]},{"id":"fe2f2f69.538e6","type":"function","z":"c206ac56.ec99c8","name":"","func":"global.set(\"device1\", undefined); // clear history\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":120,"wires":[[]]},{"id":"a350f8b4.19fac","type":"postgres","z":"c206ac56.ec99c8","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":true,"outputs":1,"x":590,"y":360,"wires":[["5ae8f5f7.cf75a4"]]},{"id":"9caf36a4.fe9da8","type":"comment","z":"c206ac56.ec99c8","name":"Create local storage","info":"","x":170,"y":40,"wires":[]},{"id":"281ea7c5.d05968","type":"comment","z":"c206ac56.ec99c8","name":"Create Postgres Database","info":"","x":190,"y":180,"wires":[]},{"id":"d9756d90.a9447","type":"comment","z":"c206ac56.ec99c8","name":"Receive RTDS measurements and send to Postgres DB","info":"","x":280,"y":520,"wires":[]},{"id":"15cf0a6.82e9776","type":"inject","z":"c206ac56.ec99c8","name":"Delete","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":360,"wires":[["53ba8819.38b32"]]},{"id":"53ba8819.38b32","type":"function","z":"c206ac56.ec99c8","name":"Delete rows","func":"//msg.payload = \"DELETE FROM RANDOMNUM WHERE timestamp <= localtimestamp - interval '2 hours'\";\nvar db_hist = msg.payload - 300*1000;\nmsg.payload = \"DELETE FROM UNIT_MEAS WHERE timestamp < \" + db_hist + \"\";\nmsg.connectName = \"connect\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":360,"wires":[["a350f8b4.19fac"]]},{"id":"493929d0.eedbe8","type":"inject","z":"c206ac56.ec99c8","name":"Create","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":420,"wires":[["63fb8762.15c9e8"]]},{"id":"63fb8762.15c9e8","type":"function","z":"c206ac56.ec99c8","name":"Create UNIT_STATES","func":"msg.payload = \"CREATE TABLE UNIT_STATES( NAME VARCHAR(7) PRIMARY KEY NOT NULL, ACTIVE INT NOT NULL, FAILED INT NOT NULL, PRIO INT NOT NULL, FLEXIBILITY INT NOT NULL, AVAILABLE_FLEXIBILITY INT NOT NULL)\";\nmsg.connectName = 'connect';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":420,"wires":[["a350f8b4.19fac"]]},{"id":"80e17478.6589a8","type":"function","z":"c206ac56.ec99c8","name":"Initialize UNIT_STATES","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\n\nvar sqlWrite = \"INSERT INTO UNIT_STATES VALUES ( '\" + names[0] + \"', 1, 0, 1, 100, 0)\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ('\" + names[i] + \"', 1, 0, \" + String(i+1) + \", 100, 0)\";\n }\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":460,"wires":[["a350f8b4.19fac"]]},{"id":"6c492c88.7d8d1c","type":"inject","z":"c206ac56.ec99c8","name":"Initialize","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":460,"wires":[["80e17478.6589a8"]]},{"id":"98fe32bf.64ec48","type":"comment","z":"c206ac56.ec99c8","name":"insert initial config to persistent storage","info":"","x":910,"y":80,"wires":[]},{"id":"58ab7f46.b59168","type":"function","z":"c206ac56.ec99c8","name":"persistent storage","func":"var unit_status = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]; \n\nmsg.payload = {\n currentTerm: 0,\n voteFor: null,\n systemLog: [{\n index: 0,\n term: 0,\n command: null\n }],\n dataLog: [{\n index: 0,\n term: 0,\n command: \"\" + unit_status.toString()\n }],\n sysSnapshot: {\n index: 0,\n term: 0,\n \"virtualFuncs\": [{\n \"name\":\"FaultLoc\",\n \"device\":null\n },\n {\n \"name\":\"ServiceRes\",\n \"device\":null\n }]\n },\n dataSnapshot: {\n index: 0,\n term: 0,\n timestamp: null\n }\n};\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":80,"wires":[["cde710a9.b993a8"]]},{"id":"1eb756d4.730e99","type":"postgres","z":"c206ac56.ec99c8","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":false,"outputs":0,"x":710,"y":560,"wires":[]},{"id":"a7f06bfd.b48668","type":"function","z":"c206ac56.ec99c8","name":"insert measurements","func":"var timestamp = msg.payload[10];\nmsg.time = timestamp;\n\nvar sqlWrite = \"INSERT INTO UNIT_MEAS VALUES (\" + timestamp;\nvar i = 0\nfor (i; i < 10; i++) {\n sqlWrite = sqlWrite + \", \" + msg.payload[i];\n }\n\nsqlWrite = sqlWrite + \")\";\n\nmsg.payload = sqlWrite\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":560,"wires":[["1eb756d4.730e99"]]},{"id":"10f26799.ffa6c","type":"inject","z":"c206ac56.ec99c8","name":"Create","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":320,"wires":[["696440f1.1f9bb"]]},{"id":"696440f1.1f9bb","type":"function","z":"c206ac56.ec99c8","name":"Create UNIT_MEAS","func":"msg.payload = \"CREATE TABLE UNIT_MEAS( TIMESTAMP BIGINT PRIMARY KEY NOT NULL, U01 DECIMAL NOT NULL, U02 DECIMAL NOT NULL, U03 DECIMAL NOT NULL, U04 DECIMAL NOT NULL, U05 DECIMAL NOT NULL, U06 DECIMAL NOT NULL, U07 DECIMAL NOT NULL, U08 DECIMAL NOT NULL, U09 DECIMAL NOT NULL, U10 DECIMAL NOT NULL)\";\nmsg.connectName = 'connect';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":320,"wires":[["a350f8b4.19fac"]]},{"id":"d29dab.56ad4a58","type":"udp in","z":"c206ac56.ec99c8","name":"","iface":"","port":"11001","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":140,"y":600,"wires":[["a28566c1.725e18"]]},{"id":"a28566c1.725e18","type":"function","z":"c206ac56.ec99c8","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":300,"y":600,"wires":[["aad15ffa.bdb8a"]]},{"id":"aad15ffa.bdb8a","type":"debug","z":"c206ac56.ec99c8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":480,"y":600,"wires":[]},{"id":"5c4ed4eee2bea740","type":"comment","z":"c206ac56.ec99c8","name":"Create Postgres Tables","info":"","x":180,"y":280,"wires":[]},{"id":"b92dbb76777f4f0d","type":"inject","z":"c206ac56.ec99c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":220,"wires":[["e1e15906f4587a92"]]},{"id":"e1e15906f4587a92","type":"function","z":"c206ac56.ec99c8","name":"createdb","func":"msg.payload = \"psql -c 'CREATE DATABASE vpp' 'user=pi password=pi'\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":220,"wires":[["dbbf82d70aec4021"]]},{"id":"dbbf82d70aec4021","type":"exec","z":"c206ac56.ec99c8","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":450,"y":220,"wires":[["0ae3468a33a07a4a"],["0ae3468a33a07a4a"],["0ae3468a33a07a4a"]]},{"id":"0ae3468a33a07a4a","type":"debug","z":"c206ac56.ec99c8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":610,"y":220,"wires":[]},{"id":"ad7c0d1ed0f68d06","type":"udp in","z":"c206ac56.ec99c8","name":"","iface":"","port":"9055","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":140,"y":120,"wires":[["fe2f2f69.538e6","58ab7f46.b59168"]]},{"id":"b732853e8429b6c8","type":"tcp in","z":"c206ac56.ec99c8","name":"","server":"server","host":"","port":"9057","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":140,"y":560,"wires":[["3aae273b98bb025d"]]},{"id":"3aae273b98bb025d","type":"function","z":"c206ac56.ec99c8","name":"parse string","func":"msg.payload = msg.payload.split(\",\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":560,"wires":[["a7f06bfd.b48668"]]},{"id":"f77f070b.c25478","type":"function","z":"f825e8a0.9d51f","name":"access check","func":"var myLeaderId = global.get(\"device1.leaderId\");\nif(myLeaderId == msg.payload.id) {\n var myId = global.get(\"device1.id\");\n var virtualFunctions = msg.payload.virtualFunctions;\n for (let vf of virtualFunctions) {\n if(vf.name == \"FaultLoc\" && vf.device == myId) {\n flow.set(\"FaultLocEnabled\", true);\n flow.set(\"FaultLocId\", vf.device);\n } else if (vf.name == \"FaultLoc\" && vf.device!= myId) {\n flow.set(\"FaultLocEnabled\", false);\n flow.set(\"FaultLocId\", vf.device);\n } else if(vf.name == \"ServiceRes\" && vf.device == myId) {\n flow.set(\"ServiceResEnabled\", true);\n flow.set(\"ServiceResId\", vf.device);\n } else if(vf.name == \"ServiceRes\" && vf.device != myId) {\n flow.set(\"ServiceResEnabled\", false);\n flow.set(\"ServiceResId\", vf.device);\n }\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":180,"wires":[["6ecc2121.346a9","ea2cec30.1692a"]]},{"id":"874f9edf.346148","type":"exec","z":"f825e8a0.9d51f","command":"python3 ","addpay":"payload","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"","x":1460,"y":120,"wires":[["de4d01b7.3553a"],["43026d12.890aac"],["49bbf8d1.cf35b8","93d9142d.ba3a88"]]},{"id":"43026d12.890aac","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1790,"y":120,"wires":[]},{"id":"49bbf8d1.cf35b8","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1650,"y":140,"wires":[]},{"id":"6ecc2121.346a9","type":"function","z":"f825e8a0.9d51f","name":"start FaultLoc","func":"var isEnabled = flow.get(\"FaultLocEnabled\") || false;\n\nif(isEnabled){\n let py_path=\"/home/pi/distributed-dvam/functions/Failure_Detection.py\";\n msg.payload=\"-u \" + py_path;\n msg.msg = msg.payload;\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":160,"wires":[["3ddffbff.3a8d04"]]},{"id":"de4d01b7.3553a","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1650,"y":100,"wires":[]},{"id":"df4406bf.169eb8","type":"udp in","z":"f825e8a0.9d51f","name":"","iface":"","port":"9001","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":1160,"y":760,"wires":[["bb916d1b.bc69f","ae6c6d08.82db68","879c5c8b.8f7ae8"]]},{"id":"dc738b2b.dbc73","type":"comment","z":"f825e8a0.9d51f","name":"Receive output from FL and sent to leader","info":"","x":200,"y":760,"wires":[]},{"id":"60772234.eb2e74","type":"comment","z":"f825e8a0.9d51f","name":"FL - call Python script","info":"","x":1460,"y":60,"wires":[]},{"id":"ec039494.c9d47","type":"exec","z":"f825e8a0.9d51f","command":"python3 ","addpay":"payload","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"","x":1460,"y":240,"wires":[["5cebfc32.63f084"],["663dac7c.4504dc"],["11dd1c54.d9432c","e4e66725.559a"]]},{"id":"663dac7c.4504dc","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1790,"y":240,"wires":[]},{"id":"11dd1c54.d9432c","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1650,"y":260,"wires":[]},{"id":"ea2cec30.1692a","type":"function","z":"f825e8a0.9d51f","name":"start ServiceRes","func":"var isEnabled = flow.get(\"ServiceResEnabled\") || false;\n\nif(isEnabled){\n let py_path=\"/home/pi/distributed-dvam/functions/Service_Restoration.py\";\n msg.payload=\"-u \" + py_path;\n msg.msg = msg.payload;\n return msg;\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":200,"wires":[["f6949d11.98549"]]},{"id":"5cebfc32.63f084","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1650,"y":220,"wires":[]},{"id":"1c25bea4.df3861","type":"udp in","z":"f825e8a0.9d51f","name":"","iface":"","port":"9002","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":1160,"y":840,"wires":[["bb916d1b.bc69f","ae6c6d08.82db68","879c5c8b.8f7ae8"]]},{"id":"e90189e7.7dda8","type":"comment","z":"f825e8a0.9d51f","name":"Receive output from SR and sent to leader","info":"","x":200,"y":840,"wires":[]},{"id":"7ad5313e.ff76b","type":"comment","z":"f825e8a0.9d51f","name":"SR - call Python script","info":"","x":1460,"y":180,"wires":[]},{"id":"bb916d1b.bc69f","type":"function","z":"f825e8a0.9d51f","name":"access check","func":"if(100001 == global.get(\"device1.leaderId\")) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1320,"y":760,"wires":[[]]},{"id":"ae6c6d08.82db68","type":"function","z":"f825e8a0.9d51f","name":"access check","func":"if(100002 == global.get(\"device1.leaderId\")) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1320,"y":800,"wires":[[]]},{"id":"879c5c8b.8f7ae8","type":"function","z":"f825e8a0.9d51f","name":"access check","func":"if(100003 == global.get(\"device1.leaderId\")) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1320,"y":840,"wires":[[]]},{"id":"c36c4d45.ffe018","type":"udp out","z":"f825e8a0.9d51f","name":"","addr":"dv-raspi-4.acs-lab.eonerc.rwth-aachen.de","iface":"","port":"9003","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":1610,"y":760,"wires":[]},{"id":"c4cdf9cc.23ddd8","type":"udp out","z":"f825e8a0.9d51f","name":"","addr":"dv-raspi-5.acs-lab.eonerc.rwth-aachen.de","iface":"","port":"9003","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":1610,"y":800,"wires":[]},{"id":"e1c3a832.a1fb8","type":"udp out","z":"f825e8a0.9d51f","name":"","addr":"dv-raspi-6.acs-lab.eonerc.rwth-aachen.de","iface":"","port":"9003","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":1610,"y":840,"wires":[]},{"id":"4df67301.c0a4bc","type":"function","z":"f825e8a0.9d51f","name":"kill FaultLoc","func":"var isEnabled = flow.get(\"FaultLocEnabled\") || false;\n\nif(!isEnabled){\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":360,"wires":[["874f9edf.346148"]]},{"id":"185bcbda.b64584","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"kill","v":"SIGTERM","vt":"str"}],"repeat":"5","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1090,"y":360,"wires":[["4df67301.c0a4bc","4706625e.d45c4c"]]},{"id":"4706625e.d45c4c","type":"function","z":"f825e8a0.9d51f","name":"kill ServiceRes","func":"var isEnabled = flow.get(\"ServiceResEnabled\") || false;\n\nif(!isEnabled){\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1260,"y":400,"wires":[["ec039494.c9d47"]]},{"id":"a64b9a90.4658a8","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":740,"y":120,"wires":[["6ecc2121.346a9"]]},{"id":"c1391863.5e787","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":740,"y":240,"wires":[["ea2cec30.1692a"]]},{"id":"ebaf950d.b331f8","type":"debug","z":"f825e8a0.9d51f","name":"FL ready","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1800,"y":60,"wires":[]},{"id":"93d9142d.ba3a88","type":"function","z":"f825e8a0.9d51f","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1660,"y":60,"wires":[["ebaf950d.b331f8"]]},{"id":"e4e66725.559a","type":"function","z":"f825e8a0.9d51f","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1660,"y":180,"wires":[["1d3a7b8a.7f351c"]]},{"id":"1d3a7b8a.7f351c","type":"debug","z":"f825e8a0.9d51f","name":"SR ready","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1800,"y":180,"wires":[]},{"id":"3ddffbff.3a8d04","type":"exec","z":"f825e8a0.9d51f","command":"ps aux","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":1050,"y":120,"wires":[["be289a5.3f54568"],[],[]]},{"id":"f6949d11.98549","type":"exec","z":"f825e8a0.9d51f","command":"ps aux","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":1050,"y":240,"wires":[["a04069d8.aa8848"],[],[]]},{"id":"a7bb4ad4.8aac98","type":"comment","z":"f825e8a0.9d51f","name":"Check running FaultLocalisation","info":"","x":1130,"y":60,"wires":[]},{"id":"92117fa4.4086b","type":"comment","z":"f825e8a0.9d51f","name":"Check running ServiceRestauration","info":"","x":1140,"y":180,"wires":[]},{"id":"be289a5.3f54568","type":"function","z":"f825e8a0.9d51f","name":"","func":"// Checks for multiple occurences\nsearch = \"python3\";\n\n// Text to look in\nvar text = msg.payload.toLowerCase();\n\n// String to look for\nvar regex = new RegExp(search.toLowerCase(), 'g');\n\n// Save indices in array\nvar result = [];\n\nvar split = text.split(\" \");\n\nvar isRunning = false;\n\nfor (var i = 0; i < split.length-2; i++) {\n // Find all python3 occurences\n if ((match = regex.exec(split[i])) != null) {\n // Uncomment to see all python processes\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n \n // Checks for running FaultLocalisation\n if (split[i+2].indexOf(\"failure_detection.py\") != -1) {\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n isRunning = true;\n }\n }\n}\nif (!isRunning) {\n msg.payload = msg.msg;\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1200,"y":120,"wires":[["874f9edf.346148"]]},{"id":"a04069d8.aa8848","type":"function","z":"f825e8a0.9d51f","name":"","func":"// Checks for multiple occurences\nsearch = \"python3\"\n\n// Text to look in\nvar text = msg.payload.toLowerCase();\n\n// String to look for\nvar regex = new RegExp(search.toLowerCase(), 'g');\n\n// Save indices in array\nvar result = [];\n\nvar split = text.split(\" \");\n\nvar isRunning = false;\n\nfor (var i = 0; i < split.length-2; i++) {\n // Find all python3 occurences\n if ((match = regex.exec(split[i])) != null) {\n // Uncomment to see all python processes\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n \n //Checks for running ServiceRestauration\n if (split[i+2].indexOf(\"service_restoration.py\") != -1) {\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n isRunning = true;\n }\n }\n}\nif (!isRunning) {\n msg.payload = msg.msg;\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1200,"y":240,"wires":[["ec039494.c9d47"]]},{"id":"b5ea4f43.7ea21","type":"comment","z":"f825e8a0.9d51f","name":"DV asset function assignment","info":"","x":160,"y":60,"wires":[]},{"id":"b88ec696.342468","type":"comment","z":"f825e8a0.9d51f","name":"Kill falsy running processes","info":"","x":1110,"y":320,"wires":[]},{"id":"eff75d391a641181","type":"link in","z":"f825e8a0.9d51f","name":"AssignVirtualFunctionsIn","links":["0011097be96ce17b"],"x":75,"y":260,"wires":[["f77f070b.c25478"]]},{"id":"c0b68d9321252779","type":"inject","z":"f825e8a0.9d51f","name":"kill without check for testing","props":[{"p":"kill","v":"SIGTERM","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1130,"y":480,"wires":[["ec039494.c9d47","874f9edf.346148"]]},{"id":"df91d2f5562d9d2e","type":"exec","z":"f825e8a0.9d51f","command":"","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":1430,"y":540,"wires":[[],[],[]]},{"id":"c09f1219d31f62d5","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1260,"y":660,"wires":[["df91d2f5562d9d2e"]]},{"id":"a707268eb5faff21","type":"comment","z":"f825e8a0.9d51f","name":"message geht nur an den leader --> durch einen function-host-node (port ist fix) und EINEN udp-out ersetzen","info":"","x":1470,"y":720,"wires":[]},{"id":"c54c56dcbe4e6e04","type":"udp in","z":"f825e8a0.9d51f","name":"","iface":"","port":"9001","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":440,"y":760,"wires":[["b582a9d9dd654431"]]},{"id":"b582a9d9dd654431","type":"function","z":"f825e8a0.9d51f","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9055\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":800,"wires":[["71c647e2d845ff14"]]},{"id":"71c647e2d845ff14","type":"function","z":"f825e8a0.9d51f","name":"toLeader","func":"var leaderId = global.get(\"device1.leaderId\");\n\nif (msg.sendId == leaderId) {\n //msg.payload = \"\" + msg.payload.toString();\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":800,"wires":[["710eacc41aa5b03a"]]},{"id":"93574b7e5746bcb4","type":"udp in","z":"f825e8a0.9d51f","name":"","iface":"","port":"9002","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":440,"y":840,"wires":[["b582a9d9dd654431"]]},{"id":"3379444cca17947c","type":"tcp request","z":"f825e8a0.9d51f","name":"","server":"","port":"","out":"time","ret":"buffer","splitc":"0","newline":"","tls":"","x":890,"y":800,"wires":[[]]},{"id":"710eacc41aa5b03a","type":"function","z":"f825e8a0.9d51f","name":"parseData","func":"node.warn(typeof(msg.payload));\n\nvar s = JSON.stringify(msg.payload);\ns = JSON.parse(s);\nmsg.payload = JSON.stringify(s[\"data\"]);\n\nmsg.payload = msg.payload.substring(1,msg.payload.length-1);\nmsg.payload = msg.payload.split(',').map(Number);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":800,"wires":[["3379444cca17947c"]]},{"id":"6de242b30ec88dbb","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":400,"y":1100,"wires":[["3052ddb875329338"]]},{"id":"3052ddb875329338","type":"function","z":"f825e8a0.9d51f","name":"","func":"var prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nmsg.payload = \"[1,2,1,2,1,2,1,2]\";\nmsg.host = prefix + \"1\" + suffix;\nmsg.port = \"9088\";\n\nmsg.payload = msg.payload.substring(1,msg.payload.length-1);\nmsg.payload = msg.payload.split(',').map(Number);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":1100,"wires":[["bf4a7b9642d97bf6"]]},{"id":"bf4a7b9642d97bf6","type":"tcp request","z":"f825e8a0.9d51f","name":"","server":"","port":"","out":"time","ret":"buffer","splitc":"0","newline":"","tls":"","x":670,"y":1100,"wires":[[]]},{"id":"cfbac421b054011d","type":"tcp in","z":"f825e8a0.9d51f","name":"","server":"server","host":"","port":"9088","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":860,"y":1100,"wires":[["d0d7df3f14425ed4"]]},{"id":"d0d7df3f14425ed4","type":"function","z":"f825e8a0.9d51f","name":"","func":"msg.payload = msg.payload.split(',').map(Number);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1000,"y":1100,"wires":[["defda5e14d764d30"]]},{"id":"defda5e14d764d30","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1150,"y":1100,"wires":[]},{"id":"9461393e.0e724","type":"inject","z":"6d95b6d3.106588","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":100,"wires":[["856a3489.e1c158"]]},{"id":"856a3489.e1c158","type":"function","z":"6d95b6d3.106588","name":"generate measurements","func":"var timestamp = msg.payload;\nvar measurements = [];\nvar power = 0;\n\nvar i = 0;\nfor (i; i < 10; i++) {\n if ((flow.get(\"failure\") || false) && i == 1) {\n power = 0\n }\n else {\n power=Math.ceil(Math.random()*20)+90;\n }\n measurements.push(power);\n}\n\nmeasurements.push(timestamp);\n\nmsg.payload = measurements\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":100,"wires":[["5687ca1b485d3cab"]]},{"id":"cf757ad1.575d","type":"inject","z":"6d95b6d3.106588","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":220,"wires":[["10720989.b356e6"]]},{"id":"77710a4c.3cb504","type":"inject","z":"6d95b6d3.106588","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":300,"wires":[["507fff78.6af578"]]},{"id":"10720989.b356e6","type":"function","z":"6d95b6d3.106588","name":"","func":"flow.set(\"failure\", true)","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":220,"wires":[[]]},{"id":"507fff78.6af578","type":"function","z":"6d95b6d3.106588","name":"","func":"flow.set(\"failure\", false)","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":300,"wires":[[]]},{"id":"940e198e.53ff28","type":"comment","z":"6d95b6d3.106588","name":"Set failure","info":"","x":160,"y":180,"wires":[]},{"id":"5e06091a.1781b8","type":"comment","z":"6d95b6d3.106588","name":"Remove failure","info":"","x":180,"y":260,"wires":[]},{"id":"5687ca1b485d3cab","type":"function","z":"6d95b6d3.106588","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9057\";\n newMsg[i].sendId = 100001+i;\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":100,"wires":[["fea4e60940d46592"]]},{"id":"fea4e60940d46592","type":"tcp request","z":"6d95b6d3.106588","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":710,"y":100,"wires":[[]]},{"id":"9963bb2c3e7fd4f0","type":"comment","z":"6d95b6d3.106588","name":"Create Data","info":"","x":170,"y":60,"wires":[]}] [{"id":"e8034ec0.182578","type":"tab","label":"dv am","disabled":false,"info":""},{"id":"c206ac56.ec99c8","type":"tab","label":"data","disabled":false,"info":""},{"id":"f825e8a0.9d51f","type":"tab","label":"dv asset","disabled":false,"info":""},{"id":"6d95b6d3.106588","type":"tab","label":"Create data","disabled":false,"info":""},{"id":"3d5ce28770ed0d20","type":"postgresdb","hostname":"localhost","port":"5432","db":"vpp","ssl":false},{"id":"6a6c8a2.ae75774","type":"inject","z":"e8034ec0.182578","name":"Start","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"start","x":130,"y":260,"wires":[["2dc3a3fb.e32ef4"]]},{"id":"43189a12.ffbcf4","type":"inject","z":"e8034ec0.182578","name":"show params","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"device1","payloadType":"global","x":150,"y":80,"wires":[["6b714eca.075eb"]]},{"id":"6b714eca.075eb","type":"debug","z":"e8034ec0.182578","name":"show params","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":310,"y":80,"wires":[]},{"id":"2dc3a3fb.e32ef4","type":"file in","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","format":"lines","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":330,"y":260,"wires":[["f35585cc.e58b68"]]},{"id":"1d979cd2.bd172b","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":650,"y":260,"wires":[["10ffb8a7.ba3487"]]},{"id":"f35585cc.e58b68","type":"function","z":"e8034ec0.182578","name":"convert","func":"var newMsg;\nnewMsg = {\n payload: \"[\" + msg.payload + \"]\"\n}\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":260,"wires":[["1d979cd2.bd172b"]]},{"id":"8cfc218d.653c98","type":"function","z":"e8034ec0.182578","name":"Init. params","func":"// hardcoded device ID\nglobal.set(\"device1.id\",100001);\nglobal.set(\"device1.hostname_prefix\",\"tmp\");\nglobal.set(\"device1.hostname_suffix\",\"tmp\");\n\nglobal.set(\"device1.hostname\",global.get(\"device1.hostname_prefix\")+(global.get(\"device1.id\") - 100000)+ global.get(\"device1.hostname_suffix\"))\n\n// set initial state to follower\nglobal.set(\"device1.state\", \"follower\");\nvar randomWait = Math.ceil(Math.random()*5)+1;\nglobal.set(\"device1.randomWait\", randomWait);\n// indices and thresholds\nglobal.set(\"device1.sysCommitIndex\",1);\nglobal.set(\"device1.dataCommitIndex\",1);\nglobal.set(\"device1.sysSnapshotTH\",5);\nglobal.set(\"device1.dataSnapshotTH\",30);\nglobal.set(\"device1.sysLastApplied\",0);\nglobal.set(\"device1.dataLastApplied\",0);\nglobal.set(\"device1.timestamp\",0);\nglobal.set(\"device1.leaderId\", null);\n\n// hardcoded number of devices\nglobal.set(\"device1.nodesNum\",6);\nvar len = global.get(\"device1.nodesNum\");\n\n// hardcoded functions\nglobal.set(\"device1.virtualFuncs[0].name\", \"FaultLoc\"); \nglobal.set(\"device1.virtualFuncs[0].device\", null); // value device id\nglobal.set(\"device1.virtualFuncs[1].name\", \"ServiceRes\"); \nglobal.set(\"device1.virtualFuncs[1].device\", null); \n\n// Device 0\nglobal.set(\"device1.devices[0].id\", null);\nglobal.set(\"device1.devices[0].online\", null);\nglobal.set(\"device1.devices[0].ip\", null);\nglobal.set(\"device1.devices[0].port\", null);\nglobal.set(\"device1.devices[0].nextSysLogIndex\", null);\nglobal.set(\"device1.devices[0].nextDataLogIndex\", null);\nglobal.set(\"device1.devices[0].matchSysLogIndex\", null);\nglobal.set(\"device1.devices[0].matchDataLogIndex\", null);\n\n// hardcoded devices\n\nfor (i= 1; i<len+1;i++) {\n \n global.set(\"device1.devices[\"+i+\"].id\", 100000+i);\n global.set(\"device1.devices[\"+i+\"].online\", null);\n global.set(\"device1.devices[\"+i+\"].ip\", \"127.0.0.1\");\n global.set(\"device1.devices[\"+i+\"].port\", 10000+i);\n global.set(\"device1.devices[\"+i+\"].nextSysLogIndex\", null);\n global.set(\"device1.devices[\"+i+\"].nextDataLogIndex\", null);\n global.set(\"device1.devices[\"+i+\"].matchSysLogIndex\", null);\n global.set(\"device1.devices[\"+i+\"].matchDataLogIndex\", null);\n\n}\n\nmsg = {\n topic: \"start\"\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1050,"y":260,"wires":[["c8e8e64b.60ec28"]]},{"id":"c8e8e64b.60ec28","type":"function","z":"e8034ec0.182578","name":"timeout","func":"var myTerm = global.get(\"device1.currentTerm\");\nvar myId = global.get(\"device1.id\");\n\nif(msg.topic.includes(\"start\") || msg.topic.includes(\"myRequestVoteRPC\")){ // start timer\n context.set('count',0);\n msg.payload = { \n \"payload\": \"on\", \n \"warning\": 0,\n \"timeout\": global.get('device1.randomWait')\n };\n return msg;\n} \nelse if(msg.topic.includes(\"RPC\") && msg.payload.term >= myTerm){ //RPC from leader or candidate, to reactivate\n msg.payload = { \n \"payload\": \"on\", \n \"warning\": 0,\n \"timeout\": global.get('device1.randomWait')\n };\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":660,"y":380,"wires":[["9f80a15f.bb2a98"]]},{"id":"5b97fc86.32033c","type":"function","z":"e8034ec0.182578","name":"updateParams","func":"if(msg.payload === \"off\"){\n // random wait\n var randomWait = Math.ceil(Math.random()*5)+1;\n flow.set(\"voteCount\", 1); // vote for self, count ++\n global.set(\"device1.randomWait\", randomWait);\n global.set(\"device1.state\", \"candidate\");\n global.set(\"device1.currentTerm\", global.get(\"device1.currentTerm\")+1);\n global.set(\"device1.voteFor\", global.get(\"device1.id\"));\n msg = {\n topic:\"myRequestVoteRPC\"\n }\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":520,"wires":[["473f8dd.9f0d274","c8e8e64b.60ec28"]]},{"id":"2677e779.36a628","type":"function","z":"e8034ec0.182578","name":"leaderInit","func":"var nextSysLogIndex = global.get(\"device1.systemLog\").length;\nvar nextDataLogIndex = global.get(\"device1.dataLog\").length;\nvar myId = global.get(\"device1.id\");\nvar len = global.get(\"device1.nodesNum\");\n\nfor(var i=1; i<=len; i++){\n if(i != (myId-100000)){\n global.set(\"device1.devices[\"+i+\"].nextSysLogIndex\",nextSysLogIndex);\n global.set(\"device1.devices[\"+i+\"].nextDataLogIndex\",nextDataLogIndex);\n global.set(\"device1.devices[\"+i+\"].matchSysLogIndex\",0);\n global.set(\"device1.devices[\"+i+\"].matchDataLogIndex\",0);\n global.set(\"device1.devices[\"+i+\"].online\",false);\n } else {\n global.set(\"device1.devices[\"+i+\"].online\",true);\n }\n}\n \n \n// set leader\nglobal.set(\"device1.state\", \"leader\");\nglobal.set(\"device1.leaderId\", myId);\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1340,"y":580,"wires":[[]]},{"id":"7ee6d5c.ae9d22c","type":"function","z":"e8034ec0.182578","name":"isVote","func":"var sysLogLen = global.get(\"device1.systemLog\").length-1;\nvar dataLogLen = global.get(\"device1.dataLog\").length-1;\nvar mySysLogTerm = global.get(\"device1.systemLog[\"+sysLogLen+\"].term\");\nvar mySysLogIndex = global.get(\"device1.systemLog[\"+sysLogLen+\"].index\");\nvar myDataLogTerm = global.get(\"device1.dataLog[\"+dataLogLen+\"].term\");\nvar myDataLogIndex = global.get(\"device1.dataLog[\"+dataLogLen+\"].index\");\nvar myTerm = global.get(\"device1.currentTerm\");\nvar myVote = global.get(\"device1.voteFor\");\nvar myId = global.get(\"device1.id\");\nvar candidateId = msg.payload.candidateId;\nvar lastSysLogTerm = msg.payload.lastSysLogTerm;\nvar lastSysLogIndex = msg.payload.lastSysLogIndex;\nvar lastDataLogTerm = msg.payload.lastDataLogTerm;\nvar lastDataLogIndex = msg.payload.lastDataLogIndex;\nvar term = msg.payload.term;\nvar isVote = false;\n\n// safety 5.4.1\nif(lastSysLogTerm > mySysLogTerm && lastDataLogTerm > myDataLogTerm) {\n isVote = true;\n} else if (lastSysLogTerm >= mySysLogTerm && lastDataLogTerm >= myDataLogTerm){\n if(lastSysLogIndex >= mySysLogIndex && lastDataLogIndex >= myDataLogIndex) {\n isVote = true;\n }\n}\n\nif(myTerm < term) {\n myTerm = term;\n global.set(\"device1.state\", \"follower\");\n global.set(\"device1.voteFor\", null);\n myVote = null;\n global.set(\"device1.currentTerm\", myTerm);\n} else if(myTerm > term) {\n isVote = false;\n}\n\nif(isVote && (myVote === null || myVote == candidateId)) {\n newMsg = {\n payload: {\n id: myId,\n term: myTerm,\n voteGranted: true\n }\n }\n global.set(\"device1.voteFor\", candidateId);\n \n} else {\n newMsg = {\n payload: {\n id: myId,\n term: myTerm,\n voteGranted: false\n }\n }\n}\n\nmsg.payload = newMsg.payload;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":720,"wires":[["5703d621e5907de8"]]},{"id":"17745a55.895cfe","type":"function","z":"e8034ec0.182578","name":"replyToLeader","func":"if (msg.payload.term > global.get(\"device1.currentTerm\")){// discover higher term\n\n node.warn(\"ReplyToLeader: Back to follower\");\n\n global.set(\"device1.currentTerm\", msg.payload.term);\n global.set(\"device1.voteFor\", null);\n global.set(\"device1.state\", \"follower\"); // back to follower\n \n} else if (global.get(\"device1.state\") == \"candidate\" && msg.payload.term == global.get(\"device1.currentTerm\")) { \n global.set(\"device1.state\", \"follower\"); ////candidate discovers current leader, back to follower\n \n node.warn(\"ReplyToLeader: Candidate to follower\"); \n\n} else if (msg.payload.term < global.get(\"device1.currentTerm\")) {\n\n node.warn(\"ReplyToLeader: MSG.TERM smaller than current TERM\");\n\n let newPayload = {\n id: global.get(\"device1.id\"),\n term: global.get(\"device1.currentTerm\"),\n sysSuccess: false,\n dataSuccess: false,\n sysEntriesLen: msg.payload.sysEntries.length,\n dataEntriesLen: msg.payload.dataEntries.length\n }\n\n msg.payload = newPayload;\n return msg;\n}\n\nif(global.get(\"device1.state\") == \"follower\"){\n global.set(\"device1.leaderId\", msg.payload.leaderId); \n var myId = global.get(\"device1.id\");\n var myTerm = global.get(\"device1.currentTerm\");\n var mySystemLog = global.get(\"device1.systemLog\");\n var myDataLog = global.get(\"device1.dataLog\");\n var sysSuccess = false;\n var dataSuccess = false;\n var sysCommitIndex = Math.min(msg.payload.leaderSysCommit, mySystemLog[mySystemLog.length-1].index);\n var dataCommitIndex = Math.min(msg.payload.leaderDataCommit, myDataLog[myDataLog.length-1].index)\n global.set(\"device1.sysCommitIndex\", sysCommitIndex);\n global.set(\"device1.dataCommitIndex\", dataCommitIndex);\n var newSysLog = [];\n var newDataLog = [];\n \n // snapshot here\n var sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n var sysLastApplied = global.get(\"device1.sysLastApplied\");\n var currvirtualFuncs0 = global.get(\"device1.virtualFuncs[0].device\");\n var currvirtualFuncs1 = global.get(\"device1.virtualFuncs[1].device\");\n var sysSnapshotTH = global.get(\"device1.sysSnapshotTH\");\n if(sysLastApplied - sysSnapshotIndex > sysSnapshotTH) {\n let logAfterSnapshot = [];\n let newSysSnapshotTerm = -1;\n for(let log of mySystemLog) {\n if(log.index == sysLastApplied){\n newSysSnapshotTerm = log.term;\n let newFirstLog = {\n index: sysLastApplied,\n term: newSysSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n } else if(log.index > sysLastApplied) {\n logAfterSnapshot.push(log);\n }\n }\n global.set(\"device1.sysSnapshot.index\",sysLastApplied);\n global.set(\"device1.sysSnapshot.term\",newSysSnapshotTerm);\n global.set(\"device1.sysSnapshot.virtualFuncs[0].device\",currvirtualFuncs0);\n global.set(\"device1.sysSnapshot.virtualFuncs[1].device\",currvirtualFuncs1);\n mySystemLog = logAfterSnapshot;\n global.set(\"device1.systemLog\",mySystemLog);\n \n }\n \n var dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\n var dataLastApplied = global.get(\"device1.dataLastApplied\");\n var currTs = global.get(\"device1.timestamp\");\n var dataSnapshotTH = global.get(\"device1.dataSnapshotTH\");\n if(dataLastApplied - dataSnapshotIndex > dataSnapshotTH) {\n let logAfterSnapshot = [];\n let newDataSnapshotTerm = -1;\n for(let log of myDataLog) {\n if(log.index == dataLastApplied){\n newDataSnapshotTerm = log.term;\n let newFirstLog = {\n index: dataLastApplied,\n term: newDataSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n node.warn(\"Pushing empty log\");\n } else if(log.index > dataLastApplied) {\n logAfterSnapshot.push(log);\n node.warn(\"Pushing non-empty log\");\n }\n }\n global.set(\"device1.dataSnapshot.index\",dataLastApplied);\n global.set(\"device1.dataSnapshot.term\",newDataSnapshotTerm);\n global.set(\"device1.dataSnapshot.timestamp\",currTs);\n myDataLog = logAfterSnapshot;\n global.set(\"device1.dataLog\",myDataLog);\n \n }\n \n \n \n for (let log of mySystemLog){\n newSysLog.push(log);\n if(log.index == msg.payload.prevSysLogIndex) {\n if(log.term == msg.payload.prevSysLogTerm) {\n // mySysLog until prevSysLogIndex(newSysLog) + sysEntries in AppendEntries RPC\n if(msg.payload.sysEntries.length > 1) { // sysEntriesNotNull\n global.set(\"device1.systemLog\", newSysLog.concat(msg.payload.sysEntries.slice(1, msg.payload.sysEntries.length)));\n }\n sysSuccess = true;\n }\n break;\n } \n }\n\n for (let log of myDataLog){\n newDataLog.push(log);\n if(log.index == msg.payload.prevDataLogIndex) {\n if(log.term == msg.payload.prevDataLogTerm) {\n if(msg.payload.dataEntries.length > 1) { // dataEntriesNotNull\n global.set(\"device1.dataLog\", newDataLog.concat(msg.payload.dataEntries.slice(1, msg.payload.dataEntries.length)));\n }\n dataSuccess = true;\n }\n break;\n } \n }\n \n let newPayload = {\n id: global.get(\"device1.id\"),\n term: global.get(\"device1.currentTerm\"),\n sysSuccess: sysSuccess,\n dataSuccess: dataSuccess,\n sysEntriesLen: msg.payload.sysEntries.length,\n dataEntriesLen: msg.payload.dataEntries.length\n }\n\n msg.payload = newPayload;\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":680,"wires":[["626db20f.d92afc","5703d621e5907de8"]]},{"id":"626db20f.d92afc","type":"function","z":"e8034ec0.182578","name":"persistent storage","func":"msg.payload = {\n currentTerm: global.get(\"device1.currentTerm\"),\n voteFor: global.get(\"device1.voteFor\"),\n systemLog: global.get(\"device1.systemLog\"),\n dataLog: global.get(\"device1.dataLog\"),\n sysSnapshot: global.get(\"device1.sysSnapshot\"),\n dataSnapshot: global.get(\"device1.dataSnapshot\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":680,"wires":[["9d92fc1d.4fbb2"]]},{"id":"9d92fc1d.4fbb2","type":"file","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":1190,"y":680,"wires":[[]]},{"id":"473f8dd.9f0d274","type":"function","z":"e8034ec0.182578","name":"RequestVoteRPC","func":"var sysLogLen = global.get(\"device1.systemLog\").length-1;\nvar dataLogLen = global.get(\"device1.dataLog\").length-1;\n\nvar newMsg = {\n payload:{\n term: global.get(\"device1.currentTerm\"),\n candidateId: global.get(\"device1.id\"),\n lastSysLogIndex: global.get(\"device1.systemLog[\"+sysLogLen+\"].index\"),\n lastSysLogTerm: global.get(\"device1.systemLog[\"+sysLogLen+\"].term\"),\n lastDataLogIndex: global.get(\"device1.dataLog[\"+dataLogLen+\"].index\"),\n lastDataLogTerm: global.get(\"device1.dataLog[\"+dataLogLen+\"].term\")\n }\n};\n\nreturn newMsg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":520,"wires":[["5f8746972ea09559"]]},{"id":"3e3a97b7.c7f7b","type":"function","z":"e8034ec0.182578","name":"results recv","func":"var myTerm = global.get(\"device1.currentTerm\");\nvar voteCount = flow.get(\"voteCount\");\nvar nodesNum = global.get(\"device1.nodesNum\");\n\nif (typeof msg.payload != \"undefined\") {\n if(msg.payload.voteGranted && msg.payload.term == myTerm) {\n voteCount += 1;\n flow.set(\"voteCount\", voteCount);\n } else if (msg.payload.term > myTerm) {\n flow.set(\"voteCount\", 0);\n }\n}\n\nif(voteCount >= (nodesNum+1)/2 ) {\n flow.set(\"voteCount\", 0);\n msg.payload = { \n \"payload\": \"cancel\" // cancel timer\n };\n return msg; // leader Init\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1150,"y":580,"wires":[["2677e779.36a628","9f80a15f.bb2a98","82ba0c9b.becd58"]]},{"id":"507503c7.60aaa4","type":"inject","z":"e8034ec0.182578","name":"heartbeats","props":[{"p":"payload.heartbeat","vt":"bool","v":"true"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":"0.1","topic":"","x":150,"y":1240,"wires":[["878781ba.aef818","7a15a110.bac49","4cebd161.848db8","9a1bba8b.93412","454e8a3cfd7fdbd8"]]},{"id":"878781ba.aef818","type":"function","z":"e8034ec0.182578","name":"isLeader & AppendEntries","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar newMsg = new Array(len-1);\nvar mySystemLog = global.get(\"device1.systemLog\");\nvar myDataLog = global.get(\"device1.dataLog\");\nvar myId = global.get(\"device1.id\");\nvar myState = global.get(\"device1.state\");\nvar j = 0;\n\nif(myState == \"leader\"){ //I'm leader\n for(var i=1; i<=len; i++){\n var sendId=100000 + i;\n if(sendId != myId){\n var dataEntries = [];\n var sysEntries = [];\n var entry = {\n index: -1,\n term: -1,\n command: \" \"\n };\n sysEntries.push(entry); // add this for protobuf encode/decode\n dataEntries.push(entry);\n var prevSysLogIndex = global.get(\"device1.devices[\"+i+\"].nextSysLogIndex\")-1;\n var prevSysLogTerm = -1; // after iter. still -1? -> in snapshot\n var prevDataLogIndex = global.get(\"device1.devices[\"+i+\"].nextDataLogIndex\")-1;\n var prevDataLogTerm = -1; // after iter. still -1? -> in snapshot\n \n\n for (let log of mySystemLog){\n if(log.index == prevSysLogIndex) {\n prevSysLogTerm = log.term;\n } else if (log.index > prevSysLogIndex){\n entry = {\n index: log.index,\n term: log.term,\n command: log.command\n };\n sysEntries.push(entry);\n }\n }\n for (let log of myDataLog) {\n if(log.index == prevDataLogIndex) {\n prevDataLogTerm = log.term;\n } else if (log.index > prevDataLogIndex){\n entry = {\n index: log.index,\n term: log.term,\n command: log.command\n };\n dataEntries.push(entry);\n }\n }\n \n newMsg[j] = {\n payload:{\n term: global.get(\"device1.currentTerm\"),\n leaderId: myId,\n sendId: sendId,\n prevSysLogIndex: prevSysLogIndex,\n prevSysLogTerm: prevSysLogTerm,\n prevDataLogIndex: prevDataLogIndex,\n prevDataLogTerm: prevDataLogTerm,\n leaderSysCommit: global.get(\"device1.sysCommitIndex\"),\n leaderDataCommit: global.get(\"device1.dataCommitIndex\"),\n sysEntries: sysEntries,\n dataEntries: dataEntries\n }\n };\n j++;\n }\n }\n return [newMsg];\n \n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":1020,"wires":[["6f9c0baf10f8bc91"]]},{"id":"a102604a.fe65c8","type":"function","z":"e8034ec0.182578","name":"isUpdateTerm","func":"var myTerm = global.get(\"device1.currentTerm\");\nif(typeof msg.payload !== 'undefined'){\n if(msg.payload.term > myTerm){\n global.set(\"device1.currentTerm\", msg.payload.term);\n global.set(\"device1.voteFor\", null);\n global.set(\"device1.state\", \"follower\");\n }\n else{\n return msg;\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":980,"y":1020,"wires":[["9fca9662.48c49","5c376bdf.4bc82c","cadd8a3.2140778","ff9f0847.173b48"]]},{"id":"9fca9662.48c49","type":"function","z":"e8034ec0.182578","name":"isSuccess","func":"var serverId = msg.payload.id;\nvar nextSysLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\");\nvar nextDataLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\");\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\nvar dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\n\nif(msg.payload.sysSuccess === false){\n\n if(nextSysLogIndex - 1 > sysSnapshotIndex) {\n nextSysLogIndex -= 1;\n } else if (nextSysLogIndex <= sysSnapshotIndex) {\n nextSysLogIndex = sysSnapshotIndex + 1;\n }\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\", nextSysLogIndex);\n}\nelse{\n\n if(msg.payload.sysEntriesLen > 1) {// not heartbeat message \n nextSysLogIndex = nextSysLogIndex + msg.payload.sysEntriesLen - 1;\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\", nextSysLogIndex);\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].matchSysLogIndex\", nextSysLogIndex-1);\n }\n}\n\n\nif(msg.payload.dataSuccess === false){\n\n if(nextDataLogIndex - 1 > dataSnapshotIndex) {\n nextDataLogIndex -= 1;\n } else if (nextDataLogIndex <= dataSnapshotIndex) {\n nextDataLogIndex = dataSnapshotIndex + 1;\n }\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\", nextDataLogIndex);\n}\nelse{\n\n if(msg.payload.dataEntriesLen > 1) {\n nextDataLogIndex = nextDataLogIndex + msg.payload.dataEntriesLen - 1;\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\", nextDataLogIndex);\n global.set(\"device1.devices[\"+(serverId - 100000)+\"].matchDataLogIndex\", nextDataLogIndex-1);\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1220,"y":1040,"wires":[["1a3a2f43.16ff89"]]},{"id":"1a3a2f43.16ff89","type":"function","z":"e8034ec0.182578","name":"commitIndex++","func":"var devices = global.get(\"device1.devices\");\nvar nodesNum = global.get(\"device1.nodesNum\");\nvar majority = Math.round((nodesNum-1)/2);\nvar myId = global.get(\"device1.id\");\nvar myTerm = global.get(\"device1.currentTerm\");\nvar matchSysLogIndexArr = [];\nvar matchDataLogIndexArr = [];\nvar sysCommitIndex = global.get(\"device1.sysCommitIndex\");\nvar dataCommitIndex = global.get(\"device1.dataCommitIndex\");\nvar systemLog = global.get(\"device1.systemLog\");\nvar dataLog = global.get(\"device1.dataLog\");\nfor(let device of devices) {\n if(device.id !== null && device.id != myId) {\n matchSysLogIndexArr.push(device.matchSysLogIndex);\n matchDataLogIndexArr.push(device.matchDataLogIndex);\n }\n \n}\n\nmatchSysLogIndexArr.sort((a, b) => a - b);\nmatchDataLogIndexArr.sort((a, b) => a - b);\n\nfor(let i=majority; i>=0; i--) {\n if(matchSysLogIndexArr[i] > sysCommitIndex) {\n for(let log of systemLog) {\n if(log.index == matchSysLogIndexArr[i]) {\n if(log.term == myTerm) {\n sysCommitIndex = matchSysLogIndexArr[i];\n }\n break;\n }\n }\n }\n if(matchDataLogIndexArr[i] > dataCommitIndex) {\n for(let log of dataLog) {\n if(log.index == matchDataLogIndexArr[i]) {\n if(log.term == myTerm) {\n dataCommitIndex = matchDataLogIndexArr[i];\n }\n break;\n }\n }\n }\n}\nglobal.set(\"device1.sysCommitIndex\", sysCommitIndex);\nglobal.set(\"device1.dataCommitIndex\", dataCommitIndex);\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1380,"y":1040,"wires":[[]]},{"id":"14b1e89c.463d47","type":"function","z":"e8034ec0.182578","name":"RPC","func":"msg.topic = \"RPC\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":380,"wires":[["c8e8e64b.60ec28"]]},{"id":"5c376bdf.4bc82c","type":"function","z":"e8034ec0.182578","name":"change topic","func":"msg.topic = msg.payload.id;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1230,"y":1100,"wires":[["5f0d35de.012b5c"]]},{"id":"96868548.e8294","type":"function","z":"e8034ec0.182578","name":"isDeviceOn","func":"if(msg.payload == \"timeout\") {\n \n global.set(\"device1.devices[\" + (msg.topic - 100000) + \"].online\", false);\n} else {\n \n global.set(\"device1.devices[\" + (msg.topic - 100000) + \"].online\", true); \n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1550,"y":1100,"wires":[["683575de.cc64fc","e44b25dd.175e5"]]},{"id":"683575de.cc64fc","type":"function","z":"e8034ec0.182578","name":"assignDVAssetRequest","func":"//virtualFunc\nvar virtualFuncs = global.get(\"device1.virtualFuncs\");\n//get online devices\nvar devices = global.get(\"device1.devices\");\nvar leaderId = global.get(\"device1.leaderId\");\nvar onlineDeviceIds = {};\nvar systemLog = global.get(\"device1.systemLog\");\nvar prevLogIndex = systemLog[systemLog.length-1].index;\nvar term = global.get(\"device1.currentTerm\");\n\n\n// snapshot here\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n\n// hardcoded functions (number)\nvar currvirtualFuncs0 = global.get(\"device1.virtualFuncs[0].device\");\nvar currvirtualFuncs1 = global.get(\"device1.virtualFuncs[1].device\");\n\nvar sysLastApplied = global.get(\"device1.sysLastApplied\");\nvar sysSnapshotTH = global.get(\"device1.sysSnapshotTH\");\nif(sysLastApplied - sysSnapshotIndex > sysSnapshotTH) {\n var logAfterSnapshot = [];\n var newSysSnapshotTerm = -1;\n for(let log of systemLog) {\n if(log.index == sysLastApplied){\n newSysSnapshotTerm = log.term;\n let newFirstLog = {\n index: sysLastApplied,\n term: newSysSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n } else if(log.index > sysLastApplied) {\n logAfterSnapshot.push(log);\n }\n }\n global.set(\"device1.sysSnapshot.index\",sysLastApplied);\n global.set(\"device1.sysSnapshot.term\",newSysSnapshotTerm);\n global.set(\"device1.sysSnapshot.virtualFuncs[0].device\",currvirtualFuncs0);\n global.set(\"device1.sysSnapshot.virtualFuncs[1].device\",currvirtualFuncs1);\n systemLog = logAfterSnapshot;\n \n}\n\n// check for online devices\nfor(let device of devices) {\n if(device.online === true) {\n onlineDeviceIds[\"\"+device.id] = 0;\n }\n}\n\n// identify current workload\n// for loops tauschen, leader +1 nur beim loopen durch devices\nfor(let deviceId in onlineDeviceIds) {\n \n if (deviceId == leaderId) {\n onlineDeviceIds[\"\"+deviceId] += 1;\n }\n \n for(let virtualFunc of virtualFuncs) {\n if(deviceId == virtualFunc.device) {\n onlineDeviceIds[\"\"+deviceId] += 1;\n }\n } \n}\n\n// reassign functions\nvar j = 0;\nfor(let virtualFunc of virtualFuncs) {\n let isWorking = false;\n // own id and workload\n let relativeFreeDeviceId = global.get(\"device1.id\");\n let workload = onlineDeviceIds[\"\"+relativeFreeDeviceId];//\n for(let deviceId in onlineDeviceIds) {\n if(deviceId == virtualFunc.device) {\n isWorking = true;\n }\n }\n // if function is not assigned/working\n if(!isWorking) {\n for(let deviceId in onlineDeviceIds) {\n // check if other devices have a smaller workload than self\n if(onlineDeviceIds[deviceId] < workload) {\n workload = onlineDeviceIds[deviceId];\n relativeFreeDeviceId = parseInt(deviceId); // get min\n }\n }\n onlineDeviceIds[\"\"+relativeFreeDeviceId] += 1;\n \n //node.warn(relativeFreeDeviceId);\n \n let command = \"d\" + (relativeFreeDeviceId-100000) + \"vf\" + j;\n let entry = {\n index: prevLogIndex + 1,\n term: term,\n command: command\n }\n systemLog.push(entry);\n prevLogIndex += 1;\n }\n j++;\n}\n\nglobal.set(\"device1.systemLog\", systemLog);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1770,"y":1140,"wires":[["d8f7d54a.783cf8"]]},{"id":"7a15a110.bac49","type":"function","z":"e8034ec0.182578","name":"state machine","func":"var sysCommitIndex = global.get(\"device1.sysCommitIndex\");\nvar sysLastApplied = global.get(\"device1.sysLastApplied\");\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\nif (sysCommitIndex > sysLastApplied) { // execute command //how about roll back\n if(sysLastApplied < sysSnapshotIndex) { // execute snapshot\n var sysSnapshotVirtualFuncs = global.get(\"device1.sysSnapshot.virtualFuncs\");\n global.set(\"device1.virtualFuncs\", sysSnapshotVirtualFuncs);\n global.set(\"device1.sysLastApplied\", sysSnapshotIndex);\n } else {\n var systemLog = global.get(\"device1.systemLog\");\n var command = null;\n \n for(let log of systemLog) {\n if(log.index == sysLastApplied+1) {\n command = log.command;\n //node.warn(\"command:\");\n //node.warn(log.command);\n break;\n }\n }\n \n if(command !== null) {\n var pattern = \"(?:d)([0-9]*)(?:vf)([0-9]*)\";\n var deviceId = parseInt(command.match(pattern)[1])+100000;\n var vfId = parseInt(command.match(pattern)[2]);\n global.set(\"device1.virtualFuncs[\"+vfId+\"].device\", deviceId);\n sysLastApplied += 1;\n global.set(\"device1.sysLastApplied\", sysLastApplied);\n //node.warn(\"DeviceID: \" + deviceId);\n //node.warn(\"vfId: \" + vfId);\n //var test = command.match(pattern);\n }\n }\n\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":1160,"wires":[["cd125a54.98e9"]]},{"id":"220404b7.2bf64c","type":"function","z":"e8034ec0.182578","name":"assignDVAsset","func":"msg = {\n payload: {\n id: global.get(\"device1.id\"),\n virtualFunctions: global.get(\"device1.virtualFuncs\")\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":1160,"wires":[["f7de9d89.d7bbb8","954c09e32251cddd"]]},{"id":"cd125a54.98e9","type":"function","z":"e8034ec0.182578","name":"isLeader","func":"if(global.get(\"device1.state\") == \"leader\"){ \n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":1160,"wires":[["220404b7.2bf64c"]]},{"id":"4cebd161.848db8","type":"function","z":"e8034ec0.182578","name":"data processor","func":"\nvar dataCommitIndex = global.get(\"device1.dataCommitIndex\");\nvar dataLastApplied = global.get(\"device1.dataLastApplied\");\nvar dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\nif (dataCommitIndex > dataLastApplied) { // execute command //how about roll back\n if(dataLastApplied < dataSnapshotIndex) {\n // no need to set payload, since leader have send it to control device\n // TODO: delete current database and duplicate leader's database\n global.set(\"device1.dataLastApplied\", dataSnapshotIndex);\n \n }\n else {\n var dataLog = global.get(\"device1.dataLog\");\n var command = null;\n for(let log of dataLog) {\n if(log.index == dataLastApplied + 1) {\n command = log.command;\n break;\n }\n }\n if(command !== null) {\n // hardcoded data command pattern\n //var pattern = \"(?:s)([0-9]*)(?:m1)([0-9]*)(?:m2)([0-9]*)(?:ts)([0-9]*)\";\n //var s = command.match(pattern)[1];\n //var m1 = command.match(pattern)[2];\n //var m2 = command.match(pattern)[3];\n //var ts = command.match(pattern)[4];\n //global.set(\"device1.timestamp\", ts);\n // hardcoded sql statement to store results in DB\n //msg.topic = \"INSERT IGNORE INTO states (states, measurement1, measurement2, time) VALUES (\" + s + \",\" + m1 + \", \" + m2 + \", \" + ts + \");\";\n msg.payload = {\n command\n }\n //node.warn(command);\n //node.warn(command.split(',').map(Number));\n \n dataLastApplied += 1;\n global.set(\"device1.dataLastApplied\", dataLastApplied); \n return msg;\n }\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":1320,"wires":[["e85be469.ba8498","3eb17029.4cd0d8"]]},{"id":"d8f7d54a.783cf8","type":"function","z":"e8034ec0.182578","name":"persistent storage","func":"msg.payload = {\n currentTerm: global.get(\"device1.currentTerm\"),\n voteFor: global.get(\"device1.voteFor\"),\n systemLog: global.get(\"device1.systemLog\"),\n dataLog: global.get(\"device1.dataLog\"),\n sysSnapshot: global.get(\"device1.sysSnapshot\"),\n dataSnapshot: global.get(\"device1.dataSnapshot\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1990,"y":1140,"wires":[["7ffbb6e1.7a9dd8"]]},{"id":"7ffbb6e1.7a9dd8","type":"file","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":2210,"y":1140,"wires":[[]]},{"id":"ff9f0847.173b48","type":"function","z":"e8034ec0.182578","name":"SendSysSnapshot","func":"var serverId = msg.payload.id;\nvar nextSysLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextSysLogIndex\");\n\n//var sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n\n// snapshot here\nvar sysSnapshotIndex = global.get(\"device1.sysSnapshot.index\");\n\nvar syscount = flow.get(\"syscount\") || 1;\n\nif (syscount < 5) {\n node.warn(\"SendSysSnapshotNode:\");\n node.warn(msg.payload.sysSuccess);\n node.warn(nextSysLogIndex);\n node.warn(sysSnapshotIndex);\n}\n\nsyscount++;\n\nflow.set(\"syscount\",syscount);\n\n\n//if(msg.payload.sysSuccess === false && nextSysLogIndex - 1 == sysSnapshotIndex) {\nif(nextSysLogIndex - 1 == sysSnapshotIndex) {\n msg.payload = {\n leaderId: global.get(\"device1.id\"),\n sendId: serverId,\n term: global.get(\"device1.currentTerm\"),\n lastIncludedIndex: global.get(\"device1.sysSnapshot.index\"),\n lastIncludedTerm: global.get(\"device1.sysSnapshot.term\"),\n virtualFunctions: global.get(\"device1.sysSnapshot.virtualFuncs\")\n \n }\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":980,"wires":[["1506bd50e6d17b03"]]},{"id":"cadd8a3.2140778","type":"function","z":"e8034ec0.182578","name":"SendDataSnapshotCheck","func":"var serverId = msg.payload.id;\nvar nextDataLogIndex = global.get(\"device1.devices[\"+(serverId - 100000)+\"].nextDataLogIndex\");\nvar dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\nif(msg.payload.dataSuccess === false && nextDataLogIndex - 1 == dataSnapshotIndex) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1270,"y":900,"wires":[["e6876b38.23ad6"]]},{"id":"90cc26d4.0b84b","type":"function","z":"e8034ec0.182578","name":"UpdateSysSnapshot","func":"var myTerm = global.get(\"device1.currentTerm\");\n\nif(msg.payload.term < myTerm) {\n msg.payload = {\n term: myTerm\n }\n} else {\n var systemLog = global.get(\"device1.systemLog\");\n var lastLogIndex = systemLog[systemLog.length-1].index;\n var newSystemLog = [];\n var firstLog = {\n index:msg.payload.lastIncludedIndex,\n term: msg.payload.lastIncludedTerm,\n command: null\n }; \n newSystemLog.push(firstLog);\n global.set(\"device1.sysSnapshot.index\", msg.payload.lastIncludedIndex);\n global.set(\"device1.sysSnapshot.term\", msg.payload.lastIncludedTerm);\n global.set(\"device1.sysSnapshot.virtualFuncs\", msg.payload.virtualFunctions);\n if(lastLogIndex > msg.payload.lastIncludedIndex) {\n for(let log of systemLog) {\n if(log.index > msg.payload.lastIncludedIndex) {\n newSystemLog.push(log);\n }\n }\n }\n \n global.set(\"device1.systemLog\", newSystemLog);\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":760,"wires":[["5703d621e5907de8"]]},{"id":"619d09e2.17e938","type":"function","z":"e8034ec0.182578","name":"UpdateDataSnapshot","func":"var myTerm = global.get(\"device1.currentTerm\");\nif(msg.payload.term < myTerm) {\n msg.payload = {\n term: myTerm\n }\n} else {\n var dataLog = global.get(\"device1.dataLog\");\n var lastLogIndex = dataLog[dataLog.length-1].index;\n var newDataLog = [];\n var firstLog = {\n index:msg.payload.lastIncludedIndex,\n term: msg.payload.lastIncludedTerm,\n command: null\n }; \n newDataLog.push(firstLog);\n global.set(\"device1.dataSnapshot.index\", msg.payload.lastIncludedIndex);\n global.set(\"device1.dataSnapshot.term\", msg.payload.lastIncludedTerm);\n global.set(\"device1.dataSnapshot.timestamp\", msg.payload.ts);\n if(lastLogIndex > msg.payload.lastIncludedIndex) {\n for(let log of dataLog) {\n if(log.index > msg.payload.lastIncludedIndex) {\n newDataLog.push(log);\n }\n }\n }\n \n global.set(\"device1.dataLog\", newDataLog);\n \n msg.payload = {\n term: myTerm\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":800,"wires":[["5703d621e5907de8"]]},{"id":"658fc2f4.1026bc","type":"function","z":"e8034ec0.182578","name":"UpdateTerm","func":"var myTerm = global.get(\"device1.currentTerm\");\nif(msg.payload.term > myTerm) {\n global.set(\"device1.currentTerm\", myTerm);\n global.set(\"device1.state\", \"follower\");\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2350,"y":940,"wires":[[]]},{"id":"110fab30.51d07d","type":"function","z":"e8034ec0.182578","name":"add data command","func":"var lastTimestamp = flow.get(\"lastTimestamp\") || 0;\nnow = parseInt(Date.now());\nif(now > lastTimestamp) {\n // hardcoded structure of data command\n var command = msg.payload;\n var dataLog = global.get(\"device1.dataLog\");\n var prevLogIndex = dataLog[dataLog.length-1].index;\n var term = global.get(\"device1.currentTerm\");\n \n // snapshot here\n var dataSnapshotIndex = global.get(\"device1.dataSnapshot.index\");\n \n var dataLastApplied = global.get(\"device1.dataLastApplied\");\n var dataSnapshotTH = global.get(\"device1.dataSnapshotTH\");\n if(dataLastApplied - dataSnapshotIndex > dataSnapshotTH) {\n var logAfterSnapshot = [];\n var newDataSnapshotTerm = -1;\n for(let log of dataLog) {\n if(log.index == dataLastApplied){\n newDataSnapshotTerm = log.term;\n let newFirstLog = {\n index: dataLastApplied,\n term: newDataSnapshotTerm,\n command: null\n };\n logAfterSnapshot.push(newFirstLog);\n } else if(log.index > dataLastApplied) {\n logAfterSnapshot.push(log);\n }\n }\n global.set(\"device1.dataSnapshot.index\",dataLastApplied);\n global.set(\"device1.dataSnapshot.term\",newDataSnapshotTerm);\n global.set(\"device1.dataSnapshot.command\",command);\n dataLog = logAfterSnapshot;\n \n }\n \n var entry = {\n index: prevLogIndex + 1,\n term: term,\n command: command\n }\n dataLog.push(entry);\n global.set(\"device1.dataLog\", dataLog);\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":1540,"wires":[["20db4fdb.0a2318","6f37cb10.82e28c","19ab3a15.aa5d8e"]]},{"id":"20db4fdb.0a2318","type":"function","z":"e8034ec0.182578","name":"persistent storage","func":"msg.payload = {\n currentTerm: global.get(\"device1.currentTerm\"),\n voteFor: global.get(\"device1.voteFor\"),\n systemLog: global.get(\"device1.systemLog\"),\n dataLog: global.get(\"device1.dataLog\"),\n sysSnapshot: global.get(\"device1.sysSnapshot\"),\n dataSnapshot: global.get(\"device1.dataSnapshot\")\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":1540,"wires":[["479d48c8.9f7a7"]]},{"id":"479d48c8.9f7a7","type":"file","z":"e8034ec0.182578","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":950,"y":1540,"wires":[[]]},{"id":"5f0d35de.012b5c","type":"trigger","z":"e8034ec0.182578","name":"","op1":"","op2":"timeout","op1type":"pay","op2type":"str","duration":"2","extend":true,"overrideDelay":false,"units":"s","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":1390,"y":1100,"wires":[["96868548.e8294"]]},{"id":"63672d6f.8a13e4","type":"inject","z":"e8034ec0.182578","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1340,"y":1140,"wires":[["13f0d3b8.350424"]]},{"id":"13f0d3b8.350424","type":"function","z":"e8034ec0.182578","name":"reassign virtualFuncs","func":"var virtualFuncs = global.get(\"device1.virtualFuncs\");\nvar i = 0;\nfor(let virtualFunc of virtualFuncs) {\n virtualFuncs[i].device = null;\n i += 1;\n}\nglobal.set(\"device1.virtualFuncs\", virtualFuncs);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1520,"y":1140,"wires":[["683575de.cc64fc"]]},{"id":"e6876b38.23ad6","type":"function","z":"e8034ec0.182578","name":"SendDataSnapshot","func":"var serverId = msg.serverId;\nvar dataSnapshot = global.get(\"device1.dataSnapshot\");\nmsg.payload = {\n leaderId: global.get(\"device1.id\"),\n sendId: serverId,\n term: global.get(\"device1.currentTerm\"),\n lastIncludedIndex: parseInt(dataSnapshot.index),\n lastIncludedTerm: parseInt(dataSnapshot.term),\n ts: parseInt(dataSnapshot.timestamp),\n savedData: global.get(\"device1.dataSnapshot.command\")\n \n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1490,"y":900,"wires":[["5d04d981016bc6d7"]]},{"id":"c5aace1d.804398","type":"debug","z":"e8034ec0.182578","name":"old leader failed","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1240,"y":360,"wires":[]},{"id":"d3aab986.98d398","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":360,"wires":[["c5aace1d.804398"]]},{"id":"182141de.c0edc6","type":"debug","z":"e8034ec0.182578","name":"new leader elected","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1250,"y":400,"wires":[]},{"id":"82ba0c9b.becd58","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":400,"wires":[["182141de.c0edc6"]]},{"id":"6441d6b8.f19c3","type":"debug","z":"e8034ec0.182578","name":"device failed","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1870,"y":1100,"wires":[]},{"id":"e44b25dd.175e5","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1720,"y":1100,"wires":[["6441d6b8.f19c3"]]},{"id":"ea733857.b50658","type":"debug","z":"e8034ec0.182578","name":"vf re-allocated","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1020,"y":1160,"wires":[]},{"id":"f7de9d89.d7bbb8","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":1160,"wires":[["ea733857.b50658"]]},{"id":"df0c7fde.e70108","type":"comment","z":"e8034ec0.182578","name":"candidate","info":"","x":140,"y":220,"wires":[]},{"id":"a3c4c508.5be348","type":"comment","z":"e8034ec0.182578","name":"follower","info":"","x":130,"y":680,"wires":[]},{"id":"16eb0377.f5d345","type":"comment","z":"e8034ec0.182578","name":"leader","info":"","x":130,"y":1200,"wires":[]},{"id":"8aedaf86.888ad8","type":"comment","z":"e8034ec0.182578","name":"Number of devices and own ID hardcoded here","info":"","x":1160,"y":220,"wires":[]},{"id":"ec050daf.aafe28","type":"comment","z":"e8034ec0.182578","name":"output only if there is another device","info":"","x":360,"y":980,"wires":[]},{"id":"a2826e04.96ba1","type":"comment","z":"e8034ec0.182578","name":"message other devices","info":"","x":620,"y":980,"wires":[]},{"id":"5322b28f.4e3fec","type":"split","z":"e8034ec0.182578","name":"split","splt":"10","spltType":"len","arraySplt":"10","arraySpltType":"len","stream":false,"addname":"","x":670,"y":1320,"wires":[["040c7202e8ec3d38"]]},{"id":"b1e30b63.7bc448","type":"comment","z":"e8034ec0.182578","name":"also makes sys snapshot","info":"","x":1770,"y":1180,"wires":[]},{"id":"32925675.b64caa","type":"comment","z":"e8034ec0.182578","name":"all devices: update vf allocation","info":"","x":410,"y":1120,"wires":[]},{"id":"32535587.8d31d2","type":"comment","z":"e8034ec0.182578","name":"also makes data snapshot","info":"","x":490,"y":1580,"wires":[]},{"id":"3a1d71ba.6cd56e","type":"function","z":"e8034ec0.182578","name":"Update - unit failure","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar failed = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET FAILED = C.FAILED FROM ( VALUES ( '\" + names[0] + \"', \" + failed[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + failed[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, FAILED) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":1320,"wires":[["85cba6bd.c0f18"]]},{"id":"a3481321.eff9d","type":"function","z":"e8034ec0.182578","name":"Update - unit activation","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar status = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET ACTIVE = C.ACTIVE FROM ( VALUES ( '\" + names[0] + \"', \" + status[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + status[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, ACTIVE) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":980,"y":1280,"wires":[["85cba6bd.c0f18"]]},{"id":"85cba6bd.c0f18","type":"postgres","z":"e8034ec0.182578","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":false,"outputs":0,"x":1230,"y":1320,"wires":[]},{"id":"10ffb8a7.ba3487","type":"function","z":"e8034ec0.182578","name":"load from persistent storage","func":"global.set(\"device1\",undefined); // clear history\n\nif(msg.payload.length===1){ // if exists\n global.set(\"device1.currentTerm\", msg.payload[0].currentTerm);\n global.set(\"device1.voteFor\", msg.payload[0].voteFor);\n global.set(\"device1.systemLog\",msg.payload[0].systemLog);\n global.set(\"device1.dataLog\",msg.payload[0].dataLog);\n global.set(\"device1.sysSnapshot\", msg.payload[0].sysSnapshot);\n global.set(\"device1.dataSnapshot\", msg.payload[0].dataSnapshot);\n \n} else {\n global.set(\"device1.currentTerm\", 0);\n global.set(\"device1.voteFor\", null);\n global.set(\"device1.systemLog[0].index\",0);\n global.set(\"device1.systemLog[0].term\",0);\n global.set(\"device1.systemLog[0].command\",null);\n global.set(\"device1.dataLog[0].index\",0);\n global.set(\"device1.dataLog[0].term\",0);\n global.set(\"device1.dataLog[0].command\",null);\n global.set(\"device1.sysSnapshot.index\", 0);\n global.set(\"device1.sysSnapshot.term\", 0);\n global.set(\"device1.sysSnapshot.virtualFuncs[0].name\", \"FaultLoc\");\n global.set(\"device1.sysSnapshot.virtualFuncs[0].device\", null);\n global.set(\"device1.sysSnapshot.virtualFuncs[1].name\", \"ServiceRes\");\n global.set(\"device1.sysSnapshot.virtualFuncs[1].device\", null);\n global.set(\"device1.dataSnapshot.index\", 0);\n global.set(\"device1.dataSnapshot.term\", 0);\n global.set(\"device1.dataSnapshot.timestamp\", null);\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":260,"wires":[["8cfc218d.653c98"]]},{"id":"e85be469.ba8498","type":"function","z":"e8034ec0.182578","name":"","func":"var command = msg.payload.command;\nif(command) {\n msg.payload = command.split(',').map(Number);\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":1320,"wires":[["5322b28f.4e3fec"]]},{"id":"9a1bba8b.93412","type":"function","z":"e8034ec0.182578","name":"isLeader & dataCommand","func":"var dataLastApplied = global.get(\"device1.dataLastApplied\");\nvar command = null;\nif(global.get(\"device1.state\") == \"leader\"){ \n var dataLog = global.get(\"device1.dataLog\");\n for(let log of dataLog) {\n if(log.index == dataLastApplied) {\n command = log.command;\n break;\n }\n }\n if(command) {\n msg.payload = command.split(',').map(Number);\n return msg;\n }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":1440,"wires":[[]]},{"id":"3603e552.3536ea","type":"split","z":"e8034ec0.182578","name":"split","splt":"10","spltType":"len","arraySplt":"10","arraySpltType":"len","stream":false,"addname":"","x":850,"y":1580,"wires":[["a0fa6158.213458"]]},{"id":"a0fa6158.213458","type":"switch","z":"e8034ec0.182578","name":"","property":"payload","propertyType":"msg","rules":[{"t":"index","v":"0","vt":"num","v2":"0","v2t":"num"},{"t":"index","v":"1","vt":"num","v2":"1","v2t":"num"},{"t":"index","v":"2","vt":"num","v2":"2","v2t":"num"}],"checkall":"true","repair":false,"outputs":3,"x":1010,"y":1580,"wires":[["8491bef5.a35f98"],["7198942e.f5b2c4"],["c40085a686a1f474"]]},{"id":"b07e41ef.2a8b58","type":"postgres","z":"e8034ec0.182578","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":false,"outputs":0,"x":1450,"y":1580,"wires":[]},{"id":"6f37cb10.82e28c","type":"function","z":"e8034ec0.182578","name":"","func":"var dataLog = global.get(\"device1.dataLog\");\nvar dataLastApplied = global.get(\"device1.dataLastApplied\");\nfor(let log of dataLog) {\n if(log.index == dataLastApplied) {\n command = log.command;\n break;\n }\n}\nif(command) {\n msg.payload = command.split(',').map(Number);\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":1580,"wires":[["3603e552.3536ea"]]},{"id":"9f80a15f.bb2a98","type":"mytimeout","z":"e8034ec0.182578","name":"","outtopic":"","outsafe":"","outwarning":"Warning","outunsafe":"off","warning":"5","timer":"30","debug":false,"ndebug":false,"ignoreCase":false,"repeat":false,"again":false,"x":850,"y":380,"wires":[["5b97fc86.32033c","d3aab986.98d398"],[]]},{"id":"3eb17029.4cd0d8","type":"function","z":"e8034ec0.182578","name":"take time","func":"var myState = global.get(\"device1.state\");\nif(myState == \"follower\"){\n msg.date = parseInt(Date.now());\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":1360,"wires":[["bf99977b.1dc21"]]},{"id":"bf99977b.1dc21","type":"debug","z":"e8034ec0.182578","name":"data command received","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":730,"y":1360,"wires":[]},{"id":"19ab3a15.aa5d8e","type":"function","z":"e8034ec0.182578","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":1500,"wires":[["ba61460f.c3cea"]]},{"id":"ba61460f.c3cea","type":"debug","z":"e8034ec0.182578","name":"data command added","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":940,"y":1500,"wires":[]},{"id":"7198942e.f5b2c4","type":"function","z":"e8034ec0.182578","name":"Update - unit failure","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar failed = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET FAILED = C.FAILED FROM ( VALUES ( '\" + names[0] + \"', \" + failed[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + failed[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, FAILED) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1190,"y":1580,"wires":[["b07e41ef.2a8b58"]]},{"id":"8491bef5.a35f98","type":"function","z":"e8034ec0.182578","name":"Update - unit activation","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar status = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET ACTIVE = C.ACTIVE FROM ( VALUES ( '\" + names[0] + \"', \" + status[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + status[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, ACTIVE) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1200,"y":1540,"wires":[["b07e41ef.2a8b58"]]},{"id":"b2cde435ac09a8c8","type":"comment","z":"e8034ec0.182578","name":"Read persistent storage","info":"","x":320,"y":220,"wires":[]},{"id":"bf2b6e298f3a8e0e","type":"comment","z":"e8034ec0.182578","name":"Init Term / Logs / Snapshot","info":"","x":830,"y":220,"wires":[]},{"id":"c385cce04ce02b57","type":"comment","z":"e8034ec0.182578","name":"Init parameters","info":"","x":1060,"y":180,"wires":[]},{"id":"f5e15eec8e459022","type":"comment","z":"e8034ec0.182578","name":"Loop","info":"","x":830,"y":340,"wires":[]},{"id":"1cfb607e7b3c5378","type":"comment","z":"e8034ec0.182578","name":"Request Votes from other devices","info":"","x":650,"y":480,"wires":[]},{"id":"5581712efefb15d0","type":"comment","z":"e8034ec0.182578","name":"Init leader and set next / match indices","info":"","x":1430,"y":540,"wires":[]},{"id":"65d1529c825035d1","type":"comment","z":"e8034ec0.182578","name":"Write persistens storage","info":"","x":990,"y":640,"wires":[]},{"id":"7b140ddc3b3bebda","type":"comment","z":"e8034ec0.182578","name":"Append Entries","info":"","x":980,"y":980,"wires":[]},{"id":"d3e424a412dd5eba","type":"comment","z":"e8034ec0.182578","name":"DataSnapshot","info":"","x":1230,"y":860,"wires":[]},{"id":"5219faa00c283942","type":"comment","z":"e8034ec0.182578","name":"SysSnapshot","info":"","x":1230,"y":940,"wires":[]},{"id":"095f38e191be1d09","type":"comment","z":"e8034ec0.182578","name":"make dataCommand","info":"","x":370,"y":1400,"wires":[]},{"id":"454e8a3cfd7fdbd8","type":"function","z":"e8034ec0.182578","name":"Check virtual assignment","func":"msg = {\n payload: {\n id: global.get(\"device1.id\"),\n virtualFunctions: global.get(\"device1.virtualFuncs\")\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":1240,"wires":[[]]},{"id":"c40085a686a1f474","type":"function","z":"e8034ec0.182578","name":"Update - unit available flexibility","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar av_flex = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET AVAILABLE_FLEXIBILITY = C.AVAILABLE_FLEXIBILITY FROM ( VALUES ( '\" + names[0] + \"', \" + av_flex[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + av_flex[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, AVAILABLE_FLEXIBILITY) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1230,"y":1620,"wires":[["b07e41ef.2a8b58"]]},{"id":"88800c24c8448a17","type":"function","z":"e8034ec0.182578","name":"Update - unit available flexibility","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\nvar av_flex = msg.payload\n\nvar sqlWrite = \"UPDATE UNIT_STATES AS M SET AVAILABLE_FLEXIBILITY = C.AVAILABLE_FLEXIBILITY FROM ( VALUES ( '\" + names[0] + \"', \" + av_flex[0] + \" )\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ( '\" + names[i] + \"', \" + av_flex[i] + \" )\";\n }\n\nsqlWrite = sqlWrite + \" ) AS C(NAME, AVAILABLE_FLEXIBILITY) WHERE C.NAME = M.NAME\"\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1010,"y":1360,"wires":[["85cba6bd.c0f18"]]},{"id":"040c7202e8ec3d38","type":"switch","z":"e8034ec0.182578","name":"","property":"payload","propertyType":"msg","rules":[{"t":"index","v":"0","vt":"num","v2":"0","v2t":"num"},{"t":"index","v":"1","vt":"num","v2":"1","v2t":"num"},{"t":"index","v":"2","vt":"num","v2":"2","v2t":"num"}],"checkall":"true","repair":false,"outputs":3,"x":790,"y":1320,"wires":[["a3481321.eff9d"],["3a1d71ba.6cd56e"],["88800c24c8448a17"]]},{"id":"5f8746972ea09559","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9054\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nflow.set(\"voteCount\", 1);\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":790,"y":520,"wires":[["8bbadb902812373d"]]},{"id":"cc3ee8e61e7e014f","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":890,"y":580,"wires":[["f77426521f69308d"]]},{"id":"b5c5283949b29bd5","type":"tcp in","z":"e8034ec0.182578","name":"","server":"server","host":"","port":9054,"datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":140,"y":720,"wires":[["22d97f5b4bf69158"]]},{"id":"9e8f5a354ad3eb90","type":"tcp out","z":"e8034ec0.182578","name":"","host":"","port":"","beserver":"reply","base64":false,"end":false,"tls":"","x":1050,"y":760,"wires":[]},{"id":"36bdd2368f037954","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":770,"y":580,"wires":[["cc3ee8e61e7e014f"]]},{"id":"f77426521f69308d","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":1010,"y":580,"wires":[["3e3a97b7.c7f7b"]]},{"id":"22d97f5b4bf69158","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":270,"y":720,"wires":[["4759aa603ba068a3","5aed97c5bedd1905","4538c7f3cb0a8cb1","3b925a2d83cb3541","96f53eeb1fc07946"]]},{"id":"5703d621e5907de8","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":930,"y":760,"wires":[["9e8f5a354ad3eb90"]]},{"id":"8bbadb902812373d","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":580,"wires":[["36bdd2368f037954"]]},{"id":"4759aa603ba068a3","type":"function","z":"e8034ec0.182578","name":"RequestVote","func":"if (msg.payload.func == \"RequestVote\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":720,"wires":[["7ee6d5c.ae9d22c","14b1e89c.463d47"]]},{"id":"5aed97c5bedd1905","type":"function","z":"e8034ec0.182578","name":"AppendEntries","func":"if (msg.payload.func == \"AppendEntries\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":680,"wires":[["17745a55.895cfe","14b1e89c.463d47"]]},{"id":"4538c7f3cb0a8cb1","type":"function","z":"e8034ec0.182578","name":"SendSysSnapshot","func":"if (msg.payload.func == \"SendSysSnapshot\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":760,"wires":[["90cc26d4.0b84b"]]},{"id":"3b925a2d83cb3541","type":"function","z":"e8034ec0.182578","name":"SendDataSnapshot","func":"if (msg.payload.func == \"SendDataSnapshot\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":800,"wires":[["619d09e2.17e938"]]},{"id":"2e283c9da7afbc58","type":"comment","z":"e8034ec0.182578","name":"response","info":"","x":940,"y":720,"wires":[]},{"id":"6f9c0baf10f8bc91","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar ident = msg.payload.sendId - 100000;\n\nmsg.host = prefix + ident + suffix;\nmsg.port = \"9054\";\nmsg.sendId = 100000+ident;\nmsg.payload.func = \"AppendEntries\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":1020,"wires":[["e3075d272d368e0e"]]},{"id":"e3075d272d368e0e","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":1020,"wires":[["ea1916f3768498a2"]]},{"id":"de6c75391121cb2c","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":690,"y":1080,"wires":[["86e3f9cfc8f6cae0"]]},{"id":"86e3f9cfc8f6cae0","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":810,"y":1080,"wires":[["a102604a.fe65c8"]]},{"id":"5d04d981016bc6d7","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9054\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"SendDataSnapshot\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1670,"y":900,"wires":[["d91029af30d9e993"]]},{"id":"d91029af30d9e993","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1820,"y":900,"wires":[["6c96aa710feb750e"]]},{"id":"6c96aa710feb750e","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1950,"y":900,"wires":[["b836828fc215281b"]]},{"id":"b836828fc215281b","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":2070,"y":900,"wires":[["6bf2228941ab98ad"]]},{"id":"6bf2228941ab98ad","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":2190,"y":900,"wires":[["658fc2f4.1026bc"]]},{"id":"1506bd50e6d17b03","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\nvar sendId = msg.payload.sendId;\nvar digit = String(sendId).slice(-1);\n\nvar newMsg;\n\n//for (i= 0; i<len;i++) {\nlet clone = JSON.parse(JSON.stringify(msg));\nnewMsg = clone;\nnewMsg.host = prefix + digit + suffix;\nnewMsg.port = \"9054\"\nnewMsg.payload.func = \"SendSysSnapshot\"\n//}\n\nreturn newMsg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1670,"y":980,"wires":[["35dfc499ac9e60b2"]]},{"id":"35dfc499ac9e60b2","type":"function","z":"e8034ec0.182578","name":"toOthers","func":"var myId = global.get(\"device1.id\");\n\nif (myId != msg.sendId) {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1820,"y":980,"wires":[["029af64f3c4b5ea3"]]},{"id":"029af64f3c4b5ea3","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1950,"y":980,"wires":[["3cbdf438b0bc8cbe"]]},{"id":"3cbdf438b0bc8cbe","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":2070,"y":980,"wires":[["c4fe538d3b3c831b"]]},{"id":"c4fe538d3b3c831b","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"obj","pretty":false,"x":2190,"y":980,"wires":[["658fc2f4.1026bc"]]},{"id":"954c09e32251cddd","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9054\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"AssignVirtualFunctions\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":1200,"wires":[["d8e7fae1232d045c"]]},{"id":"d8e7fae1232d045c","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":1010,"y":1200,"wires":[["91c0b7872256d6ed"]]},{"id":"91c0b7872256d6ed","type":"tcp request","z":"e8034ec0.182578","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":1130,"y":1200,"wires":[[]]},{"id":"ea1916f3768498a2","type":"json","z":"e8034ec0.182578","name":"","property":"payload","action":"str","pretty":false,"x":570,"y":1080,"wires":[["de6c75391121cb2c"]]},{"id":"96f53eeb1fc07946","type":"function","z":"e8034ec0.182578","name":"AssignVirtualFunctions","func":"if (msg.payload.func == \"AssignVirtualFunctions\") {\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":840,"wires":[["0011097be96ce17b"]]},{"id":"0011097be96ce17b","type":"link out","z":"e8034ec0.182578","name":"","mode":"link","links":["eff75d391a641181"],"x":635,"y":840,"wires":[]},{"id":"4f267f9ff6ead2a1","type":"comment","z":"e8034ec0.182578","name":"Reset / Restart Devices","info":"","x":580,"y":40,"wires":[]},{"id":"047bb659641db7b3","type":"inject","z":"e8034ec0.182578","name":"Reset","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":530,"y":80,"wires":[["2f0a2d9a6a5ae277"]]},{"id":"abc7f37fcb86b2c1","type":"inject","z":"e8034ec0.182578","name":"Restart","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":530,"y":120,"wires":[["b8f1030f757eaeae"]]},{"id":"31c9e50922f4356b","type":"udp out","z":"e8034ec0.182578","name":"","addr":"","iface":"","port":"","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":810,"y":80,"wires":[]},{"id":"cec0f2e3bc81a7a5","type":"udp out","z":"e8034ec0.182578","name":"","addr":"","iface":"","port":"","ipv":"udp4","outport":"","base64":false,"multicast":"false","x":810,"y":120,"wires":[]},{"id":"2f0a2d9a6a5ae277","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].ip = \"dv-raspi-\" + (i+1) + \".acs-lab.eonerc.rwth-aachen.de\"\n newMsg[i].port = \"9055\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":80,"wires":[["31c9e50922f4356b"]]},{"id":"b8f1030f757eaeae","type":"function","z":"e8034ec0.182578","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].ip = \"dv-raspi-\" + (i+1) + \".acs-lab.eonerc.rwth-aachen.de\"\n newMsg[i].port = \"9056\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":120,"wires":[["cec0f2e3bc81a7a5"]]},{"id":"bdfbcb5df0b6488b","type":"udp in","z":"e8034ec0.182578","name":"","iface":"","port":"9056","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":140,"y":300,"wires":[["2dc3a3fb.e32ef4"]]},{"id":"b77c725d549754fc","type":"tcp in","z":"e8034ec0.182578","name":"","server":"server","host":"","port":"9055","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":140,"y":1540,"wires":[["bccc8582091ccdaf"]]},{"id":"bccc8582091ccdaf","type":"function","z":"e8034ec0.182578","name":"parseData","func":"var command = msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":1540,"wires":[["110fab30.51d07d"]]},{"id":"db1b91c55349dd57","type":"comment","z":"e8034ec0.182578","name":"Show params","info":"","x":150,"y":40,"wires":[]},{"id":"5ae8f5f7.cf75a4","type":"debug","z":"c206ac56.ec99c8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":730,"y":360,"wires":[]},{"id":"cde710a9.b993a8","type":"file","z":"c206ac56.ec99c8","name":"","filename":"/home/pi/Desktop/device1","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":590,"y":80,"wires":[[]]},{"id":"5ef2ff32.208ae","type":"inject","z":"c206ac56.ec99c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":140,"y":80,"wires":[["fe2f2f69.538e6","58ab7f46.b59168"]]},{"id":"fe2f2f69.538e6","type":"function","z":"c206ac56.ec99c8","name":"","func":"global.set(\"device1\", undefined); // clear history\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":120,"wires":[[]]},{"id":"a350f8b4.19fac","type":"postgres","z":"c206ac56.ec99c8","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":true,"outputs":1,"x":590,"y":360,"wires":[["5ae8f5f7.cf75a4"]]},{"id":"9caf36a4.fe9da8","type":"comment","z":"c206ac56.ec99c8","name":"Create local storage","info":"","x":170,"y":40,"wires":[]},{"id":"281ea7c5.d05968","type":"comment","z":"c206ac56.ec99c8","name":"Create Postgres Database","info":"","x":190,"y":180,"wires":[]},{"id":"d9756d90.a9447","type":"comment","z":"c206ac56.ec99c8","name":"Receive RTDS measurements and send to Postgres DB","info":"","x":280,"y":520,"wires":[]},{"id":"15cf0a6.82e9776","type":"inject","z":"c206ac56.ec99c8","name":"Delete","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":360,"wires":[["53ba8819.38b32"]]},{"id":"53ba8819.38b32","type":"function","z":"c206ac56.ec99c8","name":"Delete rows","func":"//msg.payload = \"DELETE FROM RANDOMNUM WHERE timestamp <= localtimestamp - interval '2 hours'\";\nvar db_hist = msg.payload - 300*1000;\nmsg.payload = \"DELETE FROM UNIT_MEAS WHERE timestamp < \" + db_hist + \"\";\nmsg.connectName = \"connect\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":360,"wires":[["a350f8b4.19fac"]]},{"id":"493929d0.eedbe8","type":"inject","z":"c206ac56.ec99c8","name":"Create","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":420,"wires":[["63fb8762.15c9e8"]]},{"id":"63fb8762.15c9e8","type":"function","z":"c206ac56.ec99c8","name":"Create UNIT_STATES","func":"msg.payload = \"CREATE TABLE UNIT_STATES( NAME VARCHAR(7) PRIMARY KEY NOT NULL, ACTIVE INT NOT NULL, FAILED INT NOT NULL, PRIO INT NOT NULL, FLEXIBILITY INT NOT NULL, AVAILABLE_FLEXIBILITY INT NOT NULL)\";\nmsg.connectName = 'connect';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":420,"wires":[["a350f8b4.19fac"]]},{"id":"80e17478.6589a8","type":"function","z":"c206ac56.ec99c8","name":"Initialize UNIT_STATES","func":"var names = [ 'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10' ];\n\nvar sqlWrite = \"INSERT INTO UNIT_STATES VALUES ( '\" + names[0] + \"', 1, 0, 1, 100, 0)\";\nvar i = 1;\nfor (i; i < names.length; i++) {\n sqlWrite = sqlWrite + \", ('\" + names[i] + \"', 1, 0, \" + String(i+1) + \", 100, 0)\";\n }\n\nmsg.payload = sqlWrite;\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":460,"wires":[["a350f8b4.19fac"]]},{"id":"6c492c88.7d8d1c","type":"inject","z":"c206ac56.ec99c8","name":"Initialize","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":460,"wires":[["80e17478.6589a8"]]},{"id":"98fe32bf.64ec48","type":"comment","z":"c206ac56.ec99c8","name":"insert initial config to persistent storage","info":"","x":910,"y":80,"wires":[]},{"id":"58ab7f46.b59168","type":"function","z":"c206ac56.ec99c8","name":"persistent storage","func":"var unit_status = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]; \n\nmsg.payload = {\n currentTerm: 0,\n voteFor: null,\n systemLog: [{\n index: 0,\n term: 0,\n command: null\n }],\n dataLog: [{\n index: 0,\n term: 0,\n command: \"\" + unit_status.toString()\n }],\n sysSnapshot: {\n index: 0,\n term: 0,\n \"virtualFuncs\": [{\n \"name\":\"FaultLoc\",\n \"device\":null\n },\n {\n \"name\":\"ServiceRes\",\n \"device\":null\n }]\n },\n dataSnapshot: {\n index: 0,\n term: 0,\n timestamp: null\n }\n};\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":80,"wires":[["cde710a9.b993a8"]]},{"id":"1eb756d4.730e99","type":"postgres","z":"c206ac56.ec99c8","postgresdb":"3d5ce28770ed0d20","name":"vpp","output":false,"outputs":0,"x":710,"y":560,"wires":[]},{"id":"a7f06bfd.b48668","type":"function","z":"c206ac56.ec99c8","name":"insert measurements","func":"var timestamp = msg.payload[10];\nmsg.time = timestamp;\n\nvar sqlWrite = \"INSERT INTO UNIT_MEAS VALUES (\" + timestamp;\nvar i = 0\nfor (i; i < 10; i++) {\n sqlWrite = sqlWrite + \", \" + msg.payload[i];\n }\n\nsqlWrite = sqlWrite + \")\";\n\nmsg.payload = sqlWrite\nmsg.connectName = \"connect\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":560,"wires":[["1eb756d4.730e99"]]},{"id":"10f26799.ffa6c","type":"inject","z":"c206ac56.ec99c8","name":"Create","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":320,"wires":[["696440f1.1f9bb"]]},{"id":"696440f1.1f9bb","type":"function","z":"c206ac56.ec99c8","name":"Create UNIT_MEAS","func":"msg.payload = \"CREATE TABLE UNIT_MEAS( TIMESTAMP BIGINT PRIMARY KEY NOT NULL, U01 DECIMAL NOT NULL, U02 DECIMAL NOT NULL, U03 DECIMAL NOT NULL, U04 DECIMAL NOT NULL, U05 DECIMAL NOT NULL, U06 DECIMAL NOT NULL, U07 DECIMAL NOT NULL, U08 DECIMAL NOT NULL, U09 DECIMAL NOT NULL, U10 DECIMAL NOT NULL)\";\nmsg.connectName = 'connect';\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":320,"wires":[["a350f8b4.19fac"]]},{"id":"d29dab.56ad4a58","type":"udp in","z":"c206ac56.ec99c8","name":"","iface":"","port":"11001","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":140,"y":600,"wires":[["a28566c1.725e18"]]},{"id":"a28566c1.725e18","type":"function","z":"c206ac56.ec99c8","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":300,"y":600,"wires":[["aad15ffa.bdb8a"]]},{"id":"aad15ffa.bdb8a","type":"debug","z":"c206ac56.ec99c8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":480,"y":600,"wires":[]},{"id":"5c4ed4eee2bea740","type":"comment","z":"c206ac56.ec99c8","name":"Create Postgres Tables","info":"","x":180,"y":280,"wires":[]},{"id":"b92dbb76777f4f0d","type":"inject","z":"c206ac56.ec99c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":220,"wires":[["e1e15906f4587a92"]]},{"id":"e1e15906f4587a92","type":"function","z":"c206ac56.ec99c8","name":"createdb","func":"msg.payload = \"psql -c 'CREATE DATABASE vpp' 'user=pi password=pi'\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":220,"wires":[["dbbf82d70aec4021"]]},{"id":"dbbf82d70aec4021","type":"exec","z":"c206ac56.ec99c8","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":450,"y":220,"wires":[["0ae3468a33a07a4a"],["0ae3468a33a07a4a"],["0ae3468a33a07a4a"]]},{"id":"0ae3468a33a07a4a","type":"debug","z":"c206ac56.ec99c8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":610,"y":220,"wires":[]},{"id":"ad7c0d1ed0f68d06","type":"udp in","z":"c206ac56.ec99c8","name":"","iface":"","port":"9055","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":140,"y":120,"wires":[["fe2f2f69.538e6","58ab7f46.b59168"]]},{"id":"b732853e8429b6c8","type":"tcp in","z":"c206ac56.ec99c8","name":"","server":"server","host":"","port":"9057","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":140,"y":560,"wires":[["3aae273b98bb025d"]]},{"id":"3aae273b98bb025d","type":"function","z":"c206ac56.ec99c8","name":"parse string","func":"msg.payload = msg.payload.split(\",\");\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":560,"wires":[["a7f06bfd.b48668"]]},{"id":"f77f070b.c25478","type":"function","z":"f825e8a0.9d51f","name":"access check","func":"var myLeaderId = global.get(\"device1.leaderId\");\nif(myLeaderId == msg.payload.id) {\n var myId = global.get(\"device1.id\");\n var virtualFunctions = msg.payload.virtualFunctions;\n for (let vf of virtualFunctions) {\n if(vf.name == \"FaultLoc\" && vf.device == myId) {\n flow.set(\"FaultLocEnabled\", true);\n flow.set(\"FaultLocId\", vf.device);\n } else if (vf.name == \"FaultLoc\" && vf.device!= myId) {\n flow.set(\"FaultLocEnabled\", false);\n flow.set(\"FaultLocId\", vf.device);\n } else if(vf.name == \"ServiceRes\" && vf.device == myId) {\n flow.set(\"ServiceResEnabled\", true);\n flow.set(\"ServiceResId\", vf.device);\n } else if(vf.name == \"ServiceRes\" && vf.device != myId) {\n flow.set(\"ServiceResEnabled\", false);\n flow.set(\"ServiceResId\", vf.device);\n }\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":180,"wires":[["6ecc2121.346a9","ea2cec30.1692a"]]},{"id":"874f9edf.346148","type":"exec","z":"f825e8a0.9d51f","command":"python3 ","addpay":"payload","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"","x":980,"y":220,"wires":[["de4d01b7.3553a"],["43026d12.890aac"],["49bbf8d1.cf35b8","93d9142d.ba3a88"]]},{"id":"43026d12.890aac","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":220,"wires":[]},{"id":"49bbf8d1.cf35b8","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1170,"y":240,"wires":[]},{"id":"6ecc2121.346a9","type":"function","z":"f825e8a0.9d51f","name":"start FaultLoc","func":"var isEnabled = flow.get(\"FaultLocEnabled\") || false;\n\nif(isEnabled){\n let py_path=\"/home/pi/distributed-dvam/functions/Failure_Detection.py\";\n msg.payload=\"-u \" + py_path;\n msg.msg = msg.payload;\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":160,"wires":[["3ddffbff.3a8d04"]]},{"id":"de4d01b7.3553a","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1170,"y":200,"wires":[]},{"id":"dc738b2b.dbc73","type":"comment","z":"f825e8a0.9d51f","name":"Receive output from FL and sent to leader","info":"","x":200,"y":460,"wires":[]},{"id":"60772234.eb2e74","type":"comment","z":"f825e8a0.9d51f","name":"FL - call Python script","info":"","x":980,"y":160,"wires":[]},{"id":"ec039494.c9d47","type":"exec","z":"f825e8a0.9d51f","command":"python3 ","addpay":"payload","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"","x":980,"y":340,"wires":[["5cebfc32.63f084"],["663dac7c.4504dc"],["11dd1c54.d9432c","e4e66725.559a"]]},{"id":"663dac7c.4504dc","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":340,"wires":[]},{"id":"11dd1c54.d9432c","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1170,"y":360,"wires":[]},{"id":"ea2cec30.1692a","type":"function","z":"f825e8a0.9d51f","name":"start ServiceRes","func":"var isEnabled = flow.get(\"ServiceResEnabled\") || false;\n\nif(isEnabled){\n let py_path=\"/home/pi/distributed-dvam/functions/Service_Restoration.py\";\n msg.payload=\"-u \" + py_path;\n msg.msg = msg.payload;\n return msg;\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":200,"wires":[["f6949d11.98549"]]},{"id":"5cebfc32.63f084","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1170,"y":320,"wires":[]},{"id":"e90189e7.7dda8","type":"comment","z":"f825e8a0.9d51f","name":"Receive output from SR and sent to leader","info":"","x":200,"y":580,"wires":[]},{"id":"7ad5313e.ff76b","type":"comment","z":"f825e8a0.9d51f","name":"SR - call Python script","info":"","x":980,"y":280,"wires":[]},{"id":"4df67301.c0a4bc","type":"function","z":"f825e8a0.9d51f","name":"kill FaultLoc","func":"var isEnabled = flow.get(\"FaultLocEnabled\") || false;\n\nif(!isEnabled){\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":360,"wires":[["874f9edf.346148"]]},{"id":"185bcbda.b64584","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"kill","v":"SIGTERM","vt":"str"}],"repeat":"5","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":570,"y":380,"wires":[["4df67301.c0a4bc","4706625e.d45c4c"]]},{"id":"4706625e.d45c4c","type":"function","z":"f825e8a0.9d51f","name":"kill ServiceRes","func":"var isEnabled = flow.get(\"ServiceResEnabled\") || false;\n\nif(!isEnabled){\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":400,"wires":[["ec039494.c9d47"]]},{"id":"a64b9a90.4658a8","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":120,"wires":[["6ecc2121.346a9"]]},{"id":"c1391863.5e787","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":240,"wires":[["ea2cec30.1692a"]]},{"id":"ebaf950d.b331f8","type":"debug","z":"f825e8a0.9d51f","name":"FL ready","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1320,"y":160,"wires":[]},{"id":"93d9142d.ba3a88","type":"function","z":"f825e8a0.9d51f","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1180,"y":160,"wires":[["ebaf950d.b331f8"]]},{"id":"e4e66725.559a","type":"function","z":"f825e8a0.9d51f","name":"take time","func":"msg.date = parseInt(Date.now());\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1180,"y":280,"wires":[["1d3a7b8a.7f351c"]]},{"id":"1d3a7b8a.7f351c","type":"debug","z":"f825e8a0.9d51f","name":"SR ready","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"date","targetType":"msg","statusVal":"","statusType":"auto","x":1320,"y":280,"wires":[]},{"id":"3ddffbff.3a8d04","type":"exec","z":"f825e8a0.9d51f","command":"ps aux","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":570,"y":140,"wires":[["be289a5.3f54568"],[],[]]},{"id":"f6949d11.98549","type":"exec","z":"f825e8a0.9d51f","command":"ps aux","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":570,"y":220,"wires":[["a04069d8.aa8848"],[],[]]},{"id":"a7bb4ad4.8aac98","type":"comment","z":"f825e8a0.9d51f","name":"Check running FaultLocalisation","info":"","x":650,"y":100,"wires":[]},{"id":"92117fa4.4086b","type":"comment","z":"f825e8a0.9d51f","name":"Check running ServiceRestauration","info":"","x":660,"y":180,"wires":[]},{"id":"be289a5.3f54568","type":"function","z":"f825e8a0.9d51f","name":"","func":"// Checks for multiple occurences\nsearch = \"python3\";\n\n// Text to look in\nvar text = msg.payload.toLowerCase();\n\n// String to look for\nvar regex = new RegExp(search.toLowerCase(), 'g');\n\n// Save indices in array\nvar result = [];\n\nvar split = text.split(\" \");\n\nvar isRunning = false;\n\nfor (var i = 0; i < split.length-2; i++) {\n // Find all python3 occurences\n if ((match = regex.exec(split[i])) != null) {\n // Uncomment to see all python processes\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n \n // Checks for running FaultLocalisation\n if (split[i+2].indexOf(\"failure_detection.py\") != -1) {\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n isRunning = true;\n }\n }\n}\nif (!isRunning) {\n msg.payload = msg.msg;\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":140,"wires":[["874f9edf.346148"]]},{"id":"a04069d8.aa8848","type":"function","z":"f825e8a0.9d51f","name":"","func":"// Checks for multiple occurences\nsearch = \"python3\"\n\n// Text to look in\nvar text = msg.payload.toLowerCase();\n\n// String to look for\nvar regex = new RegExp(search.toLowerCase(), 'g');\n\n// Save indices in array\nvar result = [];\n\nvar split = text.split(\" \");\n\nvar isRunning = false;\n\nfor (var i = 0; i < split.length-2; i++) {\n // Find all python3 occurences\n if ((match = regex.exec(split[i])) != null) {\n // Uncomment to see all python processes\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n \n //Checks for running ServiceRestauration\n if (split[i+2].indexOf(\"service_restoration.py\") != -1) {\n //node.warn(split[i] + \" \" + split[i+1] + \" \" + split[i+2]);\n isRunning = true;\n }\n }\n}\nif (!isRunning) {\n msg.payload = msg.msg;\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":220,"wires":[["ec039494.c9d47"]]},{"id":"b5ea4f43.7ea21","type":"comment","z":"f825e8a0.9d51f","name":"DV asset function assignment","info":"","x":160,"y":60,"wires":[]},{"id":"b88ec696.342468","type":"comment","z":"f825e8a0.9d51f","name":"Kill falsy running processes","info":"","x":630,"y":280,"wires":[]},{"id":"eff75d391a641181","type":"link in","z":"f825e8a0.9d51f","name":"AssignVirtualFunctionsIn","links":["0011097be96ce17b"],"x":55,"y":180,"wires":[["f77f070b.c25478"]]},{"id":"c0b68d9321252779","type":"inject","z":"f825e8a0.9d51f","name":"kill without check for testing","props":[{"p":"kill","v":"SIGTERM","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":630,"y":320,"wires":[["ec039494.c9d47","874f9edf.346148"]]},{"id":"c54c56dcbe4e6e04","type":"udp in","z":"f825e8a0.9d51f","name":"","iface":"","port":"9001","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":100,"y":500,"wires":[["b582a9d9dd654431"]]},{"id":"b582a9d9dd654431","type":"function","z":"f825e8a0.9d51f","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9055\"\n newMsg[i].sendId = 100001+i;\n newMsg[i].payload.func = \"RequestVote\"\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":520,"wires":[["71c647e2d845ff14"]]},{"id":"71c647e2d845ff14","type":"function","z":"f825e8a0.9d51f","name":"toLeader","func":"var leaderId = global.get(\"device1.leaderId\");\n\nif (msg.sendId == leaderId) {\n //msg.payload = \"\" + msg.payload.toString();\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":520,"wires":[["710eacc41aa5b03a"]]},{"id":"93574b7e5746bcb4","type":"udp in","z":"f825e8a0.9d51f","name":"","iface":"","port":"9002","ipv":"udp4","multicast":"false","group":"","datatype":"buffer","x":100,"y":540,"wires":[["b582a9d9dd654431"]]},{"id":"3379444cca17947c","type":"tcp request","z":"f825e8a0.9d51f","name":"","server":"","port":"","out":"time","ret":"buffer","splitc":"0","newline":"","tls":"","x":710,"y":520,"wires":[[]]},{"id":"710eacc41aa5b03a","type":"function","z":"f825e8a0.9d51f","name":"parseData","func":"node.warn(typeof(msg.payload));\n\nvar s = JSON.stringify(msg.payload);\ns = JSON.parse(s);\nmsg.payload = JSON.stringify(s[\"data\"]);\n\nmsg.payload = msg.payload.substring(1,msg.payload.length-1);\nmsg.payload = msg.payload.split(',').map(Number);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":520,"wires":[["3379444cca17947c"]]},{"id":"6de242b30ec88dbb","type":"inject","z":"f825e8a0.9d51f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":400,"y":1100,"wires":[["3052ddb875329338"]]},{"id":"3052ddb875329338","type":"function","z":"f825e8a0.9d51f","name":"","func":"var prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nmsg.payload = \"[1,2,1,2,1,2,1,2]\";\nmsg.host = prefix + \"1\" + suffix;\nmsg.port = \"9088\";\n\nmsg.payload = msg.payload.substring(1,msg.payload.length-1);\nmsg.payload = msg.payload.split(',').map(Number);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":1100,"wires":[["bf4a7b9642d97bf6"]]},{"id":"bf4a7b9642d97bf6","type":"tcp request","z":"f825e8a0.9d51f","name":"","server":"","port":"","out":"time","ret":"buffer","splitc":"0","newline":"","tls":"","x":670,"y":1100,"wires":[[]]},{"id":"cfbac421b054011d","type":"tcp in","z":"f825e8a0.9d51f","name":"","server":"server","host":"","port":"9088","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"tls":"","x":860,"y":1100,"wires":[["d0d7df3f14425ed4"]]},{"id":"d0d7df3f14425ed4","type":"function","z":"f825e8a0.9d51f","name":"","func":"msg.payload = msg.payload.split(',').map(Number);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1000,"y":1100,"wires":[["defda5e14d764d30"]]},{"id":"defda5e14d764d30","type":"debug","z":"f825e8a0.9d51f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1150,"y":1100,"wires":[]},{"id":"9461393e.0e724","type":"inject","z":"6d95b6d3.106588","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":100,"wires":[["856a3489.e1c158"]]},{"id":"856a3489.e1c158","type":"function","z":"6d95b6d3.106588","name":"generate measurements","func":"var timestamp = msg.payload;\nvar measurements = [];\nvar power = 0;\n\nvar i = 0;\nfor (i; i < 10; i++) {\n if ((flow.get(\"failure\") || false) && i == 1) {\n power = 0\n }\n else {\n power=Math.ceil(Math.random()*20)+90;\n }\n measurements.push(power);\n}\n\nmeasurements.push(timestamp);\n\nmsg.payload = measurements\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":100,"wires":[["5687ca1b485d3cab"]]},{"id":"cf757ad1.575d","type":"inject","z":"6d95b6d3.106588","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":220,"wires":[["10720989.b356e6"]]},{"id":"77710a4c.3cb504","type":"inject","z":"6d95b6d3.106588","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":300,"wires":[["507fff78.6af578"]]},{"id":"10720989.b356e6","type":"function","z":"6d95b6d3.106588","name":"","func":"flow.set(\"failure\", true)","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":220,"wires":[[]]},{"id":"507fff78.6af578","type":"function","z":"6d95b6d3.106588","name":"","func":"flow.set(\"failure\", false)","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":300,"wires":[[]]},{"id":"940e198e.53ff28","type":"comment","z":"6d95b6d3.106588","name":"Set failure","info":"","x":160,"y":180,"wires":[]},{"id":"5e06091a.1781b8","type":"comment","z":"6d95b6d3.106588","name":"Remove failure","info":"","x":180,"y":260,"wires":[]},{"id":"5687ca1b485d3cab","type":"function","z":"6d95b6d3.106588","name":"set host/port","func":"var len = global.get(\"device1.nodesNum\") || 1;\nvar myId = global.get(\"device1.id\");\nvar prefix = global.get(\"device1.hostname_prefix\");\nvar suffix = global.get(\"device1.hostname_suffix\");\n\nvar newMsg = new Array(len-1);\n\nfor (i= 0; i<len;i++) {\n let clone = JSON.parse(JSON.stringify(msg));\n newMsg[i] = clone;\n newMsg[i].host = prefix + (i+1) + suffix;\n newMsg[i].port = \"9057\";\n newMsg[i].sendId = 100001+i;\n}\n\nreturn [newMsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":100,"wires":[["fea4e60940d46592"]]},{"id":"fea4e60940d46592","type":"tcp request","z":"6d95b6d3.106588","name":"","server":"","port":"","out":"time","ret":"string","splitc":"0","newline":"","tls":"","x":710,"y":100,"wires":[[]]},{"id":"9963bb2c3e7fd4f0","type":"comment","z":"6d95b6d3.106588","name":"Create Data","info":"","x":170,"y":60,"wires":[]}]
\ No newline at end of file \ No newline at end of file
...@@ -73,5 +73,5 @@ echo -e "\nInstallation succesful." ...@@ -73,5 +73,5 @@ echo -e "\nInstallation succesful."
# Postgresql # Postgresql
apt-get upgrade sudo apt-get upgrade
apt-get install postgresql-client sudo apt-get install postgresql-client
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment