Best IP Camera & nodes to use for plant room monitoring

Hi @damica51 , my camera's are running on POE (power of ethernet) and always connected to my BlueIris controll storage system .. and therefore no local storage required.

You can find some good wifi camera's of this brand with local storage capabilities as well.

As mentioned, sending pictures works but I guess you can kill everything. In the case of a Mosquitto broker it most likely depends on its available resources (how long it will survive). If you feed it faster then it can redistribute to subscribers I assume there is some kind of queue that will be full at some stage. What then happens is unclear to me, maybe further messages are simply rejected until there is some space available again . If you feed it that hard you should expect further delays in viewing (in addition to what rtsp already adds). Anyway, some delay is also there if you would use http/https

What you select is depending on your specific use cases

Hi Guys, Loving all the responses on this topic.

Please see Image of the setup we will be using.

After having a play around with it initially its seems quite hard work to get a balance on the scenario.

I've managed to do a couple of things with its

  1. rtsptomjpeg <> base64 works ok for small images. I think i've maxed it out with the image size & i don't think the resolution will be high enough for the remote monitoring. BUT a really good thing to know about for sending alarm messages or small snippets to a preview window, thanks for mentioning that, i will deffo explore more options with it.

  2. I came across an app called restreamer which is free. This converts the rtsp stream to http live stream & to be honest it works really really well. Supports Airplay, Chromecast & can embed the live view in an iframe. link here

Restreamer - Restreamer (datarhei.github.io)

  1. Frame Grab, again this is ok for small snippets of previews & would consider it for the same job as the base64.

@xx_Nexus_xx Love the blue iris setup, however there wont be any windows machines on site, just a linux edge device as in the pic. I will explore this option tho as its looks good for a solution moving forward. Let me know how big your 4k streams where, the camera we are using is a hik vision, 4mp. Struggled to get a full image at decent resolution over base64.

Th biggest issue i have is the data it uses over 4g is massive. Somehow need to find a happy medium with it.

@marcus-j-davies @xx_Nexus_xx also an avid UNIFI user, have one small indoor camera which i need to reinstate and i will try some of this stuff with that also.

@Slyke RTSP 1080P deffo not. its way too fast and heavy, i have dropped the 2nd channel down to 1fps and just take snap shots. The restreamer has been the best so far. However im not sure on the license, i need to check out this CC License as this project is for a pretty big customer.

i think VLC needs to create a Node for NR, Solution :grinning:

Thanks Everyone, ill send some more snaps later if anything else comes up let me know. Really keen onto getting it integrated with other things in node red.

Sy

1 Like

Hi @bceyresy ,

I implemented a similar use-case for a friend a view months back to monitor a remote shed on his farm. The key difference is that we are not doing live-stream over 4g but only updating 4k pictures on a regular or alert basis.

Our setup:

  • 1 x Solar system with battery to power laptop & cameras (and a few other devices in shed)
  • 1 x windows laptop with 4g modem, 8gb ram, 250GB SSD, BlueIris & NodeRed setup
  • 3 x 4k POE cameras with local network to laptop
  • 1 x home server (Linux machine, Docker, Node-Red , NVR storage)

Operation:

  • each camera is sending a 4k image every 10min from BlueIris to NodeRed
  • whenever a MOTION event is detected a 4k image is sent to NodeRed (Alert)
  • NodeRed is sending Alerts via Telegram to a usergroup
  • NodeRed is sending all pictures via FTP push to home-server
  • NodeRed is sending temp, humidity as well solar-info every 15min via MQTT to home-server

The above is now operating for a few months without issues. Initially we had the update frquency every 5min but there was no benefit and was unnecessarily generating 4g traffic.
Additionally,we changed to 4k cameras with COLOR-Nightvision with good results on night pictures.

1 Like

Hi @xx_Nexus_xx

Thanks for the reply, looks very interesting i will have a be having a look Blue Iris.

I have had this setup on all weekend and it works really well over MQTT for the base64 encoded image. Again refreshing every 15 seconds which consumes a lot less than the live streaming.

See screen shot of daashboard. I was going to ask, could someone write me a function node to hold the last 5 bas64 messages so i can display the previous 5 shots and then view them on the dash. Just on a continuous cycle.

Thanks.

Hi @bceyresy ,

looks like we are working similar projects :wink: .. as mentioned above (2nd item) I'm showcasing the last 10 pictures of each camera in NR dashboard
image

