بناء محطة طقس ذكية: دليلك الشامل لاستخدام Node.js و Raspberry Pi وشاشة LCD
شهدت أجهزة المنزل الذكي نموًا هائلاً خلال السنوات القليلة الماضية، حيث ارتفع عددها من أقل من 300 ألف جهاز في عام 2015 إلى ما يقرب من 1.2 مليار في عام 2020، ومن المتوقع أن يصل إلى 1.5 مليار بحلول عام 2021. ومع بلوغ متوسط عدد الأجهزة الذكية لكل منزل 8.7 جهاز بحلول عام 2021، فمن المرجح أن يكون لديك بعض هذه الأجهزة في منزلك. كمطورين، نتمتع بميزة فريدة في هذا المجال، إذ يمكننا بناء أجهزتنا المنزلية الذكية الخاصة. لم يقتصر التطور السريع على الأجهزة فحسب، بل امتد ليشمل لوحات التطوير المستخدمة فيها، والتي أصبحت أكثر تجارية وسهولة في الوصول. في هذا المقال، سنستعرض كيفية استخدام لوحة Raspberry Pi وشاشة LCD وعدد قليل من أسطر التعليمات البرمجية لمراقبة الطقس الخارجي أو في موقع جغرافي محدد.

المتطلبات الأساسية للمشروع
نظرًا لأن هذا المشروع يعتمد على مبدأ “افعلها بنفسك” (DIY)، فهناك بعض المتطلبات الأساسية التي سنحتاجها لبناء هذا الجهاز:
- لوحة
Raspberry Pi 3(أو إصدار أحدث) - شاشة
LCD - أسلاك توصيل
- مقاومة متغيرة (
Potentiometer) (اختياري) - لوحة تجارب (
Breadboard) (اختياري)
خطوات بناء محطة الطقس الذكية
بمجرد توفر جميع المتطلبات، يمكننا البدء في عملية البناء خطوة بخطوة.
الخطوة الأولى: التهيئة الأساسية وتوصيل المكونات
تتضمن هذه الخطوة الإعداد الأساسي والتحقق من جميع المكونات. في هذا العرض التوضيحي، سنستخدم واجهة برمجة تطبيقات الطقس ClimaCell Weather API كمزود لبيانات الطقس، نظرًا لتوفيرها عددًا كبيرًا من المؤشرات، بما في ذلك مؤشرات جودة الهواء. لاستخدام واجهة برمجة التطبيقات هذه، يجب علينا فتح حساب على منصتهم والحصول على مفتاح API Key، والذي سنستخدمه لتوقيع طلباتنا.

حدود استخدام ClimaCell API
الحساب مجاني ويأتي بحد أقصى 100 ساعة من استدعاءات API، وهو أكثر من كافٍ لمشروعنا. بمجرد حصولنا على مفتاح API هذا، يمكننا الانتقال إلى تهيئة الأجهزة وتوصيل شاشة LCD بلوحة Raspberry Pi الخاصة بنا. يجب إيقاف تشغيل Raspberry Pi أثناء إجراء توصيلات الأسلاك.

توصيل شاشة LCD بلوحة Raspberry Pi
توصيل الأسلاك بين شاشة LCD ولوحة التطوير هو كالتالي:

سيؤدي هذا التوصيل المادي إلى تشغيل شاشة LCD بأقصى سطوع وتباين. مستوى السطوع ليس مشكلة، لكن التباين يمثل تحديًا لأننا لن نتمكن من رؤية الأحرف على الشاشة. لهذا السبب، نحتاج إلى إضافة مقاومة متغيرة (potentiometer) واحدة على الأقل لضبط مستوى التباين.

في هذه المرحلة، يمكننا تشغيل لوحة Raspberry Pi، ويجب أن نرى شاشة LCD تعمل. بمساعدة المقاومة المتغيرة، يجب أن نكون قادرين على التحكم في التباين.
الخطوة الثانية: تهيئة المشروع البرمجي
كلغة برمجة، سنستخدم Node.js لكتابة التعليمات البرمجية. إذا لم يكن لديك Node.js مثبتًا بالفعل على لوحة Raspberry Pi الخاصة بك، فيمكنك اتباع هذه التعليمات البسيطة. في مجلد جديد، قم بتشغيل الأمر npm init -y لإعداد حزمة npm جديدة، متبوعًا بالأمر npm install lcd node-fetch لتثبيت هاتين الاعتماديتين الضروريتين.
- سيتم استخدام
lcdللتواصل مع شاشةLCD. - سيتم استخدام
node-fetchلإجراء طلباتHTTPإلىClimaCell API.
ذكرنا أننا بحاجة إلى مفتاح API Key للتواصل مع مزود بيانات الطقس. يمكنك وضع مفتاح API السري الخاص بك مباشرة في الكود الرئيسي، أو يمكنك إنشاء ملف config.json لوضع هذا المفتاح وأي تهيئات أخرى متعلقة بالكود.
ملف config.json
{ "cc_key" : "<your_ClimaCell_API_key>" }
أخيرًا، لنقم بإنشاء الملف الرئيسي لمشروعنا وتضمين كل هذه الأشياء التي تحدثنا عنها.
// * Dependencies
const Lcd = require("lcd");
const fs = require("fs");
const fetch = require("node-fetch");
// * Globals
const { cc_key } = JSON.parse(fs.readFileSync("./config.json"));
الخطوة الثالثة: التعامل مع شاشة LCD
الكتابة على الشاشة أمر سهل باستخدام وحدة lcd. تعمل هذه المكتبة كطبقة تجريدية فوق كيفية تواصلنا مع الجهاز، وبهذه الطريقة لا نحتاج إلى إدارة كل أمر بشكل فردي. الكود الكامل لشاشة LCD الخاصة بنا هو كالتالي:

