Lewati ke isi

Dasar-dasar MicroPython di ESP32

Pada pertemuan kali ini akan membahas dasar-dasar penggunaan MicroPython pada mikrokontroler ESP32. Mahasiswa akan mempelajari instalasi firmware MicroPython, perbedaan Python dengan MicroPython, penggunaan REPL (Read-Eval-Print Loop), dan cara menjalankan script sederhana pada ESP32.

Alat dan Bahan

Hardware:

  • ESP32 Development Board (NodeMCU ESP32 atau ESP32 DevKit)
  • Kabel USB Type-C atau Micro-USB (sesuai dengan board ESP32)
  • Komputer/Laptop dengan sistem operasi Windows, macOS, atau Linux

Software:

  • Python 3.7 atau lebih baru
  • Visual Studio Code (VSCode)
  • Extension PyMakr atau MicroPython untuk VSCode
  • PuTTY (untuk Windows) atau Terminal (untuk macOS/Linux)
  • esptool.py untuk flashing firmware
  • Firmware MicroPython untuk ESP32

Bagian 1: Persiapan Lingkungan Pengembangan

1.1 Instalasi Python dan Tools Dasar

Sebelum memulai pengembangan dengan MicroPython, kita perlu menyiapkan lingkungan pengembangan yang tepat. Python diperlukan untuk menjalankan tools seperti esptool.py yang digunakan untuk flashing firmware ke ESP32.

Praktikum 1.1: Persiapan Lingkungan

Verifikasi Instalasi Python

Buka Command Prompt (Windows) atau Terminal (macOS/Linux) dan jalankan:

python --version

atau

python3 --version

Jika berhasil, akan muncul versi Python yang terinstal.

Langkah 3: Install pip (jika belum tersedia)

python -m ensurepip --upgrade

1.2 Instalasi di Visual Studio Code

Visual Studio Code adalah IDE yang sangat populer untuk pengembangan MicroPython karena memiliki extension yang mendukung pengembangan pada mikrokontroler.

Praktikum 1.2: Setup VSCode untuk MicroPython

Langkah 2: Install Extension MicroPython

  1. Buka VSCode
  2. Klik icon Extensions di sidebar kiri (Ctrl+Shift+X)
  3. Cari "Pymakr" atau "MicroPython"
  4. Install extension "Pymakr" oleh Pycom

Langkah 3: Konfigurasi Extension

Setelah extension terinstal: 1. Restart VSCode 2. Extension Pymakr akan muncul di sidebar 3. Kita akan mengkonfigurasinya setelah ESP32 siap

1.3 Instalasi Tools Komunikasi Serial

Untuk berkomunikasi dengan ESP32, kita memerlukan aplikasi terminal serial. PuTTY adalah pilihan populer untuk Windows, sementara macOS dan Linux memiliki terminal built-in.

Praktikum 1.3: Setup Tools Komunikasi

Untuk Windows - Install PuTTY:

  1. Kunjungi https://www.putty.org/
  2. Download PuTTY installer
  3. Install dengan mengikuti wizard
  4. PuTTY akan tersedia di Start Menu

Untuk macOS/Linux - Menggunakan Terminal Built-in:

Terminal sudah tersedia secara default. Kita akan menggunakan command screen atau minicom:

# Install screen (jika belum ada)
# macOS
brew install screen

# Linux
sudo apt install screen

1.4 Instalasi esptool.py

esptool.py adalah utility resmi dari Espressif untuk flashing firmware ke chip ESP32. Tool ini diperlukan untuk menginstal firmware MicroPython.

Praktikum 1.4: Install esptool.py

Langkah 1: Install esptool menggunakan pip

pip install esptool

atau

pip3 install esptool

Langkah 2: Verifikasi Instalasi

esptool.py version

Jika berhasil, akan muncul informasi versi esptool.


Bagian 2: Pengenalan MicroPython dan ESP32

2.1 Apa itu MicroPython?

MicroPython adalah implementasi lean dan efisien dari bahasa pemrograman Python 3 yang dioptimalkan untuk mikrokontroler dan sistem embedded. MicroPython dikembangkan oleh Damien George pada tahun 2013 dengan tujuan membawa kemudahan Python ke dunia embedded systems.

Karakteristik MicroPython:

  • Lightweight: Dirancang untuk berjalan pada mikrokontroler dengan memori terbatas
  • Interactive: Mendukung REPL untuk pengembangan interaktif
  • Python-compatible: Sebagian besar syntax Python standar dapat digunakan
  • Hardware-oriented: Menyediakan library khusus untuk mengakses hardware

