الجمعة، 29 مايو 2026

سنترا - أذكى كاميرا مراقبة منزلية الصنع

Sentra هي كاميرا مراقبة ذكية تعمل بالبطارية يمكنك تركيبها بنفسك، وتتميز ببث مباشر عبر الواي فاي، وكشف الحركة، والرؤية الليلية، والتسجيل على بطاقة SD.



المواد المستخدمة في هذا المشروع

مكونات الأجهزة

وحدة كاميرا الذكاء الاصطناعي DFRobot ESP32-S3 (التعرف على حواف الصور، الرؤية الليلية، التفاعل الصوتي ChatGPT)

بطارية، 3.7 فولت
شاحن بطاريات ليثيوم أيون USB 

تطبيقات برمجية وخدمات عبر الإنترنت

لوحة تحكم سنترا
أوتوديسك فيوجن
بيئة تطوير أردوينو
أدوات يدوية وآلات تصنيع
مكواة لحام (عامة)
سلك لحام خالٍ من الرصاص
قصة
مرحباً أيها المبدعون، أنا شغوفٌ ببناء مشاريع تجمع بين الهندسة والأنظمة المدمجة وتصميم المنتجات، لتُنتج شيئاً عملياً وجذاباً في آنٍ واحد.

في هذا المشروع، ابتكرتُ "سنترا" - كاميرا المراقبة الذكية "سنترا" - نظام مراقبة ذكي يعمل بالبطارية بالكامل، مبنيٌّ على معالج ESP32-S3. تجمع "سنترا" بين بث الفيديو المباشر عبر الواي فاي، والتسجيل المستمر على بطاقة SD، وكشف الحركة، والرؤية الليلية التلقائية، ومراقبة الصوت في الوقت الفعلي، وحتى الإعلانات الصوتية الآلية، كل ذلك في جهاز صغير الحجم مصمم خصيصاً.

صُمِّم الهيكل الخارجي والواجهة بالكامل باستخدام برنامج Autodesk Fusion 360، مع التركيز على التصميم الأنيق، وسهولة الحمل، وتجربة مستخدم عصرية. إلى جانب المكونات المادية، طورتُ أيضاً لوحة تحكم مخصصة تعمل في الوقت الفعلي، وتعمل مباشرةً على أي متصفح - دون الحاجة إلى تطبيقات أو اشتراكات أو خدمات سحابية.

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

هذا المشروع هو محاولتي لإنشاء نظام كاميرا ذكي لا يبدو كمشروع يدوي تقليدي، بل أقرب إلى منتج حقيقي من الجيل القادم.


الخطوة 1: تصميم CAD





كانت الخطوة الأولى في هذا المشروع تصميم الهيكل الخارجي والداخلي الكامل لكاميرا سينترا. صممت جميع الأجزاء من الصفر باستخدام برنامج أوتوديسك فيوجن 360، مع التركيز على المنحنيات الواضحة، والأبعاد المدمجة، والمسافات المناسبة بين المكونات، وسهولة التجميع.

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

استلهمتُ أفكارًا من هذا المشروع المميز لموكيش سانخلا، وأنصحكم بشدة بالاطلاع عليه أيضًا، فهو تصميم رائع وموثق جيدًا.

الخطوة الثانية: الطباعة ثلاثية الأبعاد






بعد اكتمال تصميم CAD، كانت الخطوة التالية هي طباعة جميع أجزاء الهيكل. يتكون التصميم من ثلاثة مكونات رئيسية مطبوعة:

الهيكل الرئيسي
الغطاء العلوي
امتداد الأزرار
اخترتُ لهذا التصميم خيوط PLA رمادية اللون لأنها تمنح الكاميرا مظهرًا أنيقًا وعصريًا، مع سهولة الطباعة ودقة أبعاد عالية. يُعدّ PLA خيارًا ممتازًا للحصول على سطح أملس والحفاظ على التفاوتات الدقيقة اللازمة للتجميع السليم.

الخطوة 3: تجميع Spekar




الخطوة التالية كانت تركيب السماعة داخل العلبة. قمتُ أولاً بقص أسلاك السماعة إلى الطول المناسب، ثم أضفتُ سلكًا إضافيًا لتسهيل عملية التركيب النهائية وجعلها أكثر ترتيبًا.

