📈 نمودار زندهی سنسور با EventSource (SSE) روی ESP32
دیدن یک عدد که مدام عوض میشود جالب است، ولی نمودار قصهی کامل را تعریف میکند: نور اتاق کی کم شد؟ کی چراغ را روشن کردی؟ در این پروژه ESP32 مقدار یک سنسور نور را با روش EventSource (که به آن SSE هم میگویند) پشتسرهم به مرورگر میفرستد و صفحه یک نمودار زنده میکشد. این از آن پروژههایی است که کاربرهای ووکوی زیاد میسازند و ما آن را در شبیهساز ESP32 فارسی اجرا میکنیم.
SSE چه فرقی با WebSocket دارد؟
| WebSocket | EventSource (SSE) | |
|---|---|---|
| جهت داده | دوطرفه | فقط از برد به مرورگر |
| کد سمت مرورگر | کمی بیشتر | خیلی کوتاه |
| وصل شدن دوباره بعد از قطعی | باید خودت بنویسی | مرورگر خودکار انجام میدهد |
| بهترین کاربرد | کنترل و فرمان | نمایش سنسور و نمودار |
قطعهها و سیمکشی
- مقاومت نوری (LDR): یک سر به 3V3، سر دیگر به GPIO34
- مقاومت ۱۰ کیلواهم: بین GPIO34 و GND (با LDR یک مقسم ولتاژ میسازد)
- بهجای این دو میتوانی یک پتانسیومتر بگذاری: کناریها به 3V3 و GND و وسط به GPIO34
کد کامل
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
const int SENSOR = 34; // LDR divider or potentiometer
unsigned long lastSend = 0;
AsyncWebServer server(80);
AsyncEventSource events("/events"); // the event stream lives at /events
const char page[] PROGMEM = R"rawliteral(<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body style="font-family:sans-serif;text-align:center">
<h2>Live light chart</h2>
<canvas id="c" width="320" height="160" style="border:1px solid #888"></canvas>
<p>Now: <b id="v">--</b></p>
<script>
var pts = [];
var ctx = document.getElementById('c').getContext('2d');
var es = new EventSource('/events');
es.addEventListener('light', function (e) {
var v = parseInt(e.data);
document.getElementById('v').innerText = v;
pts.push(v);
if (pts.length > 64) pts.shift(); // keep the last 64 points
ctx.clearRect(0, 0, 320, 160);
ctx.beginPath();
for (var i = 0; i < pts.length; i++) {
var x = i * 5;
var y = 160 - pts[i] * 160 / 4095;
if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
}
ctx.stroke();
});
</script></body></html>
)rawliteral";
void setup() {
Serial.begin(115200);
WiFi.begin("Wokwi-GUEST", ""); // simulator network, no password
while (WiFi.status() != WL_CONNECTED) delay(200);
Serial.println(WiFi.localIP());
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", page);
});
events.onConnect([](AsyncEventSourceClient *client) {
client->send("hello", NULL, millis(), 1000); // retry after 1 s if dropped
});
server.addHandler(&events);
server.begin();
}
void loop() {
if (millis() - lastSend > 500) { // two points per second
lastSend = millis();
int value = analogRead(SENSOR); // 0..4095
events.send(String(value).c_str(), "light", millis());
}
}
توضیح بخشهای مهم
AsyncEventSource events("/events");یک «جریان رویداد» روی مسیر/eventsمیسازد. هر صفحهای که به این مسیر وصل شود، از این به بعد پیامها را میگیرد.events.onConnectوقتی صفحهی جدیدی وصل میشود اجرا میشود. عدد1000به مرورگر میگوید اگر ارتباط قطع شد، بعد از یک ثانیه دوباره وصل شود.events.send(متن, "light", millis());سه بخش دارد: داده، اسم رویداد و یک شمارهی شناسه. اسم رویداد باید باaddEventListener('light', ...)در صفحه یکی باشد.- در جاوااسکریپت، آرایهی
ptsشصتوچهار نقطهی آخر را نگه میدارد. باshift()قدیمیترین نقطه حذف میشود و نمودار به چپ میخزد. - فرمول
160 - pts[i] * 160 / 4095عدد ۰ تا ۴۰۹۵ را به ارتفاع بوم تبدیل میکند. منها کردن از ۱۶۰ برای این است که در بوم، y از بالا به پایین زیاد میشود. - هیچ کتابخانهی نموداری لازم نشد؛
canvasخود مرورگر کافی است و صفحه روی اینترنت ملی هم بدون مشکل باز میشود.
💡 در شبیهساز، روی LDR کلیک کن و مقدار نور را عوض کن، یا ولوم را بچرخان؛ نمودار در مرورگر مجازی همان لحظه بالا و پایین میرود.
امتحانش کن
این پروژه بهصورت آماده در تینکرکد فارسی هست: نمودار زندهی سنسور با EventSource روی ESP32. نسخهی سادهتری که فقط عدد را نشان میدهد، نمایش زندهی سنسور در صفحهی وب است. خواندن کدها رایگان است و اجرای ESP32 با اشتراک Plus.
اشکالهای رایج
- نمودار خالی میماند: اسم رویداد در C++ و جاوااسکریپت یکی نیست (مثلاً
lightوLight). - عدد همیشه ۴۰۹۵ یا ۰ است: مقاومت ۱۰ کیلواهم مقسم را فراموش کردهای یا LDR را به پین ADC2 وصل کردهای که با وایفای کار نمیکند.
- نمودار خیلی تند و شلوغ است: فاصلهی ارسال را از ۵۰۰ به ۱۰۰۰ میلیثانیه برسان یا میانگین چند خواندن را بفرست.
- بعد از مدتی صفحه ثابت میماند: اگر داخل
loopیکdelayطولانی گذاشتهای، برش دار و ازmillis()استفاده کن.
برای ارتباط دوطرفه، دادهی زنده با WebSocket را بخوان و برای جدا کردن HTML از کد C++، صفحهی وب از فایل SPIFFS. همهی پروژههای این برد در صفحهی ESP32.
نمودار زندهی ESP32 را باز کن 📈