SMS
SmsProvider — راهنمای کلاینت (ESP32)
نسخه دِمو — امنیت و اعتبارسنجی عمداً ساده شده. این سند رفتار سرور و نحوه تعامل دستگاههای ESP32 با SignalR و APIهای موجود را بهصورت خلاصه شرح میدهد.
خلاصهٔ سناریو
- سرور همیشه حداکثر 10 پیامک ارسالنشده در جدول outbox نگهداری میکند.
- هر بار که پیامک رَندوم تولید میشود، در صورت لزوم پیامکهای فرستادهشده قدیمی حذف شده تا تعداد درون دیتابیس به 10 برسد.
- پس از تولید پیامک(ها)، سرور از طریق Hub SignalR رویداد
HasPendingMessagesرا به همهی کلاینتها (ESP32) ارسال میکند. - ESP32 پیامها را میفرستد و نتیجه را با POST به
/api/logs/createگزارش میدهد. - API ارسال پیامک (یکیبهیکی) حذف شده — ارسال از طریق دستگاهها انجام میشود.
چرخهٔ پیام
- سرور پیامک(های) جدید ایجاد میکند (Random generator).
- سرور رویداد SignalR با اطلاعات خلاصه برای همه ارسال میکند.
- دستگاه(ها) با Poll یا با استفاده از سرویسهای تعریفشده پیامکها را دریافت یا درخواست میکنند.
- پس از ارسال، دستگاه لاگ ارسال را به
/api/logs/createمیفرستد تا سرور شمارش لاگها را ثبت کند.
قانون دیتابیس
حداکثر پیامک در outbox: 10
ذخیرهٔ لاگها: شمارندهٔ کلی (totalDeletedMessages) در سرور ثبت میشود
دیتابیس: SQLite (کمحجم)
APIهای مرتبط (برای ESP32)
1) Poll دستورات (GET)
GET /api/commands/poll
کلاینتها میتوانند این مسیر را برای دریافت لیست پیامکهای در صف فراخوانی کنند. پاسخ شامل آرایهای از دستورات (پیامک) است:
{
"commands": [
{
"outboxId": "guid",
"phoneNumber": "09931234567",
"unicodeHexMessage": "00610062...",
"senderId": "TestLine1"
}
]
}
2) ارسال لاگها (POST)
POST /api/logs/create
کلاینتها پس از تلاش برای ارسال SMS باید نتایج را با فرمت زیر ارسال کنند (لیست):
[
{
"OutboxId": "GUID",
"PhoneNumber": "09931234567",
"StartDateTime": "2025-10-12T10:24:10Z",
"EndDateTime": "2025-10-12T10:24:16Z",
"ResponseCode": 0,
"Description": "OK"
}
]
سرور با ذخیرهٔ لاگ، آمار کلی (مانند totalDeletedMessages) را نگهداری میکند.
مثال سادهٔ کلاینت (JavaScript) — الگو برای ESP32
این مثال برای نشان دادن منطق کلی است. در ESP32 از کتابخانههای WebSocket یا SignalR client مناسب استفاده کنید.
// اتصال به SignalR hub (مثال JS برای فهم الگوریتم)
const connection = new signalR.HubConnectionBuilder()
.withUrl("/hubs/sms")
.withAutomaticReconnect()
.build();
connection.on("HasPendingMessages", async (payload) => {
console.log("HasPendingMessages:", payload);
// وقتی payload.newMessages>0 -> poll یا endpoint مناسب را برای دریافت دستورات صدا بزن
const resp = await fetch('/api/commands/poll');
const json = await resp.json();
for(const cmd of json.commands){
// فرض: sendSms locally (توابع ارسال در ESP32)
const result = await sendSmsToNetwork(cmd.phoneNumber, cmd.unicodeHexMessage, cmd.senderId);
// سپس لاگ را به سرور بفرست
await fetch('/api/logs/create', {
method: 'POST',
headers:{ 'Content-Type':'application/json' },
body: JSON.stringify([{
OutboxId: cmd.outboxId,
PhoneNumber: cmd.phoneNumber,
StartDateTime: new Date().toISOString(),
EndDateTime: new Date().toISOString(),
ResponseCode: result.code,
Description: result.msg
}])
});
}
});
connection.start().catch(e=>console.error(e));
در ESP32 از reconnection، محدودیت تلاشها و backoff استفاده کنید. لاگگیری محلی را هم فعال کنید تا در صورت قطعی شبکه، لاگها از بین نروند.
راهنمای عملیاتی کوتاه برای توسعهدهندهٔ ESP32
- همیشه روی ارتباط پایدار با Hub کار کنید: reconnect و heartbeat پیاده کنید.
- بعد از دریافت
HasPendingMessagesسریعا/api/commands/pollرا فراخوانی کنید تا دستورات را بگیرید. - هر پیامک را تکتک ارسال و نتیجه را در یک آرایه لاگ POST کنید تا سرور آمار را ثبت کند.
- بهخاطر محدودیت SQLite و کمحجم نگه داشتن دیتابیس، سرور فقط 10 پیامک در outbox نگه میدارد؛ انتظار داشته باشید با تولید جدید، قدیمیها حذف شوند.
- این یک دِموست — هیچ مکانیزم احراز هویت یا رمزنگاری برای پیامها وجود ندارد؛ برای تولید در محیط واقعی حتما امنیت اضافه کنید.