I'm using BlueIris but there are other products (like frigate as mentioned by @craigcurtin ) which can achieve the same results .. but for all of them you need enough processing power to analyse the picture quickly enough.. especially when using multiple cameras.

i'm using a normal FIFO buffer to secure the last 10 mqtt messages (incl picture) per camera and showing them, in a simple ui-template (still on Dashboard v1) .. see code below for 1 camera

[
    {
        "id": "8cd152086dfd436a",
        "type": "group",
        "z": "1c76686932178a74",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "d45d705db2ebe914",
            "adc54e4ac0f8532d",
            "101246083dad963c",
            "0af616a7b9303b90",
            "71a7c3d12c733125",
            "ce2fa4be836a7c34",
            "dacd9cc1798effc9",
            "41b36893b203fcc6",
            "695a4920fbd486a9",
            "4e400edf5cfe7bd8",
            "11b2e326b2320f17"
        ],
        "x": 564,
        "y": 239,
        "w": 742,
        "h": 202
    },
    {
        "id": "1b99e955a9f97cad",
        "type": "subflow",
        "name": "FIFO",
        "info": "# FIFO\n## First in First Out subflow\nThis flow receives a series of msg.payloads and builds a queue using FIFO (First in First out) method. The LIFO size is configurabe through subflow enviroment variables.\n\n### Input\n`msg.topic == put`\nWill add the `msg.payload` to the end of the array. Everytime a new item is received the second output sends the complete queue.\n\n`msg.topic == get`\nWill remove the first item of the stack and will send it in the first output\n\n`msg.topic == list`\nSends the complete list on the second output.\n\n### Output 1\nThe first item on the top of the stack. It is sent only when `msg.topic == get`.\n\n### Output 2\nThe complete queue in Array format. It is sent everytime a new item is added, removed or when `msg.topic == list`\n\n### Status\nAlways show the queue size.\n\n### Enviroment Variables\n`Buffer_Size` defines the size of the queue. If a new item arrives and the queue is full, the oldest item will be removed.",
        "category": "",
        "in": [
            {
                "x": 100,
                "y": 120,
                "wires": [
                    {
                        "id": "f4e8af593dda8bf3"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 1120,
                "y": 60,
                "wires": [
                    {
                        "id": "7c0a144c051ed66f",
                        "port": 0
                    }
                ]
            },
            {
                "x": 1120,
                "y": 100,
                "wires": [
                    {
                        "id": "39b6b38f614a42a6",
                        "port": 0
                    }
                ]
            }
        ],
        "env": [
            {
                "name": "Buffer_Size",
                "type": "num",
                "value": "6"
            }
        ],
        "icon": "font-awesome/fa-ellipsis-v",
        "status": {
            "x": 1120,
            "y": 140,
            "wires": [
                {
                    "id": "de6a9df2eede30c3",
                    "port": 0
                }
            ]
        }
    },
    {
        "id": "90f14a6dfe5ca406",
        "type": "switch",
        "z": "1b99e955a9f97cad",
        "name": "Topic",
        "property": "topic",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "get",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "put",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "list",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "clear",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 5,
        "x": 390,
        "y": 120,
        "wires": [
            [
                "0d69c5fc4283a7c4"
            ],
            [
                "53d55044c54ffeb2"
            ],
            [
                "ddc1eb7421e343d9"
            ],
            [
                "4cbf1be47dfafd93"
            ],
            []
        ]
    },
    {
        "id": "0d69c5fc4283a7c4",
        "type": "function",
        "z": "1b99e955a9f97cad",
        "name": "get",
        "func": "let xxx = flow.get(\"queue\");\nvar item;\n\nif (!Array.isArray(xxx)){\n    //queue = [];\n    //queue.length=0;\n    xxx.splice(0, xxx.length);\n}else\n{\n    item = xxx.pop();\n}\n\n\nflow.set(\"queue\", xxx)\nmsg.payload = item;\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 550,
        "y": 60,
        "wires": [
            [
                "c535b4175dfdd648"
            ]
        ]
    },
    {
        "id": "de6a9df2eede30c3",
        "type": "change",
        "z": "1b99e955a9f97cad",
        "name": "Count",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "$count(msg.payload)\t",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 850,
        "y": 140,
        "wires": [
            []
        ]
    },
    {
        "id": "4cbf1be47dfafd93",
        "type": "change",
        "z": "1b99e955a9f97cad",
        "name": "",
        "rules": [
            {
                "t": "delete",
                "p": "queue",
                "pt": "flow"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "queue",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 580,
        "y": 180,
        "wires": [
            [
                "de6a9df2eede30c3"
            ]
        ]
    },
    {
        "id": "ddc1eb7421e343d9",
        "type": "change",
        "z": "1b99e955a9f97cad",
        "name": "queue",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "queue",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 550,
        "y": 140,
        "wires": [
            [
                "de6a9df2eede30c3",
                "422b417b1cf9e0ea"
            ]
        ]
    },
    {
        "id": "53d55044c54ffeb2",
        "type": "function",
        "z": "1b99e955a9f97cad",
        "name": "put",
        "func": "var queue = flow.get(\"queue\")\n\n\nif (!Array.isArray(queue)){\n    queue = [];\n}else if ( queue.length >= env.get(\"Buffer_Size\") ){\n    queue.pop(1);\n}\n\nqueue.unshift(msg.payload);\n\nflow.set(\"queue\", queue);\nmsg.payload = queue;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 550,
        "y": 100,
        "wires": [
            [
                "422b417b1cf9e0ea"
            ]
        ]
    },
    {
        "id": "f4e8af593dda8bf3",
        "type": "json",
        "z": "1b99e955a9f97cad",
        "name": "",
        "property": "payload",
        "action": "str",
        "pretty": false,
        "x": 230,
        "y": 120,
        "wires": [
            [
                "90f14a6dfe5ca406"
            ]
        ]
    },
    {
        "id": "422b417b1cf9e0ea",
        "type": "split",
        "z": "1b99e955a9f97cad",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 710,
        "y": 100,
        "wires": [
            [
                "2ccfc1845e1122fe"
            ]
        ]
    },
    {
        "id": "2ccfc1845e1122fe",
        "type": "json",
        "z": "1b99e955a9f97cad",
        "name": "",
        "property": "payload",
        "action": "obj",
        "pretty": false,
        "x": 850,
        "y": 100,
        "wires": [
            [
                "39b6b38f614a42a6"
            ]
        ]
    },
    {
        "id": "39b6b38f614a42a6",
        "type": "join",
        "z": "1b99e955a9f97cad",
        "name": "",
        "mode": "auto",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": "false",
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "x": 990,
        "y": 100,
        "wires": [
            []
        ]
    },
    {
        "id": "c535b4175dfdd648",
        "type": "split",
        "z": "1b99e955a9f97cad",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 710,
        "y": 60,
        "wires": [
            [
                "acaad2afe7f73430"
            ]
        ]
    },
    {
        "id": "acaad2afe7f73430",
        "type": "json",
        "z": "1b99e955a9f97cad",
        "name": "",
        "property": "payload",
        "action": "obj",
        "pretty": false,
        "x": 850,
        "y": 60,
        "wires": [
            [
                "7c0a144c051ed66f"
            ]
        ]
    },
    {
        "id": "7c0a144c051ed66f",
        "type": "join",
        "z": "1b99e955a9f97cad",
        "name": "",
        "mode": "auto",
        "build": "object",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": "false",
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "x": 990,
        "y": 60,
        "wires": [
            []
        ]
    },
    {
        "id": "d45d705db2ebe914",
        "type": "change",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "Driveway -> Buffer",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "mqtt",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "put",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 830,
        "y": 320,
        "wires": [
            [
                "dacd9cc1798effc9"
            ]
        ]
    },
    {
        "id": "adc54e4ac0f8532d",
        "type": "link in",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "link in 48",
        "links": [
            "2942673c5bf7d2a8",
            "d0d0ce31c8a83f36",
            "137a398dfa469bb3",
            "2a805b8a5539d768"
        ],
        "x": 605,
        "y": 320,
        "wires": [
            [
                "d45d705db2ebe914"
            ]
        ]
    },
    {
        "id": "101246083dad963c",
        "type": "ui_ui-button",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "action": "click",
        "actionType": "str",
        "name": "",
        "group": "c8ac5f2f9243b373",
        "order": 1,
        "width": "6",
        "height": "1",
        "passthru": false,
        "label": "Driveway",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "x": 710,
        "y": 360,
        "wires": [
            [
                "0af616a7b9303b90"
            ]
        ]
    },
    {
        "id": "0af616a7b9303b90",
        "type": "change",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "list",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "list",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 870,
        "y": 360,
        "wires": [
            [
                "dacd9cc1798effc9"
            ]
        ]
    },
    {
        "id": "71a7c3d12c733125",
        "type": "inject",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 700,
        "y": 400,
        "wires": [
            [
                "0af616a7b9303b90"
            ]
        ]
    },
    {
        "id": "ce2fa4be836a7c34",
        "type": "ui_template",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "group": "c8ac5f2f9243b373",
        "name": "Drivway image",
        "order": 2,
        "width": "9",
        "height": 24,
        "format": "\n{{msg.payload[0].time}}     {{msg.payload[0].date}}      {{msg.payload[0].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[0].pic}}\" />\n{{msg.payload[1].time}}     {{msg.payload[1].date}}      {{msg.payload[1].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[1].pic}}\" />\n{{msg.payload[2].time}}      {{msg.payload[2].date}}     {{msg.payload[2].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[2].pic}}\" />\n{{msg.payload[3].time}}      {{msg.payload[3].date}}     {{msg.payload[3].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[3].pic}}\" />\n{{msg.payload[4].time}} {{msg.payload[4].date}} {{msg.payload[4].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[4].pic}}\" />\n{{msg.payload[5].time}} {{msg.payload[5].date}} {{msg.payload[5].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[5].pic}}\" />\n{{msg.payload[6].time}} {{msg.payload[6].date}} {{msg.payload[6].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[6].pic}}\" />\n{{msg.payload[7].time}} {{msg.payload[7].date}} {{msg.payload[7].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[7].pic}}\" />\n{{msg.payload[8].time}} {{msg.payload[8].date}} {{msg.payload[8].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[8].pic}}\" />\n{{msg.payload[9].time}} {{msg.payload[9].date}} {{msg.payload[9].ai}}\n<img width=\"100%\" height=\"100%\" alt=\"\" src=\"data:image/png;base64,{{msg.payload[9].pic}}\" />\n\n",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": false,
        "templateScope": "local",
        "className": "",
        "x": 1200,
        "y": 340,
        "wires": [
            []
        ]
    },
    {
        "id": "dacd9cc1798effc9",
        "type": "junction",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "x": 960,
        "y": 340,
        "wires": [
            [
                "41b36893b203fcc6"
            ]
        ]
    },
    {
        "id": "41b36893b203fcc6",
        "type": "subflow:1b99e955a9f97cad",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "",
        "env": [
            {
                "name": "Buffer_Size",
                "value": "10",
                "type": "num"
            }
        ],
        "x": 1030,
        "y": 340,
        "wires": [
            [],
            [
                "ce2fa4be836a7c34",
                "695a4920fbd486a9"
            ]
        ]
    },
    {
        "id": "695a4920fbd486a9",
        "type": "debug",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "debug 137",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1150,
        "y": 380,
        "wires": []
    },
    {
        "id": "4e400edf5cfe7bd8",
        "type": "change",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "name": "list",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "list",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 870,
        "y": 280,
        "wires": [
            [
                "dacd9cc1798effc9"
            ]
        ]
    },
    {
        "id": "11b2e326b2320f17",
        "type": "ui_ui-button",
        "z": "1c76686932178a74",
        "g": "8cd152086dfd436a",
        "action": "click",
        "actionType": "str",
        "name": "Clear",
        "group": "c8ac5f2f9243b373",
        "order": 1,
        "width": "3",
        "height": "1",
        "passthru": false,
        "label": "Clear",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "x": 730,
        "y": 280,
        "wires": [
            [
                "4e400edf5cfe7bd8"
            ]
        ]
    },
    {
        "id": "c8ac5f2f9243b373",
        "type": "ui_group",
        "name": "Driveway",
        "tab": "cfb78f60fecf7ee2",
        "order": 3,
        "disp": false,
        "width": "9",
        "collapse": false,
        "className": ""
    },
    {
        "id": "cfb78f60fecf7ee2",
        "type": "ui_tab",
        "name": "Cameras",
        "icon": "dashboard",
        "order": 5,
        "disabled": false,
        "hidden": false
    }
]

  1. the mqtt image is converted into base64 in a previous node
  2. the entire mqtt message including img is moved to payload
  3. the FIFO subflow is moving the entire payload into a buffer structure
  4. the FIFO is providing an array of payload on the output
  5. the last image / mqtt message is always the first in the list
  6. there is a CLEAR button/cmd to empty the FIFO buffer
  7. there is a REFRESH button/cmd to send the entire buffer to output for displat
  8. the ui-template is displaying the last 10 images with mqtt details
  9. my mqtt details are ( msg.payload.pic ,msg.payload.time, msg.payload.date) .. you will have to update your ui-template based on your structure

Hope this will help you .. have fun :wink:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.