بعد ذلك، أزلتُ الغطاء اللاصق من السماعة ووضعتها بعناية في مكان التثبيت المخصص لها داخل العلبة الرئيسية. ضغطتُ عليها ضغطًا خفيفًا لتثبيتها في مكانها.

الخطوة 4: تركيب البطارية



الخطوة التالية كانت تركيب البطارية في العلبة. في البداية، قمتُ بلحام سلكين بأطراف البطارية لتسهيل توصيل الطاقة أثناء تجميع الدوائر الإلكترونية النهائية.

كان الغطاء العلوي مُصمماً مسبقاً في برنامج Autodesk Fusion 360 مع حجرة مخصصة للبطارية، لذا تتناسب البطارية تماماً مع مكانها دون إهدار أي مساحة داخلية. بعد وضعها في مكانها، استخدمتُ كمية قليلة من الغراء لتثبيتها بإحكام.

الخطوة 5: توصيل وحدة الشحن


الخطوة التالية كانت توصيل البطارية بوحدة الشحن. في البداية، قمتُ بلحام أسلاك البطارية بالأطراف الموجبة والسالبة الصحيحة في الوحدة، مع التأكد من صحة توصيل القطبية لتجنب تلف الدائرة.

بعد ذلك، قمتُ بلحام زوج آخر من الأسلاك بأطراف خرج 5 فولت في وحدة الشحن. ستُستخدم هذه الأسلاك لاحقًا لتزويد لوحة ESP32-S3 الرئيسية داخل Sentra بالطاقة.

الخطوة 6: تهيئة الكود



قبل تحميل الكود، عليك ضبط بيانات اعتماد شبكة Wi-Fi والمنطقة الزمنية داخل الكود المصدري. ما عليك سوى استبدال القيم الافتراضية باسم شبكة Wi-Fi وكلمة المرور الخاصة بك.

#define WIFI_SSID       "Your SSID"
#define WIFI_PASS "Your Pass"
#define TZ_OFFSET_SEC -28800 // UTC-8 Pacific Standard Time (PST)



تُستخدم قيمة المنطقة الزمنية للطوابع الزمنية والتسجيلات ومزامنة وقت النظام. يمكنك تغييرها حسب منطقتك.


الخطوة 7: تحميل الكود

قبل التحميل، تأكد من تحديد إعدادات اللوحة التالية بشكل صحيح داخل بيئة تطوير Arduino:


اللوحة: وحدة تطوير ESP32S3

ذاكرة PSRAM: OPI PSRAM

حجم الذاكرة الفلاشية: 16 ميجابايت (128 ميجابايت)

نظام التقسيم: تطبيق ضخم (3 ميجابايت بدون تحديثات عبر الهواء / 1 ميجابايت SPIFFS)

تفعيل USB CDC عند بدء التشغيل

تردد المعالج: 240 ميجاهرتز

سرعة التحميل: 921600

تُعدّ إعدادات ذاكرة PSRAM وحجم الذاكرة الفلاشية بالغة الأهمية لأن Sentra يستخدم مخازن مؤقتة كبيرة لبث الفيديو وتسجيل SD والمعالجة في الوقت الفعلي. قد تؤدي الإعدادات غير الصحيحة إلى أعطال أو حلقات إعادة تشغيل أو فشل في تهيئة الكاميرا.

بعد إتمام جميع الإعدادات، قم بتوصيل لوحة ESP32-S3 باستخدام كابل USB، ثم حدد منفذ COM الصحيح، وقم بتحميل الكود. بعد اكتمال عملية التحميل بنجاح، افتح شاشة المراقبة التسلسلية لعرض عنوان IP الخاص بالجهاز وحالة النظام.

الخطوة 8: لوحة التحكم


لوحة تحكم Sentra

لجعل Sentra منتجًا ذكيًا متكاملًا، صممنا لوحة تحكم عصرية عبر الإنترنت بواجهة سهلة الاستخدام وتحكم فوري.