2.2 Perbedaan Python vs MicroPython

Meskipun MicroPython berbasis Python, ada beberapa perbedaan penting yang perlu dipahami:

Praktikum 2.1: Memahami Perbedaan Python dan MicroPython

Perbedaan Utama:

Aspek Python MicroPython
Target Platform Desktop, Server Mikrokontroler, Embedded
Memory Usage Tidak terbatas Sangat terbatas (KB-MB)
Standard Library Lengkap Subset yang dioptimalkan
Execution Interpreted Interpreted + Compiled bytecode
Hardware Access Melalui library eksternal Built-in hardware modules
File System Full OS filesystem Simple filesystem

Library yang Berbeda:

Python Standard:

import os
import sys
import datetime
import json
import urllib

MicroPython Equivalent:

import uos          # Micro OS
import sys          # Same
import utime        # Micro time
import ujson        # Micro JSON
# urllib tidak tersedia

Contoh Perbedaan Syntax:

Python:

# String formatting
name = "John"
age = 25
message = f"Hello {name}, you are {age} years old"
print(message)

MicroPython (beberapa fitur Python 3.6+ mungkin tidak tersedia):

# String formatting (method lama lebih kompatibel)
name = "John"
age = 25
message = "Hello {}, you are {} years old".format(name, age)
print(message)

2.3 Pengenalan ESP32

ESP32 adalah mikrokontroler yang dikembangkan oleh Espressif Systems. Chip ini sangat populer untuk proyek IoT karena memiliki built-in WiFi dan Bluetooth, serta performa yang tinggi dengan harga yang terjangkau.

Spesifikasi ESP32:

  • CPU: Dual-core Xtensa 32-bit LX6 (hingga 240 MHz)
  • Memory: 520 KB SRAM, 4 MB Flash (bervariasi)
  • Connectivity: WiFi 802.11 b/g/n, Bluetooth 4.2/BLE
  • GPIO: Hingga 34 pin GPIO
  • ADC: 18 channel 12-bit ADC
  • DAC: 2 channel 8-bit DAC
  • Communication: UART, SPI, I2C, I2S
  • PWM: 16 channel PWM

Praktikum 2.2: Identifikasi Board ESP32

Langkah 1: Periksa Board ESP32 Anda

Identifikasi jenis board ESP32 yang Anda miliki: - ESP32 DevKit: Board development umum dengan 30 pin - NodeMCU ESP32: Board dengan form factor NodeMCU - ESP32-CAM: Board dengan kamera built-in - ESP32-WROOM: Module ESP32 standar

Langkah 2: Periksa Port USB

Periksa jenis konektor USB pada board: - Micro-USB: Konektor persegi kecil - USB Type-C: Konektor oval yang bisa dibalik

Langkah 3: Identifikasi Pin Layout

Setiap board memiliki pin layout yang berbeda. Catat pin-pin penting: - EN: Enable pin (reset) - BOOT: Boot mode pin - GND: Ground pins - 3V3: Power supply 3.3V - GPIO pins: Pin input/output digital


Bagian 3: Instalasi Firmware MicroPython

3.1 Download Firmware MicroPython

Firmware MicroPython untuk ESP32 tersedia dalam berbagai versi. Kita akan menggunakan firmware stable terbaru yang kompatibel dengan ESP32.

Praktikum 3.1: Download Firmware

Langkah 1: Kunjungi Website MicroPython

  1. Buka browser dan kunjungi https://micropython.org/download/esp32/
  2. Pilih firmware "ESP32 with SPIRAM" jika board Anda memiliki PSRAM, atau "ESP32" untuk board standar
  3. Download file firmware dengan ekstensi .bin

Langkah 2: Verifikasi File Download

Pastikan file yang didownload memiliki: - Ekstensi .bin - Ukuran sekitar 1-2 MB - Nama yang mengandung versi MicroPython (contoh: esp32-20231005-v1.21.0.bin)

3.2 Koneksi ESP32 ke Komputer

Sebelum flashing firmware, ESP32 harus terhubung dengan komputer melalui kabel USB. Koneksi ini akan digunakan untuk transfer data dan komunikasi serial.

Praktikum 3.2: Koneksi Hardware

Langkah 1: Hubungkan ESP32

  1. Ambil kabel USB yang sesuai dengan board ESP32 Anda
  2. Hubungkan ujung USB ke komputer
  3. Hubungkan ujung lainnya ke ESP32
  4. LED power pada ESP32 harus menyala

Langkah 2: Identifikasi Port Serial

