(function () { "use strict"; const POLL_MS = 3000; const DATA_URL = (window.NODERED_URL || "").replace(/\/$/, "") + "/get-data"; const SENSORS = { suhu: { valId:"val-suhu", barId:"bar-suhu", unit:"", decimals:1, max:45, color: v=>(v>32||v<18)?"#f59e0b":"#22c55e" }, ph: { valId:"val-ph", barId:"bar-ph", unit:" pH", decimals:2, max:14, color: v=>(v<6.5||v>8.5)?"#ef4444":"#22c55e" }, amonia: { valId:"val-amonia", barId:"bar-amonia", unit:" ppm", decimals:2, max:10, color: v=>v>2?"#ef4444":v>1?"#f59e0b":"#22c55e" }, kekeruhan: { valId:"val-kekeruhan", barId:"bar-kekeruhan", unit:" NTU", decimals:1, max:150, color: v=>v>80?"#ef4444":v>40?"#f59e0b":"#22c55e" }, distance: { valId:"val-distance", barId:"bar-distance", unit:" cm", decimals:1, max:100, color: v=>v>70?"#ef4444":v>50?"#f59e0b":"#22c55e" }, }; function updateSensor(key, raw) { const cfg = SENSORS[key]; if (!cfg || raw===null || raw===undefined) return; const v = parseFloat(raw); if (isNaN(v)) return; const valEl = document.getElementById(cfg.valId); const barEl = document.getElementById(cfg.barId); if (valEl) valEl.textContent = v.toFixed(cfg.decimals) + cfg.unit; if (barEl) { barEl.style.width = Math.min(100, Math.max(0, v/cfg.max*100)) + "%"; barEl.style.background = cfg.color(v); } } function updateDevice(badgeId, valId, raw) { const valEl = document.getElementById(valId); const badgeEl = document.getElementById(badgeId); if (!valEl || !badgeEl || raw===null || raw===undefined) return; const on = (raw==1 || String(raw).toUpperCase()==="ON"); valEl.textContent = on ? "ON" : "OFF"; badgeEl.classList.toggle("on", on); badgeEl.classList.toggle("off", !on); } const RULES = [ {key:"amonia", label:"Amonia", dangerHi:2, warnHi:1 }, {key:"suhu", label:"Suhu", dangerHi:33, warnHi:30, dangerLo:17, warnLo:20 }, {key:"ph", label:"pH", dangerLo:6.0, warnLo:6.5,dangerHi:9.0,warnHi:8.5}, {key:"kekeruhan", label:"Kekeruhan", dangerHi:80, warnHi:40 }, {key:"distance", label:"Distance", dangerHi:70, warnHi:50 } ]; function checkThresholds(data) { const notifs = []; RULES.forEach(r => { const v = parseFloat(data[r.key]); if (isNaN(v)) return; if ((r.dangerHi!==undefined&&v>=r.dangerHi)||(r.dangerLo!==undefined&&v<=r.dangerLo)) notifs.push({level:"danger", msg:`⚠️ ${r.label} KRITIS: ${v.toFixed(2)}`}); else if ((r.warnHi!==undefined&&v>=r.warnHi)||(r.warnLo!==undefined&&v<=r.warnLo)) notifs.push({level:"warn", msg:`🔔 ${r.label} Abnormal: ${v.toFixed(2)}`}); }); const badge = document.querySelector(".notif-badge"); const listEl = document.querySelector("#notifDropdown ul"); if (!listEl) return; if (!notifs.length) { if (badge) badge.textContent = "0"; listEl.innerHTML = "