Monitoring Teknologi Stop Kontak Pintar Dengan Sensor PZEM-004T Berbasis Raspberry Pi Pico
MONITORING
TEKNOLOGI STOP KONTAK PINTAR DENGAN SENSOR PZEM-004T BERBASIS RASPBERRY PI PICO
Aldino Sultansyah1, Frisca Syaharani2,
Muhammad Satrio Adhy3, Salsabila Chairunisa4
Jurusan Teknik Elektro, Prodi Teknologi Rekayasa Elektronika, Politeknik
Negeri Semarang
Jl. Prof. Soedarto, Tembalang, Kec. Tembalang, Kota Semarang, Jawa Tengah,
50275
1aldino.43423003@mhs.polines.ac.id, 2frisca.43423009@ mhs.polines.ac.id, 3satrio.43423015@mhs.polines.ac.id
, 4salsabila.43423022@mhs.polines.ac.id
Abstrak
Energi listrik merupakan kebutuhan vital dalam kehidupan
sehari-hari dan sektor industri, namun alat ukur konvensional yang ada saat ini
masih memiliki keterbatasan karena hanya menampilkan total konsumsi energi
tanpa memberikan informasi penggunaan secara waktu nyata (real-time).
Keterbatasan ini membuat pengguna kesulitan memantau parameter listrik seperti
tegangan, arus, daya, energi, hingga biaya secara langsung. Untuk mengatasi
permasalahan tersebut, proyek ini merancang dan mengimplementasikan sistem
"Stop Kontak Pintar++" berbasis mikrokontroler Raspberry Pi Pico dan
sensor PZEM-004T sebagai solusi monitoring energi listrik yang murah, akurat,
dan informatif. Sistem ini
dirancang untuk mengukur berbagai parameter kelistrikan meliputi Tegangan (V),
Arus (A), Daya Aktif (W), Energi (kWh), Frekuensi (Hz), dan Power Factor
secara real-time. Selain fungsi monitoring, alat ini juga
mengintegrasikan sistem proteksi pintar berupa Over-Power Protection
menggunakan modul relay 5V yang secara otomatis memutus aliran listrik
jika beban yang terpasang melebihi batas yang diatur oleh pengguna. Data hasil
pengukuran disajikan secara interaktif melalui layar LCD
Kata
kunci: Stop Kontak Pintar, Raspberry Pi Pico, Sensor
PZEM-004T, Real-time Monitoring, Over-Power Protection.
I. PENDAHULUAN
A.
LATAR BELAKANG
Energi listrik telah menjadi kebutuhan vital dalam
kehidupan sehari-hari dan industri. Namun, alat ukur konvensional yang ada saat
ini masih sangat terbatas karena hanya menampilkan total akumulasi konsumsi
energi. Akibatnya, pengguna kesulitan untuk memantau fluktuasi parameter
penting seperti tegangan, arus, daya, dan estimasi biaya pemakaian secara waktu
nyata (real-time). Ketiadaan informasi ini membuat pola penggunaan
listrik menjadi tidak terkontrol dan menyulitkan deteksi dini terhadap
pemborosan energi.
Selain masalah transparansi data, stop kontak biasa
juga belum memiliki sistem proteksi mandiri yang adaptif. Ketika beban
elektronik yang terpasang melebihi kapasitas, risiko terjadinya panas berlebih
(overheating) hingga korsleting listrik menjadi sangat tinggi. Oleh
karena itu, diperlukan sebuah inovasi sistem monitoring energi listrik yang
murah, akurat, informatif, sekaligus memiliki fitur proteksi aktif.
Melalui proyek Stop Kontak Pintar++, kendala tersebut
coba diselesaikan. Menggunakan
Raspberry Pi Pico sebagai pengendali utama dan sensor PZEM-004T, alat ini mampu
mengukur parameter kelistrikan secara presisi. Sistem ini juga dilengkapi
dengan modul relay untuk memutus aliran secara otomatis jika terjadi
kelebihan beban (Over-Power Protection), layar LCD lokal yang
interaktif, serta dashboard laptop untuk memantau grafik pemakaian dan
mencetak laporan langsung ke format Excel.
B.
RUMUSAN MASALAH
Berdasarkan
uraian di atas, terdapat beberapa perumusan masalah yang harus
diperhatikan, yaitu:
1.
Bagaimana
cara mengukur dan memantau parameter kelistrikan (tegangan, arus, daya, energi,
frekuensi, dan power factor) secara waktu nyata (real-time)?
2.
Bagaimana
cara mengintegrasikan sistem proteksi otomatis jika terjadi penggunaan daya
listrik yang melebihi batas (over-power)?
3.
Bagaimana
menampilkan data pemantauan listrik agar mudah dipahami secara lokal sekaligus
dapat dianalisis dalam bentuk grafik dan laporan di laptop?
C.
BATASAN MASALAH
Dalam
pembuatan projek ini terdapat Batasan masalah terhadap sistem ini, yaitu:
1. Pengendali
utama yang digunakan terbatas pada mikrokontroler Raspberry Pi Pico.
2. Sensor yang digunakan untuk membaca parameter
kelistrikan khusus menggunakan PZEM-004T.
3. Parameter yang diukur terbatas pada Tegangan (V), Arus
(A), Daya Aktif (W), Energi (kWh), Frekuensi (Hz), dan Power Factor.
4. Tampilan lokal menggunakan layar LCD 16x2 dengan
navigasi 3 tombol fisik, sedangkan monitoring grafis dan ekspor laporan (format
Excel/CSV) memerlukan koneksi ke aplikasi dashboard di laptop.
5. Sistem proteksi otomatis hanya bekerja memutus aliran
listrik menggunakan modul relay 5V berdasarkan batas daya (Over-Power
Protection) yang diatur pengguna.
D.
TUJUAN
Tujuan
dari pembuatan projek ini yaitu:
1.
Monitoring
Parameter Listrik: Mampu mengukur Tegangan, Arus, Daya Aktif, Energi,
Frekuensi, dan Power Factor secara real-time.
2.
Sistem
Proteksi Pintar: Menyediakan perlindungan otomatis (Over-Power Protection)
dengan memutus aliran listrik melalui relay jika daya melebihi batas.
3.
Antarmuka
Interaktif: Menyajikan data ke dalam tampilan LCD 16x2 lokal yang mudah
dipahami dengan navigasi tiga tombol.
4.
Perekaman
& Analisis Data: Mendukung fitur live streaming ke aplikasi dashboard
laptop untuk pemantauan grafik secara langsung dan pencetakan data ke format
Excel (CSV).
II. METODOLOGI
Metodologi
proyek ini diawali dengan analisis kebutuhan komponen untuk mengintegrasikan
Raspberry Pi Pico, sensor PZEM-004T, modul relay 5V, LCD 16x2 I2C, logic
shifter, dan tiga tombol fisik. Tahap berikutnya adalah perancangan
perangkat keras (hardware), di mana aliran listrik PLN dihubungkan ke
sensor PZEM-004T untuk diukur parameternya, lalu diteruskan ke beban lampu
melalui relay. Penggunaan logic shifter diwajibkan untuk
menjembatani perbedaan level tegangan logika antara Raspberry Pi Pico (3.3V)
dengan komponen 5V lainnya. Selanjutnya, dilakukan perancangan perangkat lunak
(software) pada mikrokontroler untuk mengolah data sensor melalui
komunikasi UART, mengatur sistem navigasi menu pada LCD, serta menjalankan
algoritma proteksi otomatis (Over-Power Protection). Bersamaan dengan
itu, dirancang aplikasi dashboard pada laptop untuk menangkap aliran
data via USB, memvisualisasikannya ke dalam grafik secara langsung, dan
mengekspor laporan ke format Excel. Tahap akhir diakhiri dengan pengujian
fungsionalitas dan integrasi menyeluruh untuk memastikan akurasi pembacaan
alat, kecepatan respons proteksi relay, serta kestabilan live
streaming data.
III. KAJIAN PUSTAKA
Pembahasan dalam bagian ini meliputi perancangan
dan komponen apa saja yang digunakan dalam projek ini.
A.
Sensor PZEM-004T
Sensor PZEM-004T berfungsi
sebagai modul pengukur parameter kelistrikan utama yang terhubung langsung
dengan sumber listrik PLN (AC 220V 50 Hz). Sensor ini mampu mengukur secara
simultan berbagai parameter penting seperti Tegangan (V), Arus (A), Daya Aktif
(W), Energi (kWh), Frekuensi (Hz), dan Power Factor secara waktu nyata (real-time).
Data hasil pengukuran dikirim ke pengendali utama menggunakan protokol
komunikasi UART (TTL) berlevel logika 5V.
Gambar 1. Sensor PZEM-004T
B.
Raspberry Pi Pico
Raspberry Pi Pico digunakan
sebagai unit pengendali utama (mikrokontroler) dalam proyek ini. Perangkat ini
bertanggung jawab untuk menerima data mentah dari sensor melalui komunikasi
serial, mengolah algoritma pembatas daya (Over-Power Protection),
mengatur navigasi menu input, serta mengontrol keluaran data ke LCD dan
aplikasi dashboard di laptop. Komponen ini bekerja dengan level tegangan
logika 3.3V pada pin GPIO-nya.
Gambar 2. Raspberry Pi Pico
C.
Relay Modul 5V
Modul relay 5V berperan
sebagai sakelar elektronik yang dikendalikan langsung oleh mikrokontroler untuk
memutus atau menghubungkan aliran listrik menuju beban (lampu/perangkat
elektronik). Dalam sistem ini, relay bertindak sebagai aktuator utama
untuk sistem proteksi pintar (Over-Power Protection) yang akan aktif
secara otomatis demi mencegah terjadinya panas berlebih (overheating)
atau hubungan pendek arus listrik.

