// ============================================ // DIRECT SHELLY 1PM WASHING MACHINE SCRIPT // Fixed Duration Multiplier // ============================================ let CONFIG = { serverURL: "https://msfkwifi.com/washing/check.php", machineID: 1, // ⚠️ CHANGE THIS FOR EACH SHELLY (1, 2, 3, etc.) espId: "Shelly-Machine-1", // ⚠️ CHANGE THIS FOR EACH SHELLY commandCheckInterval: 3000, powerCheckInterval: 5000, standbyPowerThreshold: 3.0, idleThreshold: 6, gracePeriod: 60000 }; let state = { running: false, startTime: 0, durationMs: 0, voucher: "", idleCounter: 0, monitorTimer: null }; function init() { print("🚀 Shelly Controller Started - Machine ID: " + CONFIG.machineID); Timer.clear(); Timer.set(CONFIG.commandCheckInterval, true, checkServerCommand); } function checkServerCommand() { if (state.running) return; let url = CONFIG.serverURL + "?action=command&machine=" + CONFIG.machineID + "&esp_id=" + CONFIG.espId; Shelly.call("HTTP.GET", { url: url, timeout: 5 }, function (response, error_code, error_message) { if (error_code !== 0 || !response || response.code !== 200) return; try { let data = JSON.parse(response.body); if (data && data.success && data.command === "start") { // ✅ FIX: PHP sends duration in SECONDS. // We multiply by 1000 to get milliseconds. let durationSeconds = data.duration || 3600; let code = data.code || ""; print("🎫 VOUCHER RECEIVED: " + code + " | Duration: " + durationSeconds + " seconds"); startMachine(code, durationSeconds * 1000); acknowledgeStart(code); } } catch (e) { print("❌ JSON Parse Error: " + e.message); } }); } function acknowledgeStart(voucherCode) { let url = CONFIG.serverURL + "?action=started&machine=" + CONFIG.machineID + "&code=" + voucherCode + "&esp_id=" + CONFIG.espId; Shelly.call("HTTP.GET", { url: url, timeout: 5 }); } function startMachine(voucherCode, durationMs) { Shelly.call("Switch.Set", { id: 0, on: true }, function (result, error_code) { if (error_code === 0) { state.running = true; state.startTime = Date.now(); state.durationMs = durationMs; state.voucher = voucherCode; state.idleCounter = 0; if (state.monitorTimer) Timer.clear(state.monitorTimer); state.monitorTimer = Timer.set(CONFIG.powerCheckInterval, true, monitorCycle); print("🔌 Machine ON. Will run for " + (durationMs/60000).toFixed(1) + " minutes."); } }); } function monitorCycle() { if (!state.running) return; let elapsed = Date.now() - state.startTime; // 1. CHECK TIME FIRST (Reliable cutoff) if (elapsed >= state.durationMs) { print("⏰ Time is up! (Elapsed: " + Math.floor(elapsed/60000) + "m)"); stopMachine("Timer Finished"); return; } // 2. CHECK POWER (Idle detection) Shelly.call("Switch.GetStatus", { id: 0 }, function (status, error_code) { if (error_code !== 0 || !status || !state.running) return; let activePower = status.apower || 0.0; // Let's show remaining time in minutes and seconds for clarity let remainingMs = state.durationMs - elapsed; let remMins = Math.floor(remainingMs / 60000); let remSecs = Math.floor((remainingMs % 60000) / 1000); print("⚡ Power: " + JSON.stringify(activePower) + "W | Remaining: " + remMins + "m " + remSecs + "s"); if (elapsed > CONFIG.gracePeriod && activePower < CONFIG.standbyPowerThreshold) { state.idleCounter++; print("⚠️ Idle: " + state.idleCounter + "/" + CONFIG.idleThreshold); if (state.idleCounter >= CONFIG.idleThreshold) { stopMachine("Machine Idle"); } } else { state.idleCounter = 0; } }); } function stopMachine(reason) { if (!state.running) return; print("🔄 Stopping machine. Reason: " + reason); Shelly.call("Switch.Set", { id: 0, on: false }, function (result, error_code) { if (state.monitorTimer) { Timer.clear(state.monitorTimer); state.monitorTimer = null; } notifyCompletion(state.voucher); state.running = false; state.voucher = ""; state.idleCounter = 0; print("✅ Machine Turned OFF."); }); } function notifyCompletion(voucherCode) { if (!voucherCode) return; let url = CONFIG.serverURL + "?action=completed&code=" + voucherCode + "&machine=" + CONFIG.machineID + "&esp_id=" + CONFIG.espId; Shelly.call("HTTP.GET", { url: url, timeout: 5 }, function(res, err) { if (err === 0) print("✅ Server notified of COMPLETION."); }); } init();