Rectronx Circuits
Back to Blog
Tutorial Projek Akhir Tahun7 min read2026-06-17

Tutorial Projek Akhir Tahun: Cara Bina Sistem Pengurusan dan Automasi Tenaga Bilik Darjah Pintar

Bina sistem automasi tenaga bilik darjah yang boleh kawal lampu, kipas, dan AC secara automatik berdasarkan kehadiran dan jadual, dengan pemantauan penggunaan elektrik real-time. Projek FYP yang menyentuh isu kecekapan tenaga di Malaysia.

R

Rectronx

2026-06-17

Smart classroom energy management automation system

Tutorial Projek Akhir Tahun: Cara Bina Sistem Pengurusan dan Automasi Tenaga Bilik Darjah Pintar

Pernah perasan tak, bilik darjah atau dewan kuliah yang lampu dan kipas masih menyala walaupun sudah tiada sesiapa? Kita semua pernah nampak keadaan ni — dan setiap kilowatt-hour yang membazir tu adalah kos yang ditanggung universiti (dan akhirnya rakyat) tanpa sebab.

Di Malaysia, bangunan komersial dan institusi pendidikan menyumbang lebih 30% daripada jumlah penggunaan tenaga elektrik negara. Projek FYP ini bertujuan selesaikan masalah sebenar ini.


Kenapa Projek Ini Sangat Relevan?

Malaysia komited dengan sasaran kecekapan tenaga sebagai sebahagian daripada Dasar Tenaga Negara. Projek korang secara langsung menyentuh isu sustainability — ini buat projek korang bukan sahaja teknikal tetapi juga relevant secara polisi dan sosial.

Dari sudut teknikal, projek ini melibatkan kawalan beban AC (mains voltage), yang menunjukkan korang tahu cara kerja dengan sistem kuasa sebenar. Ini tunjukkan kematangan engineering.


Senarai Komponen

KomponenSpesifikasiAnggaran Harga
ESP32 DevKit V138-pinRM 20–28
PIR Sensor HC-SR501Adjustable delay, sensitivityRM 8–12 (x3)
Relay Module 4-channel5V coil, 10A contactRM 15–20
PZEM-004T v3AC Energy Meter, 100ARM 35–50
Current TransformerSCT013-100ARM 15–20
DHT22Suhu & KelembapanRM 10–15
RTC DS3231I2C Real-time ClockRM 10–15
LCD 20x4 I2CDisplayRM 18–25
Touch Sensor TTP223Butang sentuh untuk overrideRM 3–5 (x4)
LED Strip 12VSimulasi lampu untuk demoRM 20–30
Mosfet IRF520Driver LED stripRM 8–12
Kotak ProjekDIN rail atau wall mountRM 25–35

Jumlah anggaran: RM 187–267

Amaran Keselamatan: PZEM-004T bekerja dengan voltan AC 240V. Jangan sambung ke bekalan mains sebelum faham sepenuhnya. Untuk demo FYP, boleh simulasikan dengan LED strip 12V dan relay.


Logik Kawalan Automasi

Sistem menggunakan dua sumber maklumat untuk buat keputusan:

  1. Jadual kelas (dari RTC): Sistem tahu bila ada kelas dijadualkan
  2. Sensor PIR (kehadiran sebenar): Sistem kesan adakah ada orang dalam bilik

Gabungan kedua-dua sumber ini memberikan kawalan yang lebih robust:

HIDUPKAN lampu & kipas jika:
  - (Ada orang dalam bilik) ATAU
  - (Dalam tempoh jadual kelas ±15 minit)

HIDUPKAN AC jika:
  - Ada kelas DAN suhu > 28°C

Gambarajah Pendawaian

PIR Sensor (x3) ke ESP32:

  • PIR1 (depan) → GPIO34, PIR2 (tengah) → GPIO35, PIR3 (belakang) → GPIO32
  • Semua: VCC→5V, GND→GND
  • Laraskan delay PIR ke 30–60 saat supaya lampu tak terus padam bila orang duduk diam

Relay Module 4-channel ke ESP32:

  • IN1→GPIO26, IN2→GPIO27, IN3→GPIO14, IN4→GPIO12
  • VCC→5V, GND→GND
  • Kebanyakan relay module adalah active LOW (relay ON bila pin LOW)

PZEM-004T ke ESP32:

  • TX→GPIO16 (RX ESP32), RX→GPIO17 (TX ESP32)
  • Bahagian volt: sambung ke 240V AC dengan fius 10A
  • CT coil: lingkar pada satu kabel fasa