Untuk Windows: 1. Buka Device Manager (Win+X, pilih Device Manager) 2. Expand "Ports (COM & LPT)" 3. Cari "Silicon Labs CP210x" atau "CH340" atau "FTDI" 4. Catat nomor COM port (contoh: COM3, COM4)

Untuk macOS:

ls /dev/tty.usb*

Untuk Linux:

ls /dev/ttyUSB*

Langkah 3: Install Driver (jika diperlukan)

Jika ESP32 tidak terdeteksi:

Untuk Windows: - Download driver CP210x dari Silicon Labs - Atau driver CH340 jika menggunakan chip CH340 - Install driver dan restart komputer

Untuk macOS/Linux: - Driver biasanya sudah built-in - Jika tidak terdeteksi, install driver sesuai chip USB-to-Serial

3.3 Flashing Firmware MicroPython

Proses flashing adalah proses mengganti firmware default ESP32 dengan firmware MicroPython. Proses ini akan menghapus semua data yang ada di flash memory ESP32.

Praktikum 3.3: Flash Firmware ke ESP32

Langkah 1: Erase Flash Memory

Sebelum flashing firmware baru, kita perlu menghapus flash memory:

esptool.py --chip esp32 --port COM3 erase_flash

Ganti COM3 dengan port yang sesuai dengan sistem Anda: - Windows: COM3, COM4, dll. - macOS: /dev/tty.usbserial-xxx - Linux: /dev/ttyUSB0, /dev/ttyUSB1, dll.

Langkah 2: Flash Firmware MicroPython

esptool.py --chip esp32 --port COM3 --baud 460800 write_flash -z 0x1000 esp32-20231005-v1.21.0.bin

Ganti nama file firmware sesuai dengan file yang Anda download.

Langkah 3: Verifikasi Flashing

Jika proses berhasil, Anda akan melihat output seperti:

Hash of data verified.

Leaving...
Hard resetting via RTS pin...

Langkah 4: Reset ESP32

Setelah flashing selesai: 1. Tekan tombol EN/RST pada ESP32 2. Atau cabut dan colok kembali kabel USB 3. ESP32 akan boot dengan firmware MicroPython

3.4 Troubleshooting Flashing

Beberapa masalah umum yang mungkin terjadi saat flashing dan cara mengatasinya.

Praktikum 3.4: Mengatasi Masalah Flashing

Masalah 1: "Failed to connect to ESP32"

Solusi: 1. Pastikan kabel USB berfungsi dengan baik 2. Periksa driver USB-to-Serial 3. Coba port USB yang berbeda 4. Tekan dan tahan tombol BOOT saat menjalankan esptool 5. Kurangi baud rate menjadi 115200

Masalah 2: "Permission denied" (Linux/macOS)

Solusi:

sudo chmod 666 /dev/ttyUSB0

Atau tambahkan user ke grup dialout:

sudo usermod -a -G dialout $USER

Masalah 3: "Timeout waiting for packet header"

Solusi: 1. Tekan dan tahan tombol BOOT pada ESP32 2. Tekan tombol EN/RST sekali 3. Lepas tombol BOOT 4. Jalankan kembali perintah esptool


Bagian 4: Penggunaan REPL (Read-Eval-Print Loop)

4.1 Pengenalan REPL

REPL (Read-Eval-Print Loop) adalah interface interaktif yang memungkinkan kita menjalankan kode Python secara langsung pada ESP32. REPL sangat berguna untuk testing, debugging, dan eksplorasi fitur MicroPython.

Cara Kerja REPL:

  1. Read: Membaca input dari user
  2. Eval: Mengevaluasi/menjalankan kode
  3. Print: Menampilkan hasil
  4. Loop: Kembali ke langkah 1

4.2 Akses REPL melalui Serial Terminal

REPL dapat diakses melalui koneksi serial menggunakan berbagai aplikasi terminal. Kita akan menggunakan PuTTY untuk Windows dan screen untuk macOS/Linux.

Praktikum 4.1: Akses REPL dengan PuTTY (Windows)

Langkah 1: Buka PuTTY

  1. Buka aplikasi PuTTY
  2. Pilih "Serial" sebagai Connection type
  3. Masukkan Serial line: COM3 (sesuai port ESP32)
  4. Masukkan Speed: 115200
  5. Klik "Open"

Langkah 2: Masuk ke REPL

  1. Jika layar kosong, tekan Enter beberapa kali
  2. Anda akan melihat prompt MicroPython:
    MicroPython v1.21.0 on 2023-10-05; ESP32 module with ESP32
    Type "help()" for more information.
    >>> 
    

Langkah 3: Test REPL

