# main.py
# Greenhouse BAS - ESP32 + MicroPython + FastAPI
import network
import time
import json
import dht
from machine import Pin
try:
import urequests as requests
except ImportError:
import requests
# =========================================
# KONFIGURASI
# =========================================
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
# Ganti dengan URL HTTPS FastAPI Anda.
# Contoh: https://nama-acak.trycloudflare.com
API_BASE = "https://GANTI-DENGAN-URL-ANDA.trycloudflare.com"
# Harus sama dengan API_KEY pada server.py
API_KEY = "GANTI_DENGAN_TOKEN_RAHASIA"
DEVICE_ID = "GREENHOUSE-01"
SENSOR_PIN = 15
FAN_PIN = 18
HUMIDIFIER_PIN = 19
INTERVAL = 5
# Setpoint lokal awal jika server belum berhasil dihubungi
settings = {
"mode": "AUTO",
"setpoint_temp": 28.0,
"setpoint_humidity": 60.0,
"fan": False,
"humidifier": False
}
fan_on = False
humidifier_on = False
sensor = dht.DHT22(Pin(SENSOR_PIN))
fan = Pin(FAN_PIN, Pin.OUT)
humidifier = Pin(HUMIDIFIER_PIN, Pin.OUT)
fan.off()
humidifier.off()
# =========================================
# KONEKSI WIFI
# =========================================
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
def connect_wifi():
if wlan.isconnected():
return True
print("Menghubungkan ke Wi-Fi...")
try:
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
except Exception as e:
print("Wi-Fi:", e)
return False
for _ in range(30):
if wlan.isconnected():
print("Wi-Fi terhubung:", wlan.ifconfig()[0])
return True
time.sleep(1)
print("Wi-Fi belum terhubung")
return False
# =========================================
# HTTP CLIENT
# =========================================
def api_request(method, path, payload=None):
if not wlan.isconnected():
return None
url = API_BASE + path
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
response = None
try:
if method == "GET":
response = requests.get(
url, headers=headers
)
else:
response = requests.post(
url,
headers=headers,
data=json.dumps(payload)
)
if response.status_code >= 200 and \
response.status_code < 300:
try:
return response.json()
except Exception:
return None
print("HTTP status:", response.status_code)
return None
except Exception as e:
print("HTTP error:", e)
return None
finally:
if response is not None:
try:
response.close()
except Exception:
pass
# =========================================
# MENGAMBIL SETTING DARI SERVER
# =========================================
def get_command():
global settings
data = api_request("GET", "/command")
if not isinstance(data, dict):
return
mode = data.get("mode", settings["mode"])
if mode not in ("AUTO", "MANUAL"):
return
# Validasi nilai setpoint
try:
temp_sp = float(data.get(
"setpoint_temp",
settings["setpoint_temp"]
))
humidity_sp = float(data.get(
"setpoint_humidity",
settings["setpoint_humidity"]
))
if not -10 <= temp_sp <= 80:
return
if not 0 <= humidity_sp <= 100:
return
except (TypeError, ValueError):
return
settings["mode"] = mode
settings["setpoint_temp"] = temp_sp
settings["setpoint_humidity"] = humidity_sp
settings["fan"] = bool(data.get("fan", False))
settings["humidifier"] = bool(
data.get("humidifier", False)
)
# =========================================
# LOGIKA KONTROL OTOMATIS
# =========================================
def automatic_control(temp, rh):
global fan_on, humidifier_on
# Histeresis suhu: setpoint +/- 1 C
temp_sp = settings["setpoint_temp"]
if temp >= temp_sp + 1.0:
fan_on = True
elif temp <= temp_sp - 1.0:
fan_on = False
# Histeresis kelembaban: setpoint +/- 5%
rh_sp = settings["setpoint_humidity"]
if rh <= rh_sp - 5.0:
humidifier_on = True
elif rh >= rh_sp + 5.0:
humidifier_on = False
def apply_outputs():
# Interlock dasar: jangan aktifkan keduanya sekaligus.
# Ubah aturan ini jika desain greenhouse memerlukan
# kipas dan humidifier bekerja bersamaan secara aman.
if fan_on:
humidifier_on_local = False
else:
humidifier_on_local = humidifier_on
fan.value(1 if fan_on else 0)
humidifier.value(
1 if humidifier_on_local else 0
)
return humidifier_on_local
# =========================================
# PROGRAM UTAMA
# =========================================
print("Greenhouse BAS dimulai")
connect_wifi()
last_command_time = time.time() - 10
while True:
try:
# Baca sensor
sensor.measure()
temperature = sensor.temperature()
humidity = sensor.humidity()
# Ambil perintah server setiap 5 detik.
# Perintah manual tetap dipertahankan ketika
# server tidak dapat dihubungi.
if time.time() - last_command_time >= INTERVAL:
if not wlan.isconnected():
connect_wifi()
if wlan.isconnected():
get_command()
last_command_time = time.time()
# Jalankan kontrol lokal
if settings["mode"] == "AUTO":
automatic_control(temperature, humidity)
else:
fan_on = settings["fan"]
humidifier_on = settings["humidifier"]
actual_humidifier = apply_outputs()
print(
"T={:.1f} C | RH={:.1f}% | Mode={} | Fan={} | Hum={}".format(
temperature,
humidity,
settings["mode"],
fan_on,
actual_humidifier
)
)
# Kirim telemetry ke server
payload = {
"device_id": DEVICE_ID,
"temperature": temperature,
"humidity": humidity,
"fan": bool(fan_on),
"humidifier": bool(actual_humidifier),
"mode": settings["mode"]
}
if wlan.isconnected():
api_request("POST", "/telemetry", payload)
except Exception as e:
print("Kesalahan pembacaan/kontrol:", e)
# Kondisi aman jika pembacaan sensor gagal.
# Matikan aktuator dan jangan memakai data
# sensor yang sudah tidak valid.
fan_on = False
humidifier_on = False
fan.off()
humidifier.off()
time.sleep(INTERVAL)
Loading
esp32-devkit-v1
esp32-devkit-v1