TKK_E32222693/flows.json

1444 lines
38 KiB
JSON

[
{
"id": "tab1",
"type": "tab",
"label": "Dashboard Demo",
"disabled": false,
"info": ""
},
{
"id": "5f31529b3e749ebe",
"type": "mqtt in",
"z": "tab1",
"name": "MQTT Sensor",
"topic": "iot/sensor",
"qos": "0",
"datatype": "auto",
"broker": "mqtt_broker_local",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 300,
"y": 580,
"wires": [
[
"e81e5db8c5529bb0"
]
]
},
{
"id": "e81e5db8c5529bb0",
"type": "json",
"z": "tab1",
"name": "Parse JSON",
"property": "payload",
"action": "",
"pretty": false,
"x": 480,
"y": 580,
"wires": [
[
"a4575ed03e736231",
"94dd8dde94285a13"
]
]
},
{
"id": "37d04d285e6d7864",
"type": "function",
"z": "tab1",
"name": " Get Data Filter",
"func": "// Simpan pilihan ke flow untuk digunakan tombol ambil data\nflow.set(\"sensor_selected\", msg.payload);\nreturn null;\n",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 540,
"y": 780,
"wires": [
[]
]
},
{
"id": "a4575ed03e736231",
"type": "function",
"z": "tab1",
"name": "Split Sensor Data",
"func": "return [\n { payload: msg.payload.weight },\n { payload: msg.payload.humidity },\n { payload: msg.payload.soil }\n];",
"outputs": 3,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 690,
"y": 560,
"wires": [
[
"1815f02556163f1d",
"6452681ddc0cd6cd"
],
[
"edf401a2960b5562",
"22b8f2858da8ce95"
],
[
"8992134a9099bffa",
"e03f9616d12ff1df"
]
]
},
{
"id": "5a0b35725a51d4dc",
"type": "sqlite",
"z": "tab1",
"mydb": "sqlite_local",
"sqlquery": "msg.topic",
"sql": "",
"name": "Simpan ke SQLite",
"x": 810,
"y": 700,
"wires": [
[]
]
},
{
"id": "1815f02556163f1d",
"type": "ui_gauge",
"z": "tab1",
"name": "Weight",
"group": "ui_group_main",
"order": 2,
"width": 6,
"height": 0,
"gtype": "gage",
"title": "Weight (g)",
"label": "g",
"format": "{{value}}",
"min": 0,
"max": "200",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "300",
"seg2": "700",
"diff": false,
"className": "",
"x": 890,
"y": 520,
"wires": []
},
{
"id": "edf401a2960b5562",
"type": "ui_gauge",
"z": "tab1",
"name": "Humidity",
"group": "ui_group_main",
"order": 1,
"width": 6,
"height": 0,
"gtype": "gage",
"title": "Humidity (%)",
"label": "%",
"format": "{{value}}",
"min": 0,
"max": "100",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "40",
"seg2": "70",
"diff": false,
"className": "",
"x": 900,
"y": 560,
"wires": []
},
{
"id": "8992134a9099bffa",
"type": "ui_gauge",
"z": "tab1",
"name": "Soil Moisture",
"group": "ui_group_main",
"order": 3,
"width": 6,
"height": 0,
"gtype": "gage",
"title": "Soil Moisture",
"label": "%",
"format": "{{value}}",
"min": 0,
"max": 100,
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "30",
"seg2": "60",
"diff": false,
"className": "",
"x": 910,
"y": 600,
"wires": []
},
{
"id": "6452681ddc0cd6cd",
"type": "ui_chart",
"z": "tab1",
"name": "Chart Weight",
"group": "ui_group_main",
"order": 5,
"width": 6,
"height": 0,
"label": "Weight History",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "Waiting...",
"dot": false,
"ymin": "0",
"ymax": "1000",
"removeOlder": "3",
"removeOlderPoints": "100",
"removeOlderUnit": "60",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 1110,
"y": 520,
"wires": [
[]
]
},
{
"id": "22b8f2858da8ce95",
"type": "ui_chart",
"z": "tab1",
"name": "Chart Humidity",
"group": "ui_group_main",
"order": 4,
"width": 6,
"height": 0,
"label": "Humidity History",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "Waiting...",
"dot": false,
"ymin": "0",
"ymax": "100",
"removeOlder": "3",
"removeOlderPoints": "100",
"removeOlderUnit": "60",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#ff7f0e",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 1120,
"y": 560,
"wires": [
[]
]
},
{
"id": "e03f9616d12ff1df",
"type": "ui_chart",
"z": "tab1",
"name": "Chart Soil",
"group": "ui_group_main",
"order": 6,
"width": 6,
"height": 0,
"label": "Soil Moisture History",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "Waiting...",
"dot": false,
"ymin": "0",
"ymax": "100",
"removeOlder": "3",
"removeOlderPoints": "100",
"removeOlderUnit": "60",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#2ca02c",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000",
"#000000"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 1130,
"y": 600,
"wires": [
[]
]
},
{
"id": "d3167a81e47894f4",
"type": "cronplus",
"z": "tab1",
"name": "Cron Setiap 10 Menit",
"outputField": "payload",
"timeZone": "",
"storeName": "",
"commandResponseMsgOutput": "output1",
"defaultLocation": "",
"defaultLocationType": "default",
"outputs": 1,
"options": [
{
"name": "cron1menit",
"topic": "filter/weight",
"payloadType": "default",
"payload": "",
"expressionType": "cron",
"expression": "0 */10 * * * *",
"location": "",
"offset": "0",
"solarType": "all",
"solarEvents": "sunrise,sunset"
}
],
"x": 340,
"y": 700,
"wires": [
[
"1b56edf14dd48a3e"
]
]
},
{
"id": "1b56edf14dd48a3e",
"type": "function",
"z": "tab1",
"name": "Ambil dan Simpan DB",
"func": "var data = flow.get(\"last_sensor_data\");\n\nif (data) {\n msg.topic = `INSERT INTO sensor_data (weight, humidity, soil, timestamp) \n VALUES (${data.weight}, ${data.humidity}, ${data.soil}, datetime('now', 'localtime'))`;\n return msg;\n} else {\n return null;\n}\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 580,
"y": 700,
"wires": [
[
"5a0b35725a51d4dc"
]
]
},
{
"id": "94dd8dde94285a13",
"type": "function",
"z": "tab1",
"name": "Simpan data di Flow",
"func": "flow.set(\"last_sensor_data\", msg.payload);\nreturn null;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 640,
"y": 640,
"wires": [
[]
]
},
{
"id": "bbbaab907e1d9ba1",
"type": "ui_dropdown",
"z": "tab1",
"name": "",
"label": "Pilih Data Sensor ",
"tooltip": "",
"place": "Select option",
"group": "a5d4d4b9.0e5d58",
"order": 1,
"width": 0,
"height": 0,
"passthru": true,
"multiple": false,
"options": [
{
"label": "Weight",
"value": "weight",
"type": "str"
},
{
"label": "Humidity",
"value": "humidity",
"type": "str"
},
{
"label": "Soil",
"value": "soil",
"type": "str"
}
],
"payload": "",
"topic": "topic",
"topicType": "msg",
"className": "",
"x": 330,
"y": 780,
"wires": [
[
"37d04d285e6d7864"
]
]
},
{
"id": "f302ee7fa549388d",
"type": "ui_button",
"z": "tab1",
"name": "Ambil Data",
"group": "a5d4d4b9.0e5d58",
"order": 5,
"width": 0,
"height": 0,
"passthru": false,
"label": "Lihat Data 1 Jam Terakhir",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 330,
"y": 840,
"wires": [
[
"9dea1ff0914d9df1"
]
]
},
{
"id": "9dea1ff0914d9df1",
"type": "function",
"z": "tab1",
"name": "Ambil Data Sensor",
"func": "let sensor = flow.get(\"sensor_selected\") || \"weight\"; // default berat\nmsg.topic = `\n SELECT timestamp, ${sensor} AS value\n FROM sensor_data\n WHERE timestamp >= datetime('now', '-1 hour', 'localtime')\n ORDER BY timestamp ASC\n`;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 530,
"y": 840,
"wires": [
[
"b3c205b6f30ee3a1"
]
]
},
{
"id": "9c2ff6f5414057d6",
"type": "function",
"z": "tab1",
"name": "Ubah Format Chart",
"func": "let labels = [];\nlet values = [];\n\nmsg.payload.forEach(row => {\n labels.push(row.timestamp);\n values.push(row.value);\n});\n\nreturn {\n payload: [{\n series: [\"Sensor\"],\n data: [values],\n labels: labels\n }]\n};\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 910,
"y": 800,
"wires": [
[
"a1e5f5cd0e18215a"
]
]
},
{
"id": "b3c205b6f30ee3a1",
"type": "sqlite",
"z": "tab1",
"mydb": "sqlite_local",
"sqlquery": "msg.topic",
"sql": "",
"name": "Ambil Data",
"x": 730,
"y": 840,
"wires": [
[
"9c2ff6f5414057d6",
"f29389be4bd7f771"
]
]
},
{
"id": "a1e5f5cd0e18215a",
"type": "ui_chart",
"z": "tab1",
"name": "Chart 1 Jam Terakhir",
"group": "a5d4d4b9.0e5d58",
"order": 3,
"width": "9",
"height": "9",
"label": "chart",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": 1,
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 1140,
"y": 800,
"wires": [
[]
]
},
{
"id": "f29389be4bd7f771",
"type": "ui_table",
"z": "tab1",
"group": "a5d4d4b9.0e5d58",
"name": "Tabel Data Sensor 1 Jam",
"order": 6,
"width": "9",
"height": "9",
"columns": [],
"outputs": 0,
"cts": false,
"x": 930,
"y": 880,
"wires": []
},
{
"id": "1faca8d668b6c953",
"type": "mqtt in",
"z": "tab1",
"name": "MQTT IN",
"topic": "iot/sensor",
"qos": "2",
"datatype": "auto-detect",
"broker": "mqtt_broker_local",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 260,
"y": 920,
"wires": [
[
"43e20a522799a074"
]
]
},
{
"id": "43e20a522799a074",
"type": "function",
"z": "tab1",
"name": "Logika Otomasi",
"func": "let auto = flow.get(\"autoMode\") || \"OFF\";\nlet min = flow.get(\"minThreshold\") || 60;\nlet max = flow.get(\"maxThreshold\") || 90;\nlet humidity = msg.payload.humidity;\n\nif (auto === \"ON\") {\n if (humidity > max || (humidity <= max && humidity >= min)) {\n return {\n payload: {\n kipas: \"ON\",\n ptc: \"ON\"\n }\n };\n } else if (humidity < min) {\n return {\n payload: {\n kipas: \"OFF\",\n ptc: \"OFF\"\n }\n };\n }\n}\n\nreturn null; // Auto OFF → ESP32 logika lokal\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 500,
"y": 980,
"wires": [
[
"5c1f51279e899535"
]
]
},
{
"id": "5c1f51279e899535",
"type": "mqtt out",
"z": "tab1",
"name": "MQTT OUT",
"topic": "iot/control/relay",
"qos": "0",
"retain": "true",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "mqtt_broker_local",
"x": 730,
"y": 920,
"wires": []
},
{
"id": "d89d2771a3657743",
"type": "ui_switch",
"z": "tab1",
"name": "Auto Mode",
"label": "Auto Mode",
"tooltip": "",
"group": "077642f35af224dd",
"order": 1,
"width": 0,
"height": 0,
"passthru": true,
"decouple": "false",
"topic": "auto",
"topicType": "str",
"style": "",
"onvalue": "ON",
"onvalueType": "str",
"onicon": "",
"oncolor": "",
"offvalue": "OFF",
"offvalueType": "str",
"officon": "",
"offcolor": "",
"animate": false,
"className": "",
"x": 270,
"y": 980,
"wires": [
[
"e6969d414614df2a"
]
]
},
{
"id": "e6969d414614df2a",
"type": "function",
"z": "tab1",
"name": "Set Auto Mode",
"func": "flow.set(\"autoMode\", msg.payload);\n\nlet mode = msg.payload;\n\nif (mode === \"ON\") {\n let min = flow.get(\"minThreshold\") || 60;\n let max = flow.get(\"maxThreshold\") || 90;\n\n return {\n payload: {\n auto: \"ON\",\n min: min,\n max: max\n }\n };\n} else {\n return {\n payload: {\n auto: \"OFF\"\n }\n };\n}\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 520,
"y": 1040,
"wires": [
[
"c648c08be1a9d688"
]
]
},
{
"id": "c648c08be1a9d688",
"type": "mqtt out",
"z": "tab1",
"name": "MQTT OUT",
"topic": "iot/control/relay",
"qos": "0",
"retain": "true",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "mqtt_broker_local",
"x": 730,
"y": 980,
"wires": []
},
{
"id": "300d03d320030023",
"type": "ui_numeric",
"z": "tab1",
"name": "",
"label": "Min Threshold",
"tooltip": "",
"group": "077642f35af224dd",
"order": 2,
"width": 0,
"height": 0,
"wrap": false,
"passthru": true,
"topic": "min",
"topicType": "str",
"format": "{{value}}",
"min": 0,
"max": "100",
"step": 1,
"className": "",
"x": 280,
"y": 1040,
"wires": [
[
"176a870347715cfa"
]
]
},
{
"id": "1157d77839be828e",
"type": "ui_numeric",
"z": "tab1",
"name": "Max Threshold",
"label": "Max Threshold",
"tooltip": "",
"group": "077642f35af224dd",
"order": 3,
"width": 0,
"height": 0,
"wrap": false,
"passthru": true,
"topic": "max",
"topicType": "str",
"format": "{{value}}",
"min": 0,
"max": "100",
"step": 1,
"className": "",
"x": 280,
"y": 1100,
"wires": [
[
"bcea903c811a2674"
]
]
},
{
"id": "176a870347715cfa",
"type": "function",
"z": "tab1",
"name": "MIn Threshold",
"func": "flow.set(\"minThreshold\", msg.payload);\nreturn null;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 520,
"y": 1100,
"wires": [
[]
]
},
{
"id": "bcea903c811a2674",
"type": "function",
"z": "tab1",
"name": "Max Threshold",
"func": "flow.set(\"maxThreshold\", msg.payload);\nreturn null;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 500,
"y": 1160,
"wires": [
[]
]
},
{
"id": "eabf72d94dda646b",
"type": "ui_form",
"z": "tab1",
"name": "",
"label": "Input Tanggal untuk Cek Tabel Hasil Sensor",
"group": "a5d4d4b9.0e5d58",
"order": 10,
"width": 0,
"height": 0,
"options": [
{
"label": "StartDate",
"value": "StartDate",
"type": "date",
"required": true,
"rows": null
},
{
"label": "EndDate",
"value": "EndDate",
"type": "date",
"required": true,
"rows": null
}
],
"formValue": {
"StartDate": "",
"EndDate": ""
},
"payload": "",
"submit": "Load Data",
"cancel": "Cancel",
"topic": "topic",
"topicType": "msg",
"splitLayout": "",
"className": "",
"x": 890,
"y": 1080,
"wires": [
[
"a924537ad40c9a35"
]
]
},
{
"id": "a924537ad40c9a35",
"type": "function",
"z": "tab1",
"name": "function 1",
"func": "var start = msg.payload.StartDate;\nvar end = msg.payload.EndDate;\n\nmsg.topic = `SELECT ID, timestamp, weight, humidity, soil\n FROM sensor_data\n WHERE timestamp BETWEEN '${start}' AND '${end}'\n ORDER BY timestamp ASC`;\n\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1180,
"y": 1080,
"wires": [
[
"94ab216e7402fe83"
]
]
},
{
"id": "94ab216e7402fe83",
"type": "sqlite",
"z": "tab1",
"mydb": "sqlite_local",
"sqlquery": "msg.topic",
"sql": "",
"name": "",
"x": 980,
"y": 1160,
"wires": [
[
"06b6b6875d1ef97f",
"009cc5fdaef1059b"
]
]
},
{
"id": "06b6b6875d1ef97f",
"type": "ui_table",
"z": "tab1",
"group": "a5d4d4b9.0e5d58",
"name": "",
"order": 11,
"width": "18",
"height": "9",
"columns": [],
"outputs": 0,
"cts": false,
"x": 1310,
"y": 1160,
"wires": []
},
{
"id": "0e1cb4193c91927d",
"type": "ui_chart",
"z": "tab1",
"name": "",
"group": "",
"order": 12,
"width": "9",
"height": "9",
"label": "Grafik Hasil Sensor",
"chartType": "line",
"legend": "true",
"xformat": "HH:mm",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": "24",
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 3730,
"y": 2780,
"wires": [
[]
]
},
{
"id": "d40f0c435b9f0739",
"type": "function",
"z": "tab1",
"name": "function 2",
"func": "let hasil = [];\nlet terakhirJam = null;\n\nfor (let row of msg.payload) {\n let waktu = new Date(row.timestamp);\n let jam = waktu.getHours();\n\n if (jam !== terakhirJam) {\n let t = waktu.getTime();\n hasil.push(\n { topic: \"weight\", payload: row.weight, x: t },\n { topic: \"humidity\", payload: row.humidity, x: t },\n { topic: \"soil\", payload: row.soil, x: t }\n );\n terakhirJam = jam;\n }\n}\n\nreturn [hasil];\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 3740,
"y": 2620,
"wires": [
[]
]
},
{
"id": "009cc5fdaef1059b",
"type": "debug",
"z": "tab1",
"name": "debug 1",
"active": true,
"tosidebar": true,
"console": true,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "payload",
"statusType": "auto",
"x": 1010,
"y": 1220,
"wires": []
},
{
"id": "44417d6d5c88b067",
"type": "debug",
"z": "tab1",
"name": "debug 2",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 3900,
"y": 2640,
"wires": []
},
{
"id": "e24142f27563c8f7",
"type": "function",
"z": "tab1",
"name": "function 3",
"func": "let hasil = [];\n\nfor (let row of msg.payload) {\n let waktu = new Date(row.timestamp);\n let t = waktu.getTime(); // ubah ke milidetik\n\n hasil.push(\n { topic: \"weight\", payload: row.weight, x: t },\n { topic: \"humidity\", payload: row.humidity, x: t },\n { topic: \"soil\", payload: row.soil, x: t }\n );\n}\n\nreturn [hasil];\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 3740,
"y": 2680,
"wires": [
[]
]
},
{
"id": "2274b4168fa225ab",
"type": "ui_button",
"z": "tab1",
"name": "Clear Chart",
"group": "",
"order": 13,
"width": 0,
"height": 0,
"passthru": false,
"label": "Clear Chart",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 3510,
"y": 2920,
"wires": [
[]
]
},
{
"id": "f6a49940e4446c3e",
"type": "function",
"z": "tab1",
"name": "function 6",
"func": "return [\n { topic: \"weight\", payload: [] },\n { topic: \"humidity\", payload: [] },\n { topic: \"soil\", payload: [] }\n];\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 3520,
"y": 2840,
"wires": [
[]
]
},
{
"id": "21536e5562e29615",
"type": "function",
"z": "tab1",
"name": "filter 2jam",
"func": "let hasil = [];\nlet terakhirWaktu = null;\nconst intervalMs = 60 * 60 * 1000; // 1 jam = 3600000 ms\n\nfor (let row of msg.payload) {\n let waktu = new Date(row.timestamp);\n if (isNaN(waktu.getTime())) continue;\n\n let t = waktu.getTime();\n\n // Ambil hanya satu data per jam\n if (terakhirWaktu === null || (t - terakhirWaktu) >= intervalMs) {\n hasil.push(\n { topic: \"weight\", payload: row.weight, x: t },\n { topic: \"humidity\", payload: row.humidity, x: t },\n { topic: \"soil\", payload: row.soil, x: t }\n );\n terakhirWaktu = t;\n }\n}\n\nreturn [hasil];\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 3520,
"y": 2780,
"wires": [
[]
]
},
{
"id": "c6422797ed00af54",
"type": "ui_form",
"z": "tab1",
"name": "",
"label": "Input Waktu untuk Hitung Durasi Nyala Alat",
"group": "cfa831704ecb774e",
"order": 1,
"width": 0,
"height": 0,
"options": [
{
"label": "Waktu Nyala Awal",
"value": "start_date",
"type": "date",
"required": true,
"rows": null
},
{
"label": "Waktu Nyala Akhir",
"value": "end_date",
"type": "date",
"required": true,
"rows": null
}
],
"formValue": {
"start_date": "",
"end_date": ""
},
"payload": "",
"submit": "submit",
"cancel": "cancel",
"topic": "topic",
"topicType": "msg",
"splitLayout": "",
"className": "",
"x": 310,
"y": 1260,
"wires": [
[
"6ab3a01515f3839f"
]
]
},
{
"id": "6ab3a01515f3839f",
"type": "function",
"z": "tab1",
"name": "query database cari waktu",
"func": "let start = msg.payload.start_date;\nlet end = msg.payload.end_date;\n\nmsg.topic = `\n SELECT timestamp, weight FROM sensor_data \n WHERE timestamp BETWEEN '${start} 00:00:00' AND '${end} 23:59:59' \n ORDER BY timestamp ASC;\n`;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 670,
"y": 1260,
"wires": [
[
"cf6c9c8b56973d03"
]
]
},
{
"id": "cf6c9c8b56973d03",
"type": "sqlite",
"z": "tab1",
"mydb": "sqlite_local",
"sqlquery": "msg.topic",
"sql": "",
"name": "",
"x": 500,
"y": 1340,
"wires": [
[
"6d4b3c89d262ec1b"
]
]
},
{
"id": "6d4b3c89d262ec1b",
"type": "function",
"z": "tab1",
"name": "hitung waktu",
"func": "let data = msg.payload;\n\nif (!Array.isArray(data) || data.length < 2) {\n msg.payload = \"Data tidak cukup untuk menghitung durasi pengeringan.\";\n return msg;\n}\n\n// Ganti spasi jadi T agar bisa dibaca Date()\nlet waktu1 = new Date(data[0].timestamp.replace(\" \", \"T\"));\nlet waktu2 = new Date(data[data.length - 1].timestamp.replace(\" \", \"T\"));\n\nif (isNaN(waktu1) || isNaN(waktu2)) {\n msg.payload = \"Format waktu tidak valid dari database.\";\n return msg;\n}\n\nlet selisihMs = Math.abs(waktu2 - waktu1);\nlet jam = Math.floor(selisihMs / (1000 * 60 * 60));\nlet menit = Math.floor((selisihMs % (1000 * 60 * 60)) / (1000 * 60));\n\nmsg.payload = `Durasi Lama Menyala Alat: ${jam} jam ${menit} menit`;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 2,
"initialize": "",
"finalize": "",
"libs": [],
"x": 330,
"y": 1420,
"wires": [
[
"d7165d9095fce54c"
]
]
},
{
"id": "d7165d9095fce54c",
"type": "ui_text_input",
"z": "tab1",
"name": "Durasi Alat Menyala",
"label": "",
"tooltip": "",
"group": "cfa831704ecb774e",
"order": 2,
"width": "14",
"height": "2",
"passthru": true,
"mode": "text",
"delay": 300,
"topic": "topic",
"sendOnBlur": true,
"className": "",
"topicType": "msg",
"x": 600,
"y": 1420,
"wires": [
[]
]
},
{
"id": "1d392868362ac611",
"type": "ui_form",
"z": "tab1",
"name": "",
"label": "Input Berat Awal dan Akhir",
"group": "cfa831704ecb774e",
"order": 3,
"width": 0,
"height": 0,
"options": [
{
"label": "Berat Awal",
"value": "berat_awal",
"type": "number",
"required": true,
"rows": null
},
{
"label": "Berat Akhir",
"value": "berat_akhir",
"type": "number",
"required": true,
"rows": null
}
],
"formValue": {
"berat_awal": "",
"berat_akhir": ""
},
"payload": "",
"submit": "submit",
"cancel": "cancel",
"topic": "topic",
"topicType": "msg",
"splitLayout": "",
"className": "",
"x": 360,
"y": 1500,
"wires": [
[
"f9c308cbef39eb24"
]
]
},
{
"id": "f9c308cbef39eb24",
"type": "function",
"z": "tab1",
"name": "query database cari waktu",
"func": "let berat_awal = msg.payload.berat_awal;\nlet berat_akhir = msg.payload.berat_akhir;\n\nmsg.topic = `\n SELECT timestamp, weight \n FROM sensor_data \n WHERE weight IN (${berat_awal}, ${berat_akhir})\n ORDER BY timestamp ASC;\n`;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 670,
"y": 1500,
"wires": [
[
"36ad9d1719f51b71"
]
]
},
{
"id": "36ad9d1719f51b71",
"type": "sqlite",
"z": "tab1",
"mydb": "sqlite_local",
"sqlquery": "msg.topic",
"sql": "",
"name": "",
"x": 500,
"y": 1580,
"wires": [
[
"4dc76c949c967437"
]
]
},
{
"id": "4dc76c949c967437",
"type": "function",
"z": "tab1",
"name": "hitung waktu",
"func": "let data = msg.payload;\n\nif (data.length < 2) {\n msg.payload = \"Tidak ditemukan dua titik berat dalam database.\";\n return msg;\n}\n\n// Ubah ke format Date (pastikan format timestamp dari DB: 'YYYY-MM-DD HH:MM:SS')\nlet waktu1 = new Date(data[0].timestamp.replace(\" \", \"T\"));\nlet waktu2 = new Date(data[1].timestamp.replace(\" \", \"T\"));\n\nif (isNaN(waktu1) || isNaN(waktu2)) {\n msg.payload = \"Waktu tidak valid.\";\n return msg;\n}\n\nlet selisihMs = Math.abs(waktu2 - waktu1);\nlet jam = Math.floor(selisihMs / (1000 * 60 * 60));\nlet menit = Math.floor((selisihMs % (1000 * 60 * 60)) / (1000 * 60));\n\nmsg.payload = `Durasi Lama Proses Pengeringan: ${jam} jam ${menit} menit`;\nreturn msg;\n",
"outputs": 1,
"timeout": 0,
"noerr": 2,
"initialize": "",
"finalize": "",
"libs": [],
"x": 330,
"y": 1660,
"wires": [
[
"2ddc72cd58c4a8b2"
]
]
},
{
"id": "2ddc72cd58c4a8b2",
"type": "ui_text_input",
"z": "tab1",
"name": "Durasi Pengering",
"label": "",
"tooltip": "",
"group": "cfa831704ecb774e",
"order": 4,
"width": "14",
"height": "2",
"passthru": true,
"mode": "text",
"delay": 300,
"topic": "topic",
"sendOnBlur": true,
"className": "",
"topicType": "msg",
"x": 590,
"y": 1660,
"wires": [
[]
]
},
{
"id": "mqtt_broker_local",
"type": "mqtt-broker",
"name": "Local MQTT",
"broker": "localhost",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": 4,
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
},
{
"id": "sqlite_local",
"type": "sqlitedb",
"db": "C:\\Users\\Moch Alif Ridho A\\Documents\\sensor_data.db",
"mode": "RWC"
},
{
"id": "ui_group_main",
"type": "ui_group",
"name": "Sensor Monitor",
"tab": "ui_tab_main",
"order": 1,
"disp": true,
"width": "18",
"collapse": false,
"className": ""
},
{
"id": "a5d4d4b9.0e5d58",
"type": "ui_group",
"name": "Filter Data Sensor",
"tab": "c75362e0.9e6a38",
"order": 1,
"disp": true,
"width": "18",
"collapse": false,
"className": ""
},
{
"id": "077642f35af224dd",
"type": "ui_group",
"name": "Kontrol Relay",
"tab": "c94c9feca08755da",
"order": 1,
"disp": true,
"width": "18",
"collapse": false,
"className": ""
},
{
"id": "cfa831704ecb774e",
"type": "ui_group",
"name": "Hitung Lama Pengeringan",
"tab": "2e2f751f9fd061a0",
"order": 1,
"disp": true,
"width": "18",
"collapse": false,
"className": ""
},
{
"id": "ui_tab_main",
"type": "ui_tab",
"name": "Dashboard Monitoring",
"icon": "dashboard",
"order": 2,
"disabled": false,
"hidden": false
},
{
"id": "c75362e0.9e6a38",
"type": "ui_tab",
"name": "Dashboard Database ",
"icon": "dashboard",
"order": 3,
"disabled": false,
"hidden": false
},
{
"id": "c94c9feca08755da",
"type": "ui_tab",
"name": "Otomasi Relay",
"icon": "dashboard",
"order": 5,
"disabled": false,
"hidden": false
},
{
"id": "2e2f751f9fd061a0",
"type": "ui_tab",
"name": "Hitung Durasi Proses Pengeringan",
"icon": "dashboard",
"order": 5,
"disabled": false,
"hidden": false
}
]