This commit is contained in:
[Valentino Heman Budiarto] 2026-06-12 18:20:16 +07:00
parent ff02b00055
commit dad3d4f519

View File

@ -35,7 +35,7 @@ var DeviceStatusCache = map[string]string{
}
// =========================================================================
// FUNGSI 1: VERIFIKASI TOKEN (Dan Buka Gembok Relay)
// FUNGSI 1: VERIFIKASI TOKEN (Bisa Master & Mahasiswa)
// =========================================================================
func VerifyHardwareCode(c *gin.Context) {
var req VerifyRequest
@ -47,103 +47,87 @@ func VerifyHardwareCode(c *gin.Context) {
tokenInput := req.Token
sekarang := time.Now()
// 1. Token Master CS (Cleaning Service)
if tokenInput == "CS2026" {
fmt.Printf("[VERIFY] Master Token CS digunakan\n")
c.JSON(http.StatusOK, gin.H{
"status": "success", "message": "Token CS Valid", "duration_minutes": 60,
})
return
}
// 2. Token Master Admin
if tokenInput == "ADM999" {
fmt.Printf("[VERIFY] Master Token Admin digunakan\n")
c.JSON(http.StatusOK, gin.H{
"status": "success", "message": "Token Admin Valid", "duration_minutes": 999,
})
return
}
// -------------------------------------------------------------
// TARIK DATA START_TIME & END_TIME MENGGUNAKAN time.Time
// -------------------------------------------------------------
var jamMulai time.Time
var jamSelesai time.Time
sisaMenit := 0
isTokenValid := false
type ResultTime struct {
JamMulai time.Time `gorm:"column:start_time"`
JamSelesai time.Time `gorm:"column:end_time"`
}
var result ResultTime
errBooking := config.DB.Table("bookings").
Select("start_time, end_time").
Where("redeem_code = ?", tokenInput).
Scan(&result).Error
if errBooking == nil && !result.JamSelesai.IsZero() {
jamMulai = result.JamMulai
jamSelesai = result.JamSelesai
// =========================================================
// 1. PENGECEKAN KELOMPOK TOKEN MASTER (Tanpa Cek Waktu)
// =========================================================
if tokenInput == "CS2026" {
fmt.Printf("[VERIFY] Master Token CS digunakan\n")
sisaMenit = 60
isTokenValid = true
} else if tokenInput == "ADM999" {
fmt.Printf("[VERIFY] Master Token Admin digunakan\n")
sisaMenit = 999
isTokenValid = true
} else {
errSchedule := config.DB.Table("class_schedules").
// =========================================================
// 2. PENGECEKAN KELOMPOK TOKEN MAHASISWA (Cek Database & Waktu)
// =========================================================
var jamMulai time.Time
var jamSelesai time.Time
type ResultTime struct {
JamMulai time.Time `gorm:"column:start_time"`
JamSelesai time.Time `gorm:"column:end_time"`
}
var result ResultTime
// Cek Bookings
errBooking := config.DB.Table("bookings").
Select("start_time, end_time").
Where("kode_mk = ?", tokenInput).
Where("redeem_code = ?", tokenInput).
Scan(&result).Error
if errSchedule == nil && !result.JamSelesai.IsZero() {
if errBooking == nil && !result.JamSelesai.IsZero() {
jamMulai = result.JamMulai
jamSelesai = result.JamSelesai
isTokenValid = true
} else {
// Cek Jadwal Kelas Tetap
errSchedule := config.DB.Table("class_schedules").
Select("start_time, end_time").
Where("kode_mk = ?", tokenInput).
Scan(&result).Error
if errSchedule == nil && !result.JamSelesai.IsZero() {
jamMulai = result.JamMulai
jamSelesai = result.JamSelesai
isTokenValid = true
}
}
if !isTokenValid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Token salah atau tidak ditemukan"})
return
}
jamMulaiHariIni := time.Date(sekarang.Year(), sekarang.Month(), sekarang.Day(),
jamMulai.Hour(), jamMulai.Minute(), jamMulai.Second(), 0, sekarang.Location())
jamSelesaiHariIni := time.Date(sekarang.Year(), sekarang.Month(), sekarang.Day(),
jamSelesai.Hour(), jamSelesai.Minute(), jamSelesai.Second(), 0, sekarang.Location())
batasMasukAwal := jamMulaiHariIni.Add(-15 * time.Minute)
if sekarang.Before(batasMasukAwal) {
c.JSON(http.StatusForbidden, gin.H{"error": "Jadwal kelas belum dimulai"})
return
}
selisihWaktu := jamSelesaiHariIni.Sub(sekarang)
sisaMenit = int(selisihWaktu.Minutes())
if sisaMenit <= 0 {
c.JSON(http.StatusForbidden, gin.H{"error": "Waktu peminjaman sudah habis"})
return
}
}
if !isTokenValid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Token salah atau tidak ditemukan"})
return
}
// Ekstrak Jam, Menit, Detik langsung dari objek Time (Sangat Aman & Akurat)
jamMulaiHariIni := time.Date(sekarang.Year(), sekarang.Month(), sekarang.Day(),
jamMulai.Hour(), jamMulai.Minute(), jamMulai.Second(), 0, sekarang.Location())
jamSelesaiHariIni := time.Date(sekarang.Year(), sekarang.Month(), sekarang.Day(),
jamSelesai.Hour(), jamSelesai.Minute(), jamSelesai.Second(), 0, sekarang.Location())
// -------------------------------------------------------------
// LOGIKA PENOLAKAN TOKEN MASA DEPAN
// -------------------------------------------------------------
// Toleransi masuk: Hanya bisa masuk 15 menit sebelum jadwal.
batasMasukAwal := jamMulaiHariIni.Add(-15 * time.Minute)
if sekarang.Before(batasMasukAwal) {
fmt.Printf("[VERIFY] Ditolak: Kelas %s belum mulai\n", tokenInput)
c.JSON(http.StatusForbidden, gin.H{"error": "Jadwal kelas belum dimulai"})
return
}
// -------------------------------------------------------------
// LOGIKA PENOLAKAN TOKEN KADALUARSA
// -------------------------------------------------------------
selisihWaktu := jamSelesaiHariIni.Sub(sekarang)
sisaMenit := int(selisihWaktu.Minutes())
if sisaMenit <= 0 {
fmt.Printf("[VERIFY] Ditolak: Waktu kelas %s sudah habis\n", tokenInput)
c.JSON(http.StatusForbidden, gin.H{"error": "Waktu peminjaman sudah habis"})
return
}
// -------------------------------------------------------------
// JIKA LOLOS SEMUA UJIAN: IZINKAN MASUK & BUKA GEMBOK
// -------------------------------------------------------------
// =========================================================
// 3. JIKA VALID (Master / Mahasiswa), BUKA GEMBOK VIA MQTT
// =========================================================
DeviceStatusCache["lampu1"] = "on"
DeviceStatusCache["lampu2"] = "on"
// --- START BLOK MQTT UNLOCK ---
broker := os.Getenv("MQTT_BROKER")
user := os.Getenv("MQTT_USER")
pass := os.Getenv("MQTT_PASSWORD")
@ -156,19 +140,18 @@ func VerifyHardwareCode(c *gin.Context) {
client := mqtt.NewClient(opts)
if tokenMQTT := client.Connect(); tokenMQTT.Wait() && tokenMQTT.Error() == nil {
// 1. Mengirim sinyal otorisasi "UNLOCK" ke Relay dengan retain=true
// Buka Gembok Relay
client.Publish("sclass/d101/auth", 0, true, "UNLOCK").Wait()
// 2. Opsional: otomatis nyalakan lampu saat token dimasukkan
// 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 berhasil dikirim ke Relay D101\n")
fmt.Printf("[MQTT] Perintah UNLOCK dan ON dikirim (Sisa Menit: %d)\n", sisaMenit)
} else {
fmt.Printf("[MQTT ERROR] Gagal menghubungi broker: %v\n", tokenMQTT.Error())
}
// --- END BLOK MQTT UNLOCK ---
c.JSON(http.StatusOK, gin.H{
"status": "success",
@ -177,9 +160,6 @@ func VerifyHardwareCode(c *gin.Context) {
})
}
// =========================================================================
// FUNGSI 2: KONTROL DEVICE VIA HOME ASSISTANT & MQTT
// =========================================================================
// =========================================================================
// FUNGSI 2: KONTROL DEVICE VIA HOME ASSISTANT & MQTT
// =========================================================================
@ -246,9 +226,17 @@ func ControlHardware(c *gin.Context) {
switch req.Device {
case "ac":
if req.Action == "on" { entityID = "scene.ac_d101_on" } else { entityID = "scene.ac_d101_off" }
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" }
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)
@ -261,7 +249,9 @@ func ControlHardware(c *gin.Context) {
reqHA.Header.Set("Content-Type", "application/json")
httpClient := &http.Client{Timeout: 5 * time.Second}
resp, _ := httpClient.Do(reqHA)
if resp != nil { resp.Body.Close() }
if resp != nil {
resp.Body.Close()
}
}
DeviceStatusCache[req.Device] = req.Action
@ -314,4 +304,4 @@ func GetHardwareStatus(c *gin.Context) {
"status": "success",
"data": DeviceStatusCache,
})
}
}