Two issues with this

I'm trying to run this on a pi zero w, but it seems to be overtaxing it maybe? (cpu gets warm and locks up).

Second when ever I redeploy any changes to this it breaks the water depth sensor readings, they no longer come in?

flows (2).json (40.7 KB)

It would be better if you could reduce the flow in size so it can be posted directly. Or at least provide a screenshot of the flow to give people an idea of what it does.

What do you see if you run top in a command window?

[
    {
        "id": "50aec3b82ab4aece",
        "type": "tab",
        "label": "DYP-A01 Water Depth",
        "disabled": false,
        "info": "Reads water depth from DYP-A01-V2.0 ultrasonic sensor.\nUses node-red-node-pisrf (rpi-srf node).\nTrigger: GPIO 26 = PIN 37\nEcho:    GPIO 19 = PIN 35\n\nInstall: npm install node-red-node-pisrf"
    },
    {
        "id": "4aea1f817743ee56",
        "type": "rpi-srf",
        "z": "50aec3b82ab4aece",
        "name": "DYP-A01 Ultrasonic",
        "topic": "distance",
        "pulse": "30",
        "pins": "37,35",
        "precision": "0",
        "x": 110,
        "y": 100,
        "wires": [
            [
                "63d81d647a6b26c2",
                "9713c5e67470f7a7"
            ]
        ]
    },
    {
        "id": "63d81d647a6b26c2",
        "type": "function",
        "z": "50aec3b82ab4aece",
        "name": "Calc Water Depth",
        "func": "// ── Configure these for your reservoir ──────────────────────\nvar SENSOR_TO_BOTTOM_CM = 30.0; // sensor face to tank floor (cm)\nvar SENSOR_OFFSET_CM    =  1.0; // sensor dead-zone (cm)\nvar WARN_DEPTH_CM       =  5.0; // alert when depth below this\n// ─────────────────────────────────────────────────────────────\n\nvar distCm = parseFloat(msg.payload);\nif (isNaN(distCm) || distCm <= 0) { node.error('Bad distance: ' + msg.payload); return null; }\n\nvar maxDepth = SENSOR_TO_BOTTOM_CM - SENSOR_OFFSET_CM;\nvar depth    = Math.max(0, Math.min(maxDepth, SENSOR_TO_BOTTOM_CM - distCm - SENSOR_OFFSET_CM));\ndepth        = Math.round(depth * 10) / 10;\nvar pct      = Math.min(100, Math.max(0, Math.round(depth / maxDepth * 100)));\nvar status   = depth <= WARN_DEPTH_CM ? 'LOW' : 'OK';\n\n// Use GLOBAL context so the Pump tab can read this value\nglobal.set('waterStatus', status);\nglobal.set('waterDepth', depth);\n\nvar out = {\n  topic:       'waterDepth',\n  payload:     depth,\n  percent:     pct,\n  distance_cm: distCm,\n  status:      status\n};\n\nvar alert = status === 'LOW'\n  ? { topic: 'alert', payload: 'WATER LOW — depth ' + depth + 'cm (' + pct + '%) — refill reservoir!' }\n  : null;\n\nreturn [out, alert];",
        "outputs": 2,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 360,
        "y": 100,
        "wires": [
            [
                "0526447eb6eeb4e1",
                "c02b3d695be8999f",
                "7dfca4702a123e50",
                "f9cd88604f7dac6a",
                "9f7fa657192a75bf"
            ],
            []
        ]
    },
    {
        "id": "0526447eb6eeb4e1",
        "type": "debug",
        "z": "50aec3b82ab4aece",
        "name": "Debug Depth",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "true",
        "targetType": "full",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 590,
        "y": 40,
        "wires": []
    },
    {
        "id": "c02b3d695be8999f",
        "type": "ui_gauge",
        "z": "50aec3b82ab4aece",
        "name": "Water Depth Gauge",
        "group": "364f57d595c825ae",
        "order": 1,
        "width": "3",
        "height": "3",
        "gtype": "gage",
        "title": "Water Depth",
        "label": "cm",
        "format": "{{value}} cm",
        "min": "0",
        "max": "30",
        "colors": [
            "#c62828",
            "#f9a825",
            "#2e7d32"
        ],
        "seg1": "5",
        "seg2": "15",
        "x": 620,
        "y": 100,
        "wires": []
    },
    {
        "id": "7dfca4702a123e50",
        "type": "ui_text",
        "z": "50aec3b82ab4aece",
        "group": "364f57d595c825ae",
        "order": 2,
        "width": "3",
        "height": "1",
        "name": "Depth cm",
        "label": "Depth",
        "format": "{{msg.payload}} cm",
        "layout": "row-spread",
        "x": 580,
        "y": 140,
        "wires": []
    },
    {
        "id": "f9cd88604f7dac6a",
        "type": "ui_text",
        "z": "50aec3b82ab4aece",
        "group": "364f57d595c825ae",
        "order": 3,
        "width": "3",
        "height": "1",
        "name": "Fill Percent",
        "label": "Fill",
        "format": "{{msg.percent}}%",
        "layout": "row-spread",
        "x": 590,
        "y": 180,
        "wires": []
    },
    {
        "id": "9f7fa657192a75bf",
        "type": "ui_chart",
        "z": "50aec3b82ab4aece",
        "name": "Depth History",
        "group": "364f57d595c825ae",
        "order": 4,
        "width": "6",
        "height": "4",
        "label": "Water Depth (cm)",
        "chartType": "line",
        "legend": "false",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "Waiting for reading…",
        "dot": false,
        "ymin": "0",
        "ymax": "30",
        "removeOlder": "1",
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "useOneColor": false,
        "useUTC": false,
        "colors": [
            "#2e7d32",
            "#aec6cf",
            "#ff7f0e",
            "#d62728",
            "#9467bd",
            "#8c564b",
            "#e377c2",
            "#7f7f7f",
            "#bcbd22"
        ],
        "outputs": 1,
        "useDifferentColor": false,
        "className": "",
        "x": 600,
        "y": 220,
        "wires": [
            []
        ]
    },
    {
        "id": "3f22ad58570d297e",
        "type": "inject",
        "z": "50aec3b82ab4aece",
        "d": true,
        "name": "Start on Deploy",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "29",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 40,
        "wires": [
            [
                "63d81d647a6b26c2"
            ]
        ]
    },
    {
        "id": "dfc2e330c3488092",
        "type": "inject",
        "z": "50aec3b82ab4aece",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "75",
        "topic": "waterDepth",
        "payload": "23",
        "payloadType": "num",
        "x": 140,
        "y": 160,
        "wires": [
            [
                "63d81d647a6b26c2",
                "9713c5e67470f7a7"
            ]
        ]
    },
    {
        "id": "9713c5e67470f7a7",
        "type": "debug",
        "z": "50aec3b82ab4aece",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "msg",
        "x": 350,
        "y": 160,
        "wires": []
    },
    {
        "id": "0042db717430e0ee",
        "type": "tab",
        "label": "Camera",
        "disabled": false,
        "info": "USB camera snapshots via fswebcam.\n\nSetup:\n  sudo apt install fswebcam\n\nNo extra Node-RED palette nodes needed beyond node-red-node-base64.\n  cd ~/.node-red && npm install node-red-node-base64"
    },
    {
        "id": "eb6410d6673b5213",
        "type": "inject",
        "z": "0042db717430e0ee",
        "name": "Capture Every 15min",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "900",
        "crontab": "",
        "once": true,
        "onceDelay": "3",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 60,
        "wires": [
            [
                "24eade42448c8c89"
            ]
        ]
    },
    {
        "id": "24eade42448c8c89",
        "type": "exec",
        "z": "0042db717430e0ee",
        "command": "fswebcam -d /dev/video0 -r 640x480 --jpeg 85 --no-banner --quiet -",
        "addpay": false,
        "append": "",
        "useSpawn": false,
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "fswebcam Capture",
        "x": 490,
        "y": 120,
        "wires": [
            [
                "417bb0b94ca89b41"
            ],
            [],
            []
        ]
    },
    {
        "id": "5364c237af84f340",
        "type": "ui_template",
        "z": "0042db717430e0ee",
        "group": "4977006900fe6493",
        "name": "Camera Feed",
        "order": 1,
        "width": "6",
        "height": "5",
        "format": "<div style='width:100%;text-align:center;'>\n  <img ng-src='data:image/jpeg;base64,{{msg.payload}}'\n       style='width:100%;max-width:640px;border-radius:6px;' />\n</div>",
        "storeOutMessages": true,
        "fwdInMessages": false,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 820,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "fabd14b34c3c64b3",
        "type": "ui_button",
        "z": "0042db717430e0ee",
        "name": "Snapshot Now",
        "group": "4977006900fe6493",
        "order": 2,
        "width": "6",
        "height": "1",
        "passthru": false,
        "label": "📷 Take Snapshot",
        "tooltip": "Capture a snapshot immediately",
        "color": "",
        "bgcolor": "",
        "icon": "",
        "payload": "",
        "payloadType": "date",
        "topic": "",
        "topicType": "str",
        "x": 150,
        "y": 160,
        "wires": [
            [
                "24eade42448c8c89"
            ]
        ]
    },
    {
        "id": "417bb0b94ca89b41",
        "type": "base64",
        "z": "0042db717430e0ee",
        "name": "Encode JPEG",
        "action": "str",
        "property": "payload",
        "x": 780,
        "y": 100,
        "wires": [
            [
                "5364c237af84f340"
            ]
        ]
    },
    {
        "id": "cpu-tab",
        "type": "tab",
        "label": "CPU Temp",
        "disabled": false,
        "info": "Reads CPU temperature via vcgencmd and displays on dashboard."
    },
    {
        "id": "cpu-poll",
        "type": "inject",
        "z": "cpu-tab",
        "name": "Poll Every 30s",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "30",
        "crontab": "",
        "once": true,
        "onceDelay": "3",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 100,
        "wires": [
            [
                "cpu-read"
            ]
        ]
    },
    {
        "id": "cpu-read",
        "type": "exec",
        "z": "cpu-tab",
        "command": "vcgencmd measure_temp",
        "addpay": false,
        "append": "",
        "useSpawn": false,
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "vcgencmd CPU Temp",
        "x": 340,
        "y": 100,
        "wires": [
            [
                "cpu-parse"
            ],
            [],
            []
        ]
    },
    {
        "id": "cpu-parse",
        "type": "function",
        "z": "cpu-tab",
        "name": "Parse Temp",
        "func": "// vcgencmd returns: temp=42.8'C\nvar match = msg.payload.toString().match(/temp=([0-9.]+)/);\nif (!match) { node.error('Unexpected vcgencmd output: ' + msg.payload); return null; }\nvar temp = parseFloat(match[1]);\nnode.status({ fill: temp > 70 ? 'red' : temp > 60 ? 'yellow' : 'green',\n              shape: 'dot', text: temp + '°C' });\nmsg.payload = temp;\nmsg.topic   = 'cpuTemp';\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 530,
        "y": 100,
        "wires": [
            [
                "cpu-gauge",
                "cpu-debug"
            ]
        ]
    },
    {
        "id": "cpu-debug",
        "type": "debug",
        "z": "cpu-tab",
        "name": "Debug CPU Temp",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 730,
        "y": 60,
        "wires": []
    },
    {
        "id": "cpu-gauge",
        "type": "ui_gauge",
        "z": "cpu-tab",
        "name": "CPU Temp Gauge",
        "group": "cpu-ui-group",
        "order": 1,
        "width": "6",
        "height": "3",
        "gtype": "gage",
        "title": "CPU Temperature",
        "label": "°C",
        "format": "{{value}}°C",
        "min": "0",
        "max": "85",
        "colors": [
            "#2e7d32",
            "#f9a825",
            "#c62828"
        ],
        "seg1": "60",
        "seg2": "70",
        "x": 730,
        "y": 140,
        "wires": []
    },
    {
        "id": "43876d94c089ab43",
        "type": "tab",
        "label": "DHT11 Temp/Humidity",
        "disabled": false,
        "info": "Reads temperature and humidity from DHT11 sensor.\nRequires: node-red-node-dht-sensor\n  cd ~/.node-red && npm install node-red-node-dht-sensor\nAlso requires: sudo apt install libgpiod2"
    },
    {
        "id": "bd4d1f28087c0658",
        "type": "rpi-dht22",
        "z": "43876d94c089ab43",
        "name": "DHT11 Sensor (GPIO 9)",
        "topic": "dht11",
        "dht": "11",
        "pintype": "0",
        "pin": "9",
        "x": 170,
        "y": 100,
        "wires": [
            [
                "c36abf33da1e0379"
            ]
        ]
    },
    {
        "id": "99d92e95e8ac34bc",
        "type": "inject",
        "z": "43876d94c089ab43",
        "name": "Poll Every 30s",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "30",
        "crontab": "",
        "once": true,
        "onceDelay": "3",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 170,
        "y": 160,
        "wires": [
            [
                "bd4d1f28087c0658"
            ]
        ]
    },
    {
        "id": "c36abf33da1e0379",
        "type": "function",
        "z": "43876d94c089ab43",
        "name": "Parse DHT11",
        "func": "var tempC = parseFloat(msg.payload);\nvar hum   = parseFloat(msg.humidity);\n\nif (isNaN(tempC) || isNaN(hum)) {\n  node.error('DHT11: bad reading temp=' + msg.payload + ' hum=' + msg.humidity);\n  return null;\n}\n\n// DHT11 valid ranges: 0–50°C, 20–90% RH\nif (tempC < 0 || tempC > 50 || hum < 20 || hum > 90) {\n  node.error('DHT11: out-of-range temp=' + tempC + ' hum=' + hum);\n  return null;\n}\n\n// Convert to Fahrenheit\nvar tempF = Math.round(((tempC * 9/5) + 32) * 10) / 10;\n\nnode.status({ fill:'green', shape:'dot', text: tempF + '°F  ' + hum + '%' });\n\nvar warnings = [];\nif (tempF > 86) warnings.push('HIGH TEMP: ' + tempF + '°F');\nif (tempF < 59) warnings.push('LOW TEMP: '  + tempF + '°F');\nif (hum   < 40) warnings.push('LOW HUMIDITY: '  + hum + '%');\nif (hum   > 80) warnings.push('HIGH HUMIDITY: ' + hum + '%');\n\nreturn [\n  { topic: 'temperature', payload: tempF },\n  { topic: 'humidity',    payload: hum  },\n  warnings.length > 0 ? { topic: 'alert', payload: warnings.join(' | ') } : null\n];",
        "outputs": 3,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 380,
        "y": 100,
        "wires": [
            [
                "d3d9955350b18808",
                "17f2bbed796b0730",
                "6b152252c4b9cdb8"
            ],
            [
                "17d60b3e54aea756",
                "2214f439e17b9c3a",
                "cf5d1fcd4827258b"
            ],
            [
                "724b6dee2fdd2724"
            ]
        ]
    },
    {
        "id": "6b152252c4b9cdb8",
        "type": "debug",
        "z": "43876d94c089ab43",
        "name": "Debug Temp",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 610,
        "y": 40,
        "wires": []
    },
    {
        "id": "cf5d1fcd4827258b",
        "type": "debug",
        "z": "43876d94c089ab43",
        "name": "Debug Humidity",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 620,
        "y": 100,
        "wires": []
    },
    {
        "id": "724b6dee2fdd2724",
        "type": "debug",
        "z": "43876d94c089ab43",
        "name": "⚠️ Alerts",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 610,
        "y": 160,
        "wires": []
    },
    {
        "id": "d3d9955350b18808",
        "type": "ui_gauge",
        "z": "43876d94c089ab43",
        "name": "Temperature Gauge",
        "group": "dht11-ui-group",
        "order": 1,
        "width": "3",
        "height": "3",
        "gtype": "gage",
        "title": "Temperature",
        "label": "°F",
        "format": "{{value}}°F",
        "min": "32",
        "max": "122",
        "colors": [
            "#2e7d32",
            "#f9a825",
            "#c62828"
        ],
        "seg1": "68",
        "seg2": "86",
        "x": 620,
        "y": 200,
        "wires": []
    },
    {
        "id": "17d60b3e54aea756",
        "type": "ui_gauge",
        "z": "43876d94c089ab43",
        "name": "Humidity Gauge",
        "group": "dht11-ui-group",
        "order": 2,
        "width": "3",
        "height": "3",
        "gtype": "gage",
        "title": "Humidity",
        "label": "%",
        "format": "{{value}}%",
        "min": "0",
        "max": "100",
        "colors": [
            "#c62828",
            "#2e7d32",
            "#0288d1"
        ],
        "seg1": "40",
        "seg2": "70",
        "x": 620,
        "y": 240,
        "wires": []
    },
    {
        "id": "17f2bbed796b0730",
        "type": "ui_text",
        "z": "43876d94c089ab43",
        "group": "dht11-ui-group",
        "order": 3,
        "width": "3",
        "height": "1",
        "name": "Temp Text",
        "label": "Temperature",
        "format": "{{msg.payload}}°F",
        "layout": "row-spread",
        "x": 620,
        "y": 280,
        "wires": []
    },
    {
        "id": "2214f439e17b9c3a",
        "type": "ui_text",
        "z": "43876d94c089ab43",
        "group": "dht11-ui-group",
        "order": 4,
        "width": "3",
        "height": "1",
        "name": "Humidity Text",
        "label": "Humidity",
        "format": "{{msg.payload}}%",
        "layout": "row-spread",
        "x": 620,
        "y": 320,
        "wires": []
    },
    {
        "id": "audio-tab",
        "type": "tab",
        "label": "Water Low Alert Audio",
        "disabled": false,
        "info": "Plays a buzzer alert on a GPIO pin when water level has been LOW for more than 1 minute.\nReads global.waterStatus set by the DYP-A01 water depth flow.\n\nWiring:\n  Active buzzer positive → GPIO 23 (BCM)\n  Active buzzer negative → GND\n\nUses an ACTIVE buzzer (internal oscillator) — just needs HIGH/LOW.\nFor a PASSIVE buzzer use PWM mode instead."
    },
    {
        "id": "audio-poll",
        "type": "inject",
        "z": "audio-tab",
        "name": "Check Every 15s",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "15",
        "crontab": "",
        "once": true,
        "onceDelay": "5",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 130,
        "y": 100,
        "wires": [
            [
                "audio-check"
            ]
        ]
    },
    {
        "id": "audio-check",
        "type": "function",
        "z": "audio-tab",
        "name": "Check Water Status",
        "func": "var status = global.get('waterStatus') || 'OK';\nvar now    = Date.now();\n\nif (status !== 'LOW') {\n  // Water is OK — reset the LOW timer\n  flow.set('lowSince', null);\n  flow.set('alertPlaying', false);\n  node.status({ fill:'green', shape:'dot', text:'OK' });\n  return null;\n}\n\n// Water is LOW — record when it first went low\nvar lowSince = flow.get('lowSince');\nif (!lowSince) {\n  flow.set('lowSince', now);\n  node.status({ fill:'yellow', shape:'ring', text:'LOW — waiting 1min...' });\n  return null;\n}\n\nvar lowForMs  = now - lowSince;\nvar lowForSec = Math.round(lowForMs / 1000);\n\nif (lowForMs < 60000) {\n  // Not yet 1 minute\n  node.status({ fill:'yellow', shape:'ring', text:'LOW ' + lowForSec + 's / 60s' });\n  return null;\n}\n\n// Been LOW for over 1 minute — trigger alert\nnode.status({ fill:'red', shape:'dot', text:'LOW ' + lowForSec + 's — ALERT!' });\nreturn { payload: lowForSec, topic: 'waterLowAlert' };",
        "outputs": 1,
        "noerr": 0,
        "initialize": "flow.set('lowSince', null); flow.set('alertPlaying', false);",
        "finalize": "",
        "libs": [],
        "x": 350,
        "y": 100,
        "wires": [
            [
                "audio-throttle"
            ]
        ]
    },
    {
        "id": "audio-throttle",
        "type": "trigger",
        "z": "audio-tab",
        "name": "Max Once Per 5min",
        "op1": "1",
        "op2": "",
        "op1type": "pay",
        "op2type": "nul",
        "duration": "5",
        "extend": false,
        "overrideDelay": false,
        "units": "min",
        "reset": "",
        "bytopic": "all",
        "topic": "topic",
        "outputs": 1,
        "x": 580,
        "y": 100,
        "wires": [
            [
                "audio-buzz-on",
                "audio-debug",
                "audio-buzz-delay"
            ]
        ]
    },
    {
        "id": "audio-debug",
        "type": "debug",
        "z": "audio-tab",
        "name": "Alert Triggered",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 840,
        "y": 120,
        "wires": []
    },
    {
        "id": "audio-buzz-on",
        "type": "rpi-gpio out",
        "z": "audio-tab",
        "name": "Buzzer ON (GPIO 23)",
        "pin": "23",
        "set": true,
        "level": "0",
        "freq": "",
        "out": "out",
        "bcm": true,
        "x": 820,
        "y": 60,
        "wires": []
    },
    {
        "id": "audio-buzz-delay",
        "type": "delay",
        "z": "audio-tab",
        "name": "Buzz 1s",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 760,
        "y": 200,
        "wires": [
            [
                "audio-buzz-off"
            ]
        ]
    },
    {
        "id": "audio-buzz-off",
        "type": "rpi-gpio out",
        "z": "audio-tab",
        "name": "Buzzer OFF (GPIO 23)",
        "pin": "23",
        "set": true,
        "level": "0",
        "freq": "",
        "out": "out",
        "bcm": true,
        "x": 800,
        "y": 280,
        "wires": []
    },
    {
        "id": "364f57d595c825ae",
        "type": "ui_group",
        "name": "Water Depth",
        "tab": "gardyn-ui-tab",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "4977006900fe6493",
        "type": "ui_group",
        "name": "Camera",
        "tab": "gardyn-ui-tab",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "cpu-ui-group",
        "type": "ui_group",
        "name": "System",
        "tab": "gardyn-ui-tab",
        "order": 5,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "dht11-ui-group",
        "type": "ui_group",
        "name": "Temperature & Humidity",
        "tab": "gardyn-ui-tab",
        "order": 4,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "gardyn-ui-tab",
        "type": "ui_tab",
        "name": "Gardyn",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    },
    {
        "id": "44722a604f2eff7c",
        "type": "global-config",
        "env": [],
        "modules": {
            "node-red-node-pisrf": "0.4.0",
            "node-red-dashboard": "3.6.6",
            "node-red-node-base64": "1.0.0",
            "node-red-contrib-dht-sensor": "1.0.4",
            "node-red-node-pi-gpio": "2.0.7"
        }
    }
]