ما عليك سوى فتح لوحة التحكم، وإدخال عنوان IP الخاص بالكاميرا، والاتصال فورًا. تتميز الواجهة بتصميم عصري ومتجاوب، وتعمل بسلاسة على الهواتف الذكية والأجهزة اللوحية وأجهزة الكمبيوتر المكتبية، مما يمنح Sentra تجربة استخدام احترافية ومميزة.

يمكنك مشاهدة البث المباشر للكاميرا ومراقبة معلومات مهمة مثل الحركة، ومستوى البطارية، والإضاءة المحيطة، ومستوى الصوت، وحالة التسجيل، واستخدام بطاقة SD، وحالة الرؤية الليلية في الوقت الفعلي.

كما توفر لوحة التحكم وصولًا سريعًا إلى ميزات مثل التحكم في التسجيل، والإعلانات الصوتية، ووضع صفارة الإنذار، والإضاءة بالأشعة تحت الحمراء، مما يسهل إدارة الكاميرا من أي مكان على شبكتك المحلية.

الخطوة 9: تجميع كاميرا ESP32 S3


الخطوة التالية كانت تركيب لوحة كاميرا ESP32-S3 في الهيكل الرئيسي. وضعتُ اللوحة في موضع التثبيت المخصص، وبعد تثبيتها، قمتُ بتوصيل السماعة باستخدام موصل JST الخاص بها.

صُمم الهيكل لدعم التثبيت القياسي باستخدام 4 براغي صغيرة لضمان تثبيت محكم. ولأنني لم أكن أملك البراغي في ذلك الوقت، استخدمتُ كمية صغيرة من الغراء الفائق لتثبيت اللوحة مؤقتًا.

الخطوة 10: تجميع وحدة الشحن







بعد تجهيز وحدة الشحن مسبقًا، وضعتها بعناية في مكانها المخصص، وقمت بمحاذاة موصل USB Type-C مع الفتحة الموجودة على جانب الهيكل، لتسهيل شحن الكاميرا من الخارج.

بعد تثبيت الوحدة في مكانها الصحيح، قمت بتوصيل سلكي خرج 5 فولت من وحدة الشحن بمدخل الطاقة في اللوحة الرئيسية، مع التأكد من صحة القطبية قبل تشغيل النظام.

الخطوة 11: تركيب وحدة تمديد الأزرار




الآن، نقوم بتركيب قطعة تمديد الزر الصغيرة. بما أن زر لوحة ESP32-S3 موجود داخل الغلاف، فقد صممتُ قطعة التمديد هذه بشكل منفصل لتسهيل الوصول إليه من خارج الغلاف.

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

الخطوة ١٢: التجميع النهائي





الخطوة الأخيرة هي إغلاق الغطاء وإتمام عملية التجميع. قمتُ بمحاذاة الغطاء العلوي مع الهيكل الرئيسي بعناية، وتأكدتُ من وضع عدسة الكاميرا، وامتداد الزر، والأسلاك الداخلية في مكانها الصحيح قبل إغلاق الغطاء. ولتثبيت كل شيء بإحكام، استخدمتُ ثلاثة براغي من الجهة الخلفية للغطاء.

قبل استخدام كاميرا Sentra، اشحن البطارية بالكامل عبر منفذ USB Type-C. بمجرد اكتمال الشحن، تصبح الكاميرا جاهزة للاستخدام.

بعد التشغيل، افتح لوحة التحكم في متصفحك باستخدام عنوان IP الخاص بـ ESP32-S3 للوصول إلى بث الكاميرا المباشر وجميع الميزات الذكية.

نظرًا لأن Sentra تعمل بالبطارية بالكامل وهي صغيرة الحجم، يمكنك حملها بسهولة إلى أي مكان أو تثبيتها على الحائط أو المكتب أو الرف أو أي مكان ترغب في مراقبته. خلال الاختبار، تحققت من بث الفيديو المباشر، وتسجيل بطاقة SD، وكشف الحركة، والرؤية الليلية التلقائية، ومراقبة الصوت، والإعلانات الصوتية، وعناصر التحكم في لوحة التحكم للتأكد من أن كل شيء يعمل بسلاسة.

