#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// ===== WIFI & API =====
const char* WIFI_SSID = "Wokwi-GUEST"; // ganti ke WiFi real kalau bisa
const char* WIFI_PASS = ""; // (Wokwi bisa membatasi koneksi ke googleapis)
const char* GEMINI_API_KEY = "AIzaSyAnfUJ_vq5IX3G2Hyk5gkjeifxoa606hIc"; // JANGAN commit secara publik
const char* HOST = "generativelanguage.googleapis.com";
const uint16_t PORT = 443;
const char* PATH_PREFIX = "/v1beta/models/gemini-2.0-flash:generateContent?key=";
// ===== DUMMY SENSOR =====
const int PIN_SENSOR = 34;
WiFiClientSecure ssl;
HTTPClient http;
const char* httpErrorStr(int code) {
switch (code) {
case -1: return "CONNECTION_REFUSED/FAILED";
case -2: return "SEND_HEADER_FAILED";
case -3: return "SEND_PAYLOAD_FAILED";
case -4: return "NOT_CONNECTED";
case -5: return "CONNECTION_LOST";
case -6: return "NO_STREAM";
case -7: return "NO_HTTP_SERVER";
case -8: return "TOO_LESS_RAM";
case -9: return "ENCODING";
case -10: return "STREAM_WRITE";
case -11: return "READ_TIMEOUT";
default: return "UNKNOWN";
}
}
String buildPrompt(float tempC) {
String p = "Sensor dummy membaca suhu ~";
p += String(tempC, 1);
p += " C. Jelaskan status singkat (nyaman/tidak) dan 1 rekomendasi ringkas (<=20 kata).";
return p;
}
String buildRequestBody(const String& prompt) {
StaticJsonDocument<512> doc;
JsonArray contents = doc.createNestedArray("contents");
JsonObject item = contents.createNestedObject();
JsonArray parts = item.createNestedArray("parts");
parts.createNestedObject()["text"] = prompt;
JsonObject cfg = doc.createNestedObject("generationConfig");
cfg["maxOutputTokens"] = 96;
cfg["temperature"] = 0.3;
String out; serializeJson(doc, out);
return out;
}
bool beginGemini() {
// DEV ONLY: tanpa verifikasi sertifikat biar cepat running di dev.
// PRODUKSI: gunakan root CA / certificate pinning!
ssl.setInsecure();
ssl.setTimeout(15000);
// Susun path final
String path = String(PATH_PREFIX) + GEMINI_API_KEY;
// Bentuk begin(host, port, path, https=true)
bool ok = http.begin(ssl, HOST, PORT, path, true);
if (!ok) return false;
http.setTimeout(15000);
http.setReuse(true);
http.addHeader("Content-Type", "application/json");
http.addHeader("Accept", "application/json");
// http.addHeader("User-Agent", "ESP32-Gemini/1.0");
return true;
}
String postToGemini(const String& body) {
if (!beginGemini()) return "ERR: http.begin gagal";
int code = http.POST(body);
if (code <= 0) {
String msg = String("ERR HTTP ") + code + " (" + httpErrorStr(code) + ")";
http.end();
return msg;
}
String resp = http.getString();
http.end();
return resp;
}
String extractTextFromResponse(const String& json) {
// Jangan parse kalau respons bukan JSON
if (!json.startsWith("{") && !json.startsWith("[")) {
return "ERR: bukan JSON. Body: " + json;
}
DynamicJsonDocument doc(8192);
DeserializationError err = deserializeJson(doc, json);
if (err) return String("ERR parse: ") + err.c_str();
JsonVariant j = doc["candidates"][0]["content"]["parts"][0]["text"];
if (j.isNull()) {
// tampilkan sebagian body untuk debug
String snippet = json.substring(0, 200);
return "ERR: tak ada teks balasan. Snip: " + snippet;
}
return j.as<String>();
}
void setup() {
Serial.begin(115200);
delay(200);
WiFi.mode(WIFI_STA);
WiFi.setSleep(false);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("WiFi");
unsigned long t0 = millis();
while (WiFi.status() != WL_CONNECTED) {
delay(300); Serial.print(".");
if (millis() - t0 > 20000) {
Serial.println("\nWiFi timeout. Cek SSID/password atau jaringan.");
break;
}
}
Serial.println("\nIP: " + WiFi.localIP().toString());
// Tes sekali saat boot
int raw = analogRead(PIN_SENSOR);
float tempC = (raw / 4095.0) * 60.0;
String prompt = buildPrompt(tempC);
String req = buildRequestBody(prompt);
Serial.println("\n=== PROMPT ===");
Serial.println(prompt);
String resp = postToGemini(req);
Serial.println("\n=== RAW RESPONSE ===");
Serial.println(resp);
String text = extractTextFromResponse(resp);
Serial.println("\n=== GEMINI TEXT ===");
Serial.println(text);
}
unsigned long last = 0;
void loop() {
if (millis() - last > 20000) {
last = millis();
int raw = analogRead(PIN_SENSOR);
float tempC = (raw / 4095.0) * 60.0;
String prompt = buildPrompt(tempC);
String req = buildRequestBody(prompt);
String resp = postToGemini(req);
String text = extractTextFromResponse(resp);
Serial.print("\n[");
Serial.print(millis()/1000);
Serial.print("s] ");
Serial.println(text);
}
}