Are you sure node-red was even running when you ran top? I can't see it there. Certainly the processor was very lightly loaded at that time. What exactly do you mean by 'locks up'?

Run node-red-log and see what that shows when the system locks up.

Also stop and restart node red and post the startup log. Do that by running

node-red-stop
node-red-start

Copy/paste the log and post it the same way as flows are posted.

I would also suggest node-red-status

That may help.
:person_shrugging:

I have never heard of that, and is not present on my system.

isn't that a command that shows the status of node-red?

Oh, interesting.

Did a quick check.

Maybe this one then:
sudo systemctl status nodered

Maybe I did an alias for it and forgot I did.
(Sorry)

Actually I was kind of wrong in another way.
The command was/is:
node-red status.

That will start node red with a flow file called status

Ok. Wow. Seems I am really having a bad time with commands just now.

Sorry to all for any confusion.

It either completely stops responding to anything, or gets stuck in a boot error (it resets itself and gets stuck)

Then what happens if you start node-red in safe mode?

Is it node-red --safe?

See if things load ok then see what happens if you deploy it.

What stops responding? The browser? The pi in a command/ssh window?

Again, it is not clear what you mean by that. Do you mean that the pi reboots without warning? If so how do you know it is rebooting? Then again what do you mean by gets stuck?

If you do mean that the pi is randomly rebooting then this is most likely a power supply issue. If not the psu then probably another hardware problem.

The pi will not respond to a ssh, or browser, just a solid led and nothing will open/load. I know it will restart because it will sometimes show a boot error (led flashing nonstop at regular rate), or it will load and the history has disappeared and the outputs have been reintialized.

It's a hardware problem. Disconnect any external devices, usb for example, and see if that makes a difference (a faulty device can pull down the power supply). If that doesn't help then try a different power supply.
Or it could be the SD card of course.

That might suggest a problem with the SD card