كان شعورًا رائعًا أن أرى النظام بأكمله يعمل ككاميرا ذكية متكاملة، وقد أضفى ذلك حيوية على المشروع بأكمله.

الخطوة 14: الخاتمة

كان بناء Sentra تجربة ممتعة ومجزية للغاية بالنسبة لي. أردت تصميم كاميرا مراقبة منزلية الصنع لا تعمل بكفاءة فحسب، بل تتميز أيضًا بتصميم عصري، وسهولة الحمل، وأناقة التصميم. بدءًا من تصميم الهيكل باستخدام برنامج Autodesk Fusion 360، مرورًا ببناء لوحة التحكم، وصولًا إلى دمج جميع المكونات الإلكترونية، تم تصميم كل جزء من هذا المشروع وتجميعه من الصفر.

أكثر ما استمتعت به هو رؤية جميع الميزات المختلفة تتكامل في جهاز واحد صغير الحجم - بث فيديو مباشر، وكشف الحركة، ورؤية ليلية تلقائية، ومراقبة صوتية، وتسجيل على بطاقة SD، وحتى إعلانات صوتية، وكل ذلك يعمل بنظام ESP32-S3 يعمل بالبطارية.

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

آمل أن يلهم هذا المشروع الآخرين لبناء أجهزتهم الذكية الخاصة وتجربة تقنيات "اصنعها بنفسك".

مخططات

الجمعة، 22 مايو 2026

مراقب أداء الكمبيوتر ESP32 – إحصائيات النظام في الوقت الفعلي

 مراقبة وحدة المعالجة المركزية، وذاكرة الوصول العشوائي، والقرص، والشبكة، والبطارية، ووقت التشغيل على شاشة LCD I2C 16×2 مع ESP32 - مثالية لأي مكتب أو إعداد تقني منزلي الصنع.


الأشياء المستخدمة في هذا المشروع

وحدة عرض شاشة LCD من نوع DFRobot I2C 16x2 Arduino

وحدة التحكم الدقيقة DFRobot FireBeetle ESP32 IOT (تدعم Wi-Fi و Bluetooth)

بيئة تطوير أردوينو المتكاملة  Arduino IDE

قصة

لطالما انزعجتُ من اضطراري المتكرر إلى التبديل بين النوافذ (Alt+Tab) لفتح مدير المهام أو أداة مراقبة النظام للتحقق من مقدار موارد حاسوبي المستخدمة. خاصةً أثناء عمليات الرندر المكثفة أو جلسات الألعاب، كان من شأن توفر هذه المعلومات بنظرة سريعة أن يوفر عليّ الكثير من التخمينات. لذا، بدت شاشة صغيرة مخصصة لعرض حمل المعالج، واستخدام ذاكرة الوصول العشوائي، وسعة القرص، وحركة مرور الشبكة، وحالة البطارية، الحل الأمثل.


بدلاً من شراء جهاز مكتبي باهظ الثمن، قررتُ بناء جهازي الخاص. يجمع هذا المشروع بين لوحة تطوير ESP32 منخفضة التكلفة وشاشة LCD قياسية 16×2 بتقنية I2C. يقوم برنامج بايثون يعمل على الحاسوب بجمع إحصائيات النظام باستخدام مكتبة psutil، ثم يرسلها عبر اتصال تسلسلي USB بسيط إلى ESP32. يقوم المتحكم الدقيق بتحليل البيانات بصيغة JSON، ويتنقل بين عدة صفحات معلوماتية، ويُحدّث الشاشة كل بضع ثوانٍ.


النظام بأكمله محلي بالكامل؛ لا يتطلب اتصالاً بشبكة Wi-Fi، ولا خدمة سحابية، ولا إعدادات معقدة. كل شيء يعمل عبر كابل USB واحد.


البرامج والمكتبات

بيئة تطوير Arduino المتكاملة (IDE) - لتحميل برنامج ESP32 الثابت

مكتبة LiquidCrystal I2C من تطوير فرانك دي برابندر - لتشغيل شاشة LCD بتقنية I2C

مكتبة ArduinoJson (الإصدار 6) من تطوير بينوا بلانشون - لتحليل سلسلة JSON الواردة

