commit e346b8654522c6e75cb67666d244e792600a4ac9 Author: Adhitya Date: Thu Aug 7 14:14:21 2025 +0700 Upload files to "/" diff --git a/Web Air Conditioner.json b/Web Air Conditioner.json new file mode 100644 index 0000000..da17ab5 --- /dev/null +++ b/Web Air Conditioner.json @@ -0,0 +1,858 @@ +[ + { + "id": "dd166f1fb1414356", + "type": "tab", + "label": "Dashboard AC", + "disabled": false, + "info": "" + }, + { + "id": "45a2b398537a5711", + "type": "ui_switch", + "z": "dd166f1fb1414356", + "name": "Power", + "label": "Power", + "tooltip": "", + "group": "8bd4a1c79f424e45", + "order": 1, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "ac/power", + "topicType": "str", + "style": "", + "onvalue": "on", + "onvalueType": "str", + "onicon": "", + "oncolor": "", + "offvalue": "off", + "offvalueType": "str", + "officon": "", + "offcolor": "", + "animate": true, + "className": "", + "x": 210, + "y": 60, + "wires": [ + [ + "e26985a773758b5b", + "fed55988a21fe62d" + ] + ] + }, + { + "id": "e09b28a2caeb4107", + "type": "ui_dropdown", + "z": "dd166f1fb1414356", + "name": "Swing", + "label": "Swing", + "tooltip": "", + "place": "Select option", + "group": "8bd4a1c79f424e45", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "Swing ON", + "value": "on", + "type": "str" + }, + { + "label": "Swing OFF", + "value": "off", + "type": "str" + } + ], + "topic": "ac/swing", + "topicType": "str", + "className": "", + "x": 210, + "y": 180, + "wires": [ + [ + "e26985a773758b5b", + "fed55988a21fe62d" + ] + ] + }, + { + "id": "e26985a773758b5b", + "type": "mqtt out", + "z": "dd166f1fb1414356", + "name": "MQTT KONTROL AC", + "topic": "", + "qos": "", + "retain": "", + "respTopic": "", + "contentType": "", + "userProps": "", + "correl": "", + "expiry": "", + "broker": "9fbca1958dadbcd5", + "x": 480, + "y": 60, + "wires": [] + }, + { + "id": "f7fd6d577815fc4e", + "type": "mqtt in", + "z": "dd166f1fb1414356", + "name": "", + "topic": "sensor/dht22", + "qos": "2", + "datatype": "json", + "broker": "9fbca1958dadbcd5", + "nl": false, + "rap": true, + "rh": 0, + "inputs": 0, + "x": 1070, + "y": 380, + "wires": [ + [ + "4daa938f22269682", + "e834877d3f06063a", + "1c4be2044b325aeb" + ] + ] + }, + { + "id": "e834877d3f06063a", + "type": "function", + "z": "dd166f1fb1414356", + "name": "function 2", + "func": "var suhu = { payload: msg.payload.suhu };\nvar kelembapan = { payload: msg.payload.kelembapan };\nreturn [\n { payload: msg.payload.suhu },\n { payload: msg.payload.kelembapan }\n];\n\nlet data = JSON.parse(msg.payload);\nmsg.payload = {\n suhu: data.temperature,\n kelembapan: data.humidity,\n waktu: new Date().toLocaleString()\n};\nreturn msg;", + "outputs": 2, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1280, + "y": 380, + "wires": [ + [ + "6bd53add46a3c498" + ], + [ + "00983c16aeed32b2" + ] + ] + }, + { + "id": "6bd53add46a3c498", + "type": "ui_gauge", + "z": "dd166f1fb1414356", + "name": "", + "group": "565ebc18e3d1af6f", + "order": 2, + "width": 6, + "height": 4, + "gtype": "gage", + "title": "Suhu", + "label": "°C", + "format": "{{value}} °C", + "min": 0, + "max": "50", + "colors": [ + "#00b500", + "#e6e600", + "#ca3838" + ], + "seg1": "", + "seg2": "", + "diff": false, + "className": "", + "x": 1450, + "y": 360, + "wires": [] + }, + { + "id": "00983c16aeed32b2", + "type": "ui_gauge", + "z": "dd166f1fb1414356", + "name": "", + "group": "565ebc18e3d1af6f", + "order": 1, + "width": 0, + "height": 0, + "gtype": "gage", + "title": "Kelembapan", + "label": "%", + "format": "{{value}} %", + "min": 0, + "max": "100", + "colors": [ + "#00b500", + "#e6e600", + "#ca3838" + ], + "seg1": "", + "seg2": "", + "diff": false, + "className": "", + "x": 1470, + "y": 400, + "wires": [] + }, + { + "id": "cf15d38ecdd8677a", + "type": "ui_dropdown", + "z": "dd166f1fb1414356", + "name": "Fan Speed", + "label": "Fan Speed", + "tooltip": "", + "place": "Select option", + "group": "8bd4a1c79f424e45", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "Auto", + "value": "auto", + "type": "str" + }, + { + "label": "Low", + "value": "low", + "type": "str" + }, + { + "label": "Medium", + "value": "medium", + "type": "str" + }, + { + "label": "High", + "value": "high", + "type": "str" + } + ], + "topic": "ac/fan", + "topicType": "str", + "className": "", + "x": 190, + "y": 240, + "wires": [ + [ + "e26985a773758b5b", + "fed55988a21fe62d" + ] + ] + }, + { + "id": "789737a05200ad73", + "type": "ui_button", + "z": "dd166f1fb1414356", + "name": "Reset WiFi ESP32", + "group": "565ebc18e3d1af6f", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Reset WiFi ESP32", + "tooltip": "Klik untuk reset koneksi WiFi", + "color": "", + "bgcolor": "#ff6666", + "className": "", + "icon": "fa-refresh", + "payload": "reset", + "payloadType": "str", + "topic": "ac/resetwifi", + "topicType": "str", + "x": 190, + "y": 340, + "wires": [ + [ + "456c3c5f815e9edf" + ] + ] + }, + { + "id": "f043c813369ccfc7", + "type": "ui_slider", + "z": "dd166f1fb1414356", + "name": "Suhu", + "label": "Temperature", + "tooltip": "", + "group": "8bd4a1c79f424e45", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "outs": "end", + "topic": "ac/temp", + "topicType": "str", + "min": 18, + "max": 30, + "step": 1, + "className": "", + "x": 210, + "y": 120, + "wires": [ + [ + "e26985a773758b5b", + "fed55988a21fe62d" + ] + ] + }, + { + "id": "fed55988a21fe62d", + "type": "function", + "z": "dd166f1fb1414356", + "name": "Send to Firebase and UI Table", + "func": "let topic = msg.topic\nlet value = msg.payload;\nlet timestamp = Date.now();\nlet waktu = new Date().toLocaleString(\"id-ID\");\n\n// Ambil status terakhir AC\nlet lastState = flow.get(\"statusAC\") || {\n power: null,\n temp: null,\n swing: null,\n fan: null\n};\n\n// Perbarui status sesuai topik\nif (topic === \"ac/power\") {\n lastState.power = value;\n} else if (topic === \"ac/temp\") {\n lastState.temp = value;\n} else if (topic === \"ac/swing\") {\n lastState.swing = value;\n} else if (topic === \"ac/fan\") {\n lastState.fan = value;\n} else if (topic === \"reset\") {\n // Reset semua\n flow.set(\"statusAC\", null);\n flow.set(\"riwayatAC\", []);\n\n let msgFirebase = {\n payload: null,\n topic: \"ac/power\"\n };\n let msgTable = {\n payload: []\n };\n return [msgFirebase, msgTable];\n} else {\n return [null, null]; // Topik tidak dikenal\n}\n\n// Simpan ulang status terakhir\nflow.set(\"statusAC\", lastState);\n\n// Buat entry riwayat lengkap\nlet dataBaru = {\n timestamp,\n waktu,\n power: lastState.power,\n temp: lastState.temp,\n swing: lastState.swing,\n fan: lastState.fan\n};\n\n// Simpan ke array riwayat\nlet history = flow.get(\"riwayatAC\") || [];\nhistory.push(dataBaru);\n\n\nflow.set(\"riwayatAC\", history);\n\nlet msgFirebase = {\n payload: dataBaru,\n topic: `ac_${timestamp}` // untuk ID dokumen unik\n};\n\n// Kirim ke Firebase\n// let msgFirebase = {\n// payload: {\n// [timestamp]: dataBaru\n// },\n// topic: \"ac/power\"\n// };\n\n// Kirim ke UI Table\n// riwayatAC:\n// [\"on\", \"off\"]\n\nlet msgTable = {\n payload: history\n};\n\nreturn [msgFirebase, msgTable];", + "outputs": 2, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 180, + "wires": [ + [ + "afcf08f2c2555abf" + ], + [ + "9776cfb20df1c2e3" + ] + ] + }, + { + "id": "f1f65fb261894e0d", + "type": "ui_button", + "z": "dd166f1fb1414356", + "name": "Button Reset", + "group": "f893e31c484e44b1", + "order": 2, + "width": 0, + "height": 0, + "passthru": false, + "label": "Reset History", + "tooltip": "", + "color": "", + "bgcolor": "#ff6666", + "className": "", + "icon": "delete", + "payload": "", + "payloadType": "str", + "topic": "reset", + "topicType": "str", + "x": 450, + "y": 280, + "wires": [ + [ + "fed55988a21fe62d" + ] + ] + }, + { + "id": "9776cfb20df1c2e3", + "type": "ui_template", + "z": "dd166f1fb1414356", + "group": "f893e31c484e44b1", + "name": "Table Riwayat AC", + "order": 1, + "width": "6", + "height": "7", + "format": "
\n \n \n \n \n \n \n \n \n \n \n \n \n
WaktuPowerTempSwingFan
\n
\n\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 850, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "456c3c5f815e9edf", + "type": "mqtt out", + "z": "dd166f1fb1414356", + "name": "MQTT RESET WIFI", + "topic": "ac/resetwifi", + "qos": "", + "retain": "", + "respTopic": "", + "contentType": "", + "userProps": "", + "correl": "", + "expiry": "", + "broker": "9fbca1958dadbcd5", + "x": 470, + "y": 340, + "wires": [] + }, + { + "id": "77f6c3bcdb24cb4b", + "type": "function", + "z": "dd166f1fb1414356", + "name": "Builder Cron dari Form", + "func": "let waktu = msg.payload.time;\nlet aksi = msg.payload.action;\nlet hari = msg.payload.hari || \"\";\nlet tanggal = msg.payload.tanggal || \"\";\n\n// Deteksi dan ubah waktu ISO (jika input adalah string format ISO)\nif (typeof waktu === 'string' && waktu.includes(\"T\")) {\n try {\n let t = new Date(waktu);\n if (isNaN(t.getTime())) throw \"Invalid time\";\n let jam = t.getHours().toString().padStart(2, \"0\");\n let menit = t.getMinutes().toString().padStart(2, \"0\");\n waktu = `${jam}:${menit}`;\n } catch (e) {\n node.error(\"⛔ Format waktu ISO tidak valid.\");\n return null;\n }\n}\n\n// Pastikan waktu sudah dalam format HH:MM\nif (!/^\\d{2}:\\d{2}$/.test(waktu)) {\n node.error(\"⛔ Format waktu tidak valid. Harus HH:MM.\");\n return null;\n}\n\nlet [jam, menit] = waktu.split(\":\").map(Number);\nif (isNaN(jam) || isNaN(menit)) {\n node.error(\"Jam atau menit bukan angka.\");\n return null;\n}\n\nlet id = `jadwal_${jam}_${menit}_${aksi}_${Date.now()}`;\n\nlet dayMap = {\n \"Minggu\": 0,\n \"Senin\": 1,\n \"Selasa\": 2,\n \"Rabu\": 3,\n \"Kamis\": 4,\n \"Jumat\": 5,\n \"Sabtu\": 6\n};\n\nlet expression = \"\";\n\nif (hari !== \"\") {\n let hariList = hari.split(\",\").map(h => dayMap[h.trim()]);\n expression = `0 ${menit} ${jam} * * ${hariList.join(\",\")}`;\n} else if (tanggal !== \"\") {\n let dt = new Date(tanggal);\n if (isNaN(dt)) {\n node.error(\"Tanggal tidak valid.\");\n return null;\n }\n let day = dt.getDate();\n let month = dt.getMonth() + 1;\n let year = dt.getFullYear();\n expression = `0 ${menit} ${jam} ${day} ${month} * ${year}`;\n} else {\n expression = `0 ${menit} ${jam} * * *`;\n}\n\nmsg.payload = {\ncommand: \"add\",\nname: id,\n expression: expression,\n payload: {\n topic: \"ac/power\",\n payload: aksi // <- pastikan ini ada\n },\n payloadType: \"default\",\n timezone: \"Asia/Jakarta\"\n};\n\n// Simpan data jadwal ke dalam msg untuk disimpan ke tabel UI\nmsg.jadwalInfo = {\n id: id,\n waktu: waktu,\n aksi: aksi,\n hari: hari,\n tanggal: tanggal,\n expression: expression\n};\n\nreturn msg;", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 700, + "wires": [ + [ + "5de18712a68b9fad", + "10101b10536635de" + ] + ] + }, + { + "id": "dc609343abd6df63", + "type": "mqtt out", + "z": "dd166f1fb1414356", + "name": "MQTT KONTROL AC", + "topic": "ac/power", + "qos": "0", + "retain": "false", + "respTopic": "", + "contentType": "", + "userProps": "", + "correl": "", + "expiry": "", + "broker": "9fbca1958dadbcd5", + "x": 1100, + "y": 700, + "wires": [] + }, + { + "id": "549d0a5c93b2f529", + "type": "function", + "z": "dd166f1fb1414356", + "name": "function 1", + "func": "if (msg.payload && msg.payload.config && msg.payload.config.payload) {\n msg.topic = msg.payload.config.payload.topic;\n msg.payload = msg.payload.config.payload.payload;\n return msg;\n// } else {\n// node.warn(\"⛔ Payload cron tidak sesuai.\");\n// return null;\n}", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 880, + "y": 700, + "wires": [ + [ + "dc609343abd6df63", + "fed55988a21fe62d" + ] + ] + }, + { + "id": "56ae79c457a7ed78", + "type": "ui_template", + "z": "dd166f1fb1414356", + "group": "37291ecad70d0e70", + "name": "Form Jadwal AC", + "order": 1, + "width": 6, + "height": "10", + "format": "
\n

Buat Jadwal Kontrol AC

\n\n
\n
\n \n
\n\n
\n
\n \n
\n\n
\n
\n \n
\n\n
\n
\n \n
\n\n
\n \n ➕ Tambah Jadwal\n \n
\n
\n\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 180, + "y": 700, + "wires": [ + [ + "77f6c3bcdb24cb4b" + ] + ] + }, + { + "id": "018cdc13cbbcfb25", + "type": "ui_template", + "z": "dd166f1fb1414356", + "group": "9ed1eb381b037864", + "name": "", + "order": 1, + "width": "16", + "height": "10", + "format": "\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Jadwal AC
IDWaktuHariStatusTanggalExpressionStateDeletePauseResume
{{item.id}}{{item.waktu}}{{item.hari}}{{item.aksi}}{{item.tanggal}}{{item.expression}}{{item.state}}\n \n \n \n \n \n \n \n \n \n \n \n
", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 840, + "y": 820, + "wires": [ + [ + "fde5a22acf4ec433" + ] + ] + }, + { + "id": "7db5bda8a2122f27", + "type": "function", + "z": "dd166f1fb1414356", + "name": "Make table data", + "func": "let raw = msg.payload.result || [];\nif(!msg.payload || !msg.payload.result || !msg.payload.result.length){\n msg.payload = [];\n return msg;\n}\n\nmsg.payload = msg.payload.result;\n\nlet dayMapReverse = {\n \"0\": \"Minggu\",\n \"1\": \"Senin\",\n \"2\": \"Selasa\",\n \"3\": \"Rabu\",\n \"4\": \"Kamis\",\n \"5\": \"Jumat\",\n \"6\": \"Sabtu\"\n};\n\nlet jadwals = raw.map(item => {\n let expr = item.config.expression.split(\" \");\n let menit = expr[1]?.padStart(2, '0') || \"00\";\n let jam = expr[2]?.padStart(2, '0') || \"00\";\n let tanggal = \"-\";\n let hari = \"-\";\n let tahun = expr[6] !== undefined ? expr[6] : \"\";\n\n if (expr[3] !== \"*\" && expr[4] !== \"*\") {\n // By tanggal\n tanggal = `${expr[3].padStart(2, '0')}/${expr[4].padStart(2, '0')}`;\n if (tahun) tanggal += `/${tahun}`;\n } else if (expr[5] !== \"*\") {\n // By hari (misal: 1,3,5)\n hari = expr[5]\n .split(\",\")\n .map(h => dayMapReverse[h.trim()] || h)\n .join(\", \");\n }\n\n return {\n id: item.config.name,\n waktu: `${jam}:${menit}`,\n hari: hari,\n aksi: item.config.payload?.payload || \"-\", // ambil dari payload.payload\n tanggal: tanggal,\n expression: item.config.expression,\n state: item.status?.isRunning ? \"Running\" : \"Paused\"\n };\n});\n\nmsg.payload = jadwals;\nreturn msg;\n", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 660, + "y": 820, + "wires": [ + [ + "018cdc13cbbcfb25" + ] + ] + }, + { + "id": "10101b10536635de", + "type": "ui_button", + "z": "dd166f1fb1414356", + "name": "Refresh", + "group": "9ed1eb381b037864", + "order": 6, + "width": 0, + "height": 0, + "passthru": true, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-refresh", + "payload": "{\"command\":\"list-all\"}", + "payloadType": "json", + "topic": "", + "topicType": "str", + "x": 540, + "y": 620, + "wires": [ + [ + "5de18712a68b9fad" + ] + ] + }, + { + "id": "fde5a22acf4ec433", + "type": "link out", + "z": "dd166f1fb1414356", + "name": "link out 1", + "mode": "link", + "links": [ + "a7a4af9974c0b0b7" + ], + "x": 955, + "y": 820, + "wires": [] + }, + { + "id": "a7a4af9974c0b0b7", + "type": "link in", + "z": "dd166f1fb1414356", + "name": "link in 1", + "links": [ + "fde5a22acf4ec433" + ], + "x": 715, + "y": 620, + "wires": [ + [ + "5de18712a68b9fad" + ] + ] + }, + { + "id": "5de18712a68b9fad", + "type": "cronplus", + "z": "dd166f1fb1414356", + "name": "cron plus", + "outputField": "payload", + "timeZone": "Asia/Jakarta", + "storeName": "", + "commandResponseMsgOutput": "output1", + "defaultLocation": "", + "defaultLocationType": "default", + "outputs": 1, + "options": [], + "x": 680, + "y": 700, + "wires": [ + [ + "549d0a5c93b2f529", + "7db5bda8a2122f27" + ] + ] + }, + { + "id": "0d32caa7f8235bfc", + "type": "function", + "z": "dd166f1fb1414356", + "name": "function 3", + "func": "let timestamp = new Date().getTime().toString();\n\nmsg.payload = {\n suhu: 18,\n kelembapan: 70,\n waktu: new Date().toLocaleString(\"id-ID\")\n};\n\nmsg.document = timestamp;\nreturn msg;\n", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1220, + "y": 240, + "wires": [ + [ + "6e5888c6866aa74e" + ] + ] + }, + { + "id": "6e5888c6866aa74e", + "type": "Firestore out", + "z": "dd166f1fb1414356", + "name": "Kirim ke Firestore", + "collection": "sensor_dht22", + "document": "msg.document", + "operation": "set", + "admin": "6a37fe7abbfec3e2", + "eject": false, + "x": 1450, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "c0b3097096ea1936", + "type": "inject", + "z": "dd166f1fb1414356", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 1060, + "y": 240, + "wires": [ + [ + "0d32caa7f8235bfc" + ] + ] + }, + { + "id": "afcf08f2c2555abf", + "type": "Firestore out", + "z": "dd166f1fb1414356", + "name": "Kirim ke Firestore", + "collection": "KONTROL AC", + "document": "{{topic}}", + "operation": "set", + "admin": "6a37fe7abbfec3e2", + "eject": false, + "x": 830, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "4061d92b9545a878", + "type": "Firestore out", + "z": "dd166f1fb1414356", + "name": "Kirim ke Firestore", + "collection": "Sensor DHT22", + "document": "{{topic}}", + "operation": "set", + "admin": "6a37fe7abbfec3e2", + "eject": false, + "x": 1450, + "y": 460, + "wires": [ + [] + ] + }, + { + "id": "4daa938f22269682", + "type": "ui_template", + "z": "dd166f1fb1414356", + "group": "565ebc18e3d1af6f", + "name": "", + "order": 3, + "width": 0, + "height": 0, + "format": "
\n Suhu {{msg.payload.status === 'sesuai' ? 'Sudah Sesuai ✅' : 'Belum Sesuai ⚠️'}}\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 1160, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "1c4be2044b325aeb", + "type": "function", + "z": "dd166f1fb1414356", + "name": "function 4", + "func": "let timestamp = new Date().toISOString();\n\n// Ambil data sesuai field sebenarnya\nlet suhu = msg.payload.suhu;\nlet kelembapan = msg.payload.kelembapan;\nlet status = msg.payload.status;\n\nif (suhu === undefined || kelembapan === undefined) {\n node.error(\"Data suhu atau kelembapan tidak ditemukan\", msg);\n return null;\n}\n\n// Format untuk Firestore\nmsg.topic = timestamp;\nmsg.payload = {\n suhu: suhu,\n kelembapan: kelembapan,\n status: status,\n waktu: new Date().toLocaleString(\"id-ID\")\n};\n\nreturn msg;\n", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1260, + "y": 460, + "wires": [ + [ + "4061d92b9545a878" + ] + ] + }, + { + "id": "75da73cb7683e5d2", + "type": "ui_spacer", + "z": "dd166f1fb1414356", + "name": "spacer", + "group": "8bd4a1c79f424e45", + "order": 2, + "width": 3, + "height": 1 + }, + { + "id": "8bd4a1c79f424e45", + "type": "ui_group", + "name": "KONTROL AC", + "tab": "6d66f5b86ad8ba34", + "order": 1, + "disp": true, + "width": 6, + "collapse": false, + "className": "" + }, + { + "id": "9fbca1958dadbcd5", + "type": "mqtt-broker", + "name": "HiveMQ Private", + "broker": "0b5fa203aa8240e290978c7e42ed2d8b.s1.eu.hivemq.cloud", + "port": "8883", + "tls": "", + "clientid": "", + "autoConnect": true, + "usetls": true, + "protocolVersion": 4, + "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": "565ebc18e3d1af6f", + "type": "ui_group", + "name": "SUHU DAN KELEMBAPAN", + "tab": "6d66f5b86ad8ba34", + "order": 2, + "disp": true, + "width": 6, + "collapse": false, + "className": "" + }, + { + "id": "f893e31c484e44b1", + "type": "ui_group", + "name": "History", + "tab": "6d66f5b86ad8ba34", + "order": 3, + "disp": true, + "width": 6, + "collapse": false, + "className": "" + }, + { + "id": "37291ecad70d0e70", + "type": "ui_group", + "name": "ATUR JADWAL", + "tab": "39df619663f80ba7", + "order": 1, + "disp": true, + "width": 6, + "collapse": false, + "className": "" + }, + { + "id": "9ed1eb381b037864", + "type": "ui_group", + "name": "DAFTAR JADWAL", + "tab": "39df619663f80ba7", + "order": 2, + "disp": true, + "width": "16", + "collapse": false, + "className": "" + }, + { + "id": "6a37fe7abbfec3e2", + "type": "firebase admin", + "name": "FirebaseAC" + }, + { + "id": "6d66f5b86ad8ba34", + "type": "ui_tab", + "name": "CONTROL DAN MONITORING AC", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": false + }, + { + "id": "39df619663f80ba7", + "type": "ui_tab", + "name": "PENJADWALAN", + "icon": "dashboard", + "disabled": false, + "hidden": false + } +] \ No newline at end of file