9.16. الوقت وبروتوكول NTP

لا تعرف الكاميرا التي تم تشغيلها للتو ما هو الوقت على الإطلاق. تبدأ الساعة المدمجة عند لحظة اعتباطية ما (1970-01-01 في معظم اللوحات) وتعدّ تصاعدياً من تلك النقطة إلى أن يخبرها شيء ما بخلاف ذلك. إن NTP -- بروتوكول وقت الشبكة (Network Time Protocol) -- هو الطريقة التي تطلب بها الكاميرا من الشبكة الوقت الحقيقي حسب ساعة الحائط وتضبط ساعتها الخاصة بناءً على الإجابة.

9.16.1. لماذا تحتاج الكاميرا إلى معرفة الوقت

بالنسبة لكثير من البرامج النصية لا تهم ساعة الكاميرا -- فحلقة التقاط الإطارات لا تكترث بأي يوم نحن. أما بالنسبة لبعض الأمور الشائعة فالأمر يهم كثيراً:

  • الطوابع الزمنية في السجلات أو البيانات المرفوعة. يصعب فهم المدخلات التي تقول جميعها 1970-01-01 بعد وقوع الحدث.

  • المهام المجدولة. "شغّل عند الساعة 03:00" يتطلب أن تعرف الكاميرا ما هي الساعة 03:00.

9.16.2. ماذا يفعل NTP

إن NTP خدمة عامة صغيرة: شبكة من الخوادم تجيب على سؤال "كم الساعة؟" عبر تبادل UDP واحد. ترسل الكاميرا طلباً قصيراً إلى خادم NTP معروف؛ فيرد الخادم بطابع زمني دقيق (بدقة بضعة أجزاء من الألف من الثانية لأي خادم عام شائع)؛ وتستخدم الكاميرا ذلك لضبط ساعتها الخاصة. الخادم الافتراضي الذي تستخدمه الكاميرا هو pool.ntp.org، وهو تجمّع موزّع للحِمل عالمياً مصمم تحديداً لهذا النوع من العملاء.

9.16.3. واجهة برمجة Python: ntptime

تغلّف MicroPython البروتوكول في استدعاء واحد. النمط الشائع هو رفع الاتصال أولاً، ثم طلب الوقت من NTP:

import network
import ntptime
import time

wlan = network.WLAN(network.WLAN.IF_STA)
wlan.active(True)
wlan.connect("my-network", "my-password")

while not wlan.isconnected():
    time.sleep_ms(100)

ntptime.settime()                 # cam's clock is now UTC
print(time.localtime())

بعد أن يعود ntptime.settime()، تعكس الساعة الفعلية المدمجة وtime.localtime() وقت UTC الحالي. هناك مقبضان لضبط القيم الافتراضية:

  • ntptime.host هو اسم الخادم المراد الاستعلام منه. يمكنك تجاوزه (ntptime.host = "time.google.com") قبل استدعاء settime() للإشارة إلى خادم مختلف.

  • ntptime.timeout هو عدد الثواني التي ينتظرها للحصول على رد قبل الاستسلام؛ والقيمة الافتراضية قصيرة.

9.16.4. متى تستدعيه

  • بعد رفع اتصال الشبكة. يعمل NTP فوق UDP، الذي يعمل بدوره فوق إعداد IP مكتمل. انتظر أن يعيد isconnected() القيمة True أولاً.

  • بشكل دوري على الكاميرات طويلة التشغيل. تنحرف الساعة المدمجة على مدى ساعات وأيام. إن استدعاء settime() يومياً أو أسبوعياً يبقيها دقيقة.

9.16.5. المناطق الزمنية

يعيد NTP وقت UTC. لا تأتي MicroPython بقاعدة بيانات للمناطق الزمنية، لذا فإن تحويل UTC إلى الوقت المحلي هو مهمة البرنامج النصي. والأسلوب المعتاد هو إزاحة ثابتة للمنطقة الزمنية الخاصة بمكان النشر:

import time

offset = -5 * 3600                  # hours -> seconds, US Eastern
local = time.localtime(time.time() + offset)
print(local)

لا يتعامل هذا الأسلوب مع التوقيت الصيفي والثواني الكبيسة والتغييرات التاريخية للمناطق الزمنية. بالنسبة لمعظم عمليات نشر الكاميرات تكفي الإزاحة الثابتة؛ وإذا كان برنامج نصي يحتاج فعلاً إلى الوقت المدني مع التوقيت الصيفي، فأجرِ التحويل على جانب الخادم.

9.16.6. ما الذي يمكن أن يفشل

  • لا توجد شبكة بعد. يطلق ntptime.settime() الاستثناء OSError إذا لم يستطع الوصول إلى الخادم. فإما أن الاتصال غير مرفوع، أو فشل البحث عن الاسم، أو أن الخادم غير قابل للوصول، أو لم يصل أي رد خلال ntptime.timeout. أعد المحاولة بمجرد استقرار الاتصال.

  • البوابات الإلزامية. قد تجيب شبكة Wi-Fi التي تعترض طلبات DNS على اسم خادم NTP بعنوان IP الخاص بالبوابة، وتعيد طلبات NTP الموجهة إليه أجوبة بلا معنى. ستظن الكاميرا أن الشبكة مرفوعة لكن ضبط الوقت سيفشل أو سيكون خاطئاً بشكل صارخ. انتقل إلى شبكة نظيفة أو رمّز عنوان IP بشكل ثابت.

  • إرهاق التجمعات العامة. تحدّ تجمعات NTP العامة من معدل العملاء المسيئين. مرة في الساعة كافية تماماً؛ أما مرة في الدقيقة فسيؤدي إلى حظر الكاميرا.

للاطلاع على مرجع ntptime الكامل، راجع ntptime --- عميل NTP بسيط.