-
-
Save MarcelIsrafilov/37b3979085f3fd27becfaa972336a4e5 to your computer and use it in GitHub Desktop.
Intrusion detection demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"sensors": [ | |
{ | |
"label": "createAlarm", | |
"name": "createAlarm", | |
"version": "1.0.2", | |
"properties": { | |
"text": "Motion detected!", | |
"severity": "MAJOR", | |
"type": "motion", | |
"resource": "$" | |
}, | |
"position": [ | |
-39, | |
639 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "dataStream", | |
"name": "stream", | |
"version": "1.0.1", | |
"resource": "$", | |
"position": [ | |
-479, | |
193 | |
], | |
"dataTrigger": true, | |
"tickTrigger": false, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "drawRectangles", | |
"name": "detectedObjectsOnImage", | |
"version": "1.0.9", | |
"properties": { | |
"fileName": "/sandbox/images/${nodes.dataStream.rawData.stream.image}", | |
"jsonBoxes": "$${nodes.objectDetection.rawData.result}" | |
}, | |
"position": [ | |
-39, | |
421 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "motionCheck", | |
"name": "condition", | |
"version": "1.1.6", | |
"properties": { | |
"condition": "${nodes.dataStream.rawData.stream.presence}==1" | |
}, | |
"position": [ | |
-268, | |
191 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "objectDetection", | |
"name": "tensorflowjsObjectDetection", | |
"version": "1.0.20", | |
"properties": { | |
"imagefile": "/sandbox/images/${nodes.dataStream.rawData.stream.image}", | |
"imageurl": "", | |
"modelfile": "file:///sandbox/plugs/coco-ssd/model.json" | |
}, | |
"position": [ | |
-17, | |
191 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "personCheck", | |
"name": "condition", | |
"version": "1.1.6", | |
"properties": { | |
"condition": "${nodes.personGet.rawData.numberOfObjects}>0" | |
}, | |
"position": [ | |
-341, | |
419 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "personGet", | |
"name": "script", | |
"version": "2.0.1", | |
"properties": { | |
"script": "function example () {\n const boxes=JSON.parse('$${nodes.objectDetection.rawData.result}')\n const filteredBoxes= boxes.filter(function (el) {\n return ((el.class=='person' || el.class=='motorcycle' || el.class=='bird' || el.class=='cat' || el.class=='dog'));\n });\n return { numberOfObjects: filteredBoxes.length }\n}" | |
}, | |
"position": [ | |
234, | |
210 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "postFileToDiscord", | |
"name": "postFileToDiscord", | |
"version": "1.0.4", | |
"properties": { | |
"accessToken": "${vault.discordAccessToken}", | |
"fileName": "${nodes.drawRectangles.rawData.finalFileName}", | |
"channel": "${vault.discordChannelID}" | |
}, | |
"position": [ | |
286, | |
578 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
}, | |
{ | |
"label": "postFileToSlack", | |
"name": "postFileToSlack", | |
"version": "1.0.5", | |
"properties": { | |
"accessToken": "${vault.slackAccessToken}", | |
"fileName": "${nodes.drawRectangles.rawData.finalFileName}", | |
"channel": "#bot" | |
}, | |
"position": [ | |
276, | |
454 | |
], | |
"dataTrigger": false, | |
"tickTrigger": true, | |
"timeout": "PT50S" | |
} | |
], | |
"triggers": [ | |
{ | |
"sourceLabel": "personCheck", | |
"destinationLabel": "createAlarm", | |
"statesTrigger": [ | |
"True" | |
] | |
}, | |
{ | |
"sourceLabel": "objectDetection", | |
"destinationLabel": "personGet", | |
"statesTrigger": [ | |
"classified" | |
] | |
}, | |
{ | |
"sourceLabel": "motionCheck", | |
"destinationLabel": "objectDetection", | |
"statesTrigger": [ | |
"True" | |
] | |
}, | |
{ | |
"sourceLabel": "drawRectangles", | |
"destinationLabel": "postFileToDiscord", | |
"statesTrigger": [ | |
"success" | |
] | |
}, | |
{ | |
"sourceLabel": "dataStream", | |
"destinationLabel": "motionCheck", | |
"statesTrigger": [ | |
"Data" | |
] | |
}, | |
{ | |
"sourceLabel": "personGet", | |
"destinationLabel": "personCheck", | |
"statesTrigger": [ | |
"Success" | |
] | |
}, | |
{ | |
"sourceLabel": "drawRectangles", | |
"destinationLabel": "postFileToSlack", | |
"statesTrigger": [ | |
"success" | |
] | |
}, | |
{ | |
"sourceLabel": "personCheck", | |
"destinationLabel": "drawRectangles", | |
"statesTrigger": [ | |
"True" | |
] | |
} | |
], | |
"name": "demo motionsensor", | |
"user": "test@waylay.io", | |
"createTime": 1662376614862, | |
"lastUpdateTime": 1662450998524, | |
"discoveryTemplate": false, | |
"taskDefaults": { | |
"tags": {} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "detectedObjectsOnImage", | |
"version": "1.0.6", | |
"type": "sensor", | |
"script": "/*\n * ⚠️ Plugins should never throw exceptions, instead send an error back.\n *\n * ref: https://nodejs.org/api/errors.html#errors_error_first_callbacks\n */\nconst sharp = require('sharp');\n\n\nconst fileName = options.requiredProperties.fileName;\nconst jsonBoxes = options.requiredProperties.jsonBoxes;\nconst MAX_WIDTH = 1920;\nconst MAX_HEIGHT = 1080;\n\nif (!fileName || !jsonBoxes) {\n send(new Error('Missing property: fileName or jsonBoxes'));\n}\nconst dir = fileName.substring(0,fileName.lastIndexOf(\"/\"))\nlet state = \"success\"\nconst finalFileName = fileName.substring(0,fileName.lastIndexOf(\".\"))+\".markedImage.jpg\";\nconst rectanglePrefix=fileName.substring(0,fileName.lastIndexOf(\".\"))+\".rectangle\";\n\nconst images = new Array();\n\nasync function createRectangle(x, y, width, height, text, idx) {\n try {\n const svgImage = `\n <svg width=\"${width}\" height=\"${height}\">\n <style>\n .title { fill: #ff0000; font-size: 30px; font-weight: normal;}\n </style>\n <text x=\"15\" y=\"30\" text-anchor=\"left\" class=\"title\">${text}</text>\n </svg>\n `;\n \n await sharp(Buffer.from(svgImage))\n .extract({\n left: 5,\n top: 5,\n width: Math.floor(width)-10,\n height: Math.floor(height)-10\n })\n .extend({\n top: 5,\n bottom: 5,\n left: 5,\n right: 5,\n background: 'red'\n })\n .toFile(`${rectanglePrefix}${idx}.png`);\n\n } catch (error) {\n console.log(error);\n }\n}\n \nasync function composite(images,finalImage) {\n try {\n await sharp(fileName)\n .composite(images)\n .toFile(finalImage);\n\n } catch (error) {\n console.log(error);\n }\n}\n\nasync function execute(){\n const json = JSON.parse(jsonBoxes);\n for (const [idx,obj] of json.entries()){\n const y = Math.floor(obj.bbox[0])\n const x = Math.floor(obj.bbox[1])\n let width = Math.floor(obj.bbox[2])\n if(width>MAX_WIDTH){\n width = MAX_WIDTH\n }\n let height = Math.floor(obj.bbox[3])\n if(height>MAX_HEIGHT){\n height = MAX_HEIGHT\n }\n const text = obj.class\n\n images.push({\n input: `${rectanglePrefix}${idx}.png`,\n top: Math.floor(x),\n left: Math.floor(y)\n });\n\n await createRectangle(x, y, width, height, text, idx);\n }\n await composite(images,finalFileName)\n \n}\n\nexecute().then(()=>{\n const value = {\n observedState: state,\n rawData: {\n finalFileName: finalFileName\n }\n};\n\nsend(null, value);\n});\n", | |
"metadata": { | |
"author": "John Doe", | |
"iconURL": "", | |
"description": "", | |
"rawData": [ | |
{ | |
"dataType": "string", | |
"parameter": "finalFileName" | |
} | |
], | |
"configuration": [ | |
{ | |
"name": "fileName", | |
"type": "string", | |
"mandatory": true | |
}, | |
{ | |
"name": "jsonBoxes", | |
"type": "string", | |
"mandatory": true | |
} | |
], | |
"requiredProperties": [ | |
"fileName", | |
"jsonBoxes" | |
], | |
"supportedStates": [ | |
"success", | |
"error" | |
] | |
}, | |
"dependencies": { | |
"sharp": "0.30.7" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "postFileToDiscord", | |
"version": "1.0.4", | |
"type": "sensor", | |
"script": "//\nconst FormData = require('form-data')\nconst fs = require('fs-extra');\nconst axios = require('axios');\nconst { channel, accessToken, fileName} = options.requiredProperties\n\nasync function execute () {\n\n if (!accessToken || !channel || !fileName) {\n return send(new Error('Missing property'))\n }\n try {\n const stream = fs.createReadStream(fileName);\n const form = new FormData();\n form.append('files', stream);\n let headers = form.getHeaders(); \n const response = await axios.post('https://discord.com/api/v9/channels/'+channel+'/messages',\n form,\n { headers: { Authorization: `Bot ${accessToken}`, ...headers } })\n send(null, { observedState: 'Success', rawData: { response: response.data } })\n } catch (error) {\n console.error(error)\n send(null, { observedState: 'Error', rawData: { errorMessage: 'Error posting to slack api: ' + error } })\n }\n}\n\nexecute()", | |
"metadata": { | |
"author": "John Doe", | |
"iconURL": "", | |
"description": "", | |
"rawData": [ | |
{ | |
"dataType": "object", | |
"parameter": "response" | |
}, | |
{ | |
"dataType": "string", | |
"parameter": "errorMessage" | |
} | |
], | |
"configuration": [ | |
{ | |
"name": "accessToken", | |
"type": "string", | |
"mandatory": true | |
}, | |
{ | |
"name": "fileName", | |
"type": "string", | |
"mandatory": true | |
}, | |
{ | |
"name": "channel", | |
"type": "string", | |
"mandatory": true | |
} | |
], | |
"requiredProperties": [ | |
"accessToken", | |
"fileName", | |
"channel" | |
], | |
"supportedStates": [ | |
"Success", | |
"Error" | |
] | |
}, | |
"dependencies": { | |
"axios": "^0.26.1", | |
"form-data": "4.0.0", | |
"fs-extra": "10.1.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "postFileToSlack", | |
"version": "1.0.5", | |
"type": "sensor", | |
"script": "//\nconst FormData = require('form-data')\nconst fs = require('fs-extra');\nconst axios = require('axios');\nconst { channel, accessToken, fileName} = options.requiredProperties\n\nasync function execute () {\n\n if (!accessToken || !channel || !fileName) {\n return send(new Error('Missing property'))\n }\n try {\n const stream = fs.createReadStream(fileName);\n const form = new FormData();\n form.append('file', stream);\n form.append('channels', channel);\n let headers = form.getHeaders(); \n const response = await axios.post('https://slack.com/api/files.upload',\n form,\n { headers: { Authorization: `Bearer ${accessToken}`, ...headers } })\n send(null, { observedState: 'Success', rawData: { response: response.data } })\n } catch (error) {\n console.error(error)\n send(null, { observedState: 'Error', rawData: { errorMessage: 'Error posting to slack api: ' + error } })\n }\n}\n\nexecute()", | |
"metadata": { | |
"author": "John Doe", | |
"iconURL": "", | |
"description": "", | |
"rawData": [ | |
{ | |
"dataType": "object", | |
"parameter": "response" | |
}, | |
{ | |
"dataType": "string", | |
"parameter": "errorMessage" | |
} | |
], | |
"configuration": [ | |
{ | |
"name": "accessToken", | |
"type": "string", | |
"mandatory": true | |
}, | |
{ | |
"name": "fileName", | |
"type": "string", | |
"mandatory": true | |
}, | |
{ | |
"name": "channel", | |
"type": "string", | |
"mandatory": true | |
} | |
], | |
"requiredProperties": [ | |
"accessToken", | |
"fileName", | |
"channel" | |
], | |
"supportedStates": [ | |
"Success", | |
"Error" | |
] | |
}, | |
"dependencies": { | |
"axios": "^0.26.1", | |
"form-data": "4.0.0", | |
"fs-extra": "10.1.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "tensorflowjsObjectDetection", | |
"version": "1.0.18", | |
"type": "sensor", | |
"script": "//\n\nconst axios = require('axios');\nconst fs = require('fs-extra');\nconst cocoSsd = require('@tensorflow-models/coco-ssd');\n\n\n// tslint:disable-next-line: no-floating-promises\n\nconst { modelfile,imagefile, imageurl } = options.requiredProperties\n\n\nfunction base64_encode(file) {\n // read binary data\n var bitmap = fs.readFileSync(file);\n // convert binary data to base64 encoded string\n return new Buffer(bitmap).toString('base64');\n}\n\n\nasync function execute () {\n let model;\ntry {\n \n // Load the model\n const config={}\n if(modelfile){\n config.modelUrl=modelfile\n }\n \n model = await cocoSsd.load(config);\n\n\n const data = fs.readFileSync(imagefile);\n let classifyRes={};\n let state='classified'\n let imgTensor = tfnode.tidy( () => {\n try{\n return tfnode.node.decodeImage(data, 3); \n } catch (error) {\n console.error(error)\n return undefined;\n }\n })\n if(imgTensor){\n classifyRes = await model.detect(imgTensor)\n await model.dispose();\n tfnode.dispose(imgTensor)\n }else{\n state='error'\n }\n \n const classificationResult={};\n let value = {\n observedState: state,\n rawData: {\n result: classifyRes,\n }\n };\n \n if(imageurl){\n try {\n const method='POST';\n const modifiedResult={\"bounding_boxes\":[]}\n for (key in classifyRes) {\n const box={\n \"label\":classifyRes[key].class,\n \"value\":classifyRes[key].score,\n \"x\":Math.trunc(classifyRes[key].bbox[0]),\n \"y\":Math.trunc(classifyRes[key].bbox[1]),\n \"width\":Math.trunc(classifyRes[key].bbox[2]),\n \"height\":Math.trunc(classifyRes[key].bbox[3])\n \n }\n modifiedResult.bounding_boxes.push(box)\n };\n console.log(modifiedResult)\n const imgdataOriginal='data:image/png;base64, '+base64_encode(imagefile);\n const body={\n \"img\": imgdataOriginal,\n \"imgoriginal\":imgdataOriginal,\n \"classificationResult\":modifiedResult\n }\n const response = await axios({ url: imageurl, data: body, method: method, timeout: 2000 })\n value.rawData.httpSend = {\n status: response.status\n }\n } catch (error) {\n console.error(error)\n value.rawData.httpSend = {\n error: error\n } \n }\n }\n send(null, value);\n \n \n \n } catch (error) {\n console.error(error)\n send(null, { observedState: 'error', rawData: { errorMessage: 'Failed to call url: ' + error } })\n } finally {\n if(model){\n await model.dispose();\n }\n }\n\n}\n\n\n\nexecute()\n\n", | |
"metadata": { | |
"author": "John Doe", | |
"iconURL": "", | |
"description": "", | |
"rawData": [], | |
"configuration": [ | |
{ | |
"name": "imagefile", | |
"type": "string", | |
"mandatory": true | |
}, | |
{ | |
"name": "imageurl", | |
"type": "string", | |
"mandatory": false | |
}, | |
{ | |
"name": "modelfile", | |
"type": "string", | |
"mandatory": false | |
} | |
], | |
"requiredProperties": [ | |
"imagefile", | |
"imageurl", | |
"modelfile" | |
], | |
"supportedStates": [ | |
"classified", | |
"error" | |
] | |
}, | |
"dependencies": { | |
"axios": " ^0.20.0", | |
"fs-extra": "^10.1.0", | |
"@tensorflow-models/coco-ssd": "2.0.3" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment