🌍 گرفتن داده از اینترنت با ESP32: HTTPClient، خواندن JSON از API و HTTPS
تا حالا ESP32 بیشتر «جوابدهنده» بود: یک وبسرور میساخت و مرورگر از آن چیزی میخواست. ولی خیلی از پروژههای جالب برعکساند؛ برد باید خودش از اینترنت چیزی بپرسد: دمای امروز شهر، نرخ یک ارز، آخرین پیام یک ربات یا تنظیماتی که روی یک سرور گذاشتهای. ابزار این کار HTTPClient در ESP32 است. در این آموزش با یک درخواست GET وضعیت هوای تهران را از یک API رایگان میگیریم، JSON جواب را با ArduinoJson میخوانیم و با HTTPS کار میکنیم.
چه میسازیم؟
برنامهای که هر ده دقیقه یکبار از سرویس رایگان Open-Meteo، که کلید API نمیخواهد، دما و سرعت باد تهران را میپرسد و در سریال مانیتور مینویسد. جواب این سرویس چیزی شبیه این است:
{
"latitude": 35.7,
"longitude": 51.4,
"current": {
"time": "2026-10-20T14:30",
"temperature_2m": 21.4,
"wind_speed_10m": 7.9
}
}
ما فقط به سه مقدار داخل current نیاز داریم. ساختن خود API روی برد، یعنی طرف مقابل این ماجرا، را در ساخت API با JSON روی ESP32 یاد گرفتی.
قطعهها و کتابخانهها
- یک برد ESP32 و یک وایفای ۲٫۴ گیگاهرتز با اینترنت. سیمکشی لازم نیست.
HTTPClientوWiFiClientSecureهمراه هستهی ESP32 نصباند.- کتابخانهی ArduinoJson نسخهی ۷ را از Library Manager نصب کن.
کد کامل
// ESP32 HTTP client: read Tehran's weather from a public JSON API over HTTPS.
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";
const char* url = "https://api.open-meteo.com/v1/forecast"
"?latitude=35.69&longitude=51.39"
"¤t=temperature_2m,wind_speed_10m";
const unsigned long INTERVAL = 10UL * 60UL * 1000UL; // every 10 minutes
unsigned long lastFetch = 0;
bool firstRun = true;
void fetchWeather() {
WiFiClientSecure client;
client.setInsecure(); // learning only: skips the certificate check
HTTPClient http;
http.setTimeout(10000); // give up after 10 s
if (!http.begin(client, url)) {
Serial.println("Bad URL");
return;
}
int code = http.GET();
if (code == HTTP_CODE_OK) {
String body = http.getString();
JsonDocument doc; // ArduinoJson 7
DeserializationError err = deserializeJson(doc, body);
if (err) {
Serial.print("JSON error: ");
Serial.println(err.c_str());
} else {
float temp = doc["current"]["temperature_2m"] | -99.0;
float wind = doc["current"]["wind_speed_10m"] | -1.0;
const char* when = doc["current"]["time"] | "?";
Serial.print("Tehran ");
Serial.print(when);
Serial.print(": ");
Serial.print(temp, 1);
Serial.print(" C, wind ");
Serial.print(wind, 1);
Serial.println(" km/h");
}
} else {
Serial.print("HTTP error ");
Serial.print(code);
Serial.print(": ");
Serial.println(http.errorToString(code));
}
http.end(); // always free the connection
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(300);
Serial.print(".");
}
Serial.println(" OK");
}
void loop() {
if (firstRun || millis() - lastFetch >= INTERVAL) {
firstRun = false;
lastFetch = millis();
if (WiFi.status() == WL_CONNECTED) {
fetchWeather();
} else {
Serial.println("No Wi-Fi, skipping this round");
}
}
}
توضیح بخشهای مهم
WiFiClientSecure client;اتصال رمزنگاریشدهی HTTPS را میسازد. برای آدرسهایhttp://ساده بهجایشWiFiClientکافی است.client.setInsecure();میگوید گواهی سرور را بررسی نکن. اتصال هنوز رمزنگاری شده است، ولی برد مطمئن نمیشود که با سرور درست حرف میزند. پایینتر روش درست را گفتهایم.http.begin(client, url)درخواست را آماده میکند وhttp.GET()آن را میفرستد و کد وضعیت را برمیگرداند: ۲۰۰ یعنی موفق، عددهای منفی یعنی اصلاً به سرور نرسیدیم.deserializeJson(doc, body)متن JSON را به یک ساختار قابل جستوجو تبدیل میکند وdoc["current"]["temperature_2m"]مثل باز کردن پوشههای تو در تو، به عدد دما میرسد.| -99.0در ArduinoJson یعنی «اگر این کلید نبود، این مقدار پیشفرض را بده». این جلوی خراب شدن برنامه را وقتی سرور جواب ناقص میدهد میگیرد.http.end()اتصال و حافظه را آزاد میکند. فراموش کردنش بعد از چند ساعت حافظه را تمام میکند و برد ریاستارت میشود.- در
loopباmillisهر ده دقیقه یک درخواست میفرستیم. فرستادن درخواست در هر دورloopهم برد را کند میکند و هم سرویسهای رایگان تو را مسدود میکنند.
HTTPS و گواهیها
تقریباً همهی APIهای امروزی فقط HTTPS دارند. روش درست در پروژهی واقعی این است که گواهی ریشهی سرور (Root CA) را بهصورت متن در کد بگذاری و بهجای setInsecure بنویسی client.setCACert(rootCA). این گواهی را میشود از مرورگر، با کلیک روی قفل کنار آدرس سایت، صادر کرد. گواهیهای ریشه معمولاً چند سال اعتبار دارند، ولی وقتی منقضی شوند درخواستها شکست میخورند؛ پس اگر پروژهای ناگهان بعد از مدتها از کار افتاد، اول به گواهی شک کن. یک نکتهی دیگر: اتصال HTTPS حدود ۴۰ کیلوبایت حافظه میگیرد، پس دو اتصال همزمان باز نکن.
معنی کدهای وضعیت
| کد | معنی | چه کنیم؟ |
|---|---|---|
| 200 | موفق | JSON را بخوان |
| 301 یا 302 | آدرس عوض شده است | آدرس جدید را بگذار یا http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS) |
| 401 یا 403 | کلید API نداری یا اشتباه است | کلید و سربرگها را چک کن |
| 404 | این مسیر وجود ندارد | آدرس را حرف به حرف چک کن |
| 429 | درخواست زیادی فرستادهای | فاصلهی درخواستها را بیشتر کن |
| 1- | اتصال برقرار نشد | اینترنت، نام سایت یا HTTPS را چک کن |
| 11- | سرور دیر جواب داد | setTimeout را بیشتر کن |
تابع http.errorToString(code) برای کدهای منفی یک توضیح انگلیسی کوتاه چاپ میکند. اگر کد منفی میگیری و مطمئنی برد به وایفای وصل است، یک نکتهی محلی را هم در نظر بگیر: Open-Meteo یک سرویس خارجی است و وقتی فقط اینترنت داخلی در دسترس است، به آن نمیرسی. در آن شرایط یک سرویس داخلی یا سرور خودت را بهجایش بگذار؛ کد تغییری نمیکند جز آدرس.
فرستادن داده با POST
گاهی باید داده را بفرستی، مثلاً دمای اتاق را به سرور خودت. شکل کلی همان است، فقط بهجای GET از http.addHeader("Content-Type", "application/json") و بعد http.POST(text) استفاده میکنی که text را با serializeJson از یک JsonDocument ساختهای. جواب سرور هم مثل قبل با getString خوانده میشود. اگر دادهها مدام و زیاد است، بهجای HTTP سراغ MQTT برو که برای همین کار ساخته شده است.
تمرین بخش JSON در شبیهساز
وایفای شبیهساز به شبکهی Wokwi-GUEST وصل میشود ولی به اینترنت واقعی نمیرسد، پس درخواست به Open-Meteo آنجا جواب نمیگیرد. اما بیشتر اشکالها در خواندن JSON است و آن را میشود کامل تمرین کرد: همان جواب نمونه را بهصورت یک رشته در کد بگذار و پردازشش کن.
// Practise JSON parsing without internet: the API answer as a fixed string.
#include <ArduinoJson.h>
const char* sample = R"({"current":{"time":"2026-10-20T14:30","temperature_2m":21.4,"wind_speed_10m":7.9}})";
void setup() {
Serial.begin(115200);
JsonDocument doc;
DeserializationError err = deserializeJson(doc, sample);
if (err) {
Serial.print("JSON error: ");
Serial.println(err.c_str());
return;
}
float temp = doc["current"]["temperature_2m"] | -99.0;
const char* when = doc["current"]["time"] | "?";
Serial.print("At ");
Serial.print(when);
Serial.print(" it is ");
Serial.print(temp, 1);
Serial.println(" C");
if (temp > 30) Serial.println("Hot: turn the fan on");
else Serial.println("Fine: fan stays off");
}
void loop() {
}
شبیهساز تینکرکد فارسی کتابخانهی ArduinoJson را میشناسد. دو پروژهی آمادهی JSON هم آنجا هست: API با JSON روی ESP32 و API سنسور با JSON، همراه با درس «دادهی JSON». خواندن همه رایگان است و برای اجرای ESP32 اشتراک Plus لازم است.
اشکالهای رایج
- کد ۱- میگیری: اینترنت نیست، نام سایت درست نیست، یا آدرس HTTPS است و از
WiFiClientساده استفاده کردهای. - JSON error: NoMemory یا IncompleteInput: جواب خیلی بزرگ است یا ناقص رسیده است. از API فقط فیلدهای لازم را بخواه، یا با
deserializeJson(doc, http.getStream())مستقیم از جریان بخوان. - همهی عددها صفر یا مقدار پیشفرضاند: نام کلیدها را اشتباه نوشتهای. حروف بزرگ و کوچک و خط زیر مهماند؛ جواب خام را یکبار کامل چاپ کن و نگاه کن.
- برد بعد از چند ساعت ریاستارت میشود:
http.end()را جا انداختهای یا درخواستها خیلی پشت سر هماند. - به وایفای وصل نمیشود: مشکل از HTTP نیست؛ عیبیابی وایفای ESP32 را ببین.
حالا که برد میتواند از اینترنت داده بگیرد، کنار آن یک ساعت NTP به وقت تهران بساز، یا دادهها را با MQTT به داشبورد بفرست. برای کتابخانههایی مثل ArduinoJson در شبیهساز، صفحهی کتابخانهها و برای همهی پروژههای شبکه، وایفای و اینترنت اشیا را ببین.
خواندن JSON را در تینکرکد فارسی تمرین کن 🧩سؤالهای رایج
فرق HTTPClient با WebServer در ESP32 چیست؟
با WebServer خود ESP32 سرور میشود و به مرورگر جواب میدهد. با HTTPClient برعکس است: ESP32 مثل یک مرورگر از یک سرور دیگر در اینترنت چیزی میخواهد، مثلاً وضعیت هوا یا قیمت یک کالا.
setInsecure در WiFiClientSecure امن است؟
برای یادگیری و تست اشکالی ندارد، ولی گواهی سرور را بررسی نمیکند و در محصول واقعی بهتر است گواهی ریشهی سرور را با setCACert به برد بدهی تا کسی نتواند خودش را جای سرور جا بزند.
آیا HTTPClient در شبیهساز به اینترنت وصل میشود؟
نه. وایفای شبیهساز به اینترنت واقعی نمیرسد. بخش پردازش JSON را میتوانی با یک رشتهی نمونه در شبیهساز تمرین کنی و درخواست واقعی را روی برد امتحان کنی.