[
    {
        "id": "fc546c7d4e5a107a",
        "type": "tab",
        "label": "Ingest Batch Data from Object Storage",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "26b33a1b7f952bbf",
        "type": "oci-object-storage",
        "z": "fc546c7d4e5a107a",
        "name": "",
        "ociConfig": "d3fa7ef20a598e86",
        "operation": "download",
        "namespace": "<object-storage-namespace>",
        "bucketName": "<bucket-name>",
        "objectName": "",
        "filePath": "",
        "contentType": "",
        "downloadOutput": "text",
        "encoding": "utf8",
        "x": 580,
        "y": 120,
        "wires": [
            [
                "7a0cf4e98d54b3ef"
            ]
        ]
    },
    {
        "id": "efc94b7f3b5cf634",
        "type": "inject",
        "z": "fc546c7d4e5a107a",
        "name": "",
        "props": [],
        "repeat": "3600",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 110,
        "y": 120,
        "wires": [
            [
                "4bd016561702d0c5"
            ]
        ]
    },
    {
        "id": "4bd016561702d0c5",
        "type": "function",
        "z": "fc546c7d4e5a107a",
        "name": "Build file name",
        "func": "let index = flow.get(\"iotFileIndex\") || 1;\n\nlet objectName = `iot-data-${index}.csv`;\n\nmsg.fileIndex = index;\nmsg.objectName = objectName;\nmsg.payload = objectName;\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 120,
        "wires": [
            [
                "26b33a1b7f952bbf"
            ]
        ]
    },
    {
        "id": "7a0cf4e98d54b3ef",
        "type": "function",
        "z": "fc546c7d4e5a107a",
        "name": "Index Increment",
        "func": "const current = msg.fileIndex || flow.get(\"iotFileIndex\") || 1;\n\nflow.set(\"iotFileIndex\", current + 1);\n\nmsg.processedObjectName = msg.objectName;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 200,
        "y": 240,
        "wires": [
            [
                "9f134cbeaa380fba"
            ]
        ]
    },
    {
        "id": "9f134cbeaa380fba",
        "type": "csv",
        "z": "fc546c7d4e5a107a",
        "name": "",
        "spec": "rfc",
        "sep": ",",
        "hdrin": true,
        "hdrout": "none",
        "multi": "one",
        "ret": "\\r\\n",
        "temp": "deviceType,externalId,time,cpuUtil,memUtil,diskUtil,firmware,temperature,humidity,pressure,mode",
        "skip": "0",
        "strings": true,
        "include_empty_strings": "",
        "include_null_values": "",
        "x": 410,
        "y": 240,
        "wires": [
            [
                "8b4e16cb64cfb423"
            ]
        ]
    },
    {
        "id": "fd009b946e854ba1",
        "type": "catch",
        "z": "fc546c7d4e5a107a",
        "name": "",
        "scope": [
            "26b33a1b7f952bbf"
        ],
        "uncaught": false,
        "x": 130,
        "y": 440,
        "wires": [
            [
                "57041bd10705e11f"
            ]
        ]
    },
    {
        "id": "57041bd10705e11f",
        "type": "debug",
        "z": "fc546c7d4e5a107a",
        "name": "OS Node error catch",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 420,
        "y": 440,
        "wires": []
    },
    {
        "id": "784d0d034ebe5005",
        "type": "mqtt out",
        "z": "fc546c7d4e5a107a",
        "name": "",
        "topic": "",
        "qos": "1",
        "retain": "",
        "respTopic": "",
        "contentType": "application/json",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "78336d711de5e360",
        "x": 830,
        "y": 300,
        "wires": []
    },
    {
        "id": "8b4e16cb64cfb423",
        "type": "function",
        "z": "fc546c7d4e5a107a",
        "name": "csv to IoT",
        "func": "const row = msg.payload || {};\n\nconst deviceType = String(row.deviceType || \"\").trim();\nconst externalId = String(row.externalId || \"\").trim();\n\nif (!deviceType || !externalId) {\n    node.warn(\"Skipping CSV row with missing deviceType or externalId\");\n    return null;\n}\n\nconst timeValue = Number(row.time || Date.now() * 1000);\n\nif (deviceType === \"gateway\") {\n    msg.topic = \"data\";\n    msg.payload = {\n        time: timeValue,\n        cpuUtil: Number(row.cpuUtil || 0),\n        memUtil: Number(row.memUtil || 0),\n        diskUtil: Number(row.diskUtil || 0),\n        firmware: row.firmware || \"unknown\"\n    };\n} else if (deviceType === \"hvacs\") {\n    msg.topic = \"hvacs/\" + externalId;\n    msg.payload = {\n        time: timeValue,\n        temperature: Number(row.temperature || 0),\n        humidity: Number(row.humidity || 0),\n        pressure: Number(row.pressure || 0),\n        mode: row.mode || \"unknown\"\n    };\n} else {\n    node.warn(\"Unsupported CSV deviceType: \" + deviceType);\n    return null;\n}\n\nmsg.payload = JSON.stringify(msg.payload);\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 300,
        "wires": [
            [
                "784d0d034ebe5005",
                "53595345f02d9d67"
            ]
        ]
    },
    {
        "id": "53595345f02d9d67",
        "type": "debug",
        "z": "fc546c7d4e5a107a",
        "name": "MQTT Input",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 770,
        "y": 400,
        "wires": []
    },
    {
        "id": "d3fa7ef20a598e86",
        "type": "oci-config",
        "name": "",
        "authType": "resourcePrincipal",
        "region": "<region>",
        "compartmentOcid": "",
        "configFilePath": "~/.oci/config",
        "profile": "DEFAULT",
        "tenancyOcid": "",
        "userOcid": "",
        "fingerprint": "",
        "privateKeyPath": ""
    },
    {
        "id": "78336d711de5e360",
        "type": "mqtt-broker",
        "name": "",
        "broker": "<device-host>",
        "port": "8883",
        "tls": "",
        "clientid": "",
        "autoConnect": true,
        "usetls": true,
        "protocolVersion": "5",
        "keepalive": 60,
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    },
    {
        "id": "41656796a136a952",
        "type": "global-config",
        "env": [],
        "modules": {
            "oci-nodes": "0.5.0"
        }
    }
]
