diff --git a/backend/controllers/hardwarecontroller.go b/backend/controllers/hardwarecontroller.go index 4950823..0b3f0a8 100644 --- a/backend/controllers/hardwarecontroller.go +++ b/backend/controllers/hardwarecontroller.go @@ -146,13 +146,9 @@ func VerifyHardwareCode(c *gin.Context) { client := mqtt.NewClient(opts) if tokenMQTT := client.Connect(); tokenMQTT.Wait() && tokenMQTT.Error() == nil { - // Buka Gembok Relay client.Publish("sclass/d101/auth", 0, true, "UNLOCK").Wait() - - // Opsional: Nyalakan Lampu Otomatis saat login client.Publish("sclass/d101/lampu1", 0, false, "on").Wait() client.Publish("sclass/d101/lampu2", 0, false, "on").Wait() - client.Disconnect(250) fmt.Printf("[MQTT] Perintah UNLOCK dan ON dikirim (Sisa Menit: %d)\n", sisaMenit) } else { @@ -268,7 +264,7 @@ func ControlHardware(c *gin.Context) { } // ========================================================================= -// HELPER: MENGAMBIL STATE DARI HOME ASSISTANT +// HELPER 1: MENGAMBIL ANGKA DARI HOME ASSISTANT (Untuk Daya/Watt) // ========================================================================= func fetchHAState(haURL string, haToken string, entityID string) float64 { apiURL := fmt.Sprintf("%s/api/states/%s", haURL, entityID) @@ -294,11 +290,40 @@ func fetchHAState(haURL string, haToken string, entityID string) float64 { return 0 } - // Ubah string angka menjadi float val, _ := strconv.ParseFloat(stateStr, 64) return val } +// ========================================================================= +// HELPER 2: MENGAMBIL STATUS TEKS DARI HOME ASSISTANT (Untuk ON/OFF) +// ========================================================================= +func fetchHAStringState(haURL string, haToken string, entityID string) string { + apiURL := fmt.Sprintf("%s/api/states/%s", haURL, entityID) + + req, _ := http.NewRequest("GET", apiURL, nil) + req.Header.Set("Authorization", "Bearer "+haToken) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{Timeout: 3 * time.Second} + resp, err := client.Do(req) + if err != nil { + return "off" + } + defer resp.Body.Close() + + var result map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "off" + } + + stateStr, ok := result["state"].(string) + if !ok { + return "off" + } + + return stateStr +} + // ========================================================================= // FUNGSI 3: MENDAPATKAN STATUS DAYA DARI 3 MCB SEKALIGUS // ========================================================================= @@ -330,21 +355,18 @@ func GlobalPowerControl(c *gin.Context) { haURL := os.Getenv("HA_URL") haToken := os.Getenv("HA_TOKEN") - // Tentukan service HA berdasarkan request service := "turn_off" if req.Action == "on" { service = "turn_on" } apiURL := fmt.Sprintf("%s/api/services/switch/%s", haURL, service) - // Daftar MCB yang akan dieksekusi secara berurutan mcbs := []string{ "switch.wifi_smart_meter_pro_switch", // Umum "switch.wifi_smart_meter_pro_2_switch", // AC1 "switch.wifi_smart_meter_pro_3_switch", // AC2 } - // Looping untuk eksekusi satu per satu for i, mcb := range mcbs { payload := map[string]string{"entity_id": mcb} jsonPayload, _ := json.Marshal(payload) @@ -363,13 +385,11 @@ func GlobalPowerControl(c *gin.Context) { fmt.Printf("[MCB] Sinyal %s dikirim ke %s\n", req.Action, mcb) - // Berikan jeda 1 detik, KECUALI untuk iterasi terakhir if i < len(mcbs)-1 { time.Sleep(1 * time.Second) } } - // Jika dimatikan paksa, update cache perangkat IoT menjadi mati semua if req.Action == "off" { DeviceStatusCache["lampu1"] = "off" DeviceStatusCache["lampu2"] = "off" @@ -384,11 +404,49 @@ func GlobalPowerControl(c *gin.Context) { } // ========================================================================= -// FUNGSI 5: MENGIRIM STATUS REAL-TIME KE WEB FRONTEND +// FUNGSI 5: MENGIRIM STATUS REAL-TIME KE WEB FRONTEND (SENSOR FUSION) // ========================================================================= func GetHardwareStatus(c *gin.Context) { + haURL := os.Getenv("HA_URL") + haToken := os.Getenv("HA_TOKEN") + + // 1. Cek status fisik MCB di Home Assistant + mcbUmum := fetchHAStringState(haURL, haToken, "switch.wifi_smart_meter_pro_switch") + mcbAC1 := fetchHAStringState(haURL, haToken, "switch.wifi_smart_meter_pro_2_switch") + + // 2. Ambil data dari Cache (Perintah terakhir dari Web/ESP32 melalui IR/MQTT) + statusLampu1 := DeviceStatusCache["lampu1"] + statusLampu2 := DeviceStatusCache["lampu2"] + statusProyektor := DeviceStatusCache["projector"] + statusAC := DeviceStatusCache["ac"] + + // 3. LOGIKA SENSOR FUSION (Penggabungan Fisik & Virtual) + // Jika listrik MCB fisik terputus, maka otomatis perangkat di jalur tersebut PASTI MATI (off), + // mengabaikan apapun status terakhir yang ada di memori Cache. + if mcbUmum == "off" { + statusLampu1 = "off" + statusLampu2 = "off" + statusProyektor = "off" + + // Sinkronkan kembali cache agar tidak ada "state" nyangkut + DeviceStatusCache["lampu1"] = "off" + DeviceStatusCache["lampu2"] = "off" + DeviceStatusCache["projector"] = "off" + } + + if mcbAC1 == "off" { + statusAC = "off" + DeviceStatusCache["ac"] = "off" + } + + // Kirim data yang sudah divalidasi ke Web dan Layar ESP32 c.JSON(http.StatusOK, gin.H{ "status": "success", - "data": DeviceStatusCache, + "data": map[string]string{ + "lampu1": statusLampu1, + "lampu2": statusLampu2, + "projector": statusProyektor, + "ac": statusAC, + }, }) } \ No newline at end of file