Gambar 3. Relay Modul 5V
D.
LCD I2C
Layar LCD
Gambar 4. LCD I2C
E.
Push Button
Tombol fisik atau push
button dalam proyek ini berjumlah tiga buah dan dipasang sebagai komponen
masukan (input user). Tombol-tombol ini berfungsi sebagai pemilih menu (menu
navigator) lokal, yang memungkinkan pengguna untuk berinteraksi dengan
alat, beralih tampilan informasi pada layar, serta mengatur konfigurasi batas
daya maksimum (threshold) secara manual.
Gambar 5.
Push Button
F. Diagram Blok
Gambar 6. Diagram Blok
G. Diagram Alir
Gambar
7. Diagram
Alir
H.
Diagram Skematik
Gambar
8.
Diagram Skematik
I.
Program
a. Program Main.py
|
#
Memanggil modul bawaan untuk kontrol Pin, Serial (UART), dan I2C from
machine import Pin, UART, I2C #
Memanggil modul waktu untuk jeda (delay) dan perhitungan waktu (milidetik) import
time #
Memanggil modul OS untuk mengelola file sistem (membuat/menyimpan file csv) import
os #
Memanggil pustaka eksternal untuk mengendalikan layar LCD via I2C from
pico_i2c_lcd import I2cLcd
#
================= PENGATURAN PIN & KOMUNIKASI ================= #
Mengaktifkan jalur I2C0 di pin GP0 (SDA) dan GP1 (SCL) dengan kecepatan
400kHz i2c
= I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
#
Mengaktifkan jalur UART1 di pin GP4 (TX) dan GP5 (RX) dengan baudrate 9600
untuk PZEM uart
= UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
#
Mengatur pin tombol sebagai INPUT dengan Internal PULL_UP (default HIGH,
ditekan jadi LOW) btn_ok
= Pin(6, Pin.IN, Pin.PULL_UP) btn_kiri
= Pin(12, Pin.IN, Pin.PULL_UP) btn_kanan
= Pin(7, Pin.IN, Pin.PULL_UP)
#
Mengatur pin relay dan buzzer sebagai OUTPUT relay
= Pin(16, Pin.OUT) buzzer
= Pin(15, Pin.OUT)
#
Memastikan relay dalam kondisi mati (0) saat program pertama kali berjalan relay.value(0)
#
================= INISIALISASI LCD ================= #
Mencari alamat perangkat I2C yang terhubung ke Pico devices
= i2c.scan() #
Jika ada perangkat I2C yang ditemukan (panjang list tidak nol) if
len(devices) != 0: # Mendeklarasikan objek LCD dengan alamat
yang ditemukan, ukuran 2 baris x 16 kolom lcd = I2cLcd(i2c, devices[0], 2, 16) # Membersihkan layar LCD dari karakter
acak lcd.clear() # Menampilkan teks awalan lcd.putstr("Sistem Memulai..") # Jeda 1 detik agar tulisan bisa dibaca time.sleep(1) # Bersihkan layar kembali untuk bersiap
masuk ke menu utama lcd.clear()
#
================= FUNGSI BACA PZEM ================= def
read_pzem(): # Deretan byte Modbus RTU untuk meminta
data (Read Input Register) ke PZEM req = b'\x01\x04\x00\x00\x00\x0A\x70\x0D' # Mengirim perintah tersebut melalui
jalur Serial/UART uart.write(req) # Jeda 0.2 detik memberi waktu PZEM untuk
memproses dan membalas data time.sleep(0.2) # Mengecek apakah ada data balasan yang
masuk di buffer UART if uart.any(): # Membaca seluruh data balasan dan
menyimpannya di variabel 'resp' resp = uart.read() # Memastikan balasan komplit (minimal
25 byte sesuai spesifikasi PZEM) if len(resp) >= 25: # Menggabungkan High Byte dan Low
Byte lalu membaginya sesuai resolusi sensor voltage = (resp[3] << 8 |
resp[4]) / 10.0 # Resolusi 0.1 V current = (resp[5] << 8 |
resp[6]) / 1000.0 # Resolusi 0.001 A power = (resp[9] << 8 |
resp[10]) / 10.0 # Resolusi 0.1 W energy = (resp[13] << 8 |
resp[14]) # Resolusi 1 Wh # Mengembalikan ke-4 nilai
tersebut ke program utama return voltage, current, power,
energy # Jika gagal membaca/tidak ada alat,
kembalikan nilai kosong (None) return None, None, None, None
#
================= FUNGSI BANTUAN (UTILITY) ================= def
beep(): """Membunyikan buzzer
selama 0.05 detik sebagai efek suara tombol""" buzzer.value(1) # Nyalakan buzzer time.sleep(0.05) # Tunggu 50 milidetik buzzer.value(0) # Matikan buzzer
def
tunggu_lepas(btn): """Mencegah double-click
dengan menahan program selama tombol masih ditekan""" # Selama tombol masih bernilai 0
(ditekan), program akan berputar di sini while btn.value() == 0: time.sleep(0.05) # Cek setiap 50 milidetik # Beri sedikit jeda ekstra setelah tombol
dilepas agar stabil (debouncing) time.sleep(0.05)
#
================= VARIABEL SISTEM UI & KONTROL ================= #
Daftar menu yang akan ditampilkan di layar menu_list
= ["1. Parameter", "2. Relay", "3. Batas Daya",
"4. Streaming", "5. Info Sistem"] #
Indeks untuk melacak menu mana yang sedang dipilih (dimulai dari 0) menu_index
= 0
#
Penanda apakah kita sedang di daftar menu (True) atau di dalam isi menu
(False) in_menu
= True #
Penanda halaman untuk membagi tampilan sensor (0: Tegangan/Arus, 1:
Daya/Energi) param_page
= 0 #
Penanda status hidup/mati relay internal (default mati) relay_status
= False
#
Variabel Sensor & Telemetri last_pzem_read
= 0 # Menyimpan catatan waktu
terakhir sensor dibaca v,
i, p, e = 0, 0, 0, 0 # Variabel
penampung nilai sensor terakhir power_limit
= 0 # Batas daya proteksi, 0
berarti proteksi OFF is_streaming
= False # Penanda apakah mode kirim
data live ke laptop sedang aktif
#
================= LOOP UTAMA ================= while
True: # Program akan berjalan terus menerus di dalam blok ini # ---------------- 1. BACA SENSOR &
PROTEKSI REAL-TIME ---------------- # Jika selisih waktu sekarang dan
pembacaan terakhir lebih dari 1000ms (1 detik) if time.ticks_ms() - last_pzem_read >
1000: # Panggil fungsi baca sensor, simpan
hasilnya ke variabel sementara temp_v, temp_i, temp_p, temp_e =
read_pzem() # Jika hasilnya valid (bukan None) if temp_v is not None: # Perbarui variabel utama dengan
nilai terbaru v, i, p, e = temp_v, temp_i,
temp_p, temp_e # --- LOGIKA STREAMING LIVE KE
LAPTOP --- # Jika mode streaming aktif (ON) if is_streaming: # Kirim data ke port Serial
USB laptop, format CSV (dipisah koma)
print(f"{v},{i},{p},{e}") # --- LOGIKA PROTEKSI OVER-POWER
--- # Jika batas daya tidak 0, DAN
relay sedang ON, DAN daya (p) melebihi batas if power_limit > 0 and
relay_status == True and p > power_limit: # Paksa status relay menjadi
False relay_status = False # Matikan sakelar relay
secara fisik relay.value(0) # Bunyikan alarm peringatan
sebanyak 3 kali berturut-turut for _ in range(3): beep() time.sleep(0.1) # Catat waktu saat ini sebagai waktu
pembacaan terakhir last_pzem_read = time.ticks_ms()
# ---------------- 2. BACA INPUT TOMBOL
---------------- # JIKA TOMBOL KIRI DITEKAN if btn_kiri.value() == 0: beep() # Bunyikan suara if in_menu: # Geser pilihan menu ke kiri
(berputar kembali ke belakang jika < 0) menu_index = (menu_index - 1) %
len(menu_list) else: # Aksi tombol kiri di dalam menu
spesifik if menu_index == 0: param_page = 0 # Di Menu
Parameter: Tampilkan Tegangan & Arus elif menu_index == 1: # Di Menu Relay: Ubah status
kebalikannya (ON jadi OFF, OFF jadi ON) relay_status = not
relay_status relay.value(1 if relay_status
else 0) # Update fisik relay elif menu_index == 2: # Di Menu Batas Daya: Kurangi
batas sebanyak 10W (tidak boleh kurang dari 0) power_limit = max(0,
power_limit - 10) elif menu_index == 3: # Di Menu Streaming: Tombol
Kiri berfungsi menyalakan/mematikan Live Data is_streaming = not
is_streaming lcd.clear() if is_streaming: lcd.putstr("Live
Stream: ON ")
print("---START---") # Tanda mulai di laptop else: lcd.putstr("Live
Stream: OFF")
print("---END---") #
Tanda berhenti di laptop time.sleep(1) # Tahan layar 1
detik agar tulisan terbaca # Tunggu sampai tombol benar-benar
dilepas, lalu bersihkan layar tunggu_lepas(btn_kiri) lcd.clear()
# JIKA TOMBOL KANAN DITEKAN if btn_kanan.value() == 0: beep() if in_menu: # Geser pilihan menu ke kanan
(berputar kembali ke awal jika melewati batas) menu_index = (menu_index + 1) %
len(menu_list) else: # Aksi tombol kanan di dalam menu
spesifik if menu_index == 0: param_page = 1 # Di Menu
Parameter: Tampilkan Daya & Energi elif menu_index == 1: # Di Menu Relay: Lakukan hal
yang sama seperti tombol kiri (Toggle) relay_status = not
relay_status relay.value(1 if relay_status
else 0) elif menu_index == 2: # Di Menu Batas Daya: Tambah
batas sebanyak 10W (maksimal 2200W) power_limit = min(2200,
power_limit + 10) elif menu_index == 3: # Di Menu Streaming: Tombol
Kanan berfungsi menyimpan 1 baris log ke memori internal lcd.clear()
lcd.putstr("Tersimpan!
") try: # Buka file
"data_log.csv" dengan mode "a" (append = tambah di akhir
baris) with
open("data_log.csv", "a") as file: # Tulis nilai V, I,
P, E dipisahkan koma, lalu diakhiri \n (baris baru)
file.write(f"{v},{i},{p},{e}\n") except OSError: # Abaikan error jika
gagal menyimpan (misal memori penuh) pass time.sleep(1) # Tahan layar 1
detik lcd.clear() # Tunggu sampai tombol dilepas, lalu
bersihkan layar tunggu_lepas(btn_kanan) lcd.clear()
# JIKA TOMBOL OK DITEKAN if btn_ok.value() == 0: beep() # Balik keadaan variabel in_menu
(Masuk menu jika di luar, keluar menu jika di dalam) in_menu = not in_menu tunggu_lepas(btn_ok) lcd.clear()
# ---------------- 3. TAMPILKAN UI LCD
---------------- # JIKA BERADA DI DAFTAR MENU if in_menu: lcd.move_to(0, 0) # Pindahkan kursor
ke Baris 1, Kolom 1 lcd.putstr("Pilih Menu: ") lcd.move_to(0, 1) # Pindahkan kursor
ke Baris 2, Kolom 1 # Ambil nama menu dari list
berdasarkan indeks, beri kurung siku teks_menu =
f"<{menu_list[menu_index]}>" # Cetak dengan format spasi sisa agar
memenuhi 16 kolom (menimpa teks lama) lcd.putstr(f"{teks_menu:
<16}") # JIKA MASUK KE DALAM ISI MENU
(MENGGUNAKAN TOMBOL OK) else: if menu_index == 0: # --- TAMPILAN
MENU 1: PARAMETER --- if v is not None: if param_page == 0: lcd.move_to(0, 0) lcd.putstr(f"V:
{v:.1f} V ") # Format 1 angka
desimal lcd.move_to(0, 1) lcd.putstr(f"I:
{i:.2f} A ") # Format 2 angka
desimal else: lcd.move_to(0, 0) lcd.putstr(f"P:
{p:.1f} W ") # Format 1 angka
desimal lcd.move_to(0, 1) lcd.putstr(f"E: {e}
Wh ") # Tampilkan utuh (bulat) else: # Jika PZEM belum merespon lcd.move_to(0, 0) lcd.putstr("Menunggu
PZEM...") lcd.move_to(0, 1) lcd.putstr("Tekan OK:
Keluar") elif menu_index == 1: # --- TAMPILAN
MENU 2: KONTROL RELAY --- lcd.move_to(0, 0) if relay_status: lcd.putstr("Status:
ON ") else: lcd.putstr("Status:
OFF ") lcd.move_to(0, 1) lcd.putstr("< Ubah
> OK:Kel") # Panduan tombol di
baris kedua elif menu_index == 2: # --- TAMPILAN
MENU 3: BATAS DAYA --- lcd.move_to(0, 0) if power_limit == 0: lcd.putstr("Limit:
OFF ") else: lcd.putstr(f"Limit:
{power_limit} W ") lcd.move_to(0, 1) lcd.putstr("<Kurang Tambah>") # Panduan tombol di baris
kedua elif menu_index == 3: # --- TAMPILAN
MENU 4: STREAMING/LOGGER --- lcd.move_to(0, 0) if is_streaming: lcd.putstr("Status: LIVE
OND") # Ada typo sedikit di 'OND', biasanya 'ON ' else: lcd.putstr("Data
Logger ") lcd.move_to(0, 1) lcd.putstr("<Live Simpan>") # Kiri untuk Live,
Kanan untuk Simpan Log elif menu_index == 4: # --- TAMPILAN
MENU 5: INFO SISTEM --- lcd.move_to(0, 0) lcd.putstr("Sistem v1.3 ") # Menampilkan versi sistem lcd.move_to(0, 1) lcd.putstr("Tekan OK:
Keluar")
# Memberikan sedikit waktu istirahat pada
CPU Pico (100 milidetik per siklus) time.sleep(0.1) |
b. Program
Monitoring.py
|
#
Memanggil modul bawaan untuk kontrol Pin, Serial (UART), dan I2C from
machine import Pin, UART, I2C #
Memanggil modul waktu untuk jeda (delay) dan perhitungan waktu (milidetik) import
time #
Memanggil modul OS untuk mengelola file sistem (membuat/menyimpan file csv) import
os #
Memanggil pustaka eksternal untuk mengendalikan layar LCD via I2C from
pico_i2c_lcd import I2cLcd
#
================= PENGATURAN PIN & KOMUNIKASI ================= #
Mengaktifkan jalur I2C0 di pin GP0 (SDA) dan GP1 (SCL) dengan kecepatan
400kHz i2c
= I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
#
Mengaktifkan jalur UART1 di pin GP4 (TX) dan GP5 (RX) dengan baudrate 9600
untuk PZEM uart
= UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
#
Mengatur pin tombol sebagai INPUT dengan Internal PULL_UP (default HIGH,
ditekan jadi LOW) btn_ok
= Pin(6, Pin.IN, Pin.PULL_UP) btn_kiri
= Pin(12, Pin.IN, Pin.PULL_UP) btn_kanan
= Pin(7, Pin.IN, Pin.PULL_UP)
#
Mengatur pin relay dan buzzer sebagai OUTPUT relay
= Pin(16, Pin.OUT) buzzer
= Pin(15, Pin.OUT)
#
Memastikan relay dalam kondisi mati (0) saat program pertama kali berjalan relay.value(0)
#
================= INISIALISASI LCD ================= #
Mencari alamat perangkat I2C yang terhubung ke Pico devices
= i2c.scan() #
Jika ada perangkat I2C yang ditemukan (panjang list tidak nol) if
len(devices) != 0: # Mendeklarasikan objek LCD dengan alamat
yang ditemukan, ukuran 2 baris x 16 kolom lcd = I2cLcd(i2c, devices[0], 2, 16) # Membersihkan layar LCD dari karakter
acak lcd.clear() # Menampilkan teks awalan lcd.putstr("Sistem Memulai..") # Jeda 1 detik agar tulisan bisa dibaca time.sleep(1) # Bersihkan layar kembali untuk bersiap
masuk ke menu utama lcd.clear()
#
================= FUNGSI BACA PZEM ================= def
read_pzem(): # Deretan byte Modbus RTU untuk meminta
data (Read Input Register) ke PZEM req = b'\x01\x04\x00\x00\x00\x0A\x70\x0D' # Mengirim perintah tersebut melalui
jalur Serial/UART uart.write(req) # Jeda 0.2 detik memberi waktu PZEM untuk
memproses dan membalas data time.sleep(0.2) # Mengecek apakah ada data balasan yang
masuk di buffer UART if uart.any(): # Membaca seluruh data balasan dan
menyimpannya di variabel 'resp' resp = uart.read() # Memastikan balasan komplit (minimal
25 byte sesuai spesifikasi PZEM) if len(resp) >= 25: # Menggabungkan High Byte dan Low
Byte lalu membaginya sesuai resolusi sensor voltage = (resp[3] << 8 |
resp[4]) / 10.0 # Resolusi 0.1 V current = (resp[5] << 8 |
resp[6]) / 1000.0 # Resolusi 0.001 A power = (resp[9] << 8 |
resp[10]) / 10.0 # Resolusi 0.1 W energy = (resp[13] << 8 |
resp[14]) # Resolusi 1 Wh # Mengembalikan ke-4 nilai
tersebut ke program utama return voltage, current, power,
energy # Jika gagal membaca/tidak ada alat,
kembalikan nilai kosong (None) return None, None, None, None
#
================= FUNGSI BANTUAN (UTILITY) ================= def
beep(): """Membunyikan buzzer
selama 0.05 detik sebagai efek suara tombol""" buzzer.value(1) # Nyalakan buzzer time.sleep(0.05) # Tunggu 50 milidetik buzzer.value(0) # Matikan buzzer
def
tunggu_lepas(btn): """Mencegah double-click
dengan menahan program selama tombol masih ditekan""" # Selama tombol masih bernilai 0
(ditekan), program akan berputar di sini while btn.value() == 0: time.sleep(0.05) # Cek setiap 50 milidetik # Beri sedikit jeda ekstra setelah tombol
dilepas agar stabil (debouncing) time.sleep(0.05)
#
================= VARIABEL SISTEM UI & KONTROL ================= #
Daftar menu yang akan ditampilkan di layar menu_list
= ["1. Parameter", "2. Relay", "3. Batas Daya",
"4. Streaming", "5. Info Sistem"] #
Indeks untuk melacak menu mana yang sedang dipilih (dimulai dari 0) menu_index
= 0
#
Penanda apakah kita sedang di daftar menu (True) atau di dalam isi menu
(False) in_menu
= True #
Penanda halaman untuk membagi tampilan sensor (0: Tegangan/Arus, 1:
Daya/Energi) param_page
= 0 #
Penanda status hidup/mati relay internal (default mati) relay_status
= False
#
Variabel Sensor & Telemetri last_pzem_read
= 0 # Menyimpan catatan waktu
terakhir sensor dibaca v,
i, p, e = 0, 0, 0, 0 # Variabel
penampung nilai sensor terakhir power_limit
= 0 # Batas daya proteksi, 0
berarti proteksi OFF is_streaming
= False # Penanda apakah mode kirim
data live ke laptop sedang aktif
#
================= LOOP UTAMA ================= while
True: # Program akan berjalan terus menerus di dalam blok ini # ---------------- 1. BACA SENSOR &
PROTEKSI REAL-TIME ---------------- # Jika selisih waktu sekarang dan
pembacaan terakhir lebih dari 1000ms (1 detik) if time.ticks_ms() - last_pzem_read >
1000: # Panggil fungsi baca sensor, simpan
hasilnya ke variabel sementara temp_v, temp_i, temp_p, temp_e =
read_pzem() # Jika hasilnya valid (bukan None) if temp_v is not None: # Perbarui variabel utama dengan
nilai terbaru v, i, p, e = temp_v, temp_i,
temp_p, temp_e # --- LOGIKA STREAMING LIVE KE
LAPTOP --- # Jika mode streaming aktif (ON) if is_streaming: # Kirim data ke port Serial
USB laptop, format CSV (dipisah koma)
print(f"{v},{i},{p},{e}") # --- LOGIKA PROTEKSI OVER-POWER
--- # Jika batas daya tidak 0, DAN
relay sedang ON, DAN daya (p) melebihi batas if power_limit > 0 and
relay_status == True and p > power_limit: # Paksa status relay menjadi
False relay_status = False # Matikan sakelar relay
secara fisik relay.value(0) # Bunyikan alarm peringatan
sebanyak 3 kali berturut-turut for _ in range(3): beep() time.sleep(0.1) # Catat waktu saat ini sebagai waktu
pembacaan terakhir last_pzem_read = time.ticks_ms()
# ---------------- 2. BACA INPUT TOMBOL
---------------- # JIKA TOMBOL KIRI DITEKAN if btn_kiri.value() == 0: beep() # Bunyikan suara if in_menu: # Geser pilihan menu ke kiri
(berputar kembali ke belakang jika < 0) menu_index = (menu_index - 1) %
len(menu_list) else: # Aksi tombol kiri di dalam menu
spesifik if menu_index == 0: param_page = 0 # Di Menu
Parameter: Tampilkan Tegangan & Arus elif menu_index == 1: # Di Menu Relay: Ubah status
kebalikannya (ON jadi OFF, OFF jadi ON) relay_status = not
relay_status relay.value(1 if relay_status
else 0) # Update fisik relay elif menu_index == 2: # Di Menu Batas Daya: Kurangi
batas sebanyak 10W (tidak boleh kurang dari 0) power_limit = max(0,
power_limit - 10) elif menu_index == 3: # Di Menu Streaming: Tombol
Kiri berfungsi menyalakan/mematikan Live Data is_streaming = not
is_streaming lcd.clear() if is_streaming: lcd.putstr("Live
Stream: ON ")
print("---START---") # Tanda mulai di laptop else: lcd.putstr("Live
Stream: OFF")
print("---END---") #
Tanda berhenti di laptop time.sleep(1) # Tahan layar 1
detik agar tulisan terbaca # Tunggu sampai tombol benar-benar
dilepas, lalu bersihkan layar tunggu_lepas(btn_kiri) lcd.clear()
# JIKA TOMBOL KANAN DITEKAN if btn_kanan.value() == 0: beep() if in_menu: # Geser pilihan menu ke kanan
(berputar kembali ke awal jika melewati batas) menu_index = (menu_index + 1) %
len(menu_list) else: # Aksi tombol kanan di dalam menu
spesifik if menu_index == 0: param_page = 1 # Di Menu
Parameter: Tampilkan Daya & Energi elif menu_index == 1: # Di Menu Relay: Lakukan hal
yang sama seperti tombol kiri (Toggle) relay_status = not
relay_status relay.value(1 if relay_status
else 0) elif menu_index == 2: # Di Menu Batas Daya: Tambah
batas sebanyak 10W (maksimal 2200W) power_limit = min(2200,
power_limit + 10) elif menu_index == 3: # Di Menu Streaming: Tombol
Kanan berfungsi menyimpan 1 baris log ke memori internal lcd.clear()
lcd.putstr("Tersimpan!
") try: # Buka file
"data_log.csv" dengan mode "a" (append = tambah di akhir
baris) with
open("data_log.csv", "a") as file: # Tulis nilai V, I,
P, E dipisahkan koma, lalu diakhiri \n (baris baru)
file.write(f"{v},{i},{p},{e}\n") except OSError: # Abaikan error jika
gagal menyimpan (misal memori penuh) pass time.sleep(1) # Tahan layar 1
detik lcd.clear() # Tunggu sampai tombol dilepas, lalu
bersihkan layar tunggu_lepas(btn_kanan) lcd.clear()
# JIKA TOMBOL OK DITEKAN if btn_ok.value() == 0: beep() # Balik keadaan variabel in_menu
(Masuk menu jika di luar, keluar menu jika di dalam) in_menu = not in_menu tunggu_lepas(btn_ok) lcd.clear()
# ---------------- 3. TAMPILKAN UI LCD
---------------- # JIKA BERADA DI DAFTAR MENU if in_menu: lcd.move_to(0, 0) # Pindahkan kursor
ke Baris 1, Kolom 1 lcd.putstr("Pilih Menu: ") lcd.move_to(0, 1) # Pindahkan kursor
ke Baris 2, Kolom 1 # Ambil nama menu dari list
berdasarkan indeks, beri kurung siku teks_menu =
f"<{menu_list[menu_index]}>" # Cetak dengan format spasi sisa agar
memenuhi 16 kolom (menimpa teks lama) lcd.putstr(f"{teks_menu:
<16}") # JIKA MASUK KE DALAM ISI MENU
(MENGGUNAKAN TOMBOL OK) else: if menu_index == 0: # --- TAMPILAN
MENU 1: PARAMETER --- if v is not None: if param_page == 0: lcd.move_to(0, 0) lcd.putstr(f"V:
{v:.1f} V ") # Format 1 angka
desimal lcd.move_to(0, 1) lcd.putstr(f"I:
{i:.2f} A ") # Format 2 angka
desimal else: lcd.move_to(0, 0) lcd.putstr(f"P:
{p:.1f} W ") # Format 1 angka
desimal lcd.move_to(0, 1) lcd.putstr(f"E: {e}
Wh ") # Tampilkan utuh (bulat) else: # Jika PZEM belum merespon lcd.move_to(0, 0) lcd.putstr("Menunggu
PZEM...") lcd.move_to(0, 1) lcd.putstr("Tekan OK:
Keluar") elif menu_index == 1: # --- TAMPILAN
MENU 2: KONTROL RELAY --- lcd.move_to(0, 0) if relay_status: lcd.putstr("Status:
ON ") else: lcd.putstr("Status:
OFF ") lcd.move_to(0, 1) lcd.putstr("< Ubah
> OK:Kel") # Panduan tombol di
baris kedua elif menu_index == 2: # --- TAMPILAN
MENU 3: BATAS DAYA --- lcd.move_to(0, 0) if power_limit == 0: lcd.putstr("Limit:
OFF ") else: lcd.putstr(f"Limit:
{power_limit} W ") lcd.move_to(0, 1) lcd.putstr("<Kurang Tambah>") # Panduan tombol di baris
kedua elif menu_index == 3: # --- TAMPILAN
MENU 4: STREAMING/LOGGER --- lcd.move_to(0, 0) if is_streaming: lcd.putstr("Status: LIVE
OND") # Ada typo sedikit di 'OND', biasanya 'ON ' else: lcd.putstr("Data
Logger ") lcd.move_to(0, 1) lcd.putstr("<Live Simpan>") # Kiri untuk Live,
Kanan untuk Simpan Log elif menu_index == 4: # --- TAMPILAN
MENU 5: INFO SISTEM --- lcd.move_to(0, 0) lcd.putstr("Sistem v1.3 ") # Menampilkan versi sistem lcd.move_to(0, 1) lcd.putstr("Tekan OK:
Keluar")
# Memberikan sedikit waktu istirahat pada
CPU Pico (100 milidetik per siklus) time.sleep(0.1) |
c.
d. Program lcd_api.py
|
import
time from
lcd_api import LcdApi
#
Mendeklarasikan class I2cLcd yang merupakan "anak" (turunan) dari
class LcdApi class
I2cLcd(LcdApi): # ================= MAPPING PIN IC
PCF8574 KE PIN LCD ================= # Modul I2C di belakang LCD menggunakan
IC PCF8574. # Konstanta di bawah ini digunakan untuk
mengatur bit ke pin yang tepat menggunakan operasi Bitwise. MASK_RS = 0x01 # 0000 0001 -> Pin RS (Register
Select). 0=Perintah, 1=Karakter/Teks MASK_RW = 0x02 # 0000 0010 -> Pin RW
(Read/Write). Di modul ini selalu Write (biasanya tidak dipakai) MASK_E
= 0x04 # 0000 0100
-> Pin E (Enable). Kaki ini harus diberi pulsa (High ke Low) agar LCD
membaca data SHIFT_BACKLIGHT = 3 # Lampu latar (Backlight) terhubung ke
bit ke-3 (Posisi nilai 8) SHIFT_DATA = 4
# Pin Data D4-D7 LCD terhubung ke bit ke-4 hingga ke-7 pada IC PCF8574
def __init__(self, i2c, i2c_addr,
num_lines, num_columns): """Fungsi Inisialisasi
Hardware I2C ke LCD""" self.i2c = i2c # Objek I2C dari Pico (misal
I2C(0, sda=Pin(0), scl=Pin(1))) self.i2c_addr = i2c_addr # Alamat I2C modul LCD (biasanya 0x27
atau 0x3F) # Kirim data kosong (0) untuk mereset
kondisi pin pada IC PCF8574 self.i2c.writeto(self.i2c_addr,
bytearray([0])) time.sleep(0.020) # Tunggu 20ms agar
tegangan stabil setelah power-on # --- PROSEDUR WAJIB INISIALISASI LCD
MODE 4-BIT --- # Berdasarkan datasheet HD44780,
untuk masuk ke mode 4-bit, # kita harus mengirim perintah khusus
(0x3) sebanyak 3 kali berturut-turut.
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT) time.sleep(0.005) # Jeda 5ms
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT) time.sleep(0.001) # Jeda 1ms
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT) time.sleep(0.001) # Terakhir, kirim perintah (0x2)
untuk mengunci LCD ke Mode 4-bit
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT >> 1) time.sleep(0.001) # Setelah hardware siap di mode
4-bit, panggil fungsi inisialisasi dari "induk" (LcdApi) super().__init__(num_lines,
num_columns) # Pastikan pengaturan baris
diterapkan (misal 2 baris)
self.hal_write_command(self.LCD_FUNCTION | self.LCD_FUNCTION_2LINES)
def hal_write_init_nibble(self, nibble): """Fungsi khusus untuk
mengirim 4-bit data saat fase awal (booting) saja""" # Ambil 4-bit data, geser posisinya
ke bit 4-7 (pin D4-D7) byte = ((nibble >> 4) &
0x0f) << self.SHIFT_DATA # Metode Pulsa Enable: Data
dimasukkan, pin E dinyalakan (MASK_E) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) # Pin E dimatikan. Saat transisi High
ke Low inilah LCD membaca data tersebut self.i2c.writeto(self.i2c_addr,
bytearray([byte]))
def hal_backlight_on(self): """Menyalakan
transistor lampu latar di modul I2C""" # Mengirim logika 1 yang digeser ke
posisi bit lampu (bit ke-3) self.i2c.writeto(self.i2c_addr,
bytearray([1 << self.SHIFT_BACKLIGHT]))
def hal_backlight_off(self): """Mematikan
transistor lampu latar""" # Kirim logika 0 ke seluruh pin self.i2c.writeto(self.i2c_addr,
bytearray([0]))
def hal_write_command(self, cmd): """Menerjemahkan
perintah (Command) hex menjadi pulsa listrik I2C""" # Pin RS tetap 0 karena ini adalah
Perintah (Command), bukan Teks (Data) # 1. PENGIRIMAN 4-BIT PERTAMA (HIGH
NIBBLE) # Ambil bit lampu latar, lalu
gabungkan dengan 4-bit atas dari data (cmd) byte = ((self.backlight <<
self.SHIFT_BACKLIGHT) | (((cmd >> 4) & 0x0f) <<
self.SHIFT_DATA)) # Berikan pulsa Enable (ON) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) # Matikan pulsa Enable (OFF - LCD
mengeksekusi) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) # 2. PENGIRIMAN 4-BIT KEDUA (LOW
NIBBLE) # Ambil bit lampu latar, lalu
gabungkan dengan 4-bit bawah dari data (cmd & 0x0f) byte = ((self.backlight <<
self.SHIFT_BACKLIGHT) | ((cmd & 0x0f) << self.SHIFT_DATA)) # Berikan pulsa Enable (ON) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) # Matikan pulsa Enable (OFF - LCD
mengeksekusi) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) # Beberapa perintah berat seperti
Clear Screen (0x01) atau Return Home (0x02) butuh waktu proses lebih lama di
IC LCD if cmd <= 3: time.sleep(0.005) # Beri jeda
ekstra 5ms agar IC LCD tidak hang
def hal_write_data(self, data): """Menerjemahkan teks
(Data) menjadi pulsa listrik I2C""" # Konsepnya sama persis dengan
write_command di atas (dibagi 2 bagian High & Low). # PERBEDAANNYA HANYA SATU: Kita
tambahkan MASK_RS (Register Select = 1) # Ini memberi tahu IC LCD bahwa
sinyal yang masuk adalah huruf yang harus digambar di layar. # 1. Kirim 4-bit Pertama (High
Nibble) + RS = 1 byte = (self.MASK_RS |
(self.backlight << self.SHIFT_BACKLIGHT) | (((data >> 4) &
0x0f) << self.SHIFT_DATA)) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) # 2. Kirim 4-bit Kedua (Low Nibble) +
RS = 1 byte = (self.MASK_RS |
(self.backlight << self.SHIFT_BACKLIGHT) | ((data & 0x0f) <<
self.SHIFT_DATA)) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) |
Program pico_i2c_lcd.py
|
import
time from
lcd_api import LcdApi
#
Mendeklarasikan class I2cLcd yang merupakan "anak" (turunan) dari
class LcdApi class
I2cLcd(LcdApi): # ================= MAPPING PIN IC
PCF8574 KE PIN LCD ================= # Modul I2C di belakang LCD menggunakan
IC PCF8574. # Konstanta di bawah ini digunakan untuk
mengatur bit ke pin yang tepat menggunakan operasi Bitwise. MASK_RS = 0x01 # 0000 0001 -> Pin RS (Register
Select). 0=Perintah, 1=Karakter/Teks MASK_RW = 0x02 # 0000 0010 -> Pin RW
(Read/Write). Di modul ini selalu Write (biasanya tidak dipakai) MASK_E
= 0x04 # 0000 0100
-> Pin E (Enable). Kaki ini harus diberi pulsa (High ke Low) agar LCD
membaca data SHIFT_BACKLIGHT = 3 # Lampu latar (Backlight) terhubung ke
bit ke-3 (Posisi nilai 8) SHIFT_DATA = 4
# Pin Data D4-D7 LCD terhubung ke bit ke-4 hingga ke-7 pada IC PCF8574
def __init__(self, i2c, i2c_addr,
num_lines, num_columns): """Fungsi Inisialisasi
Hardware I2C ke LCD""" self.i2c = i2c # Objek I2C dari Pico (misal
I2C(0, sda=Pin(0), scl=Pin(1))) self.i2c_addr = i2c_addr # Alamat I2C modul LCD (biasanya 0x27
atau 0x3F) # Kirim data kosong (0) untuk mereset
kondisi pin pada IC PCF8574 self.i2c.writeto(self.i2c_addr,
bytearray([0])) time.sleep(0.020) # Tunggu 20ms agar
tegangan stabil setelah power-on # --- PROSEDUR WAJIB INISIALISASI LCD
MODE 4-BIT --- # Berdasarkan datasheet HD44780,
untuk masuk ke mode 4-bit, # kita harus mengirim perintah khusus
(0x3) sebanyak 3 kali berturut-turut.
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT) time.sleep(0.005) # Jeda 5ms
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT) time.sleep(0.001) # Jeda 1ms
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT) time.sleep(0.001) # Terakhir, kirim perintah (0x2)
untuk mengunci LCD ke Mode 4-bit
self.hal_write_init_nibble(self.LCD_FUNCTION_8BIT >> 1) time.sleep(0.001) # Setelah hardware siap di mode
4-bit, panggil fungsi inisialisasi dari "induk" (LcdApi) super().__init__(num_lines,
num_columns) # Pastikan pengaturan baris
diterapkan (misal 2 baris)
self.hal_write_command(self.LCD_FUNCTION | self.LCD_FUNCTION_2LINES)
def hal_write_init_nibble(self, nibble): """Fungsi khusus untuk
mengirim 4-bit data saat fase awal (booting) saja""" # Ambil 4-bit data, geser posisinya
ke bit 4-7 (pin D4-D7) byte = ((nibble >> 4) &
0x0f) << self.SHIFT_DATA # Metode Pulsa Enable: Data
dimasukkan, pin E dinyalakan (MASK_E) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) # Pin E dimatikan. Saat transisi High
ke Low inilah LCD membaca data tersebut self.i2c.writeto(self.i2c_addr,
bytearray([byte]))
def hal_backlight_on(self): """Menyalakan
transistor lampu latar di modul I2C""" # Mengirim logika 1 yang digeser ke
posisi bit lampu (bit ke-3) self.i2c.writeto(self.i2c_addr,
bytearray([1 << self.SHIFT_BACKLIGHT]))
def hal_backlight_off(self): """Mematikan
transistor lampu latar""" # Kirim logika 0 ke seluruh pin self.i2c.writeto(self.i2c_addr,
bytearray([0]))
def hal_write_command(self, cmd): """Menerjemahkan
perintah (Command) hex menjadi pulsa listrik I2C""" # Pin RS tetap 0 karena ini adalah
Perintah (Command), bukan Teks (Data) # 1. PENGIRIMAN 4-BIT PERTAMA (HIGH
NIBBLE) # Ambil bit lampu latar, lalu
gabungkan dengan 4-bit atas dari data (cmd) byte = ((self.backlight <<
self.SHIFT_BACKLIGHT) | (((cmd >> 4) & 0x0f) <<
self.SHIFT_DATA)) # Berikan pulsa Enable (ON) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) # Matikan pulsa Enable (OFF - LCD
mengeksekusi) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) # 2. PENGIRIMAN 4-BIT KEDUA (LOW
NIBBLE) # Ambil bit lampu latar, lalu
gabungkan dengan 4-bit bawah dari data (cmd & 0x0f) byte = ((self.backlight <<
self.SHIFT_BACKLIGHT) | ((cmd & 0x0f) << self.SHIFT_DATA)) # Berikan pulsa Enable (ON) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) # Matikan pulsa Enable (OFF - LCD
mengeksekusi) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) # Beberapa perintah berat seperti
Clear Screen (0x01) atau Return Home (0x02) butuh waktu proses lebih lama di
IC LCD if cmd <= 3: time.sleep(0.005) # Beri jeda
ekstra 5ms agar IC LCD tidak hang
def hal_write_data(self, data): """Menerjemahkan teks
(Data) menjadi pulsa listrik I2C""" # Konsepnya sama persis dengan
write_command di atas (dibagi 2 bagian High & Low). # PERBEDAANNYA HANYA SATU: Kita
tambahkan MASK_RS (Register Select = 1) # Ini memberi tahu IC LCD bahwa
sinyal yang masuk adalah huruf yang harus digambar di layar. # 1. Kirim 4-bit Pertama (High
Nibble) + RS = 1 byte = (self.MASK_RS |
(self.backlight << self.SHIFT_BACKLIGHT) | (((data >> 4) &
0x0f) << self.SHIFT_DATA)) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) # 2. Kirim 4-bit Kedua (Low Nibble) +
RS = 1 byte = (self.MASK_RS |
(self.backlight << self.SHIFT_BACKLIGHT) | ((data & 0x0f) <<
self.SHIFT_DATA)) self.i2c.writeto(self.i2c_addr,
bytearray([byte | self.MASK_E])) self.i2c.writeto(self.i2c_addr,
bytearray([byte])) |
IV. HASIL DAN PEMBAHASAN
A.
Gambar Alat
Gambar
9.
Gambar Alat
B.
Cara kerja
Sistem Stop Kontak Pintar++ bekerja secara otomatis dan
terintegrasi melalui siklus pengambilan data, pengolahan data, hingga eksekusi
proteksi serta visualisasi informasi. Siklus kerja ini dimulai ketika beban
listrik (seperti lampu) dihubungkan ke stop kontak pintar yang tersambung
dengan sumber listrik utama PLN bertegangan AC 220V 50 Hz. Pada titik
distribusi beban ini, sensor PZEM-004T langsung bekerja membaca parameter
kelistrikan secara waktu nyata (real-time). Sensor ini secara simultan
mengukur besaran fisis berupa tegangan, arus, daya aktif (Watt), serta
akumulasi energi (Wh) yang diserap oleh beban.
Setelah parameter kelistrikan terbaca, sensor PZEM-004T
mentransmisikan data pengukuran tersebut ke mikrokontroler Raspberry Pi Pico
melalui jalur komunikasi serial UART. Mengingat adanya perbedaan tegangan
kerja, sinyal logika komunikasi ini melewati komponen logic shifter
terlebih dahulu untuk menyesuaikan level tegangan agar aman bagi pin GPIO
mikrokontroler. Di dalam Raspberry Pi Pico, data mentah tersebut kemudian
diolah secara komputasi. Mikrokontroler tidak hanya bertugas menghitung data,
tetapi juga memproses input dari tiga tombol fisik (push button) yang
ditekan oleh pengguna. Tombol-tombol ini berfungsi untuk menavigasi menu
alat—seperti menu Parameter, Kontrol Relay, Batas Daya, dan Live Stream—yang
disertai dengan umpan balik (feedback) suara dari komponen buzzer.
Hasil pengolahan data dari mikrokontroler kemudian
disalurkan ke dua jalur keluaran utama. Jalur pertama adalah tampilan lokal
pada layar LCD 16x2 via komunikasi I2C yang menampilkan informasi numerik
sesuai dengan menu navigasi yang dipilih pengguna. Jalur kedua adalah
pengiriman aliran data (live streaming) menuju gawai atau laptop melalui
koneksi kabel USB. Di sisi laptop, data serial ini ditangkap oleh aplikasi dashboard
interaktif untuk divisualisasikan dalam bentuk grafik pemantauan secara
langsung dan dapat diekspor menjadi laporan tertulis dalam format Excel.
Bersamaan dengan proses pemantauan tersebut, sistem
kendali proteksi aktif berjalan di latar belakang. Raspberry Pi Pico secara
terus-menerus membandingkan nilai daya aktif (Watt) aktual hasil bacaan sensor
dengan batas daya maksimum (threshold) yang telah diatur oleh pengguna.
Jika daya aktual terdeteksi melebihi batas aman tersebut, mikrokontroler akan
langsung memicu algoritma proteksi pintar (Over-Power Protection) dan
mengirimkan sinyal digital untuk memutus modul relay. Putusnya sakelar relay
ini secara otomatis langsung menghentikan aliran listrik menuju beban guna
mencegah terjadinya panas berlebih (overheating) atau bahaya korsleting
listrik. Pengoperasian relay ini juga dapat dikontrol secara manual oleh
pengguna melalui menu yang tersedia pada alat.
C. Hasil
Gambar 10. Tampilan Saat Alat Bekerja
Gambar 11. Tampilan
Monitoring
Berdasarkan hasil implementasi dan pengujian yang telah
dilakukan, sistem "Stop Kontak Pintar++" berbasis Raspberry Pi Pico
dan sensor PZEM-004T ini berhasil mendeteksi dan memonitor berbagai parameter
kelistrikan seperti tegangan, arus, daya, energi, frekuensi, dan power
factor secara waktu nyata (real-time) dengan baik. Integrasi
perangkat keras menunjukkan bahwa seluruh komponen utama, termasuk modul relay
5V, tiga tombol fisik sebagai navigator menu, serta indikator buzzer,
dapat beroperasi secara sinkron di bawah kendali mikrokontroler. Informasi data
kelistrikan lokal dapat ditampilkan secara interaktif pada layar LCD
V. KESIMPULAN
Berdasarkan hasil perancangan, implementasi, dan
pengujian yang telah dilakukan, dapat disimpulkan bahwa proyek sistem Stop
Kontak Pintar++ berbasis mikrokontroler Raspberry Pi Pico dan sensor PZEM-004T
telah berhasil dibuat dan berfungsi secara optimal. Sistem ini terbukti mampu
memonitor berbagai parameter kelistrikan vital seperti tegangan, arus, daya,
dan energi secara waktu nyata (real-time), serta menampilkannya secara
interaktif pada layar LCD 16x2 lokal. Selain itu, integrasi dengan aplikasi dashboard
di laptop melalui koneksi USB berjalan dengan baik, sehingga pengguna dapat
memantau grafik pemakaian langsung serta mengekspor data laporan ke dalam
format Excel dengan mudah. Fitur keamanan aktif berupa sistem proteksi pintar (Over-Power
Protection) juga menunjukkan performa yang responsif, di mana modul relay
secara otomatis memutus aliran listrik dengan baik saat mendeteksi adanya beban
berlebih yang melewati batas aman yang diatur pengguna. Secara keseluruhan,
alat ini tidak hanya ramah pengguna dan aplikatif, melainkan juga memiliki
potensi besar untuk dikembangkan lebih lanjut dalam ekosistem rumah pintar (smart
home), manajemen energi, serta peningkatan efisiensi penggunaan listrik di
masa depan.
VI. REFERENSI
1.
Raspberry
Pi Ltd. (2020). Raspberry Pi Pico Datasheet: An RP2040-based microcontroller
board. Cambridge: Raspberry Pi Press.
2. Ningbo Peacefair Electronic Technology Co., Ltd.
(2018). PZEM-004T V3.0 AC Electronic Module User Manual. Ningbo:
Peacefair.
3. Songle Relay Co., Ltd. (2016). SRD Series Relay
Datasheet (SRD-05VDC-SL-C). Ningbo: Songle.
4. Budiharto, W. (2020). Rancang Bangun Sistem
Elektronika dan IoT Berbasis Mikrokontroler. Jakarta: Penerbit Andi.
5. Ibrahim, D. (2015). Raspberry Pi Embedded Projects
Hotshot. Birmingham: Packt Publishing.
6. Setiawan, A., & Ramadhani, S. (2022). Sistem
Monitoring Konsumsi Energi Listrik Berbasis IoT Menggunakan Sensor PZEM-004T. Jurnal
Teknologi dan Sistem Komputer, 10(2), 115-122.
7. Badan Standardisasi Nasional. (2011). Persyaratan Umum
Instalasi Listrik 2011 (PUIL 2011). SNI 0225:2011. Jakarta: BSN.
8. International Electrotechnical Commission. (2020). IEC
62053-21: Electricity metering equipment - Particular requirements - Part 21:
Static meters for AC active energy (classes 0,5, 1 and 2). Geneva: IEC.
9. Python Software Foundation. (2025). MicroPython
Documentation for Raspberry Pi Pico. Diakses dari https://docs.micropython.org/
10. EasyEDA Team. (2026). EasyEDA User Manual:
Schematic and PCB Design Schematic. Diakses dari https://docs.easyeda.com/
Penulis
atas nama Aldino Sultansyah dilahirkan di Semarang, 2 Desember 2005. Penulis
telah menempuh pendidikan formal di SD Negeri Tambakaji 04, SMP Negeri 16
Semarang, dan SMK Penerbangan Semarang. Tahun 2023 penulis menyelesaikan
pendidikannya di SMK. Pada tahun 2023 penulis mengikuti seleksi mahasiswa baru
Sarjana Terapan (D4) dan diterima menjadi mahasiswa baru Sarjana Terapan (D4)
dikampus Politeknik Negeri Semarang (Polines) dengan Program Studi D4 Teknologi
Rekayasa Elektronika, Jurusan Teknik Elektro. Penulis terdaftar dengan NIM. 4.34.23.0.03. Apabila ada
kritik, saran dan pertanyaan mengenai penelitian ini, bisa via email: aldino.43423003@mhs.polines.ac.id
Penulis atas nama Frisca Syaharani dilahirkan di Kab.
Semarang, 29 September 2005. Penulis telah menempuh pendidikan formal di SD
Negeri 04 Banyubiru, SMP Negeri 01 Banyubiru, dan SMK Negeri 2 Salatiga. Tahun
2023 penulis menyelesaikan pendidikannya di SMK. Pada tahun 2023 penulis
mengikuti seleksi mahasiswa baru Sarjana Terapan (D4) dan diterima menjadi
mahasiswa baru Sarjana Terapan (D4) dikampus Politeknik Negeri Semarang
(Polines) dengan Program Studi D4 Teknologi Rekayasa Elektronika, Jurusan
Teknik Elektro. Penulis terdaftar dengan NIM. 4.34.23.0.09. Apabila ada kritik,
saran dan pertanyaan mengenai penelitian ini, bisa via email: frisca.43423009@mhs.polines.ac.id
Penulis atas nama Muhammad Satrio Adhy dilahirkan di Semarang,
29 Januari 2005 . Penulis telah menempuh pendidikan formal di SD Negeri Purwoyoso
03, SMP Negeri 18 Semarang, dan SMA Islam Sultan Agung 1 Semarang. Tahun 2023
penulis menyelesaikan pendidikannya di SMA. Pada tahun 2023 penulis mengikuti
seleksi mahasiswa baru Sarjana Terapan (D4) dan diterima menjadi mahasiswa baru
Sarjana Terapan (D4) dikampus Politeknik Negeri Semarang (Polines) dengan
Program Studi D4- Teknologi Rekayasa Elektronika, Jurusan Teknik Elektro. Penulis
terdaftar dengan NIM 4.34.23.0.15. Apabila ada kritik, saran dan pertanyaan
mengenai penelitian ini, bisa via email: satrio.43423015@mhs.polines.ac.id
Penulis atas nama Salsabila Chairunisa dilahirkan di Salatiga,
15 Mei 2004. Penulis telah menempuh pendidikan formal di SDIT Darul Falah
Semarang, SMP Negeri 20 Semarang, dan SMK Negeri 3 Salatiga. Tahun 2023 penulis
telah menyelesaikan pendidikannya di SMK. Pada tahun 2023 penulis mengikuti
seleksi mahasiswa baru Sarjana Terapan(D4) dan diterima menjadi mahasiswa baru
Sarjana Terapan(D4) di kampus Politeknik Negeri Semarang(Polines) dengan program
studi D4 Teknologi Rekayasa Elektronika, Jurusan Teknik Elektro. Penulis
terdaftar dengan NIM 4.34.23.0.22 Apabila ada kritik, saran dan pertanyaan
mengenai penelitian ini, bisa via email: salsabila.43423022@mhs.polines.ac.id
PRESENTASI
https://canva.link/6bmp7ocijhz0i2j
Komentar
Posting Komentar