[
    {
        "id": "mobilenet_unet_tab",
        "type": "tab",
        "label": "MobileNet_UNet Semantic Segmentation",
        "disabled": false,
        "info": "# MobileNet_UNet Semantic Segmentation\n\n## Introduction\n\nMobileNet_UNet semantic segmentation algorithm, supporting USB camera snapshot, USB video stream, and MIPI video stream modes.\n\n## Usage Process\n\n### Mode 1: USB Snapshot Segmentation\n1. **Take Photo**: Click the \"📷 Take USB Photo\" button.\n2. **Auto Segmentation**: The system automatically segments the photo using MobileNet_UNet.\n3. **View Result**: The segmentation result is displayed directly in the Node-RED editor.\n\n### Mode 2: USB Video Stream (Real-time)\n1. **Start Stream**: Click the \"🎥 USB Camera Stream\" button.\n2. **View Visuals**: Click \"Open Web Visualization\" to view real-time results in a browser.\n3. **Stop Service**: Click \"Stop Segmentation Service\" when finished.\n\n### Mode 3: MIPI Video Stream (Real-time)\n1. **Start Stream**: Click the \"📹 MIPI Camera Stream\" button.\n2. **View Visuals**: Click \"Open Web Visualization\" to view real-time results in a browser.\n3. **Stop Service**: Click \"Stop Segmentation Service\" when finished.\n\n## Supported Platforms\n\n- RDK X5\n- RDK S100\n- RDK X3\n\n## Core Communication Config\n\n### WebSocket Video Stream\n- **Stream URL**: `http://{host}:8000`\n- **Image Topic**: `/image` (JPEG encoded stream)\n- **Performance**: Real-time detection, low latency\n\n## Notes\n\n- Snapshot segmentation results are automatically saved to the `/tmp/mobilenet_unet/` directory.\n- For video stream modes, start the stream first before opening the visualization page.\n- The segmentation process takes a few seconds to initialize, please wait patiently.",
        "env": []
    },
    {
        "id": "comment_photo_section",
        "type": "comment",
        "z": "mobilenet_unet_tab",
        "name": "📷 Snapshot Segmentation Workflow",
        "info": "Click the button to take a photo, automatically segment, and display the result.",
        "x": 150,
        "y": 40,
        "wires": []
    },
    {
        "id": "inject_take_photo",
        "type": "inject",
        "z": "mobilenet_unet_tab",
        "name": "📷 Take USB Photo",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 140,
        "y": 100,
        "wires": [
            [
                "rdk_camera_take_photo"
            ]
        ]
    },
    {
        "id": "rdk_camera_take_photo",
        "type": "rdk-camera takephoto",
        "z": "mobilenet_unet_tab",
        "cameratype": "1",
        "filemode": "2",
        "filename": "photo.jpg",
        "filedefpath": "0",
        "filepath": "/tmp/mobilenet_unet",
        "fileformat": "jpeg",
        "resolution": "2",
        "rotation": "0",
        "fliph": "0",
        "flipv": "0",
        "brightness": "50",
        "contrast": "0",
        "sharpness": "0",
        "quality": "80",
        "imageeffect": "none",
        "exposuremode": "auto",
        "iso": "0",
        "agcwait": "1.0",
        "led": "0",
        "awb": "auto",
        "name": "Take Photo",
        "x": 350,
        "y": 100,
        "wires": [
            [
                "debug_camera_output",
                "function_prepare_segmentation"
            ]
        ]
    },
    {
        "id": "debug_camera_output",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Debug: Camera Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 550,
        "y": 60,
        "wires": []
    },
    {
        "id": "debug_prepare_seg",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Debug: Prepare Seg",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 750,
        "y": 60,
        "wires": []
    },
    {
        "id": "function_prepare_segmentation",
        "type": "function",
        "z": "mobilenet_unet_tab",
        "name": "Prepare Segmentation",
        "func": "// Ensure directory exists and get photo path\nconst saveDir = '/tmp/mobilenet_unet';\n\nif (!fs.existsSync(saveDir)) {\n    fs.mkdirSync(saveDir, { recursive: true });\n}\n\nlet photoPath = null;\nlet photoFileName = null;\n\n// Use file path from msg.payload\nif (msg.payload && typeof msg.payload === 'string' && msg.payload.trim()) {\n    photoPath = msg.payload.trim();\n    \n    if (fs.existsSync(photoPath)) {\n        photoFileName = path.basename(photoPath);\n        node.status({ fill: 'green', shape: 'dot', text: 'Photo: ' + photoFileName });\n        \n        msg.photoPath = photoPath;\n        msg.photoFileName = photoFileName;\n        msg.photoDir = saveDir;\n        \n        return msg;\n    } else {\n        const self = node;\n        let retryCount = 0;\n        const maxRetries = 5;\n        \n        const checkFile = function() {\n            if (fs.existsSync(photoPath)) {\n                const newMsg = {\n                    photoPath: photoPath,\n                    photoFileName: path.basename(photoPath),\n                    photoDir: saveDir\n                };\n                self.status({ fill: 'green', shape: 'dot', text: 'Photo found' });\n                self.send(newMsg);\n            } else if (retryCount < maxRetries) {\n                retryCount++;\n                setTimeout(checkFile, 500);\n            } else {\n                self.error('Photo file not found: ' + photoPath);\n                self.status({ fill: 'red', shape: 'dot', text: 'Photo Missing' });\n            }\n        };\n        \n        setTimeout(checkFile, 500);\n        return null;\n    }\n} else if (msg.payload && Buffer.isBuffer(msg.payload)) {\n    // Save buffer to file\n    photoFileName = 'photo.jpg';\n    photoPath = path.join(saveDir, photoFileName);\n    try {\n        fs.writeFileSync(photoPath, msg.payload);\n        node.status({ fill: 'green', shape: 'dot', text: 'Photo saved' });\n        \n        msg.photoPath = photoPath;\n        msg.photoFileName = photoFileName;\n        msg.photoDir = saveDir;\n        \n        return msg;\n    } catch (err) {\n        node.error('Failed to save photo: ' + err.message);\n        return null;\n    }\n} else {\n    // Default fallback\n    photoFileName = 'photo.jpg';\n    photoPath = path.join(saveDir, photoFileName);\n    if (!fs.existsSync(photoPath)) {\n        node.error('Cannot find photo file, check camera config');\n        node.status({ fill: 'red', shape: 'dot', text: 'Photo Missing' });\n        return null;\n    }\n    node.status({ fill: 'green', shape: 'dot', text: 'Using default path' });\n    \n    msg.photoPath = photoPath;\n    msg.photoFileName = photoFileName;\n    msg.photoDir = saveDir;\n    \n    return msg;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "fs",
                "module": "fs"
            },
            {
                "var": "path",
                "module": "path"
            }
        ],
        "x": 550,
        "y": 100,
        "wires": [
            [
                "debug_prepare_seg",
                "function_build_seg_command"
            ]
        ]
    },
    {
        "id": "function_build_seg_command",
        "type": "function",
        "z": "mobilenet_unet_tab",
        "name": "Build Segmentation Command",
        "func": "// Build Segmentation Command\nconst photoDir = msg.photoDir || '/tmp/mobilenet_unet';\nconst photoFileName = msg.photoFileName || 'photo.jpg';\n\n// Build full launch command\nconst pwdCmd = 'pwd';\nmsg.payload = 'cd ' + photoDir + ' && source /opt/tros/humble/setup.bash && cp -r /opt/tros/humble/lib/dnn_node_example/config/ . 2>/dev/null || true && echo \"=== Starting MobileNet_UNet Segmentation ===\" && echo \"Work Dir: $(pwd)\" && echo \"Image File: ' + photoFileName + '\" && echo \"Checking image existence...\" && ls -lh ' + photoFileName + ' 2>&1 && echo \"Starting segmentation...\" && ros2 launch dnn_node_example dnn_node_example_feedback.launch.py dnn_example_config_file:=config/mobilenet_unet_workconfig.json dnn_example_image:=' + photoFileName + ' dnn_example_dump_render_img:=1';\n\nnode.status({ fill: 'blue', shape: 'dot', text: 'Command built' });\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 750,
        "y": 100,
        "wires": [
            [
                "debug_build_command",
                "exec_start_segmentation"
            ]
        ]
    },
    {
        "id": "debug_build_command",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Debug: Built Command",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 950,
        "y": 60,
        "wires": []
    },
    {
        "id": "exec_start_segmentation",
        "type": "exec",
        "z": "mobilenet_unet_tab",
        "name": "Start Segmentation",
        "command": "",
        "addpay": true,
        "append": "",
        "useSpawn": true,
        "timer": "0",
        "oldrc": false,
        "x": 950,
        "y": 100,
        "wires": [
            [
                "debug_seg_output",
                "function_wait_and_refresh"
            ],
            [
                "debug_seg_error"
            ],
            []
        ]
    },
    {
        "id": "debug_seg_output",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Segmentation Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1180,
        "y": 80,
        "wires": []
    },
    {
        "id": "debug_seg_error",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Segmentation Error",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1180,
        "y": 120,
        "wires": []
    },
    {
        "id": "comment_video_section",
        "type": "comment",
        "z": "mobilenet_unet_tab",
        "name": "🎥 USB Stream Segmentation Workflow",
        "info": "Start real-time USB camera stream for continuous segmentation.",
        "x": 150,
        "y": 200,
        "wires": []
    },
    {
        "id": "inject_usb_video",
        "type": "inject",
        "z": "mobilenet_unet_tab",
        "name": "🎥 USB Camera Stream",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "usb_video",
        "payload": "start",
        "payloadType": "str",
        "x": 140,
        "y": 260,
        "wires": [
            [
                "exec_usb_video"
            ]
        ]
    },
    {
        "id": "exec_usb_video",
        "type": "exec",
        "z": "mobilenet_unet_tab",
        "name": "USB Stream Launcher",
        "command": "source /opt/tros/humble/setup.bash && export CAM_TYPE=usb && ros2 launch dnn_node_example dnn_node_example.launch.py dnn_example_dump_render_img:=0 dnn_example_config_file:=config/mobilenet_unet_workconfig.json dnn_example_image_width:=640 dnn_example_image_height:=480",
        "addpay": false,
        "append": "",
        "useSpawn": true,
        "timer": "120",
        "oldrc": false,
        "x": 380,
        "y": 260,
        "wires": [
            [
                "debug_usb_video_output"
            ],
            [
                "debug_usb_video_error"
            ],
            []
        ]
    },
    {
        "id": "debug_usb_video_output",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "USB Stream Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 650,
        "y": 240,
        "wires": []
    },
    {
        "id": "debug_usb_video_error",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "USB Stream Error",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 650,
        "y": 280,
        "wires": []
    },
    {
        "id": "comment_mipi_video_section",
        "type": "comment",
        "z": "mobilenet_unet_tab",
        "name": "📹 MIPI Stream Segmentation Workflow",
        "info": "Start real-time MIPI camera stream for continuous segmentation.",
        "x": 150,
        "y": 320,
        "wires": []
    },
    {
        "id": "inject_mipi_video",
        "type": "inject",
        "z": "mobilenet_unet_tab",
        "name": "📹 MIPI Camera Stream",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "mipi_video",
        "payload": "start",
        "payloadType": "str",
        "x": 140,
        "y": 380,
        "wires": [
            [
                "exec_mipi_video"
            ]
        ]
    },
    {
        "id": "exec_mipi_video",
        "type": "exec",
        "z": "mobilenet_unet_tab",
        "name": "MIPI Stream Launcher",
        "command": "source /opt/tros/humble/setup.bash && export CAM_TYPE=mipi && ros2 launch dnn_node_example dnn_node_example.launch.py dnn_example_dump_render_img:=1 dnn_example_config_file:=config/mobilenet_unet_workconfig.json dnn_example_image_width:=1920 dnn_example_image_height:=1080",
        "addpay": false,
        "append": "",
        "useSpawn": true,
        "timer": "120",
        "oldrc": false,
        "x": 380,
        "y": 380,
        "wires": [
            [
                "debug_mipi_video_output"
            ],
            [
                "debug_mipi_video_error"
            ],
            []
        ]
    },
    {
        "id": "debug_mipi_video_output",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "MIPI Stream Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 650,
        "y": 360,
        "wires": []
    },
    {
        "id": "debug_mipi_video_error",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "MIPI Stream Error",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 650,
        "y": 400,
        "wires": []
    },
    {
        "id": "comment_browser_section",
        "type": "comment",
        "z": "mobilenet_unet_tab",
        "name": "2️⃣ View Detection Results",
        "info": "View real-time detection feed in browser",
        "x": 200,
        "y": 440,
        "wires": []
    },
    {
        "id": "inject_browser",
        "type": "inject",
        "z": "mobilenet_unet_tab",
        "name": "Open Web Visualization",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "http://{host}:8000",
        "payloadType": "str",
        "x": 140,
        "y": 480,
        "wires": [
            [
                "openurl_browser"
            ]
        ]
    },
    {
        "id": "openurl_browser",
        "type": "rdk-tools openurl",
        "z": "mobilenet_unet_tab",
        "name": "",
        "x": 380,
        "y": 480,
        "wires": []
    },
    {
        "id": "comment_display_section",
        "type": "comment",
        "z": "mobilenet_unet_tab",
        "name": "🖼️ Snapshot Result Display",
        "info": "Automatically read latest segmentation result and display in editor",
        "x": 150,
        "y": 540,
        "wires": []
    },
    {
        "id": "inject_refresh_display",
        "type": "inject",
        "z": "mobilenet_unet_tab",
        "name": "Refresh Display",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "topic": "",
        "payload": "",
        "payloadType": "str",
        "x": 140,
        "y": 600,
        "wires": [
            [
                "exec_find_latest"
            ]
        ]
    },
    {
        "id": "exec_find_latest",
        "type": "exec",
        "z": "mobilenet_unet_tab",
        "name": "Find Latest Result",
        "command": "cd /tmp/mobilenet_unet && ls -t render_*.jpg render_*.jpeg 2>/dev/null | head -1",
        "addpay": false,
        "append": "",
        "useSpawn": false,
        "timer": "",
        "oldrc": false,
        "x": 350,
        "y": 600,
        "wires": [
            [
                "function_check_file"
            ],
            [],
            []
        ]
    },
    {
        "id": "exec_list_dir",
        "type": "exec",
        "z": "mobilenet_unet_tab",
        "name": "List Directory (Debug)",
        "command": "cd /tmp/mobilenet_unet && echo \"Current Dir: $(pwd)\" && echo \"Content:\" && ls -lh 2>&1",
        "addpay": false,
        "append": "",
        "useSpawn": false,
        "timer": "",
        "oldrc": false,
        "x": 350,
        "y": 640,
        "wires": [
            [
                "debug_find_result"
            ],
            [],
            []
        ]
    },
    {
        "id": "debug_find_result",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Debug: Find Result",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 550,
        "y": 620,
        "wires": []
    },
    {
        "id": "function_check_file",
        "type": "function",
        "z": "mobilenet_unet_tab",
        "name": "Check File Path",
        "func": "// Extract file path\nvar output = msg.payload ? msg.payload.toString().trim() : '';\n\nif (!output) {\n    node.status({ fill: 'yellow', shape: 'dot', text: 'File not found' });\n    return null;\n}\n\n// Get first line\nvar lines = output.split('\\n').filter(line => line.trim().length > 0);\nvar filename = lines.length > 0 ? lines[0].trim() : '';\n\nif (filename && !filename.startsWith('/')) {\n    filename = '/tmp/mobilenet_unet/' + filename;\n}\n\nif (!filename) {\n    node.warn('Cannot extract file path');\n    node.status({ fill: 'red', shape: 'dot', text: 'Extraction failed' });\n    return null;\n}\n\nmsg.filename = filename;\nnode.status({ fill: 'green', shape: 'dot', text: 'Found: ' + path.basename(filename) });\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "path",
                "module": "path"
            }
        ],
        "x": 550,
        "y": 600,
        "wires": [
            [
                "debug_file_path",
                "file_read_image"
            ]
        ]
    },
    {
        "id": "debug_file_path",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Debug: File Path",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 750,
        "y": 620,
        "wires": []
    },
    {
        "id": "file_read_image",
        "type": "file in",
        "z": "mobilenet_unet_tab",
        "name": "Read Image",
        "filename": "",
        "format": "buffer",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 750,
        "y": 600,
        "wires": [
            [
                "image_viewer_result"
            ]
        ]
    },
    {
        "id": "image_viewer_result",
        "type": "image viewer",
        "z": "mobilenet_unet_tab",
        "name": "Display Segmentation Result",
        "width": "640",
        "data": "payload",
        "dataType": "msg",
        "active": true,
        "x": 950,
        "y": 600,
        "wires": [
            []
        ]
    },
    {
        "id": "comment_control_section",
        "type": "comment",
        "z": "mobilenet_unet_tab",
        "name": "🎮 Controls",
        "info": "Stop Segmentation Service",
        "x": 150,
        "y": 680,
        "wires": []
    },
    {
        "id": "inject_stop",
        "type": "inject",
        "z": "mobilenet_unet_tab",
        "name": "Stop Segmentation Service",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "topic": "",
        "payload": "stop",
        "payloadType": "str",
        "x": 140,
        "y": 740,
        "wires": [
            [
                "exec_stop_all"
            ]
        ]
    },
    {
        "id": "exec_stop_all",
        "type": "exec",
        "z": "mobilenet_unet_tab",
        "name": "Stop Service",
        "command": "sudo pkill -9 -f hobot_usb_cam; sudo pkill -9 -f dnn_node_example; sudo pkill -9 -f hobot_codec_republish; sudo pkill -9 -f websocket; sudo pkill -9 -f python3; sudo pkill -9 -f 'ros2 launch'; sudo pkill -9 -f 'ros2 run'; sleep 2; sudo rm -rf /dev/shm/*; ros2 daemon stop 2>/dev/null; sleep 1; echo '✓ Service stopped completely, resources released'",
        "addpay": false,
        "append": "",
        "useSpawn": false,
        "timer": "10",
        "oldrc": false,
        "x": 350,
        "y": 740,
        "wires": [
            [
                "debug_stop_info"
            ],
            [],
            []
        ]
    },
    {
        "id": "debug_stop_info",
        "type": "debug",
        "z": "mobilenet_unet_tab",
        "name": "Stop Status",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 550,
        "y": 740,
        "wires": []
    },
    {
        "id": "function_wait_and_refresh",
        "type": "function",
        "z": "mobilenet_unet_tab",
        "name": "Wait for Completion",
        "func": "// Poll check for segmentation result\nconst saveDir = '/tmp/mobilenet_unet';\n\nif (typeof global.refreshScheduled === 'undefined') {\n    global.refreshScheduled = false;\n}\nif (typeof global.processedFiles === 'undefined') {\n    global.processedFiles = new Set();\n}\n\nif (!global.refreshScheduled) {\n    global.refreshScheduled = true;\n    \n    let checkCount = 0;\n    const maxChecks = 40; // 40 * 500ms = 20s\n    const self = node;\n    let timerId = null;\n    \n    const checkFile = function() {\n        checkCount++;\n        \n        try {\n            if (!fs.existsSync(saveDir)) {\n                self.warn('Dir Not Found: ' + saveDir);\n                if (checkCount < maxChecks) {\n                    timerId = setTimeout(checkFile, 500);\n                } else {\n                    global.refreshScheduled = false;\n                    self.status({ fill: 'red', shape: 'dot', text: 'Dir Not Found' });\n                }\n                return;\n            }\n            \n            const files = fs.readdirSync(saveDir).filter(f => \n                f.startsWith('render_') && (f.endsWith('.jpg') || f.endsWith('.jpeg') || f.endsWith('.JPG') || f.endsWith('.JPEG'))\n            );\n            \n            if (files.length > 0) {\n                files.sort((a, b) => {\n                    const statA = fs.statSync(path.join(saveDir, a));\n                    const statB = fs.statSync(path.join(saveDir, b));\n                    return statB.mtime - statA.mtime;\n                });\n                \n                const latestFile = files[0];\n                const filePath = path.join(saveDir, latestFile);\n                const fileStat = fs.statSync(filePath);\n                \n                const now = Date.now();\n                const fileTime = fileStat.mtime.getTime();\n                const timeDiff = (now - fileTime) / 1000;\n                \n                if (global.processedFiles.has(filePath)) {\n                    if (timerId) clearTimeout(timerId);\n                    global.refreshScheduled = false;\n                    self.status({ fill: 'green', shape: 'dot', text: 'Result Displayed' });\n                    return;\n                }\n                \n                if (timeDiff < 10) {\n                    global.processedFiles.add(filePath);\n                    if (timerId) clearTimeout(timerId);\n                    global.refreshScheduled = false;\n                    self.status({ fill: 'green', shape: 'dot', text: 'Result Generated: ' + latestFile });\n                    self.send({filename: filePath});\n                    return;\n                } else {\n                    self.status({ fill: 'blue', shape: 'dot', text: 'Waiting for new file... (' + checkCount + '/' + maxChecks + ')' });\n                }\n            } else {\n                self.status({ fill: 'yellow', shape: 'dot', text: 'Checking... (' + checkCount + '/' + maxChecks + ')' });\n            }\n        } catch (err) {\n            self.warn('Check file failed: ' + err.message);\n        }\n        \n        if (checkCount < maxChecks) {\n            timerId = setTimeout(checkFile, 500);\n        } else {\n            global.refreshScheduled = false;\n            self.status({ fill: 'yellow', shape: 'dot', text: 'Timeout, no result found' });\n        }\n    };\n    \n    timerId = setTimeout(checkFile, 3000);\n}\nreturn null;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "fs",
                "module": "fs"
            },
            {
                "var": "path",
                "module": "path"
            }
        ],
        "x": 1180,
        "y": 100,
        "wires": [
            [
                "debug_file_path",
                "file_read_image"
            ]
        ]
    },
    {
        "id": "global_config_mobilenet_unet",
        "type": "global-config",
        "env": [],
        "modules": {
            "node-red-node-rdk-camera": "0.0.17",
            "node-red-contrib-image-tools": "2.1.1"
        }
    }
]