Python 3 - لتشغيل برنامج مراقبة الكمبيوتر

pyserial - لمعالجة الاتصال التسلسلي عبر USB من Python

psutil - لجمع معلومات النظام في الوقت الفعلي (وحدة المعالجة المركزية، الذاكرة، القرص، الشبكة، البطارية، وقت التشغيل)

يمكنك تثبيت حزمتي Python باستخدام:

pip install pyserial psutil


في بيئة تطوير Arduino المتكاملة (IDE)، استخدم مدير المكتبات لتثبيت LiquidCrystal I2C وArduinoJson (الإصدار 6).


🔌 مخطط التوصيل

من أفضل مزايا استخدام شاشة LCD بتقنية I2C هو قلة التوصيلات المطلوبة: أربعة أسلاك فقط. يعمل ناقل I2C على خطي إشارة (SDA وSCL) بالإضافة إلى خطي الطاقة والأرضي.








هام: منافذ I2C الافتراضية في معظم لوحات ESP32 هي GPIO21 (SDA) وGPIO22 (SCL). إذا كانت لوحتك تستخدم منافذ مختلفة، فغيّر سطر Wire.begin(SDA, SCL) في البرنامج.

⚙️ إعداد برنامج ESP32 الثابت

يستمع ESP32 باستمرار إلى البيانات التسلسلية، ويبني رسالة JSON حرفًا حرفًا، ويحللها فقط بعد استلام كائن كامل. هذه الطريقة الموثوقة تتجنب مشاكل البيانات المجزأة أو الجزئية.

1. تثبيت حزمة اللوحة

إذا لم يسبق لك استخدام ESP32 مع بيئة تطوير Arduino المتكاملة (IDE):

انتقل إلى ملف > تفضيلات، وأضف عنوان URL الخاص بفهرس لوحة Espressif ESP32 إلى حقل عناوين URL الإضافية لمدير اللوحات.



افتح الأدوات > اللوحة > مدير اللوحات، وابحث عن esp32 وقم بتثبيت الحزمة من Espressif Systems.

حدد وحدة تطوير ESP32 (أو لوحتك المحددة) من قائمة اللوحات.



٢. تحميل الرسم التخطيطي

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

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ArduinoJson.h>

// LCD configuration
#define LCD_ADDRESS 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2

LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);

// Serial buffer – large enough for full JSON
#define SERIAL_BUFFER_SIZE 1024
char serialBuffer[SERIAL_BUFFER_SIZE];
int bufferIndex = 0;

// JSON accumulator: wait for balanced braces
int braceBalance = 0;
bool insideJson = false;

// Global variables (same as before)
float cpu_total = 0, cpu_cores[8] = {0};
int cpu_freq = 0;
float ram_perc = 0, ram_used = 0, ram_total = 0;
float disk_perc = 0, disk_used = 0, disk_total = 0;
float net_up = 0, net_down = 0;
int bat_perc = -1;
bool bat_plugged = false;
int uptime_h = 0, uptime_m = 0;

// Page cycling
unsigned long lastPageChange = 0;
const unsigned long PAGE_INTERVAL = 3000;
int currentPage = 0;
const int TOTAL_PAGES = 5;

// ========== JSON PARSING ==========
void parseStats(const char* jsonString) {
Serial.print("RAW JSON (full): ");
Serial.println(jsonString);

StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, jsonString);
if (error) {
Serial.print("❌ JSON parse failed: ");
Serial.println(error.c_str());
return;
}
Serial.println("✅ JSON parsed successfully");

cpu_total = doc["cpu_total"] | 0.0f;
cpu_freq = doc["cpu_freq"] | 0;
JsonArray cores = doc["cores"];
for (int i = 0; i < cores.size() && i < 8; i++) cpu_cores[i] = cores[i].as<float>();
ram_perc = doc["ram_perc"] | 0.0f;
ram_used = doc["ram_used"] | 0.0f;
ram_total = doc["ram_total"] | 0.0f;
disk_perc = doc["disk_perc"] | 0.0f;
disk_used = doc["disk_used"] | 0.0f;
disk_total = doc["disk_total"] | 0.0f;
net_up = doc["net_up"] | 0.0f;
net_down = doc["net_down"] | 0.0f;
bat_perc = doc["bat_perc"] | -1;
bat_plugged = doc["bat_plugged"] | false;
uptime_h = doc["uptime_h"] | 0;
uptime_m = doc["uptime_m"] | 0;