Coba jalankan perintah sederhana:

>>> print("Hello, ESP32!")
Hello, ESP32!
>>> 2 + 3
5
>>> 

Praktikum 4.2: Akses REPL dengan Screen (macOS/Linux)

Langkah 1: Buka Terminal

screen /dev/ttyUSB0 115200

Ganti /dev/ttyUSB0 dengan port yang sesuai.

Langkah 2: Masuk ke REPL

Tekan Enter beberapa kali hingga muncul prompt >>>.

Langkah 3: Keluar dari Screen

Untuk keluar dari screen: Ctrl+A kemudian K, lalu Y.

4.3 Perintah Dasar REPL

REPL MicroPython memiliki beberapa perintah khusus yang berguna untuk mengelola ESP32.

Praktikum 4.3: Eksplorasi Perintah REPL

Langkah 1: Perintah Help

>>> help()

Akan menampilkan informasi bantuan MicroPython.

Langkah 2: Informasi Sistem

>>> import sys
>>> sys.implementation
(name='micropython', version=(1, 21, 0))

>>> sys.platform
'esp32'

Langkah 3: Informasi Memory

>>> import gc
>>> gc.mem_free()
4096000

>>> gc.mem_alloc()
15648

Langkah 4: Soft Reset

>>> import machine
>>> machine.soft_reset()

Perintah ini akan restart MicroPython tanpa reset hardware.

Langkah 5: Informasi Hardware

>>> import machine
>>> machine.freq()
240000000

>>> machine.unique_id()
b'\x24\x0a\xc4\x04\xa7\x88'

4.4 Eksplorasi Module MicroPython

MicroPython menyediakan berbagai module yang dapat digunakan untuk mengakses fitur ESP32. Mari kita eksplorasi module-module yang tersedia.

Praktikum 4.4: Eksplorasi Module

Langkah 1: Daftar Module Built-in

>>> help('modules')
__main__          gc                ubinascii         urandom
_boot             machine           ucollections      ure
_onewire          math              uerrno            uselect
_thread           micropython       uhashlib          usocket
_uasyncio         network           uheapq            ussl
_webrepl          neopixel          uio               ustruct
btree             ntptime           ujson             utime
builtins          onewire           uos               utimeq
cmath             sys               uplatform         uzlib
dht               time              urequests         webrepl
ds18x20           uarray            urequests         webrepl_setup
esp               ubluetooth        uurequests
esp32             ubinascii         framebuf
Plus any modules on the filesystem

Langkah 2: Eksplorasi Module Machine

>>> import machine
>>> dir(machine)
['__class__', '__name__', 'ADC', 'DAC', 'I2C', 'PWM', 'RTC', 'SPI', 'Timer', 'UART', 'WDT', 'deepsleep', 'disable_irq', 'enable_irq', 'freq', 'idle', 'lightsleep', 'mem16', 'mem32', 'mem8', 'reset', 'reset_cause', 'sleep', 'soft_reset', 'time_pulse_us', 'unique_id', 'wake_reason']

Langkah 3: Eksplorasi Module ESP32

>>> import esp32
>>> dir(esp32)
['__class__', '__name__', 'WAKEUP_ALL_LOW', 'WAKEUP_ANY_HIGH', 'hall_sensor', 'raw_temperature', 'wake_on_ext0', 'wake_on_ext1', 'wake_on_touch']

Langkah 4: Test Sensor Built-in

>>> esp32.hall_sensor()
-30

>>> esp32.raw_temperature()
128

Bagian 5: Script Sederhana dan Upload File

5.1 Menulis Script Sederhana di REPL

Sebelum membuat file script, kita akan belajar menulis dan menjalankan kode sederhana langsung di REPL. Ini berguna untuk testing dan eksperimen cepat.

Praktikum 5.1: Script Dasar di REPL

Langkah 1: Variabel dan Operasi Dasar

>>> # Deklarasi variabel
>>> nama = "ESP32"
>>> versi = 1.21
>>> aktif = True

>>> # Operasi matematika
>>> a = 10
>>> b = 20
>>> hasil = a + b
>>> print(f"Hasil: {hasil}")
Hasil: 30

Langkah 2: Struktur Kontrol

>>> # Conditional statement
>>> suhu = 25
>>> if suhu > 30:
...     print("Panas")
... elif suhu > 20:
...     print("Hangat")
... else:
...     print("Dingin")
... 
Hangat

Langkah 3: Loop

>>> # For loop
>>> for i in range(5):
...     print(f"Iterasi: {i}")
... 
Iterasi: 0
Iterasi: 1
Iterasi: 2
Iterasi: 3
Iterasi: 4