Touch Sensor TTP223 (x4):

  • GPIO4 (lampu), GPIO5 (kipas), GPIO18 (AC), GPIO19 (override)

RTC DS3231 & LCD (I2C):

  • SDA→GPIO21, SCL→GPIO22

Kod Arduino/ESP32

#include <WiFi.h>
#include <HTTPClient.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <DHT.h>
#include <PZEM004Tv30.h>
#include <ArduinoJson.h>

const char* ssid       = "WiFi_Kampus";
const char* password   = "Password_WiFi";
const char* serverURL  = "http://dashboard.server.com/api/energy";

#define PIR1_PIN    34
#define PIR2_PIN    35
#define PIR3_PIN    32
#define DHT_PIN     4
#define RELAY_LAMPU 26
#define RELAY_KIPAS 27
#define RELAY_AC    14
#define RELAY_PAPAN 12
#define TOUCH_LAMPU 5
#define TOUCH_KIPAS 18
#define TOUCH_AC    19
#define TOUCH_OVR   21  // Override button

struct JadualKelas {
  int hariMinggu; // 0=Ahad, 1=Isnin...6=Sabtu
  int jamMula, minMula, jamTamat, minTamat;
};

JadualKelas jadual[] = {
  {1, 8, 0, 10, 0},   // Isnin 8:00–10:00
  {1, 14, 0, 16, 0},  // Isnin 14:00–16:00
  {2, 10, 0, 12, 0},  // Selasa 10:00–12:00
  {3, 8, 0, 10, 0},   // Rabu 8:00–10:00
  {4, 14, 0, 17, 0},  // Khamis 14:00–17:00
  {5, 9, 0, 11, 0},   // Jumaat 9:00–11:00
};
const int BILANGAN_JADUAL = 6;
const unsigned long TIMEOUT_KOSONG = 300000; // 5 minit

DHT dht(DHT_PIN, DHT22);
LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS3231 rtc;
PZEM004Tv30 pzem(Serial2, 16, 17);

bool statusLampu = false, statusKipas = false, statusAC = false;
bool modManual = false, adaOrang = false;
unsigned long lastMotion = 0;
float voltas, amper, kuasa, tenaga;
unsigned long lastDashboard = 0;

bool periksaJadual() {
  DateTime now = rtc.now();
  int masaSekarang = now.hour() * 60 + now.minute();

  for (int i = 0; i < BILANGAN_JADUAL; i++) {
    if (jadual[i].hariMinggu == now.dayOfTheWeek()) {
      int masaMula  = jadual[i].jamMula * 60 + jadual[i].minMula;
      int masaTamat = jadual[i].jamTamat * 60 + jadual[i].minTamat;
      if (masaSekarang >= (masaMula - 15) && masaSekarang < masaTamat) return true;
    }
  }
  return false;
}

bool periksaKehadiran() {
  if (digitalRead(PIR1_PIN) || digitalRead(PIR2_PIN) || digitalRead(PIR3_PIN)) {
    lastMotion = millis();
    return true;
  }
  return (millis() - lastMotion < TIMEOUT_KOSONG);
}

void kawalRelay(int pin, bool &status, bool hidupkan) {
  if (status != hidupkan) {
    status = hidupkan;
    digitalWrite(pin, hidupkan ? LOW : HIGH); // Active LOW
  }
}

void bacaTenaga() {
  voltas = pzem.voltage();
  amper  = pzem.current();
  kuasa  = pzem.power();
  tenaga = pzem.energy();
}

void kendalikanTouch() {
  static unsigned long lastTouch = 0;
  if (millis() - lastTouch < 500) return;

  if (digitalRead(TOUCH_OVR)) {
    modManual = !modManual;
    lastTouch = millis();
  }

  if (modManual) {
    if (digitalRead(TOUCH_LAMPU)) { kawalRelay(RELAY_LAMPU, statusLampu, !statusLampu); lastTouch = millis(); }
    if (digitalRead(TOUCH_KIPAS)) { kawalRelay(RELAY_KIPAS, statusKipas, !statusKipas); lastTouch = millis(); }
    if (digitalRead(TOUCH_AC))    { kawalRelay(RELAY_AC,    statusAC,    !statusAC);    lastTouch = millis(); }
  }
}