Serial.print("CPU: "); Serial.println(cpu_total);
Serial.print("RAM: "); Serial.println(ram_perc);
Serial.print("DISK: "); Serial.println(disk_perc);
}

// ========== DISPLAY PAGES (unchanged) ==========
void showPage0() {
lcd.setCursor(0,0); lcd.print("CPU "); lcd.print(cpu_total,0); lcd.print("% "); lcd.print(cpu_freq); lcd.print("MHz");
lcd.setCursor(0,1); lcd.print("Cores:");
for(int i=0;i<2 && cpu_cores[i]>0;i++) { lcd.print(" "); lcd.print((int)cpu_cores[i]); lcd.print("%"); }
}
void showPage1() {
lcd.setCursor(0,0); lcd.print("RAM "); lcd.print(ram_perc,0); lcd.print("% Used:");
lcd.setCursor(0,1); lcd.print(ram_used,1); lcd.print("/"); lcd.print(ram_total,1); lcd.print("GB");
}
void showPage2() {
lcd.setCursor(0,0); lcd.print("DISK "); lcd.print(disk_perc,0); lcd.print("% Used:");
lcd.setCursor(0,1); lcd.print(disk_used,1); lcd.print("/"); lcd.print(disk_total,1); lcd.print("GB");
}
void showPage3() {
lcd.setCursor(0,0); lcd.print("NET ↑"); lcd.print(net_up,0); lcd.print("MB");
lcd.setCursor(0,1); lcd.print(" ↓"); lcd.print(net_down,0); lcd.print("MB");
}
void showPage4() {
lcd.setCursor(0,0);
if(bat_perc>=0){ lcd.print("BAT "); lcd.print(bat_perc); lcd.print("%"); if(bat_plugged) lcd.print(" CHG"); else lcd.print(" ");}
else lcd.print("No battery ");
lcd.setCursor(0,1); lcd.print("UP "); lcd.print(uptime_h); lcd.print("h "); lcd.print(uptime_m); lcd.print("m ");
}
void updateDisplay() {
lcd.clear();
switch(currentPage){
case 0: showPage0(); break; case 1: showPage1(); break; case 2: showPage2(); break;
case 3: showPage3(); break; case 4: showPage4(); break; default: showPage0();
}
}

// ========== SETUP ==========
void setup() {
Serial.begin(115200);
Wire.begin(21,22);
lcd.begin(); lcd.backlight();
lcd.print(" PC Monitor "); lcd.setCursor(0,1); lcd.print(" v2.1 ");
delay(2000); lcd.clear(); updateDisplay();
Serial.println("ESP32 ready – waiting for JSON data...");
}

// ========== MAIN LOOP ==========
void loop() {
// Read all available serial characters
while (Serial.available()) {
char ch = Serial.read();

// Track braces to find complete JSON object
if (ch == '{') {
insideJson = true;
braceBalance = 1;
bufferIndex = 0;
serialBuffer[bufferIndex++] = ch;
}
else if (insideJson) {
serialBuffer[bufferIndex++] = ch;
if (ch == '{') braceBalance++;
else if (ch == '}') braceBalance--;

// When braces balance back to zero, we have a full JSON object
if (braceBalance == 0) {
serialBuffer[bufferIndex] = '\0';
parseStats(serialBuffer);
insideJson = false;
bufferIndex = 0;
// Immediately update display with new data
updateDisplay();
}
// Prevent buffer overflow
if (bufferIndex >= SERIAL_BUFFER_SIZE - 1) {
bufferIndex = 0;
insideJson = false;
Serial.println("Buffer overflow, resetting");
}
}
// Ignore any characters outside JSON (like stray newlines)
}

// Cycle pages
if (millis() - lastPageChange >= PAGE_INTERVAL) {
lastPageChange = millis();
currentPage = (currentPage + 1) % TOTAL_PAGES;
updateDisplay();
}
}