>>> # While loop
>>> counter = 0
>>> while counter < 3:
...     print(f"Counter: {counter}")
...     counter += 1
... 
Counter: 0
Counter: 1
Counter: 2

Langkah 4: Function

>>> def sapa(nama):
...     return f"Halo, {nama}!"
... 
>>> pesan = sapa("MicroPython")
>>> print(pesan)
Halo, MicroPython!

5.2 Sistem File MicroPython

MicroPython pada ESP32 memiliki sistem file sederhana yang memungkinkan kita menyimpan dan menjalankan script Python. File-file ini disimpan di flash memory ESP32.

Praktikum 5.2: Eksplorasi File System

Langkah 1: Periksa File System

>>> import uos
>>> uos.listdir()
['boot.py']

Langkah 2: Informasi Storage

>>> uos.statvfs('/')
(4096, 4096, 504, 504, 504, 0, 0, 0, 0, 255)

Langkah 3: Direktori Kerja

>>> uos.getcwd()
'/'

5.3 Membuat dan Menjalankan File Script

Ada beberapa cara untuk membuat dan menjalankan file script di MicroPython. Kita akan menggunakan REPL untuk membuat file sederhana terlebih dahulu.

Praktikum 5.3: Membuat File Script Pertama

Langkah 1: Membuat File dengan REPL

>>> # Membuat file hello.py
>>> with open('hello.py', 'w') as f:
...     f.write('print("Hello dari file script!")\n')
...     f.write('print("MicroPython di ESP32")\n')
... 

Langkah 2: Verifikasi File

>>> uos.listdir()
['boot.py', 'hello.py']

Langkah 3: Membaca Isi File

>>> with open('hello.py', 'r') as f:
...     content = f.read()
...     print(content)
... 
print("Hello dari file script!")
print("MicroPython di ESP32")

Langkah 4: Menjalankan File Script

>>> exec(open('hello.py').read())
Hello dari file script!
MicroPython di ESP32

Atau menggunakan import:

>>> import hello
Hello dari file script!
MicroPython di ESP32

5.4 Upload File menggunakan VSCode

Menggunakan REPL untuk membuat file cukup merepotkan untuk script yang kompleks. VSCode dengan extension Pymakr memungkinkan kita untuk upload file langsung dari komputer ke ESP32.

Praktikum 5.4: Setup VSCode untuk Upload File

Langkah 1: Konfigurasi Pymakr

  1. Buka VSCode
  2. Buat folder baru untuk project MicroPython
  3. Buka folder tersebut di VSCode
  4. Klik icon Pymakr di sidebar
  5. Klik "Add Device"
  6. Pilih port serial ESP32 (contoh: COM3)
  7. Klik "Connect"

Langkah 2: Membuat File Script di VSCode

Buat file baru main.py:

# main.py - Script utama ESP32
import utime

def main():
    print("=== Program ESP32 Dimulai ===")
    print("Waktu boot:", utime.ticks_ms())

    # Loop utama
    counter = 0
    while counter < 10:
        print(f"Loop ke-{counter + 1}")
        utime.sleep(1)
        counter += 1

    print("=== Program Selesai ===")

if __name__ == "__main__":
    main()

Langkah 3: Upload File ke ESP32

  1. Klik kanan pada file main.py
  2. Pilih "Pymakr > Upload to device"
  3. File akan diupload ke ESP32

Langkah 4: Verifikasi Upload

Di REPL, periksa apakah file sudah terupload:

>>> uos.listdir()
['boot.py', 'hello.py', 'main.py']

Langkah 5: Jalankan Script

>>> exec(open('main.py').read())
=== Program ESP32 Dimulai ===
Waktu boot: 12345
Loop ke-1
Loop ke-2
Loop ke-3
...

5.5 Auto-start Script dengan boot.py dan main.py

MicroPython memiliki dua file khusus yang dijalankan otomatis saat ESP32 boot: - boot.py: Dijalankan pertama kali saat boot - main.py: Dijalankan setelah boot.py

Praktikum 5.5: Membuat Auto-start Script

Langkah 1: Periksa boot.py Default

>>> with open('boot.py', 'r') as f:
...     print(f.read())
... 
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
#import webrepl
#webrepl.start()
import gc
gc.collect()

Langkah 2: Buat Custom main.py

Buat file main.py di VSCode:

# main.py - Auto-start script
import utime
import machine

