Pendahuluan — Dari HTTP ke HTTPS di ESP32

Seri 1 sudah mengajarkan WiFi (#4), web server lokal (#6), dan MQTT (#7). Di Tier 2, MQTT TLS (#17) mengamankan koneksi ke broker Mosquitto (#16) di jaringan lokal — misalnya 192.168.1.50.

Artikel Tier 2 ini fokus pada skenario berbeda: ESP32 memanggil REST API publik lewat HTTPS — webhook, layanan cloud, atau backend VPS di internet. Kita pakai WiFiClientSecure + HTTPClient, bukan protokol MQTT. Ini melengkapi REST vs MQTT (#20), Firebase (#30), dan persiapan capstone greenhouse (#39).

Prasyarat: Paham GPIO (#3), WiFi (#4), DHT22 (#5), dan idealnya sudah baca MQTT TLS (#17) agar tidak bingung antara TLS untuk broker vs TLS untuk HTTP.

HTTPS vs HTTP — Mengapa Harus Terenkripsi?

HTTP mengirim data sensor (suhu, lokasi, token API) dalam bentuk teks biasa — siapa pun di jaringan WiFi publik atau ISP bisa membaca paket. HTTPS membungkus HTTP di dalam TLS: server membuktikan identitas lewat sertifikat, lalu saluran terenkripsi.

AspekHTTPHTTPS
Port default80443
EnkripsiTidakTLS 1.2+
Verifikasi serverTidakRoot CA
Cocok untuk API cloud
Web server ESP32 lokal (#6)✅ LANOpsional

WiFiClientSecure vs WiFiClient Biasa

Library HTTPClient Arduino bisa memakai WiFiClient untuk URL http:// atau WiFiClientSecure untuk https://. Kelas secure menambahkan handshake TLS di atas TCP — mirip konsep di MQTT TLS (#17), tapi stack aplikasinya HTTP, bukan publish/subscribe.

  • WiFiClient — cukup untuk web server lokal (#6) di LAN
  • WiFiClientSecure — wajib untuk API eksternal, Firebase (#30), webhook produksi

Pro tip: Artikel ini tidak membutuhkan SPI.h — tidak ada SD Card atau periferal SPI seperti di logging SD (#37). Cukup WiFi + sensor DHT22 (#5).

Perbedaan dengan MQTT TLS (#17)

TopikMQTT TLS (#17)HTTPS REST (artikel ini)
ProtokolMQTT publish/subscribeHTTP GET/POST request-response
Library utamaPubSubClient + WiFiClientSecureHTTPClient + WiFiClientSecure
Port umum8883 (broker)443 (web API)
Target tipikalBroker 192.168.1.50Domain publik api.example.com
Pola dataTopic + payload berkelanjutanEndpoint + JSON sekali kirim

Keduanya memakai setCACert() untuk verifikasi server — konsep sertifikat sama, konteks aplikasi berbeda. Baca #20 untuk memilih arsitektur proyek.

HTTPClient + WiFiClientSecure — Pola Dasar

Alur standar di firmware ESP32:

  1. Connect WiFi dengan placeholder GANTI_NAMA_WIFI / GANTI_PASSWORD_WIFI
  2. Instansiasi WiFiClientSecure client
  3. Panggil client.setCACert(root_ca) dengan sertifikat CA yang di-embed
  4. http.begin(client, url) — pass client secure ke HTTPClient
  5. GET atau POST → baca http.getString() atau status code
  6. http.end() setiap selesai

Prasyarat & Koneksi WiFi

Sama seperti seluruh seri — jangan hardcode SSID/password di repo publik:

#include <WiFi.h>

const char* WIFI_SSID = "GANTI_NAMA_WIFI";
const char* WIFI_PASS = "GANTI_PASSWORD_WIFI";

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi OK");
}

Untuk deploy lapangan, simpan kredensial di NVS (#12) — pola yang sama dipakai di capstone #10.

Mendapatkan Root CA Certificate

Server HTTPS mempresentasikan rantai sertifikat; ESP32 perlu root CA (Certificate Authority) tepercaya untuk memverifikasi bahwa Anda benar-benar berbicara dengan server yang dimaksud — bukan penyerang man-in-the-middle.

Cara umum mengambil root CA (contoh untuk Let's Encrypt / ISRG):

openssl s_client -showcerts -connect api.example.com:443 < /dev/null 2>/dev/null \
  | openssl x509 -outform PEM > ca.pem

Atau unduh bundle CA resmi dari dokumentasi penyedia API. Salin isi PEM ke variabel const char* root_ca di sketch.

Embed Sertifikat Root CA di Firmware

Sertifikat disimpan sebagai string multiline di flash — tidak perlu filesystem eksternal:

const char* root_ca =
  "-----BEGIN CERTIFICATE-----\n"
  "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
  "... baris base64 dari ca.pem ...\n"
  "-----END CERTIFICATE-----\n";

Ganti baris tengah dengan isi file ca.pem Anda. Jangan commit sertifikat produksi sensitif jika organisasi Anda punya kebijakan khusus — untuk CA publik, ini aman.

setCACert — Verifikasi Server yang Benar

#include <WiFiClientSecure.h>
#include <HTTPClient.h>

WiFiClientSecure secureClient;

void setupSecureHttp() {
  secureClient.setCACert(root_ca);
  // Opsional: setTimeout jika API lambat
  secureClient.setTimeout(15000);
}

Tanpa setCACert, handshake TLS gagal atau library menolak koneksi — ESP32 tidak punya trust store lengkap seperti browser desktop.

setInsecure — Hanya untuk Development

Baris berikut mematikan verifikasi sertifikat:

secureClient.setInsecure(); // JANGAN di produksi!

Berguna saat prototyping cepat di lab — misalnya API self-signed tanpa CA. Di lapangan atau cloud, selalu pakai setCACert. Sama seperti peringatan di MQTT TLS (#17): jangan bawa kebijakan dev ke produksi.

HTTPS GET — Baca Data dari API

Contoh membaca konfigurasi atau status dari endpoint:

void httpsGetExample() {
  HTTPClient http;
  const char* url = "https://api.example.com/v1/status";

  if (!http.begin(secureClient, url)) {
    Serial.println("http.begin gagal");
    return;
  }

  int code = http.GET();
  if (code == HTTP_CODE_OK) {
    String body = http.getString();
    Serial.println(body);
  } else {
    Serial.printf("GET error: %d\n", code);
  }
  http.end();
}

Response bisa JSON — parse dengan ArduinoJson jika perlu threshold suhu untuk relay di artikel capstone #10.

HTTPS POST — Kirim Data Sensor JSON

Pola utama artikel ini: kirim pembacaan DHT22 (#5) ke backend REST, paralel atau pengganti MQTT:

void httpsPostSensor(float tempC, float humPct, long unixTs) {
  HTTPClient http;
  const char* url = "https://api.example.com/v1/sensors";

  if (!http.begin(secureClient, url)) return;

  http.addHeader("Content-Type", "application/json");
  // Header auth — ganti dengan token Anda, jangan commit ke repo
  http.addHeader("Authorization", "Bearer GANTI_TOKEN_API");

  char payload[200];
  snprintf(payload, sizeof(payload),
    "{\"unix\":%ld,\"timestamp\":\"2026-07-02T14:30:00\","
    "\"temp\":%.1f,\"hum\":%.1f,\"device\":\"esp32-dht22\"}",
    unixTs, tempC, humPct);

  int code = http.POST(payload);
  Serial.printf("POST %d\n", code);
  if (code > 0) {
    Serial.println(http.getString());
  }
  http.end();
}

Payload JSON dengan Timestamp NTP

Gunakan waktu akurat dari NTP (#34) — contoh unix 1782977400 dan ISO 2026-07-02T14:30:00 konsisten di seluruh seri:

time_t now = time(nullptr); // setelah configTime() NTP
struct tm ti;
localtime_r(&now, &ti);
char iso[25];
strftime(iso, sizeof(iso), "%Y-%m-%dT%H:%M:%S", &ti);

char payload[220];
snprintf(payload, sizeof(payload),
  "{\"unix\":%ld,\"timestamp\":\"%s\",\"temp\":%.1f,\"hum\":%.1f}",
  (long)now, iso, tempC, humPct);

Backend Python (#18) bisa menerima POST HTTPS dengan skema field yang sama seperti payload MQTT — memudahkan migrasi dari broker ke REST.

Kontras: Broker Lokal 192.168.1.50 vs API HTTPS Publik

LingkunganAlamat contohProtokolArtikel terkait
Broker rumah / VPS LAN192.168.1.50:1883MQTT plain / TLS 8883#16, #17
API cloud / SaaShttps://api.example.comHTTPS 443#38 (ini)
Firebasehttps://*.firebaseio.comHTTPS + token#30
Web server ESP32http://192.168.1.xHTTP LAN#6

Node MQTT di LAN bisa pakai user kindo_esp32 dengan password GANTI_PASSWORD_MQTT — itu pola broker, bukan header REST. Jangan campur kredensial MQTT ke header Authorization API kecuali backend Anda memang mendesainnya demikian.

REST API vs MQTT — Kapan Pakai HTTPS?

Rangkuman dari #20:

  • HTTPS REST — laporan berkala ke SaaS, webhook, integrasi HTTP-only, mobile backend
  • MQTT — banyak device, real-time, broker pusat, dashboard Grafana (#19)
  • Keduanya — hybrid seperti capstone #10: MQTT lokal + HTTPS backup ke cloud

Error Handling & Kode Respons HTTP

  • 200 OK — sukses GET/POST
  • 201 Created — resource baru tersimpan
  • 401 Unauthorized — token API salah atau kedaluwarsa
  • 429 Too Many Requests — rate limit; tambah interval kirim
  • -1 dari HTTPClient — gagal TLS, DNS, atau timeout

Log kode ke Serial dan, jika perlu, simpan counter error di NVS (#12) untuk diagnosa setelah deep sleep (#11).

Timeout, Reconnect & Stabilitas WiFi

http.setTimeout(20000);
http.setReuse(false); // tutup koneksi bersih tiap request

Setelah deep sleep (#11), WiFi mungkin putus — panggil connectWiFi() ulang sebelum HTTPS. Untuk node yang hanya POST sekali per bangun, satu request lalu sleep sudah cukup.

Library Include — Tidak Perlu SPI.h

Daftar include untuk artikel ini:

  • WiFi.h — koneksi jaringan
  • WiFiClientSecure.h — lapisan TLS
  • HTTPClient.h — GET/POST HTTP(S)
  • DHT.h — sensor demo (#5)
  • Tidak SPI.h / SD.h — logging offline ada di #37

Sketch Lengkap — WiFi, GET, POST DHT22

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <time.h>

const char* WIFI_SSID = "GANTI_NAMA_WIFI";
const char* WIFI_PASS = "GANTI_PASSWORD_WIFI";

const char* root_ca =
  "-----BEGIN CERTIFICATE-----\n"
  "GANTI_DENGAN_ISI_CA_PEM_ANDA\n"
  "-----END CERTIFICATE-----\n";

#define DHT_PIN  4
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);

WiFiClientSecure client;
const char* API_POST = "https://api.example.com/v1/sensors";
const char* API_GET  = "https://api.example.com/v1/config";

void setupNtp() {
  configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  struct tm ti;
  while (!getLocalTime(&ti)) delay(200);
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  delay(2000);

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  client.setCACert(root_ca);
  setupNtp();

  // Demo GET
  HTTPClient httpGet;
  if (httpGet.begin(client, API_GET)) {
    int c = httpGet.GET();
    Serial.printf("GET %d\n", c);
    httpGet.end();
  }

  // Demo POST sensor
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  if (!isnan(t) && !isnan(h)) {
    HTTPClient httpPost;
    if (httpPost.begin(client, API_POST)) {
      httpPost.addHeader("Content-Type", "application/json");
      char body[180];
      snprintf(body, sizeof(body),
        "{\"unix\":1782977400,\"timestamp\":\"2026-07-02T14:30:00\","
        "\"temp\":%.1f,\"hum\":%.1f}", t, h);
      int c = httpPost.POST(body);
      Serial.printf("POST %d\n", c);
      httpPost.end();
    }
  }
}

void loop() {
  delay(60000);
}

PlatformIO — Dependency

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
    adafruit/DHT sensor library@^1.4

HTTPClient dan WiFiClientSecure sudah termasuk framework Arduino ESP32 — tidak perlu lib tambahan untuk TLS dasar.

Integrasi Dashboard & Otomasi

Data yang masuk via HTTPS POST bisa diolah server yang sama dengan pipeline MQTT:

Keamanan & Best Practice

  • Selalu setCACert di produksi — hindari setInsecure()
  • Jangan simpan token API atau password WiFi di Git — pakai GANTI_* placeholder
  • Rotasi token jika firmware pernah bocor; simpan token di NVS (#12)
  • HTTPS tidak menggantikan autentikasi aplikasi — tetap butuh API key atau OAuth di header
  • Perbarui root CA jika penyedia ganti CA (jarang, tapi pernah terjadi)
  • Pisahkan MQTT broker (192.168.1.50) dari API publik — attack surface berbeda

Estimasi Biaya (Indonesia)

KomponenHarga (Rp)
ESP32 DevKit35.000 – 55.000
DHT2235.000 – 55.000
Breadboard + jumper15.000 – 25.000
API cloud gratis tier0 (Firebase #30, webhook, dll.)
VPS HTTPS (opsional)50.000 – 150.000 / bulan
Total hardware demo~85.000 – 135.000

Checklist Sebelum Demo

  • ☐ WiFi connect dengan GANTI_NAMA_WIFI / GANTI_PASSWORD_WIFI
  • ☐ Root CA benar — TLS handshake sukses (bukan -1)
  • setInsecure() tidak aktif di build demo
  • ☐ GET mengembalikan 200 atau respons yang diharapkan
  • ☐ POST JSON berisi unix + suhu/kelembaban DHT22
  • ☐ Token API pakai placeholder GANTI_TOKEN_API
  • ☐ Serial log menampilkan kode HTTP, bukan stack trace TLS

FAQ Singkat

Sama dengan MQTT TLS (#17)?
Tidak — #17 mengamankan broker MQTT; artikel ini mengamankan HTTP REST ke API web.
Perlu SPI.h?
Tidak — tidak ada SD Card. Lihat #37 jika butuh log offline.
setInsecure aman di rumah?
Hanya prototyping singkat. Untuk API produksi, wajib setCACert.
Bisa gabung MQTT + HTTPS?
Ya — MQTT ke 192.168.1.50 untuk real-time, HTTPS untuk backup cloud (#20).
Firebase sudah HTTPS?
Ya — #30 memakai pola serupa dengan token, bukan CA custom.

Tips & Troubleshooting

  • HTTP -1 / connection refused: Cek URL, DNS, firewall router, dan validitas root_ca
  • Certificate verify failed: Salah CA atau server pakai intermediate — unduh ulang chain yang benar
  • 401 terus: Token salah; jangan pakai password MQTT sebagai Bearer token
  • Heap low: Kurangi ukuran String; pakai buffer char[] untuk payload
  • DHT NaN: Sama seperti #5 — jangan POST jika bacaan invalid
  • Deep sleep gagal POST: Beri waktu cukup setelah wake untuk WiFi + TLS sebelum sleep lagi (#11)

Deep Sleep, NVS & URL API

Simpan URL endpoint dan interval POST di NVS (#12) agar bisa ganti backend tanpa re-flash. Node deep sleep (#11) bangun → WiFi → NTP (#34) → satu POST HTTPS → tidur — hemat energi dibanding maintain koneksi MQTT persisten.

Hybrid: MQTT Lokal + HTTPS Cloud

Arsitektur capstone #10 bisa diperluas: publish ke broker 192.168.1.50 untuk Home Assistant (#21), sekaligus POST HTTPS ke VPS untuk rekan yang tidak punya akses LAN. Data dari SD Card (#37) bisa di-upload lewat HTTPS saat backlog sync.

Langkah Selanjutnya — Menuju Greenhouse #39

HTTPS REST melengkapi puzzle keamanan Tier 2 setelah MQTT TLS (#17). Anda sekarang bisa:

  • Mengirim sensor ke API cloud dengan TLS dan verifikasi CA
  • Membedakan kapan MQTT (#7), REST (#20), atau keduanya
  • Mempersiapkan backend yang menerima JSON dengan timestamp 1782977400 / 2026-07-02T14:30:00

Di artikel berikutnya, capstone greenhouse (#39) akan menggabungkan multi-sensor, logging SD (#37), MQTT, dan HTTPS ke satu sistem monitoring kebun lengkap — lanjutkan di halaman artikel Koding Indonesia.