بعد التحميل، افتح شاشة المراقبة التسلسلية (115200 باود) لرؤية رسالة "ESP32 جاهز".



ثم أغلق الشاشة - حان وقت إعداد جانب الكمبيوتر.

3. 💻 سكربت بايثون - جمع إحصائيات الكمبيوتر

يستخدم سكربت بايثون مكتبة psutil للحصول على معلومات النظام مباشرةً. تُرسل جميع البيانات المُجمّعة ككائن JSON واحد (متبوعًا بسطر جديد) عبر المنفذ التسلسلي إلى ESP32. يعمل السكربت باستمرار، ويُحدّث البيانات كل ثانيتين افتراضيًا.

يكفي تغيير سطر واحد فقط: يجب ضبط SERIAL_PORT على منفذ COM الصحيح (في نظام ويندوز) أو مسار الجهاز (في نظامي لينكس/ماك أو إس) الخاص بـ ESP32.

4. الحصول على منفذ COM

في نظام ويندوز: افتح إدارة الأجهزة، وابحث ضمن المنافذ (COM وLPT) عن منفذ مثل USB Serial Port (COMx).



لينكس: شغّل الأمر ls /dev/ttyUSB* أو ls /dev/ttyACM*؛ عادةً ما يظهر ESP32 كـ /dev/ttyUSB0.

ماك أو إس: سيظهر كـ /dev/cu.usbserial-xxxx.

5. كتابة الكود البرمجي

أنشئ ملفًا باسم pc_monitor.py والصق المحتوى التالي. عدّل قيمة SERIAL_PORT وفقًا لذلك.

import serial
import psutil
import time
import json

# === CONFIGURATION ===
SERIAL_PORT = 'COM4' # Change to your ESP32 port (e.g., '/dev/ttyUSB0')
BAUD_RATE = 115200
UPDATE_INTERVAL = 2 # seconds

def get_system_stats():
"""Return a dictionary with all stats."""
# CPU
cpu_total = psutil.cpu_percent(interval=0.5)
cpu_freq = psutil.cpu_freq().current if psutil.cpu_freq() else 0
cpu_cores = psutil.cpu_percent(percpu=True)

# Memory
mem = psutil.virtual_memory()
ram_perc = round(mem.percent, 1)
ram_used = round(mem.used / (1024**3), 1)
ram_total = round(mem.total / (1024**3), 1)

# Disk (C:\ on Windows, / on Linux)
disk = psutil.disk_usage('/')
disk_perc = round(disk.percent, 1)
disk_used = round(disk.used / (1024**3), 1)
disk_total = round(disk.total / (1024**3), 1)

# Network (cumulative MB)
net = psutil.net_io_counters()
net_up = round(net.bytes_sent / (1024**2), 1)
net_down = round(net.bytes_recv / (1024**2), 1)

# Battery
battery = psutil.sensors_battery()
bat_perc = battery.percent if battery else -1
bat_plugged = battery.power_plugged if battery else False