def startup_message():
    """Menampilkan pesan startup"""
    print("\n" + "="*40)
    print("    ESP32 MicroPython System")
    print("="*40)
    print(f"Chip ID: {machine.unique_id()}")
    print(f"Frequency: {machine.freq()} Hz")
    print(f"Free Memory: {gc.mem_free()} bytes")
    print("="*40 + "\n")

def main_loop():
    """Loop utama program"""
    print("Memulai program utama...")

    # Contoh loop sederhana
    for i in range(5):
        print(f"Sistem berjalan... {i+1}/5")
        utime.sleep(2)

    print("Program utama selesai.")
    print("ESP32 siap menerima perintah REPL.")

# Jalankan saat boot
if __name__ == "__main__":
    startup_message()
    main_loop()

Langkah 3: Upload dan Test

  1. Upload file main.py ke ESP32
  2. Reset ESP32 (tekan tombol EN/RST)
  3. Amati output di serial terminal

Langkah 4: Membuat boot.py Custom

Buat file boot.py custom:

# boot.py - Custom boot script
import gc
import utime

print("Booting ESP32...")
print("MicroPython Custom Boot Script")

# Konfigurasi sistem
gc.collect()  # Garbage collection
print(f"Free memory after GC: {gc.mem_free()} bytes")

# Delay sebelum menjalankan main.py
print("Waiting 2 seconds before main...")
utime.sleep(2)

Bagian 6: Praktik Lanjutan dan Debugging

6.1 Debugging dan Error Handling

Debugging adalah proses penting dalam pengembangan embedded systems. MicroPython menyediakan beberapa tools untuk membantu debugging.

Praktikum 6.1: Teknik Debugging

Langkah 1: Print Debugging

Buat file debug_example.py:

# debug_example.py - Contoh debugging
import utime

def calculate_average(numbers):
    """Menghitung rata-rata dengan debugging"""
    print(f"[DEBUG] Input: {numbers}")
    print(f"[DEBUG] Type: {type(numbers)}")

    if not numbers:
        print("[ERROR] List kosong!")
        return None

    total = sum(numbers)
    count = len(numbers)
    average = total / count

    print(f"[DEBUG] Total: {total}")
    print(f"[DEBUG] Count: {count}")
    print(f"[DEBUG] Average: {average}")

    return average

# Test function
test_data = [10, 20, 30, 40, 50]
result = calculate_average(test_data)
print(f"Hasil: {result}")

# Test dengan data kosong
empty_data = []
result2 = calculate_average(empty_data)
print(f"Hasil 2: {result2}")

Langkah 2: Exception Handling

# exception_example.py - Contoh error handling
import machine

def safe_division(a, b):
    """Pembagian dengan error handling"""
    try:
        result = a / b
        print(f"Hasil: {a} / {b} = {result}")
        return result
    except ZeroDivisionError:
        print("Error: Pembagian dengan nol!")
        return None
    except TypeError:
        print("Error: Tipe data tidak valid!")
        return None

def test_memory_info():
    """Test akses informasi memory"""
    try:
        import gc
        free_mem = gc.mem_free()
        alloc_mem = gc.mem_alloc()
        print(f"Memory bebas: {free_mem}")
        print(f"Memory terpakai: {alloc_mem}")
    except Exception as e:
        print(f"Error mengakses memory info: {e}")

# Test functions
safe_division(10, 2)
safe_division(10, 0)
safe_division("10", 2)
test_memory_info()

6.2 Monitoring System Resources

Monitoring penggunaan resource sistem penting untuk memastikan program berjalan optimal pada ESP32 yang memiliki keterbatasan memory.

Praktikum 6.2: System Monitoring

Langkah 1: Memory Monitoring

# memory_monitor.py - Monitor penggunaan memory
import gc
import utime

class MemoryMonitor:
    def __init__(self):
        self.initial_free = gc.mem_free()
        self.initial_alloc = gc.mem_alloc()

    def show_memory_status(self, label=""):
        """Menampilkan status memory"""
        free_mem = gc.mem_free()
        alloc_mem = gc.mem_alloc()

        print(f"\n=== Memory Status {label} ===")
        print(f"Free Memory: {free_mem} bytes")
        print(f"Allocated Memory: {alloc_mem} bytes")
        print(f"Total Memory: {free_mem + alloc_mem} bytes")

        # Perbandingan dengan kondisi awal
        free_diff = free_mem - self.initial_free
        alloc_diff = alloc_mem - self.initial_alloc

        print(f"Free Memory Change: {free_diff:+d} bytes")
        print(f"Allocated Memory Change: {alloc_diff:+d} bytes")
        print("=" * 30)

    def force_gc(self):
        """Paksa garbage collection"""
        print("Menjalankan garbage collection...")
        gc.collect()
        self.show_memory_status("After GC")

