HTTP API
تناسب واجهة HTTP API الأجهزة التي لا تستطيع إبقاء اتصال مفتوح، والشبكات التي لا تسمح إلا بحركة HTTPS العادية، ومراحل التطوير الأولى للبرنامج الثابت (firmware): فخلافاً لـ MQTT، يجيبك كل طلب بما فعلته المنصة بكل قراءة أرسلتها.
عنوان URL الأساسي
https://api.sensocan.com/api/v1
المصادقة
يحمل كل طلب رمز وصول الجهاز كرمز Bearer:
Authorization: Bearer {DEVICE_ACCESS_TOKEN}
احصل على الرمز من تفاصيل الجهاز ← عرض الرمز. يخصّ الرمز جهازاً واحداً، ويجب أن يكون عنوان URL الذي ترسل إليه هو UUID الجهاز نفسه.

يصدر إجراء إعادة الإنشاء في مربع الحوار نفسه رمزاً جديداً ويُبطل القديم في الحال. وكل جهاز يستخدم الرمز القديم يبدأ بتلقّي 401 حتى تبرمج الرمز الجديد عليه.
الترويسات (headers)
| الترويسة | القيمة | مطلوبة |
|---|---|---|
Authorization | Bearer {DEVICE_ACCESS_TOKEN} | نعم |
Content-Type | application/json | نعم |
Accept | application/json | مستحسنة: بدونها تعود استجابة حد المعدل (rate limit) صفحة HTML بدلاً من JSON |
نقاط النهاية (endpoints)
1. قراءة واحدة لمستشعر واحد
POST /devices/{device_uuid}/sensors/{sensor}/readings
{sensor} هو إما المعرّف النصي (slug) للمستشعر أو UUID الخاص به، وكلاهما معروض في صفحة المستشعر.
{
"data": {
"value": 25.5,
"timestamp": "2026-09-03T10:00:00Z"
},
"battery_voltage": 3.7
}
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
data | كائن | نعم | قراءة واحدة فقط. استخدم نقطة النهاية المجمّعة لعدة قراءات |
data.value | رقم | نعم | القيم غير الرقمية مرفوضة |
data.timestamp | نص بصيغة ISO 8601 | لا | القيمة الافتراضية هي وقت وصول الطلب |
battery_voltage | رقم (بالفولت)، 0–100 | لا | يأتي بجوار data لا داخله |
يُحفظ أي مفتاح آخر داخل data كبيانات وصفية مرافقة للقراءة؛ راجع القواعد المشتركة لحمولة البيانات (payload).
2. عدة قراءات لمستشعر واحد
POST /devices/{device_uuid}/sensors/{sensor}/readings/bulk
{
"data": [
{ "value": 22.1, "timestamp": "2026-09-03T09:00:00Z" },
{ "value": 22.4, "timestamp": "2026-09-03T09:15:00Z" },
{ "value": 22.8, "timestamp": "2026-09-03T09:30:00Z" }
],
"battery_voltage": 3.6
}
يجب أن يكون data مصفوفة تضم عنصراً واحداً على الأقل، ويتبع كل عنصر القواعد نفسها الموضحة أعلاه لـ data.
3. قراءات لعدة مستشعرات
POST /devices/{device_uuid}/readings
{
"data": [
{
"sensor_slug": "temp_01",
"value": 25.5,
"timestamp": "2026-09-03T10:00:00Z"
},
{ "sensor_uuid": "7a8b9c0d-1234-5678-90ab-cdef12345678", "value": 60.2 },
{ "sensor_slug": "door_01", "value": 1 }
],
"battery_voltage": 3.7
}
يسمي كل عنصر مستشعره بنفسه عبر sensor_slug أو sensor_uuid، وأحدهما مطلوب. استخدم نقطة النهاية هذه مع جهاز يضم عدة مستشعرات: ثلاثة طلبات منفصلة تؤدي العمل نفسه ثلاث مرات.
ماذا تخبرك الاستجابة
كل طلب تمرّ منه قراءة واحدة على الأقل يجيب بـ 202 Accepted:
{
"message": "Readings accepted and queued for rule chain processing.",
"accepted": 3,
"duplicates": 0,
"rejected": {},
"sensor": "temp_01"
}
| الحقل | المعنى |
|---|---|
accepted | القراءات التي سُلِّمت إلى سلسلة القواعد |
duplicates | القراءات التي تبيّن أنها تكرار لشيء أُرسل من قبل. تُحتسب نجاحاً، فإعادة إرسال المخزن المؤقت آمنة |
rejected | أسباب الإهمال التي وقعت مع عدد كل سبب. تكون فارغة ({}) عندما لا يُهمَل شيء |
sensor | المعرّف الذي وضعته في عنوان URL، معاداً إليك. يظهر فقط في نقطتَي النهاية الخاصتين بمستشعر واحد |
النجاح الجزئي يبقى 202: خمس قراءات مرسلة، ثلاث منها مقبولة واثنتان مرفوضتان، تعطيك 202 مع التفصيل. اقرأ الأرقام، ولا تعتبر رمز الحالة وحده دليلاً على أن "كل شيء قد وصل".
تُسلَّم القراءة المقبولة إلى سلسلة القواعد التي تنطبق على ذلك المستشعر، والسلسلة هي التي تقرر ما يحدث لها، بما في ذلك حفظها من عدمه. وسلسلة بلا خطوة حفظ تنتج هذا بالضبط: استجابات 202 سليمة ولا بيانات في أي مكان في الواجهة. يبدأ كل حساب بـ سلسلة القواعد الافتراضية التي تحفظ القراءات؛ فإن بنيت سلسلتك الخاصة، فتحقق منها في الإدارة ← سلاسل القواعد.
أسباب الرفض
المفاتيح التي يمكن أن تظهر داخل rejected:
| المفتاح | ما معناه | كيف تعالجه |
|---|---|---|
dropped_unknown_sensor | المعرّف لم يطابق أي مستشعر على هذا الجهاز | قارنه بقيمة slug وبـ UUID في صفحة المستشعر. المطابقة تامة وتراعي حالة الأحرف |
dropped_missing_identifier | عنصر في الدفعة لا يحمل sensor_slug ولا sensor_uuid | امنح كل عنصر أحد المعرّفين |
dropped_missing_value | قراءة بلا value | أرسل value مع كل قراءة، ولا ترسل null لعينة فاشلة بل تجاوزها |
dropped_invalid_shape | بنية data لا تطابق نقطة النهاية | أرسل كائناً إلى نقطة النهاية المفردة، ومصفوفة إلى المجمّعة وإلى نقطة الدفعات |
dropped_future_timestamp | طابع زمني ظل متقدماً على وقت الخادم بعد تصحيح الساعة | أرسل طابعاً زمنياً بصيغة ISO 8601، أو احذفه ليُستخدم وقت الوصول |
dropped_duplicate | القيمة نفسها للمستشعر نفسه وصلت مرة أخرى ضمن نافذة كبت التكرار | لا شيء تعالجه. يُبلَّغ عنها في duplicates ولا تظهر أبداً داخل rejected |
الأخطاء
| رمز الحالة | جسم الاستجابة | السبب والحل |
|---|---|---|
401 | {"message":"Device authentication token required.","error":"missing_token"} | لا توجد ترويسة Authorization، أو أنها ليست بصيغة Bearer … |
401 | {"message":"Invalid device authentication token.","error":"invalid_token"} | الرمز لا يخص الجهاز المذكور في عنوان URL، أو أُعيد إنشاؤه |
404 | {"message":"Device not found.","error":"device_not_found"} | قيمة {device_uuid} في عنوان URL ليست جهازاً. انسخها مرة أخرى من تفاصيل الجهاز |
404 | {"message":"No reading matched a sensor on this device.","error":"sensor_not_found","sensors":["temp_01"]} | لا شيء في الحمولة يشير إلى مستشعر حقيقي. يسرد sensors المعرّفات التي لم تطابق شيئاً |
422 | {"message":"Validation failed.","errors":{"data.value":["The sensor value is required."]}} | جسم الطلب مشوّه البنية. يسمي errors الحقل المخالف |
422 | {"message":"No readings were accepted.","error":"no_readings_accepted","rejected":{"dropped_missing_value":2}} | الجسم صالح لكن كل القراءات أُهملت. يوضح rejected السبب |
429 | {"message":"Too Many Attempts."} | بلغت حد المعدل. تراجع وأعد المحاولة، وانظر أدناه |
أسباب شائعة لفشل التحقق خلف 422 Validation failed: data مفقود أو فارغ، value مفقود أو ليس رقماً، timestamp بصيغة تاريخ غير قابلة للتحليل، عنصر في الدفعة بلا sensor_slug ولا sensor_uuid، battery_voltage خارج المدى 0–100.
حد المعدل
الحد هو 1000 طلب في الدقيقة. ويُحتسب لكل عنوان مصدر، لذا تتقاسم عدة أجهزة خلف اتصال إنترنت واحد الحصة نفسها.
| الترويسة | متى تظهر | المعنى |
|---|---|---|
X-RateLimit-Limit | كل استجابة | السقف: 1000 |
X-RateLimit-Remaining | كل استجابة | الطلبات المتبقية في النافذة الحالية |
Retry-After | 429 فقط | عدد الثواني قبل إعادة المحاولة |
X-RateLimit-Reset | 429 فقط | موعد إعادة ضبط النافذة |
التزم بـ Retry-After بدل إعادة المحاولة فوراً، وضاعف فترة الانتظار أسّياً إن ظللت تبلغ الحد. وإذا اقترب جهاز من الحد، فاجمع مستشعراته في طلب واحد بدل إرسال طلب لكل مستشعر.
مثال عملي
curl -X POST \
https://api.sensocan.com/api/v1/devices/a1b2c3d4-e5f6-7890-abcd-ef1234567890/readings \
-H "Authorization: Bearer your-device-access-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"data": [
{ "sensor_slug": "temp_01", "value": 25.5 },
{ "sensor_slug": "humidity_01", "value": 60.2 }
],
"battery_voltage": 3.7
}'
{
"message": "Readings accepted and queued for rule chain processing.",
"accepted": 2,
"duplicates": 0,
"rejected": {}
}
التعامل مع الاستجابات في البرنامج الثابت
202: امسح من مخزنك المؤقت كل ما احتُسب فيacceptedوduplicates. القراءة الواردة فيrejectedلن تنجح عند إعادة المحاولة، فسجّلها بدل إعادة إرسالها بلا نهاية.401و404: مشكلة في الإعدادات لا عطل عابر. أوقف إعادة المحاولة وأبلغ عنها حيث يراها مشغّل.422: خلل في البرنامج الثابت. سجّل جسم الاستجابة، فهو يسمي الحقل المخالف.429: انتظر عدد الثواني المذكور فيRetry-Afterثم أعد المحاولة.5xxأو بلا استجابة: عطل عابر. ضاعف فترة الانتظار أسّياً وأبقِ القراءات في المخزن المؤقت؛ فالطوابع الزمنية تجعل التعبئة اللاحقة دقيقة، والساعة المتقدمة لا تكلفك شيئاً.
استكشاف الأخطاء وإصلاحها
استجابات 202 لكن لا بيانات في أي مكان. افتح تفاصيل الجهاز. يعرض جدول المستشعرات لكل مستشعر القيمة الحالية وآخر تحديث.

إذا كان آخر اتصال يتحدث بينما تعرض كل المستشعرات "لا توجد بيانات"، فسلسلة القواعد لا تحفظ القراءات؛ تحقق من الإدارة ← سلاسل القواعد. وإذا تحدّث بعض المستشعرات دون بعضها، فمعرّفات الصامتة منها لا تطابق أي مستشعر على هذا الجهاز، وهذا ما كان يقوله جسم 404 وأعداد rejected.
كل شيء يعيد 401. تأكد من أن الرمز لم يُعَد إنشاؤه، وأن UUID الجهاز في عنوان URL يخص الجهاز الذي يعود إليه هذا الرمز. الرمز الذي يعمل مع جهاز يُرفض مع جهاز آخر.
القراءات المخزّنة مؤقتاً تعود بوصفها تكرارات. هذه هي الاستجابة المتوقعة لإعادة الإرسال. اعتبرها قد وصلت وتابع تفريغ مخزنك المؤقت.