NVR: capture, store, email pictures/videos from IP camera streams

This video is my simple NVR implementation for Node Red. It just shows how easy it is to capture pictures, video clips from RTSP streams server by IP cameras. This flow offers an entire framework for capturing footage, storing in database, simple reporting, sending images over email etc.

There is a longer video which explains the details of the flow: https://youtu.be/ihZWrJmbGFY

[{"id":"9efa042c.1ed728","type":"tab","label":"NVR","disabled":false,"info":""},{"id":"a92f1b2f.277878","type":"debug","z":"9efa042c.1ed728","name":"","active":false,"console":"false","complete":"true","x":770,"y":160,"wires":[]},{"id":"161395bd.44fcda","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":100,"y":140,"wires":[["fbd47d60.0e2dc"]]},{"id":"59d467aa.79d638","type":"exec","z":"9efa042c.1ed728","command":"avconv -i rtsp://user:[email protected]:554/ch01.264 -frames 1 -qscale 1 -f image2 ","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Grab a frame","x":530,"y":80,"wires":[["ccefbf92.43434","5181ecea.300284","2664e0ab.3ccb"],[],["a92f1b2f.277878","37e6ad7b.6e58e2"]]},{"id":"ccefbf92.43434","type":"ui_template","z":"9efa042c.1ed728","group":"675036dd.603328","name":"Static image","order":2,"width":0,"height":0,"format":"<div height=\"210\" style=\"height: 210px;\">\n<img src=\"/grab.jpg\"/ width=\"280\"><br/>\n<a href=\"/grab.jpg\" target=\"_blank\">Full screen</a>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":790,"y":40,"wires":[[]]},{"id":"5181ecea.300284","type":"debug","z":"9efa042c.1ed728","name":"","active":false,"console":"false","complete":"true","x":770,"y":80,"wires":[]},{"id":"efab5927.df2fe8","type":"file","z":"9efa042c.1ed728","name":"","filename":"/home/pi/avconv.out","appendNewline":true,"createDir":false,"overwriteFile":"true","x":820,"y":120,"wires":[]},{"id":"37e6ad7b.6e58e2","type":"function","z":"9efa042c.1ed728","name":"Statistics","func":"var now = new Date();\nvar stat = context.get(\"stat\");\nif (stat===undefined) {\n    // Initialize the object in case NR restart\n    stat = { \"count\": 0, \"success\": 0, \"rate\": 0.0, \"last\": now};\n}\nif (msg.topic===\"reset\") {\n    // Reset message was received: reset statistics\n    stat = { \"count\": 0, \"success\": 0, \"rate\": 0.0, \"last\": now};\n} else {\n    // Update statistics\n    stat.count++;\n    if (msg.payload.code===0) {\n        stat.success++;\n    }    \n    stat.rate=stat.success/stat.count;\n    stat.last=now;\n}\n\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\nmsg.formattedtime = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;\nmsg.success = stat.success;\nmsg.rate = Math.floor(stat.rate*100);\n\nnode.status({fill:\"blue\",shape:\"ring\",text:\"Frames: \"+msg.success+\" | \"+msg.rate+\"% | Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n\n// Saving data in the context\ncontext.set(\"stat\",stat);\n\nreturn msg;\n\n\n","outputs":1,"noerr":0,"x":680,"y":280,"wires":[["e8b0a469.8ba128","b06a46c8.57af78","df71ef74.0f8d2"]]},{"id":"ae82c778.306d48","type":"inject","z":"9efa042c.1ed728","name":"Reset stat","topic":"reset","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":480,"y":280,"wires":[["37e6ad7b.6e58e2"]]},{"id":"e8b0a469.8ba128","type":"ui_text","z":"9efa042c.1ed728","group":"e16e06ca.f38438","order":1,"width":0,"height":0,"name":"Last time","label":"Last grab","format":"{{msg.formattedtime}}","layout":"row-spread","x":881.0000839233398,"y":200.39999198913574,"wires":[]},{"id":"b06a46c8.57af78","type":"ui_text","z":"9efa042c.1ed728","group":"e16e06ca.f38438","order":2,"width":0,"height":0,"name":"Frame count","label":"Frames grabbed","format":"{{msg.success}}","layout":"row-spread","x":890.8999900817871,"y":236.1999807357788,"wires":[]},{"id":"df71ef74.0f8d2","type":"ui_text","z":"9efa042c.1ed728","group":"e16e06ca.f38438","order":3,"width":0,"height":0,"name":"Success rate","label":"Success rate","format":"{{msg.rate}} %","layout":"row-spread","x":891.8999633789062,"y":274.1999740600586,"wires":[]},{"id":"92f3cf3b.51ac8","type":"ui_button","z":"9efa042c.1ed728","name":"Refresh","group":"675036dd.603328","order":1,"width":0,"height":0,"passthru":false,"label":"Refresh image","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":84.59999084472656,"y":94.13333797454834,"wires":[["fbd47d60.0e2dc"]]},{"id":"67d53350.bb09dc","type":"debug","z":"9efa042c.1ed728","name":"","active":true,"console":"false","complete":"true","x":778.0000152587891,"y":1040.0000228881836,"wires":[]},{"id":"848f3283.66a9a","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":128.00001525878906,"y":1000.0000228881836,"wires":[["db6e6672.8e0358"]]},{"id":"a5aeed17.49a44","type":"exec","z":"9efa042c.1ed728","command":"avconv -i rtsp://user:[email protected]:554/ch01.264 -r 10 -t 30 -y -vcodec copy -an ","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Capture video","x":548.0000152587891,"y":960.0000228881836,"wires":[["a9b89709.b65498","677574cb.bbb1fc","2664e0ab.3ccb"],["8a971c90.ebe9b"],["67d53350.bb09dc","1c4d41e8.c597be"]]},{"id":"a9b89709.b65498","type":"ui_template","z":"9efa042c.1ed728","group":"cb67921.cf4df7","name":"Video link","order":2,"width":0,"height":0,"format":"<div height=\"70\" style=\"height: 70px;\">\n<a href=\"/video.mp4\" target=\"_blank\">Open video</a>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":788.0000152587891,"y":920.0000228881836,"wires":[[]]},{"id":"677574cb.bbb1fc","type":"debug","z":"9efa042c.1ed728","name":"","active":true,"console":"false","complete":"true","x":778.0000152587891,"y":960.0000228881836,"wires":[]},{"id":"8a971c90.ebe9b","type":"file","z":"9efa042c.1ed728","name":"","filename":"/home/pi/avconv.out","appendNewline":true,"createDir":false,"overwriteFile":"true","x":828.0000152587891,"y":1000.0000228881836,"wires":[]},{"id":"1c4d41e8.c597be","type":"function","z":"9efa042c.1ed728","name":"Statistics","func":"var now = new Date();\nvar stat = context.get(\"stat\");\nif (stat===undefined) {\n    // Initialize the object in case NR restart\n    stat = { \"count\": 0, \"success\": 0, \"rate\": 0.0, \"last\": now};\n}\nif (msg.topic===\"reset\") {\n    // Reset message was received: reset statistics\n    stat = { \"count\": 0, \"success\": 0, \"rate\": 0.0, \"last\": now};\n} else {\n    // Update statistics\n    stat.count++;\n    if (msg.payload.code===0) {\n        stat.success++;\n    }    \n    stat.rate=stat.success/stat.count;\n    stat.last=now;\n}\n\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\nmsg.formattedtime = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;\nmsg.success = stat.success;\nmsg.rate = Math.floor(stat.rate*100);\n\nnode.status({fill:\"blue\",shape:\"ring\",text:\"Videos: \"+msg.success+\" | \"+msg.rate+\"% | Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n\n// Saving data in the context\ncontext.set(\"stat\",stat);\n\nreturn msg;\n\n\n","outputs":1,"noerr":0,"x":668.0000152587891,"y":1160.0000228881836,"wires":[["c7d29921.7b3a88","dec88d14.74771","9131b705.d7da98"]]},{"id":"4d857e74.bf6e6","type":"inject","z":"9efa042c.1ed728","name":"Reset stat","topic":"reset","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":468.00001525878906,"y":1160.0000228881836,"wires":[["1c4d41e8.c597be"]]},{"id":"c7d29921.7b3a88","type":"ui_text","z":"9efa042c.1ed728","group":"984422e9.d6d96","order":1,"width":0,"height":0,"name":"Video Last time","label":"Last grab","format":"{{msg.formattedtime}}","layout":"row-spread","x":888.0000152587891,"y":1080.0000228881836,"wires":[]},{"id":"dec88d14.74771","type":"ui_text","z":"9efa042c.1ed728","group":"984422e9.d6d96","order":2,"width":0,"height":0,"name":"Video count","label":"Video files","format":"{{msg.success}}","layout":"row-spread","x":878.0000152587891,"y":1120.0000228881836,"wires":[]},{"id":"9131b705.d7da98","type":"ui_text","z":"9efa042c.1ed728","group":"984422e9.d6d96","order":3,"width":0,"height":0,"name":"Video Success rate","label":"Success rate","format":"{{msg.rate}} %","layout":"row-spread","x":898.0000152587891,"y":1160.0000228881836,"wires":[]},{"id":"60807950.8a1308","type":"ui_button","z":"9efa042c.1ed728","name":"Capture","group":"cb67921.cf4df7","order":1,"width":0,"height":0,"passthru":false,"label":"Capture video","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":112.60000610351562,"y":954.1333608627319,"wires":[["db6e6672.8e0358"]]},{"id":"71c22335.23098c","type":"comment","z":"9efa042c.1ed728","name":"Frame grabber","info":"This section of the flow is responsible for \ngrabbing a single out of the RTSP feed of the IP\nCamera. It uses avconv to do that which is part\nof the libav-tools for raspberry pi.\n\nThe trigger can be an inject, or a UI button.\nThe statistic node keeps a track of the number of\ngrabbed frames and the success rate (when the\nvideo conversion/grabbing was successful). The \nStatistic node also has a reset input which can \nbe used to periodically reset the stats (e.g.\ndaily, weekly).\n\nI directed the second output of the Exec node to\na file, as the output of the avconv is usually \nquite long and if there are errors you don't\nsee the entire output in the debug window, so in\nthat case just open to output and see what the issue\nis.","x":125.625,"y":36.5000057220459,"wires":[]},{"id":"b3106a10.da69e8","type":"comment","z":"9efa042c.1ed728","name":"Video capture","info":"This section of the flow captures a fixed length \nvideo of the RTSP feed.\nIt works very similar to the frame capture above,\nthe only main difference is the parameters in the\ncommmand line.","x":118.00001525878906,"y":900.0000228881836,"wires":[]},{"id":"fbd47d60.0e2dc","type":"change","z":"9efa042c.1ed728","name":"Set filename","rules":[{"t":"set","p":"payload","pt":"msg","to":"/home/pi/node-red-static/grab.jpg","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":80,"wires":[["59d467aa.79d638"]]},{"id":"db6e6672.8e0358","type":"change","z":"9efa042c.1ed728","name":"Set filename","rules":[{"t":"set","p":"payload","pt":"msg","to":"/home/pi/node-red-static/video.mp4","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":298.00001525878906,"y":960.0000228881836,"wires":[["a5aeed17.49a44"]]},{"id":"f44069e.c6a9998","type":"function","z":"9efa042c.1ed728","name":"Frame grab","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"frame_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"store\";                                        // Flag to store this image in the DB\nmsg.type = \"timelapse\";                                     // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":380,"wires":[["59d467aa.79d638"]]},{"id":"6bd4711d.97ae","type":"inject","z":"9efa042c.1ed728","name":"Grab a frame","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":130,"y":380,"wires":[["f44069e.c6a9998"]]},{"id":"6626a216.c8071c","type":"function","z":"9efa042c.1ed728","name":"Save to DB","func":"// only run this if the topic contains 'store', so the manual frame grabs do not get\n// stored in the database\nif (msg.topic.indexOf(\"store\") !== -1) {\n\n    msg.topic = \"INSERT INTO nvr (type,path,wwwpath,filename,epoch) \" +\n            \"VALUES ('\"+msg.type+\"','\"+msg.path+\"','\"+msg.wwwpath+\"','\"+msg.file+\"',\"+msg.epoch+\");\";\n    \n    node.status({fill:\"blue\",shape:\"ring\",text:\"Last update: \"+msg.formatteddate});\n    \n    return msg;\n}","outputs":1,"noerr":0,"x":990,"y":340,"wires":[["1862d096.0aa7ef"]]},{"id":"1862d096.0aa7ef","type":"sqlite","z":"9efa042c.1ed728","mydb":"1c25415d.b8427f","name":"Node Red DB","x":1180,"y":340,"wires":[[]]},{"id":"3fc38f78.17dab","type":"function","z":"9efa042c.1ed728","name":"Video capture","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"video_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".mp4\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"store\";                                        // Flag to store this image in the DB\nmsg.type = \"videotest\";                                     // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":328.00001525878906,"y":1080.0000228881836,"wires":[["a5aeed17.49a44"]]},{"id":"f752e943.e325d8","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":128.00001525878906,"y":1080.0000228881836,"wires":[["3fc38f78.17dab"]]},{"id":"7f436228.923ccc","type":"function","z":"9efa042c.1ed728","name":"Email image","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"frame_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"store|email\";                                  // Flag to store this image in the DB\nmsg.type = \"front\";                                         // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":420,"wires":[["59d467aa.79d638"]]},{"id":"3802963b.c35a2a","type":"inject","z":"9efa042c.1ed728","name":"Email a pic","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":120,"y":420,"wires":[["7f436228.923ccc"]]},{"id":"2664e0ab.3ccb","type":"function","z":"9efa042c.1ed728","name":"Dummy","func":"\nreturn msg;","outputs":1,"noerr":0,"x":780,"y":380,"wires":[["6626a216.c8071c","cb390310.7a97e","83fd6a62.ba5898","606e90cf.e660c","e85ffa62.1a8b98"]]},{"id":"cb390310.7a97e","type":"function","z":"9efa042c.1ed728","name":"Compose email","func":"// only run this if the topic contains 'email', so other types do not get emailed\nif (msg.topic.indexOf(\"email\") !== -1) {\n\n    msg.filename = msg.path + msg.file;\n    \n    node.status({fill:\"blue\",shape:\"ring\",text:\"Last update: \"+msg.formatteddate});\n    \n    return msg;\n}","outputs":1,"noerr":0,"x":1000,"y":400,"wires":[["7159813e.2bdb4"]]},{"id":"50e67922.ab82c8","type":"e-mail","z":"9efa042c.1ed728","server":"smtp.gmail.com","port":"465","secure":true,"name":"[email protected]","dname":"Email notification","x":1390,"y":400,"wires":[]},{"id":"7159813e.2bdb4","type":"change","z":"9efa042c.1ed728","name":"Set up email","rules":[{"t":"set","p":"attachments","pt":"msg","to":"[{\t    \"filename\": msg.file, \t    \"path\": msg.filename,\t    \"content\": $$.payload\t}]","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"Front door motion","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"Dear,<br><br>Motion has been detected at the front door<br>In attachment you can find a snapshot.<br><br>Kind regards,<br>Your Node-Red flow","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1190,"y":400,"wires":[["50e67922.ab82c8"]]},{"id":"db1675ae.6608a8","type":"comment","z":"9efa042c.1ed728","name":"Image / Video Log","info":"","x":138.00000762939453,"y":1664.0000324249268,"wires":[]},{"id":"6eed45ad.3a9f4c","type":"template","z":"9efa042c.1ed728","name":"Formatting","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<table>\n    <tr><th>ID</th><th>Type</th><th>Timestamp</th><th>File</th></tr>\n    {{#payload}}\n        <tr class=\"\">\n            <td>{{id}}</td>\n            <td>{{type}}</td>\n            <td>{{timestamp}}</td>\n            <td><a href=\"{{wwwpath}}{{filename}}\" target=\"_blank\">{{filename}}</a></td>\n        </tr>\n    {{/payload}}\n</table>\n","x":737.0000076293945,"y":2039.0000324249268,"wires":[["e60dddf1.8029c"]]},{"id":"46d1c098.824e5","type":"function","z":"9efa042c.1ed728","name":"SQL","func":"context.set(msg.topic,msg.payload);\n\nvar d = new Date();\nvar epoch = d.getTime();\nvar fromdate = 0;\nvar enddate = 0;\n\nmsg.topic = \"SELECT * FROM nvr WHERE id>0 \";\n\nif (context.get(\"type\")!==undefined) {\n    if (context.get(\"type\")!==\"*\") {\n        msg.topic = msg.topic + \" AND type = '\"+context.get(\"type\")+\"'\";\n    }\n}\n\nif (context.get(\"time\")!==undefined) {\n    switch (context.get(\"time\")) {\n        case 0:\n            fromdate = epoch - 1000*60*60*24;\n            msg.topic = msg.topic + \" AND epoch > \"+fromdate;\n            break;\n        case 1:\n            fromdate = epoch - 1000*60*60*24*7;\n            msg.topic = msg.topic + \" AND epoch > \"+fromdate;\n            break;\n        case 2:\n            fromdate = epoch - 1000*60*60*24*30;\n            msg.topic = msg.topic + \" AND epoch > \"+fromdate;\n            break;\n    }\n}\n\n// msg.topic = msg.topic.substring(0,msg.topic.length-2);\nmsg.topic = msg.topic+ \" ORDER BY id\";\nreturn msg;","outputs":1,"noerr":0,"x":324.00000762939453,"y":2038.0000324249268,"wires":[["3f0bae61.7c1962"]]},{"id":"a67b5ea9.1f61","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":157.00000762939453,"y":2038.0000324249268,"wires":[["46d1c098.824e5"]]},{"id":"bf2db74c.7ebda8","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"x":278.00000762939453,"y":1904.0000324249268,"wires":[["e022fd92.f69d2"]]},{"id":"e022fd92.f69d2","type":"change","z":"9efa042c.1ed728","name":"Initial value","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":458.00000762939453,"y":1904.0000324249268,"wires":[["c997c751.b0e9e8"]]},{"id":"82ca9c8d.fa89b","type":"function","z":"9efa042c.1ed728","name":"Process systems","func":"var output = [];\noutput.push({\"All systems\":\"*\"});\nfor (var i = 0; i < msg.payload.length; i++) {\n    obj = {};\n    obj [msg.payload[i].type]=msg.payload[i].type;\n    output.push(obj);\n}\nmsg.options = output;\nreturn msg;","outputs":1,"noerr":0,"x":478.00000762939453,"y":1784.0000324249268,"wires":[["968f6573.a694c8"]]},{"id":"b0228a6d.84f3e8","type":"ui_button","z":"9efa042c.1ed728","name":"","group":"a06d1d6b.bdef2","order":1,"width":"3","height":"1","passthru":false,"label":"Refresh","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"refresh","x":668.0000076293945,"y":1844.0000324249268,"wires":[["46d1c098.824e5"]]},{"id":"c997c751.b0e9e8","type":"ui_dropdown","z":"9efa042c.1ed728","name":"Time filter","label":"","place":"","group":"a06d1d6b.bdef2","order":3,"width":"4","height":"1","passthru":true,"options":[{"label":"Last 24 hrs","value":0,"type":"num"},{"label":"Last 7 days","value":1,"type":"num"},{"label":"Last 30 days","value":2,"type":"num"},{"label":"All","value":3,"type":"num"}],"payload":"","topic":"time","x":668.0000076293945,"y":1904.0000324249268,"wires":[["46d1c098.824e5"]]},{"id":"968f6573.a694c8","type":"ui_dropdown","z":"9efa042c.1ed728","name":"Type","label":"","place":"","group":"a06d1d6b.bdef2","order":5,"width":"5","height":"1","passthru":true,"options":[{"label":"All","value":"*","type":"str"},{"label":"timelapse","value":"timelapse","type":"str"},{"label":"front","value":"front","type":"str"},{"label":"videotest","value":"videotest","type":"str"}],"payload":"","topic":"type","x":678.0000076293945,"y":1784.0000324249268,"wires":[["46d1c098.824e5"]]},{"id":"e60dddf1.8029c","type":"ui_template","z":"9efa042c.1ed728","group":"a06d1d6b.bdef2","name":"Log output","order":6,"width":0,"height":0,"format":"<div ng-bind-html=\"msg.payload\" height=\"600\" style=\"height: 600px;\"><br/></div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":958.0000076293945,"y":2039.0000324249268,"wires":[[]]},{"id":"3f0bae61.7c1962","type":"sqlite","z":"9efa042c.1ed728","mydb":"1c25415d.b8427f","name":"Node Red DB","x":532.0000076293945,"y":2038.0000324249268,"wires":[["6eed45ad.3a9f4c"]]},{"id":"68a84ff2.caa05","type":"inject","z":"9efa042c.1ed728","name":"Email 3 pics","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":130,"y":460,"wires":[["ce7424a5.0105c8"]]},{"id":"ce7424a5.0105c8","type":"function","z":"9efa042c.1ed728","name":"1st img","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"frame_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"3mail/1|delete\";                               // Flag to store this image in the DB\nmsg.type = \"temp\";                                          // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":460,"wires":[["9b2e9667.e1a578","59d467aa.79d638"]]},{"id":"94e6544f.7a4998","type":"function","z":"9efa042c.1ed728","name":"2st img","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"frame_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"3mail/2|delete\";                               // Flag to store this image in the DB\nmsg.type = \"temp\";                                          // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":520,"wires":[["910a4663.888b28","59d467aa.79d638"]]},{"id":"8082b36d.9fca8","type":"function","z":"9efa042c.1ed728","name":"3rd img","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"frame_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"3mail/3|delete\";                               // Flag to store this image in the DB\nmsg.type = \"temp\";                                          // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":580,"wires":[["59d467aa.79d638"]]},{"id":"9b2e9667.e1a578","type":"delay","z":"9efa042c.1ed728","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":140,"y":520,"wires":[["94e6544f.7a4998"]]},{"id":"910a4663.888b28","type":"delay","z":"9efa042c.1ed728","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":140,"y":580,"wires":[["8082b36d.9fca8"]]},{"id":"83fd6a62.ba5898","type":"function","z":"9efa042c.1ed728","name":"Compose email 3","func":"// only run this if the topic contains 'email', so other types do not get emailed\nif (msg.topic.indexOf(\"3mail\") !== -1) {\n\n    if (msg.topic.indexOf(\"/1\") !== -1) {\n        context.set(\"file1\", msg.path + msg.file);\n    }\n    if (msg.topic.indexOf(\"/2\") !== -1) {\n        context.set(\"file2\", msg.path + msg.file);\n    }\n    if (msg.topic.indexOf(\"/3\") !== -1) {\n        msg.file3 = msg.path + msg.file;\n        msg.file1 = context.get(\"file1\");\n        msg.file2 = context.get(\"file2\");\n        msg.payload = msg.file1 + \" \" + msg.file2 + \" \" + msg.file3;\n        node.status({fill:\"blue\",shape:\"ring\",text:\"Last update: \"+msg.formatteddate});\n        return msg;\n    }\n    \n}","outputs":1,"noerr":0,"x":1010,"y":460,"wires":[["ac788639.9a1f38"]]},{"id":"ac788639.9a1f38","type":"change","z":"9efa042c.1ed728","name":"Set up email","rules":[{"t":"set","p":"attachments","pt":"msg","to":"[{\t    \"filename\": \"Image1.jpg\", \t    \"path\": msg.file1,\t    \"content\": $$.payload\t},\t{\t    \"filename\": \"Image2.jpg\", \t    \"path\": msg.file2,\t    \"content\": $$.payload\t},\t{\t    \"filename\": \"Image3.jpg\", \t    \"path\": msg.file3,\t    \"content\": $$.payload\t}]","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"Front door motion","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"Dear,<br><br>Motion has been detected at the front door<br>In attachment you can find a 3 snapshots.<br><br>Kind regards,<br>Your Node-Red flow","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1190,"y":460,"wires":[["50e67922.ab82c8"]]},{"id":"6e97a4dc.7c8a0c","type":"delay","z":"9efa042c.1ed728","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1200,"y":520,"wires":[["d8a70733.d24de8"]]},{"id":"d8a70733.d24de8","type":"exec","z":"9efa042c.1ed728","command":"sudo rm ","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Delete images","x":1380,"y":520,"wires":[[],[],[]]},{"id":"1d2feed2.02ee51","type":"sqlite","z":"9efa042c.1ed728","mydb":"1c25415d.b8427f","name":"Node Red DB","x":508.00000762939453,"y":1724.0000324249268,"wires":[["82ca9c8d.fa89b"]]},{"id":"4cdfebb3.4cdd34","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"00 3 * * *","once":false,"x":138.00000762939453,"y":1724.0000324249268,"wires":[["b4336ef9.06d2e"]]},{"id":"b4336ef9.06d2e","type":"change","z":"9efa042c.1ed728","name":"Set SQL","rules":[{"t":"set","p":"topic","pt":"msg","to":"SELECT DISTINCT type from nvr","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":308.00000762939453,"y":1724.0000324249268,"wires":[["1d2feed2.02ee51"]]},{"id":"606e90cf.e660c","type":"function","z":"9efa042c.1ed728","name":"Delete pictures","func":"// only run this if the topic contains 'email', so other types do not get emailed\nvar send = false;\nif (msg.topic.indexOf(\"delete\") !== -1) {\n\n    msg.payload = msg.path + msg.file;\n    send = true;\n    if (msg.topic.indexOf(\"/1\") !== -1) {\n        context.set(\"file1\", msg.path + msg.file);\n        send = false;\n    }\n    if (msg.topic.indexOf(\"/2\") !== -1) {\n        context.set(\"file2\", msg.path + msg.file);\n        send = false;\n    }\n    if (msg.topic.indexOf(\"/3\") !== -1) {\n        msg.file3 = msg.path + msg.file;\n        msg.file1 = context.get(\"file1\");\n        msg.file2 = context.get(\"file2\");\n        msg.payload = msg.file1 + \" \" + msg.file2 + \" \" + msg.file3;\n        send = true;\n    } \n        \n    if (send) {\n        node.status({fill:\"blue\",shape:\"ring\",text:\"Last update: \"+msg.formatteddate});\n        return msg;\n    }\n\n    \n}","outputs":1,"noerr":0,"x":1000,"y":520,"wires":[["6e97a4dc.7c8a0c"]]},{"id":"e85ffa62.1a8b98","type":"function","z":"9efa042c.1ed728","name":"Tweet image","func":"// only run this if the topic contains 'email', so other types do not get emailed\nif (msg.topic.indexOf(\"tweet\") !== -1) {\n\n    msg.filename = msg.path + msg.file;\n    \n    node.status({fill:\"blue\",shape:\"ring\",text:\"Last update: \"+msg.formatteddate});\n    \n    return msg;\n}","outputs":1,"noerr":0,"x":990,"y":580,"wires":[["3606c596.2f6c8a"]]},{"id":"53ed43f.f6b91bc","type":"twitter out","z":"9efa042c.1ed728","twitter":"","name":"Tweet","x":1510,"y":580,"wires":[]},{"id":"fe5e05f6.dc5d88","type":"change","z":"9efa042c.1ed728","name":"Set up tweet","rules":[{"t":"set","p":"media","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"Image from the front door","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1350,"y":580,"wires":[["53ed43f.f6b91bc","52573496.bc77ac"]]},{"id":"3606c596.2f6c8a","type":"file in","z":"9efa042c.1ed728","name":"Read image","filename":"","format":"utf8","chunk":false,"sendError":false,"x":1170,"y":580,"wires":[["fe5e05f6.dc5d88","afd0c8a3.9d63b8"]]},{"id":"3fe6a4d4.b4df1c","type":"inject","z":"9efa042c.1ed728","name":"Tweet a frame","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":130,"y":620,"wires":[["c51cf57f.0a85b8"]]},{"id":"c51cf57f.0a85b8","type":"function","z":"9efa042c.1ed728","name":"Frame grab","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"frame_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"tweet|delete\";                                 // Flag to store this image in the DB\nmsg.type = \"timelapse\";                                     // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":620,"wires":[["59d467aa.79d638"]]},{"id":"48dac303.25c24c","type":"inject","z":"9efa042c.1ed728","name":"Grab a frame","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":810,"y":640,"wires":[["e27eca44.184fa8"]]},{"id":"e27eca44.184fa8","type":"change","z":"9efa042c.1ed728","name":"Set filename","rules":[{"t":"set","p":"filename","pt":"msg","to":"/home/pi/node-red-static/grab.jpg","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":640,"wires":[["3606c596.2f6c8a"]]},{"id":"afd0c8a3.9d63b8","type":"debug","z":"9efa042c.1ed728","name":"","active":true,"console":"false","complete":"true","x":1365.8571515764509,"y":650.5714198521205,"wires":[]},{"id":"52573496.bc77ac","type":"debug","z":"9efa042c.1ed728","name":"","active":true,"console":"false","complete":"true","x":1550,"y":640,"wires":[]},{"id":"866e0069.da033","type":"comment","z":"9efa042c.1ed728","name":"Delete old pictures","info":"","x":138.00000762939453,"y":2124.0000324249268,"wires":[]},{"id":"eaa06376.68fe4","type":"inject","z":"9efa042c.1ed728","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":128.00000762939453,"y":2184.0000324249268,"wires":[["1264fe76.2b8012"]]},{"id":"1264fe76.2b8012","type":"function","z":"9efa042c.1ed728","name":"SQL (older than 30 days)","func":"var d = new Date();\nvar epoch = d.getTime();\n\n// today - 30 days\nvar fromdate = epoch - 1000*60*60*24*30;\n\nmsg.topic = \"SELECT * FROM nvr WHERE epoch < \"+fromdate;\n\nreturn msg;","outputs":1,"noerr":0,"x":358.00000762939453,"y":2184.0000324249268,"wires":[["4a90a27f.4f1a5c"]]},{"id":"4a90a27f.4f1a5c","type":"sqlite","z":"9efa042c.1ed728","mydb":"1c25415d.b8427f","name":"Node Red DB","x":608.0000076293945,"y":2184.0000324249268,"wires":[["16f8cd9.c442a32"]]},{"id":"f43773ab.04fb9","type":"exec","z":"9efa042c.1ed728","command":"sudo rm ","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Delete images","x":1348.0000076293945,"y":2184.0000324249268,"wires":[[],[],[]]},{"id":"16f8cd9.c442a32","type":"split","z":"9efa042c.1ed728","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":798.0000076293945,"y":2184.0000324249268,"wires":[["58a0e5b7.6a59dc"]]},{"id":"58a0e5b7.6a59dc","type":"delay","z":"9efa042c.1ed728","name":"","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"50","randomLast":"500","randomUnits":"milliseconds","drop":false,"x":948.0000076293945,"y":2184.0000324249268,"wires":[["ac43dfad.5b253","c2bd4748.fce518"]]},{"id":"cc750eb0.b57a7","type":"sqlite","z":"9efa042c.1ed728","mydb":"1c25415d.b8427f","name":"Node Red DB","x":1348.0000076293945,"y":2244.0000324249268,"wires":[[]]},{"id":"ac43dfad.5b253","type":"change","z":"9efa042c.1ed728","name":"Set SQL","rules":[{"t":"set","p":"topic","pt":"msg","to":"\"DELETE * FROM nvr where filename='\" & payload.filename & \"'\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1128.0000076293945,"y":2244.0000324249268,"wires":[["cc750eb0.b57a7"]]},{"id":"c2bd4748.fce518","type":"change","z":"9efa042c.1ed728","name":"Set filename","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.path & payload.filename","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1138.0000076293945,"y":2184.0000324249268,"wires":[["f43773ab.04fb9"]]},{"id":"fa52360b.8fd1d8","type":"inject","z":"9efa042c.1ed728","name":"Noon timelapse","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":138,"y":706,"wires":[["7f834a77.89c694"]]},{"id":"7f834a77.89c694","type":"function","z":"9efa042c.1ed728","name":"Frame grab","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// Last update: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\n// file path with / at the end\nvar path = \"/home/pi/node-red-static/\";                     // This is the path\nvar filename = \"noon_\"+yyyy+mm+dd+\"-\"+hh+mm+ss+\".jpg\";     // file name\nmsg.payload = path + filename;                              // pass the full path to payload for the exec node to add to the end of the command\nmsg.file = filename;                                        // To be used later to store the information in the DB\nmsg.path = path;                                            // Same as above\nmsg.wwwpath = \"/\";                                          // Same as above\nmsg.topic = \"store\";                                        // Flag to store this image in the DB\nmsg.type = \"Noon timelapse\";                                     // Image type e.g. Front camera, etc.\nmsg.epoch = now.getTime();                                  // Current timestamp\nmsg.formatteddate = dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss;   // Formatted timestamp to be used later\n\nreturn msg;","outputs":1,"noerr":0,"x":308,"y":706,"wires":[["59d467aa.79d638"]]},{"id":"675036dd.603328","type":"ui_group","z":"","name":"Frame Grab","tab":"7af2d9c8.0a9148","order":1,"disp":true,"width":"6"},{"id":"e16e06ca.f38438","type":"ui_group","z":"","name":"Frame Statistics","tab":"7af2d9c8.0a9148","order":2,"disp":true,"width":"6"},{"id":"cb67921.cf4df7","type":"ui_group","z":"","name":"Video Capture","tab":"7af2d9c8.0a9148","order":3,"disp":true,"width":"6"},{"id":"984422e9.d6d96","type":"ui_group","z":"","name":"Video Statistics","tab":"7af2d9c8.0a9148","order":4,"disp":true,"width":"6"},{"id":"1c25415d.b8427f","type":"sqlitedb","z":0,"db":"/home/pi/sqlite/nodered"},{"id":"a06d1d6b.bdef2","type":"ui_group","z":"","name":"Report","tab":"7af2d9c8.0a9148","order":5,"disp":true,"width":"12"},{"id":"7af2d9c8.0a9148","type":"ui_tab","z":"","name":"NVR","icon":"dashboard","order":13}]

Flow Info

Created 7 years, 1 month ago
Updated 5 years, 3 months ago
Rating: 4.5 4

Owner

Actions

Rate:

Node Types

Core
  • change (x10)
  • comment (x4)
  • debug (x6)
  • delay (x4)
  • exec (x4)
  • file (x2)
  • file in (x1)
  • function (x19)
  • inject (x15)
  • split (x1)
  • template (x1)
Other
  • e-mail (x1)
  • sqlite (x5)
  • sqlitedb (x1)
  • tab (x1)
  • twitter out (x1)
  • ui_button (x3)
  • ui_dropdown (x2)
  • ui_group (x5)
  • ui_tab (x1)
  • ui_template (x3)
  • ui_text (x6)

Tags

  • nvr
  • rtsp
  • camera
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option