# Test memory monitoring
monitor = MemoryMonitor()
monitor.show_memory_status("Initial")

# Simulasi penggunaan memory
big_list = []
for i in range(1000):
    big_list.append(f"Item {i}")

monitor.show_memory_status("After Creating List")

# Hapus list dan jalankan GC
del big_list
monitor.force_gc()

Langkah 2: System Information

# system_info.py - Informasi sistem ESP32
import machine
import esp32
import sys
import uos

def show_system_info():
    """Menampilkan informasi sistem lengkap"""
    print("\n" + "="*50)
    print("           ESP32 SYSTEM INFORMATION")
    print("="*50)

    # Hardware Info
    print("\n--- Hardware Information ---")
    print(f"Chip ID: {machine.unique_id().hex()}")
    print(f"CPU Frequency: {machine.freq():,} Hz")
    print(f"Hall Sensor: {esp32.hall_sensor()}")
    print(f"Temperature: {esp32.raw_temperature()}")

    # Software Info
    print("\n--- Software Information ---")
    print(f"MicroPython: {sys.implementation}")
    print(f"Platform: {sys.platform}")
    print(f"Version: {sys.version}")

    # Memory Info
    import gc
    print("\n--- Memory Information ---")
    print(f"Free Memory: {gc.mem_free():,} bytes")
    print(f"Allocated Memory: {gc.mem_alloc():,} bytes")

    # File System Info
    print("\n--- File System Information ---")
    print(f"Current Directory: {uos.getcwd()}")
    print(f"Files: {uos.listdir()}")

    # Storage Info
    try:
        stat = uos.statvfs('/')
        block_size = stat[0]
        total_blocks = stat[2]
        free_blocks = stat[3]

        total_size = block_size * total_blocks
        free_size = block_size * free_blocks
        used_size = total_size - free_size

        print(f"Total Storage: {total_size:,} bytes")
        print(f"Used Storage: {used_size:,} bytes")
        print(f"Free Storage: {free_size:,} bytes")
    except:
        print("Storage info not available")

    print("="*50 + "\n")

# Jalankan system info
show_system_info()

6.3 Performance Testing

Testing performa penting untuk memastikan kode berjalan efisien pada ESP32. Kita akan membuat beberapa benchmark sederhana.

Praktikum 6.3: Performance Benchmark

Langkah 1: Time Measurement

# performance_test.py - Test performa
import utime

def time_function(func, *args, **kwargs):
    """Mengukur waktu eksekusi fungsi"""
    start_time = utime.ticks_ms()
    result = func(*args, **kwargs)
    end_time = utime.ticks_ms()

    execution_time = utime.ticks_diff(end_time, start_time)
    print(f"Fungsi {func.__name__} selesai dalam {execution_time} ms")

    return result

def cpu_intensive_task(iterations=10000):
    """Task yang menggunakan CPU intensif"""
    result = 0
    for i in range(iterations):
        result += i * i
    return result

def memory_intensive_task(size=1000):
    """Task yang menggunakan memory intensif"""
    data = []
    for i in range(size):
        data.append(f"Data item {i}")
    return len(data)

def string_operations_test(count=1000):
    """Test operasi string"""
    text = ""
    for i in range(count):
        text += f"Item {i} "
    return len(text)

# Jalankan benchmark
print("=== Performance Benchmark ===")

# Test CPU intensive
result1 = time_function(cpu_intensive_task, 5000)
print(f"CPU Test Result: {result1}")

# Test memory intensive
result2 = time_function(memory_intensive_task, 500)
print(f"Memory Test Result: {result2}")

# Test string operations
result3 = time_function(string_operations_test, 100)
print(f"String Test Result: {result3}")

print("=== Benchmark Selesai ===")

Langkah 2: Memory Usage Test

# memory_usage_test.py - Test penggunaan memory
import gc

