package controllers import ( "bytes" "encoding/json" "fmt" "net/http" "os" "time" mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/gin-gonic/gin" ) // --- STRUKTUR DATA REQUEST --- type DeviceControlRequest struct { Device string `json:"device"` Action string `json:"action"` } // ========================================================================= // FUNGSI 1: VERIFIKASI HARDWARE (Mengatasi Error undefined di main.go) // ========================================================================= func VerifyHardwareCode(c *gin.Context) { // Ini adalah fungsi bawaan yang mengembalikan status verified // agar main.go tidak error saat memanggilnya. c.JSON(http.StatusOK, gin.H{ "status": "success", "message": "Hardware terverifikasi", }) } // ========================================================================= // FUNGSI 2: KONTROL DEVICE VIA HOME ASSISTANT & MQTT // ========================================================================= func ControlHardware(c *gin.Context) { var req DeviceControlRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Format data tidak valid"}) return } // --- SKENARIO 1: KONTROL LAMPU (Via MQTT ke ESP32 Relay) --- if req.Device == "lampu1" || req.Device == "lampu2" { broker := os.Getenv("MQTT_BROKER") user := os.Getenv("MQTT_USER") pass := os.Getenv("MQTT_PASSWORD") // Setup Konfigurasi Klien MQTT Golang opts := mqtt.NewClientOptions() opts.AddBroker(broker) opts.SetUsername(user) opts.SetPassword(pass) opts.SetClientID(fmt.Sprintf("Golang-SCLASS-%d", time.Now().Unix())) client := mqtt.NewClient(opts) if token := client.Connect(); token.Wait() && token.Error() != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Golang gagal terhubung ke MQTT Broker"}) return } defer client.Disconnect(250) // Tentukan Topik topic := fmt.Sprintf("sclass/d101/%s", req.Device) // Publish Pesan token := client.Publish(topic, 0, false, req.Action) token.Wait() c.JSON(http.StatusOK, gin.H{ "status": "success", "message": fmt.Sprintf("Berhasil mengirim perintah %s ke %s via MQTT", req.Action, req.Device), }) return } // --- SKENARIO 2: KONTROL AC & PROYEKTOR (Via Home Assistant) --- if req.Device == "ac" || req.Device == "projector" { haURL := os.Getenv("HA_URL") haToken := os.Getenv("HA_TOKEN") var entityID string switch req.Device { case "ac": if req.Action == "on" { entityID = "scene.ac_d101_on" } else { entityID = "scene.ac_d101_off" } case "projector": if req.Action == "on" { entityID = "scene.projector_d101_on" } else { entityID = "scene.projector_d101_off" } } apiURL := fmt.Sprintf("%s/api/services/scene/turn_on", haURL) payload := map[string]string{"entity_id": entityID} jsonPayload, _ := json.Marshal(payload) reqHA, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonPayload)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal membuat request ke HA"}) return } reqHA.Header.Set("Authorization", "Bearer "+haToken) reqHA.Header.Set("Content-Type", "application/json") httpClient := &http.Client{Timeout: 5 * time.Second} resp, err := httpClient.Do(reqHA) if err != nil { c.JSON(http.StatusGatewayTimeout, gin.H{"error": "Gagal menghubungi Home Assistant"}) return } defer resp.Body.Close() c.JSON(http.StatusOK, gin.H{ "status": "success", "message": fmt.Sprintf("Berhasil memicu scene %s", entityID), }) return } // Jika device tidak dikenali c.JSON(http.StatusBadRequest, gin.H{"error": "Device tidak dikenali sistem"}) } func GetPowerStatus(c *gin.Context) { haURL := os.Getenv("HA_URL") haToken := os.Getenv("HA_TOKEN") // Ganti dengan Entity ID sensor daya kamu di Home Assistant entityID := "sensor.kwh_meter_power" 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{} resp, err := client.Do(req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"power": 0}) return } defer resp.Body.Close() var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) // Ambil nilai state (angka watt) powerStr, ok := result["state"].(string) if !ok { c.JSON(http.StatusOK, gin.H{"power": 0}) return } c.JSON(http.StatusOK, gin.H{"power": powerStr}) }