const lcd = new Lcd({ rs: 26, e: 19, data: [13, 6, 5, 11], cols: 16, rows: 2 });
function writeToLcd(col, row, data) {
return new Promise((resolve, reject) => {
lcd.setCursor(col, row);
lcd.print(data, (err) => {
if (err) {
reject();
}
resolve();
});
});
}
الخطوة الأولى كانت إنشاء كائن lcd جديد وتمرير الدبابيس التي استخدمناها كوسيطات. تمثل المفاتيح cols و rows عدد الأعمدة والصفوف لشاشة LCD الخاصة بنا. 16×2 هو النوع الذي استخدمته في هذا المثال. إذا كانت شاشة LCD الخاصة بك تحتوي على 8 أعمدة وصف واحد فقط، فاستبدل 16 و 2 بالقيم الخاصة بك. للكتابة على الشاشة، نحتاج إلى استخدام هاتين الدالتين على التوالي:
lcd.setCursor()– لتحديد الموضع الذي ستبدأ منه الكتابة.lcd.print()– لطباعة النص.
في الوقت نفسه، قمنا بتغليف هاتين الدالتين في Promise للاستفادة من الكلمات المفتاحية async/await. في هذه المرحلة، يمكنك استخدام هذه الدالة وطباعة شيء ما على شاشتك. على سبيل المثال، يجب أن يقوم الأمر writeToLcd(0,0,'Hello World') بطباعة الرسالة Hello World على الصف الأول بدءًا من العمود الأول.
الخطوة الرابعة: جلب وعرض بيانات الطقس
الخطوة التالية هي جلب بيانات الطقس وطباعتها على الشاشة. توفر ClimaCell الكثير من معلومات بيانات الطقس، بالإضافة إلى جودة الهواء وحبوب اللقاح ومؤشرات الحرائق وغيرها. البيانات واسعة، ولكن تذكر أن شاشة LCD الخاصة بك تحتوي على 16 عمودًا وصفين فقط – أي 32 حرفًا فقط. إذا كنت ترغب في عرض المزيد من أنواع البيانات وكان هذا الحد صغيرًا جدًا بالنسبة لك، فيمكنك استخدام تأثير التمرير (scroll effect).

لهذا العرض التوضيحي، سنبقي الأمور بسيطة وسسنطبع البيانات التالية على شاشة LCD:
- التاريخ الحالي (الساعة، الدقائق، الثواني)
- درجة الحرارة
- شدة الهطول (الأمطار)

async function getWeatherData(apiKey, lat, lon) {
const url = `https://api.climacell.co/v3/weather/realtime?lat=${lat}&lon=${lon}&unit_system=si&fields=temp&fields=precipitation&apikey=${apiKey}`;
const res = await fetch(url);
const data = await res.json();
return data;
}
async function printWeatherData() {
const { temp, precipitation } = await getWeatherData(cc_key, 45.658, 25.6012);
// first row
await writeToLcd(0, 0, Math.round(temp.value) + temp.units);
// second row
const precipitationMessage =
"Precip.: " + precipitation.value + precipitation.units;
await writeToLcd(0, 1, precipitationMessage);
}
للحصول على بيانات من ClimaCell لموقع معين، تحتاج إلى إرسال إحداثياته الجغرافية، خط العرض (latitude) وخط الطول (longitude). للعثور على إحداثيات مدينتك، يمكنك استخدام أداة مجانية مثل latlong.net، ثم يمكنك حفظها في ملف config.json جنبًا إلى جنب مع مفتاح API الخاص بك، أو يمكنك كتابتها مباشرة في الكود. في هذه المرحلة، يكون تنسيق البيانات الذي يتم إرجاعه بواسطة استدعاء API كالتالي:
{
lat : 45.658 ,
lon : 25.6012 ,
temp : { value : 17.56 , units : 'C' },
precipitation : { value : 0.3478 , units : 'mm/hr' },
observation_time : { value : '2020-06-22T16:30:22.941Z' }
}
يمكننا فك هيكلة هذا الكائن (deconstruct) والحصول على قيمتي temp و precipitation وطباعتهما على الصف الأول والثاني.
الخطوة الخامسة: تجميع المنطق البرمجي وتحديث الشاشة
كل ما نحتاجه الآن هو كتابة المنطق البرمجي لسكربتنا، وتحديث شاشة LCD عند وصول بيانات جديدة.