def memory_usage_test():
    """Test penggunaan memory untuk berbagai operasi"""

    def get_memory_usage():
        return gc.mem_alloc()

    print("=== Memory Usage Test ===")

    # Baseline memory
    gc.collect()
    baseline = get_memory_usage()
    print(f"Baseline memory: {baseline} bytes")

    # Test 1: List creation
    print("\nTest 1: Creating large list")
    mem_before = get_memory_usage()
    large_list = [i for i in range(1000)]
    mem_after = get_memory_usage()
    print(f"Memory before: {mem_before} bytes")
    print(f"Memory after: {mem_after} bytes")
    print(f"Memory used: {mem_after - mem_before} bytes")

    # Test 2: String operations
    print("\nTest 2: String concatenation")
    mem_before = get_memory_usage()
    big_string = ""
    for i in range(100):
        big_string += f"String number {i} with some text. "
    mem_after = get_memory_usage()
    print(f"Memory before: {mem_before} bytes")
    print(f"Memory after: {mem_after} bytes")
    print(f"Memory used: {mem_after - mem_before} bytes")

    # Cleanup
    del large_list
    del big_string
    gc.collect()

    final_memory = get_memory_usage()
    print(f"\nFinal memory after cleanup: {final_memory} bytes")
    print(f"Memory recovered: {mem_after - final_memory} bytes")

# Jalankan test
memory_usage_test()

6.4 Best Practices untuk MicroPython ESP32

Beberapa best practices yang perlu diikuti saat mengembangkan aplikasi MicroPython pada ESP32.

Praktikum 6.4: Implementasi Best Practices

Langkah 1: Efficient Code Structure

# best_practices_example.py - Contoh best practices
import gc
import utime

class ESP32Application:
    """Template aplikasi ESP32 yang efisien"""

    def __init__(self, name="ESP32 App"):
        self.name = name
        self.running = False
        self.setup_complete = False

        # Jalankan setup
        self.setup()

    def setup(self):
        """Setup awal aplikasi"""
        print(f"Setting up {self.name}...")

        # Garbage collection di awal
        gc.collect()

        # Konfigurasi hardware jika diperlukan
        # (akan dibahas di pertemuan selanjutnya)

        self.setup_complete = True
        print("Setup complete!")

    def run(self):
        """Main loop aplikasi"""
        if not self.setup_complete:
            print("Error: Setup belum selesai!")
            return

        self.running = True
        print(f"Starting {self.name}...")

        try:
            while self.running:
                self.loop()
                utime.sleep_ms(100)  # Yield CPU

        except KeyboardInterrupt:
            print("\nProgram dihentikan oleh user")
        except Exception as e:
            print(f"Error: {e}")
        finally:
            self.cleanup()

    def loop(self):
        """Loop utama - override di subclass"""
        # Implementasi loop aplikasi
        pass

    def stop(self):
        """Hentikan aplikasi"""
        self.running = False

    def cleanup(self):
        """Cleanup resources"""
        print("Cleaning up...")
        gc.collect()
        print("Cleanup complete!")

# Contoh implementasi aplikasi
class SimpleCounterApp(ESP32Application):
    """Aplikasi counter sederhana"""

    def __init__(self):
        self.counter = 0
        self.max_count = 10
        super().__init__("Simple Counter")

    def loop(self):
        """Loop counter"""
        self.counter += 1
        print(f"Counter: {self.counter}")

        if self.counter >= self.max_count:
            print("Counter reached maximum!")
            self.stop()

        utime.sleep(1)

# Test aplikasi
if __name__ == "__main__":
    app = SimpleCounterApp()
    app.run()

Langkah 2: Error Handling dan Logging

# logging_example.py - Sistem logging sederhana
import utime

class SimpleLogger:
    """Logger sederhana untuk ESP32"""

    LEVELS = {
        'DEBUG': 0,
        'INFO': 1,
        'WARNING': 2,
        'ERROR': 3
    }

    def __init__(self, level='INFO'):
        self.level = self.LEVELS.get(level, 1)
        self.start_time = utime.ticks_ms()

    def _log(self, level, message):
        """Internal logging method"""
        if self.LEVELS[level] >= self.level:
            timestamp = utime.ticks_diff(utime.ticks_ms(), self.start_time)
            print(f"[{timestamp:06d}ms] {level}: {message}")

    def debug(self, message):
        self._log('DEBUG', message)

    def info(self, message):
        self._log('INFO', message)

    def warning(self, message):
        self._log('WARNING', message)

    def error(self, message):
        self._log('ERROR', message)

# Contoh penggunaan logger
logger = SimpleLogger('DEBUG')

def safe_operation(a, b):
    """Operasi dengan logging dan error handling"""
    logger.debug(f"Starting operation with a={a}, b={b}")

    try:
        if b == 0:
            logger.warning("Division by zero attempted")
            return None

        result = a / b
        logger.info(f"Operation successful: {a}/{b} = {result}")
        return result

    except Exception as e:
        logger.error(f"Unexpected error: {e}")
        return None

# Test logging
logger.info("Program started")
safe_operation(10, 2)
safe_operation(10, 0)
safe_operation("invalid", 2)
logger.info("Program finished")