void kemaskiniLCD() {
  DateTime now = rtc.now();
  lcd.clear();
  char buf[20];
  sprintf(buf, "%02d:%02d %02d/%02d/%04d", now.hour(), now.minute(), now.day(), now.month(), now.year());
  lcd.setCursor(0, 0); lcd.print(buf);
  lcd.setCursor(0, 1);
  lcd.print("L:" + String(statusLampu ? "ON " : "OFF") +
            " K:" + String(statusKipas ? "ON " : "OFF") +
            " AC:" + String(statusAC ? "ON" : "OFF"));
  lcd.setCursor(0, 2);
  lcd.print("W:" + String(kuasa, 0) + " T:" + String(dht.readTemperature(), 1) + "C");
  lcd.setCursor(0, 3);
  lcd.print(modManual ? "MOD:MANUAL " : "MOD:AUTO   ");
  lcd.print(adaOrang ? "ADA" : "KOSONG");
}

void hantarDashboard() {
  if (WiFi.status() != WL_CONNECTED) return;
  DateTime now = rtc.now();
  float suhu = dht.readTemperature();

  StaticJsonDocument<300> doc;
  doc["timestamp"] = now.unixtime();
  doc["voltas"] = voltas; doc["amper"] = amper;
  doc["kuasa_w"] = kuasa; doc["tenaga_kwh"] = tenaga;
  doc["suhu"] = suhu; doc["ada_orang"] = adaOrang;
  doc["lampu"] = statusLampu; doc["kipas"] = statusKipas;
  doc["ac"] = statusAC; doc["mod_manual"] = modManual;
  String body; serializeJson(doc, body);

  HTTPClient http;
  http.begin(serverURL);
  http.addHeader("Content-Type", "application/json");
  http.POST(body); http.end();
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  for (int pin : {PIR1_PIN, PIR2_PIN, PIR3_PIN}) pinMode(pin, INPUT);
  for (int pin : {RELAY_LAMPU, RELAY_KIPAS, RELAY_AC, RELAY_PAPAN})
    { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); } // Semua relay OFF
  for (int pin : {TOUCH_LAMPU, TOUCH_KIPAS, TOUCH_AC, TOUCH_OVR}) pinMode(pin, INPUT);

  dht.begin(); lcd.init(); lcd.backlight(); rtc.begin();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { delay(500); }
  Serial.println("WiFi OK");
}

void loop() {
  kendalikanTouch();
  adaOrang = periksaKehadiran();
  bacaTenaga();

  if (!modManual) {
    bool adaKelas = periksaJadual();
    bool perluHidup = adaOrang || adaKelas;
    kawalRelay(RELAY_LAMPU, statusLampu, perluHidup);
    kawalRelay(RELAY_KIPAS, statusKipas, perluHidup);
    float suhu = dht.readTemperature();
    kawalRelay(RELAY_AC, statusAC, (adaKelas && suhu > 28.0));
  }

  kemaskiniLCD();

  if (millis() - lastDashboard > 30000) {
    hantarDashboard();
    lastDashboard = millis();
  }

  delay(1000);
}

Langkah Demi Langkah

Langkah 1 — Tentukan Skop Bilik Darjah Pilih bilik darjah yang spesifik sebagai konteks. Buat pelan lantai mudah dan tunjukkan di mana sensor dan beban diletakkan.

Langkah 2 — Isikan Jadual Kelas Edit array jadual[] untuk sepadan dengan jadual bilik darjah yang dipilih. Dapatkan jadual sebenar dari fakulti jika boleh.

Langkah 3 — Kalibrasi PIR Sensor Laraskan sensitivity dan delay PIR. Uji dengan berjalan dan duduk diam — pastikan sistem detect kehadiran dengan betul.

Langkah 4 — Setup PZEM-004T dengan Berhati-hati Baca manual dengan teliti. Untuk ujian, gunakan beban kecil seperti lampu mentol. Jangan uji dengan beban besar dulu.

Langkah 5 — Bina Dashboard Pemantauan Tenaga Dashboard web yang papar graf penggunaan kuasa dari masa ke masa adalah value-add yang significant.


Tips Pembentangan

  • Quantify penjimatan: "Kalau lampu dan kipas dimatikan 2 jam sehari apabila bilik kosong, fakulti boleh jimat RM X sebulan."
  • Tunjukkan perbandingan sebelum-selepas: Data penggunaan elektrik sebelum vs selepas sistem dipasang.
  • Demo mod manual: Tunjukkan override capability — sistem tidak sekadar automasi buta.
  • Terangkan logik jadual + PIR: Kombinasi lebih robust dari sekadar PIR sahaja.

Penutup

Sistem automasi tenaga bilik darjah ini tunjukkan bahawa engineering boleh membuat perbezaan nyata dalam kecekapan operasi institusi. Untuk ESP32, PIR sensor, relay module, dan PZEM-004T, lawati Rectronx di rectronx.com.

Need Help With Your FYP?

We've helped hundreds of students complete their projects on time. Get a free quote today.

Chat with Rectronx