# Uptime
uptime_sec = time.time() - psutil.boot_time()
uptime_h = int(uptime_sec // 3600)
uptime_m = int((uptime_sec % 3600) // 60)

stats = {
"cpu_total": cpu_total,
"cpu_freq": cpu_freq,
"cores": cpu_cores,
"ram_perc": ram_perc,
"ram_used": ram_used,
"ram_total": ram_total,
"disk_perc": disk_perc,
"disk_used": disk_used,
"disk_total": disk_total,
"net_up": net_up,
"net_down": net_down,
"bat_perc": bat_perc,
"bat_plugged": bat_plugged,
"uptime_h": uptime_h,
"uptime_m": uptime_m
}
return stats

def main():
try:
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(2) # Allow ESP32 to reset after serial open
print(f"Connected to {SERIAL_PORT}. Sending stats every {UPDATE_INTERVAL}s.\n")
while True:
stats = get_system_stats()
json_str = json.dumps(stats) + "\n"
ser.write(json_str.encode())
print("Sent:", json_str.strip())
time.sleep(UPDATE_INTERVAL)
except serial.SerialException as e:
print(f"Serial error: {e}")
except KeyboardInterrupt:
print("\nExiting...")
finally:
if 'ser' in locals() and ser.is_open:
ser.close()

if __name__ == "__main__":
main()


٦. تشغيل البرنامج النصي

تأكد من توصيل وحدة ESP32 بمنفذ USB وإغلاق برنامج مراقبة المنفذ التسلسلي الخاص بـ Arduino (لأنه يحجب المنفذ).

افتح نافذة طرفية (موجه الأوامر، أو PowerShell، أو طرفية Linux/macOS) داخل المجلد الذي تم حفظ ملف pc_monitor.py فيه.

نفّذ الأمر التالي:

python pc_monitor.py


يجب أن ترى بيانات JSON تُطبع كل ثانيتين



في الوقت نفسه، ستبدأ شاشة LCD في وحدة ESP32 بعرض معلومات النظام مباشرةً.

7. 📺 ما تراه على شاشة LCD

تتنقل الشاشة بين خمس صفحات مختلفة، حيث تبقى كل صفحة لمدة 3 ثوانٍ قبل الانتقال إلى الصفحة التالية.

يتم تحديث البيانات فور وصول حزمة JSON جديدة من الحاسوب (كل ثانيتين)، لذا تبقى جميع الأرقام محدثة.

8. 🧪 الاختبار والتشغيل الأولي

عند توصيل الطاقة لأول مرة، ستعرض شاشة LCD شاشة بدء تشغيل قصيرة (PC Monitor v2.0) ثم صفحة الإحصائيات الأولى. إذا لم يتم استلام أي بيانات تسلسلية، فستبقى القيم عند الصفر.

بمجرد بدء تشغيل برنامج بايثون، ستلاحظ تغير الأرقام مباشرةً. كما يعرض الحاسوب كل حزمة JSON مُرسلة، لتتمكن من التحقق من إرسال البيانات فعليًا.

🖨️ غلاف مطبوع بتقنية الطباعة ثلاثية الأبعاد - من صنع JUSTWAY



بعد التأكد من عمل الدوائر الإلكترونية، تتمثل الخطوة التالية في إضفاء مظهر نهائي واحترافي على المشروع. يتطلب تصميم وطباعة غلاف يتناسب بدقة مع لوحة ESP32 وشاشة LCD وجميع الأسلاك وقتًا وطابعة ثلاثية الأبعاد جيدة.






مناسب تمامًا للوحات تطوير ESP32 القياسية وشاشات LCD I2C 16×2




فتحات لمنفذ USB والتهوية






متوفر بألوان متعددة (أسود، أبيض، شفاف)



سرعة في التنفيذ وشحن عالمي

👈 تفضل بزيارة JUSTWAY للحصول على عرض سعر لتصميم علبة مخصصة لك.

📚 أفكار أخيرة

يحوّل هذا المشروع وحدة ESP32 رخيصة الثمن وشاشة LCD بسيطة بتقنية I2C إلى شاشة عرض أداء مخصصة لجهاز الكمبيوتر، توضع على مكتبك. لا يتطلب المشروع اتصالاً بالإنترنت أو خدمات سحابية خارجية، ويكفي كابل USB واحد فقط للطاقة والبيانات. يتميز المشروع بمرونة استخدام لغة بايثون ومنصة أردوينو، كما يسهّل بروتوكول JSON إضافة أو تغيير البيانات المعروضة.


إذا واجهت أي مشكلة، تذكر التحقق من النقاط الأساسية أولاً: عنوان I2C، والتوصيلات الصحيحة، ومنفذ COM الصحيح، ومعدل نقل البيانات (115200). يحتوي كود ESP32 المرفق على خاصية تحليل JSON مدمجة مع تقارير الأخطاء، لذا سيُظهر لك مُراقب المنفذ التسلسلي دائمًا المشكلة بالتحديد.


الآن، ابدأ ببناء شاشتك الخاصة، ولن تحتاج إلى التبديل بين النوافذ للعودة إلى مدير المهام. إذا قمت ببناء واحدة، شاركنا صورك وأي تعديلات أجريتها - سأكون سعيدًا برؤية إبداعك.

مترجم