async function main() {
await printWeatherData();
setInterval(() => {
printWeatherData();
}, 5 * 60 * 1000);
setInterval(async () => {
await writeToLcd(8, 0, new Date().toISOString().substring(11, 19));
}, 1000);
}
lcd.on("ready", main);
// * If ctrl+c is hit, free resources and exit.
process.on("SIGINT", () => {
lcd.close();
process.exit();
});
يتم تحديث بيانات الطقس كل 5 دقائق. ولكن نظرًا لوجود حد 100 استدعاء API في الساعة تفرضه ClimaCell، يمكننا الذهاب أبعد من ذلك وتحديث بيانات الطقس كل دقيقة. بالنسبة للتاريخ الحالي، لدينا خياران: يمكننا استخدام الخاصية observation_time وعرض التاريخ الذي تم فيه استلام البيانات، أو يمكننا إنشاء ساعة حقيقية وعرض الوقت الحالي. لقد اخترت الخيار الثاني، ولكن لا تتردد في القيام بذلك كما يحلو لك.
لطباعة الوقت في الزاوية العلوية اليمنى، يجب علينا أولاً حساب عمود البداية بحيث يتناسب النص بشكل مريح. لهذا يمكننا استخدام الصيغة التالية: إجمالي عدد الأعمدة مطروحًا منه طول النص المراد عرضه. يحتوي التاريخ على 8 أحرف، وبما أن الشاشة تحتوي على 16 عمودًا، يجب أن نبدأ من العمود رقم 8.
إعداد LCD غير متزامن (asynchronous)، لذلك يجب علينا استخدام الدالة lcd.on() التي توفرها المكتبة ذات الصلة، حتى نعرف متى تم تهيئة LCD وأصبحت جاهزة للاستخدام. من أفضل الممارسات الأخرى في الأنظمة المدمجة (embedded systems) هي إغلاق وتحرير الموارد التي تستخدمها. لهذا السبب نستخدم حدث SIGINT لإغلاق شاشة LCD عند إيقاف البرنامج. تتضمن الأحداث الأخرى المشابهة لهذا:
SIGUSR1وSIGUSR2– لالتقاط أحداث مثل إعادة تشغيلnodemon.uncaughtException– لالتقاط الاستثناءات غير المعالجة.
الخطوة السادسة: تشغيل السكربت بشكل دائم
السكربت مكتمل، وفي هذه المرحلة يمكننا تشغيل برنامجنا. ولكن هناك شيء واحد آخر يجب علينا القيام به قبل الانتهاء. في هذه المرحلة، ربما تكون متصلاً بلوحة Raspberry Pi الخاصة بك باستخدام SSH أو مباشرة بكابل HDMI وشاشة. بغض النظر عن الطريقة، عند إغلاق الطرفية (terminal)، سيتوقف البرنامج. وفي الوقت نفسه، إذا قمت بإيقاف تشغيل جهازك وبعد فترة أو فورًا قمت بتشغيله مرة أخرى، فلن يبدأ السكربت وسيتعين عليك تشغيله يدويًا. لحل هذه المشكلة، يمكننا استخدام مدير عمليات مثل pm2. إليك الخطوات:
sudo npm install pm2 -g– لتثبيتpm2عالميًا.sudo pm2 startup– لإنشاء سكربت بدء التشغيل لمديرpm2.pm2 start index.js– لبدء تشغيل التطبيق (افترض أن ملفك الرئيسي هوindex.js).pm2 save– لحفظ قائمة العمليات الخاصة بك عبر إعادة تشغيل الخادم.
الآن يمكنك إعادة تشغيل لوحتك وسيبدأ السكربت تلقائيًا عندما يصبح الجهاز جاهزًا.
الخلاصة التقنية
من هذه النقطة، يمكنك تخصيص جهازك الجديد بالطريقة التي تريدها. إذا وجدت بيانات الطقس هذه مهمة لك (أو أي بيانات أخرى من ClimaCell، مثل تلوث الهواء، حبوب اللقاح، مؤشر الحرائق، أو مخاطر الطرق)، يمكنك إنشاء غلاف مخصص لوضع لوحة Raspberry Pi وشاشة LCD فيه. ثم بعد إضافة بطارية، يمكنك وضع الجهاز في منزلك. تعتبر Raspberry Pi مثل جهاز كمبيوتر شخصي، لذا يمكنك القيام بالكثير عليها أكثر مما تفعله عادة على متحكم دقيق (microcontroller) مثل Arduino. ولهذا السبب، من السهل دمجها مع الأجهزة الأخرى التي لديك في منزلك.