Contain Electronic projects with codes
تحتوي على مشاريع مع الكودات البرمجيه الخاصه بها
هەموو بەرهەمەکان
-
SkyTech Password Wallet
SkyTech Pass Wallet جهاز SkyTech Pass Wallet هو مدير كلمات مرور فعلي (Hardware) ومولد رموز مصادقة ثنائية (TOTP) يعمل بشكل غير متصل بالإنترنت. يعمل كلوحة مفاتيح USB (Plug & Play) لإدخال بيانات تسجيل الدخول تلقائيًا دون الحاجة إلى تثبيت أي برامج. المميزات إدخال تلقائي آمن (Plug & Play): يعمل كلوحة مفاتيح USB فعلية لكتابة بياناتك بضغطة زر، مما يقلل مخاطر برمجيات التجسس. تخزين محلي مستقل (Offline): يحفظ كلمات المرور ويولد رموز المصادقة (TOTP) داخليًا بعيدًا عن الإنترنت والخدمات السحابية. إدارة لاسلكية سهلة: ينشئ شبكة Wi-Fi محلية خاصة ومؤقتة لإضافة وتعديل الحسابات عبر متصفح الهاتف بسهولة. المكونات المعالج: لوحة ESP32-S3، تدعم USB مباشرة واستخدام الجهاز كلوحة مفاتيح (USB HID). الشاشة: شاشة OLED بحجم 0.96 بوصة، عالية التباين لعرض الحسابات ورموز TOTP بوضوح. أدوات التحكم: مفتاحان ضاغطان (Push Buttons) للتنقل بين القوائم وتأكيد الإدخال. الكـــــود: //Gmail TOTPconst char* WIFI_SSID = "Samsung s23";const char* WIFI_PASSWORD = "11111111";const char* GMAIL_TOTP_BASE32 = "aaaa bbbb cccc dddd eeee ffff gggg hhhh"; #include <WiFi.h>#include <WebServer.h>#include <DNSServer.h>#include <Preferences.h>#include <time.h>#include <TOTP.h>#include "USB.h"#include "USBHIDKeyboard.h" #include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64#define OLED_RESET -1Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); USBHIDKeyboard Keyboard;WebServer server(80);DNSServer dnsServer;Preferences prefs; // ===== Buttons =====#define BTN_OK_UP 11#define BTN_DOWN 10#define I2C_SDA 8#define I2C_SCL 9 // ===== Wi-Fi / Time =====const char* NTP_SERVER_1 = "pool.ntp.org";const char* NTP_SERVER_2 = "time.google.com";const long GMT_OFFSET_SEC = 3 * 3600; // Saudi Arabiaconst int DAYLIGHT_OFFSET_SEC = 0; uint8_t gmailTotpSecret[64];size_t gmailTotpSecretLen = 0;TOTP* gmailTotp = nullptr; // ===== Timing =====const unsigned long DEBOUNCE_MS = 180;const unsigned long HOLD_TIME_MS = 700;const unsigned long USB_STARTUP_DELAY_MS = 800; // was 3000const byte DNS_PORT = 53; // ===== Menu =====enum ItemType { ITEM_SUBMENU, ITEM_TEXT, ITEM_TOTP, ITEM_INFO}; struct MenuItem { const char* name; ItemType type; const char* textValue; TOTP* totp;}; enum MenuScreen { SCREEN_MAIN, SCREEN_PASSWORDS, SCREEN_PASSWORD_ACTIONS, SCREEN_TOTP, SCREEN_TOTP_VIEW, SCREEN_SETTINGS}; MenuScreen currentScreen = SCREEN_MAIN;int selectedIndex = 0;int menuScrollOffset = 0; MenuItem mainMenuItems[] = { {"Passwords", ITEM_SUBMENU, nullptr, nullptr}, {"TOTP", ITEM_SUBMENU, nullptr, nullptr}, {"Settings", ITEM_SUBMENU, nullptr, nullptr}}; const int MAX_PASSWORD_ITEMS = 12; MenuItem passwordMenuItems[MAX_PASSWORD_ITEMS];int passwordMenuCount = 4; char passwordNameValues[MAX_PASSWORD_ITEMS][32] = { "Gmail", "GitHub", "AWS", "Bank"}; MenuItem passwordActionMenuItems[] = { {"Username", ITEM_INFO, nullptr, nullptr}, {"Password", ITEM_INFO, nullptr, nullptr}, {"UserTabPass", ITEM_INFO, nullptr, nullptr}}; MenuItem totpMenuItems[] = { {"Google TOTP", ITEM_TOTP, nullptr, nullptr}}; MenuItem settingsMenuItems[] = {}; MenuItem* getCurrentMenuItems() { switch (currentScreen) { case SCREEN_PASSWORDS: return passwordMenuItems; case SCREEN_PASSWORD_ACTIONS: return passwordActionMenuItems; case SCREEN_TOTP: return totpMenuItems; case SCREEN_SETTINGS: return settingsMenuItems; case SCREEN_MAIN: default: return mainMenuItems; }} int getCurrentMenuCount() { switch (currentScreen) { case SCREEN_PASSWORDS: return passwordMenuCount; case SCREEN_PASSWORD_ACTIONS: return sizeof(passwordActionMenuItems) / sizeof(passwordActionMenuItems[0]); case SCREEN_TOTP: return sizeof(totpMenuItems) / sizeof(totpMenuItems[0]); case SCREEN_SETTINGS: return 0; case SCREEN_MAIN: default: return sizeof(mainMenuItems) / sizeof(mainMenuItems[0]); }} const char* getScreenTitle() { switch (currentScreen) { case SCREEN_PASSWORDS: return "Passwords"; case SCREEN_PASSWORD_ACTIONS: return "Send As"; case SCREEN_TOTP: return "TOTP"; case SCREEN_TOTP_VIEW: return "TOTP"; case SCREEN_SETTINGS: return "Settings"; case SCREEN_MAIN: default: return "Dr. Passwords"; }} // ===== Time sync state =====bool timeSynced = false;int activeTotpIndex = 0;unsigned long lastTotpRedraw = 0;bool settingsPortalActive = false;String settingsApPassword;int activePasswordIndex = 0; char passwordTextValues[MAX_PASSWORD_ITEMS][128] = { "MyGmailPassword123", "MyGitHubPassword456", "MyAwsPassword789", "MyBankPassword000"}; char passwordUsernameValues[MAX_PASSWORD_ITEMS][128] = { "user.alpha01", "bluefalcon77", "cloud.user23", "banking_hero", "gamma.node", "pixel.rider", "tiger_login", "neo.account", "orbit.user", "delta.signin", "fastlane.id", "quantum.user"}; // ===== Button states =====bool lastDownState = HIGH;bool btnPressed = false;bool holdTriggered = false;unsigned long btnPressStart = 0;unsigned long lastDownPress = 0;bool downHoldHandled = false; // ===== Base32 decode (for TOTP) =====int base32Value(char c) { if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a'; if (c >= '2' && c <= '7') return c - '2' + 26; return -1;} size_t decodeBase32(const char* input, uint8_t* output, size_t maxOutputLen) { int buffer = 0; int bitsLeft = 0; size_t outLen = 0; while (*input) { char c = *input++; if (c == ' ' || c == '=' || c == '-') continue; int val = base32Value(c); if (val < 0) continue; buffer = (buffer << 5) | val; bitsLeft += 5; if (bitsLeft >= 8) { bitsLeft -= 8; if (outLen >= maxOutputLen) return 0; output[outLen++] = (buffer >> bitsLeft) & 0xFF; } } return outLen;} bool initTotp() { gmailTotpSecretLen = decodeBase32(GMAIL_TOTP_BASE32, gmailTotpSecret, sizeof(gmailTotpSecret)); if (gmailTotpSecretLen == 0) return false; gmailTotp = new TOTP(gmailTotpSecret, gmailTotpSecretLen); return true;} // ===== UI =====void drawMenu() { display.clearDisplay(); // رسم العنوان display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(0, 0); display.println(getScreenTitle()); // رسم خط فاصل تحت العنوان display.drawLine(0, 10, 128, 10, SSD1306_WHITE); MenuItem* items = getCurrentMenuItems(); int itemCount = getCurrentMenuCount(); const int startY = 14; const int lineHeight = 12; // ارتفاع مناسب للخط بحجم 1 const int visibleItems = 4; // 4 عناصر كحد أقصى في الشاشة if (selectedIndex < menuScrollOffset) { menuScrollOffset = selectedIndex; } if (selectedIndex >= menuScrollOffset + visibleItems) { menuScrollOffset = selectedIndex - visibleItems + 1; } if (menuScrollOffset < 0) menuScrollOffset = 0; if (itemCount <= visibleItems) menuScrollOffset = 0; int endIndex = menuScrollOffset + visibleItems; if (endIndex > itemCount) endIndex = itemCount; int y = startY; for (int i = menuScrollOffset; i < endIndex; i++) { display.setCursor(2, y); if (i == selectedIndex) { // رسم خلفية بيضاء مع نص أسود للعنصر المحدد لإبرازه display.fillRect(0, y - 1, 118, lineHeight, SSD1306_WHITE); display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); display.print("> "); display.println(items[i].name); } else { // نص أبيض عادي للعناصر غير المحددة display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); display.print(" "); display.println(items[i].name); } y += lineHeight; } // مؤشرات التمرير (أسهم صغيرة على يمين الشاشة) display.setTextColor(SSD1306_WHITE); if (menuScrollOffset > 0) { display.setCursor(120, 14); display.print("^"); } if (endIndex < itemCount) { display.setCursor(120, 50); display.print("v"); } display.display();} void showSendingScreen(const char* text) { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(10, 20); display.println("Sending..."); display.setCursor(10, 40); display.println(text); display.display();} bool syncTimeOverWiFi() { WiFi.mode(WIFI_STA); while (true) { WiFi.disconnect(true); delay(200); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); unsigned long start = millis(); while (WiFi.status() != WL_CONNECTED && millis() - start < 20000) { delay(250); } if (WiFi.status() == WL_CONNECTED) { configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER_1, NTP_SERVER_2); struct tm timeinfo; start = millis(); while (millis() - start < 20000) { if (getLocalTime(&timeinfo)) { WiFi.disconnect(true); WiFi.mode(WIFI_OFF); return true; } delay(250); } } WiFi.disconnect(true); delay(500); }} bool getCurrentUnixTime(time_t &unixTime) { time(&unixTime); return unixTime > 1700000000;} void showStatusScreen(const char* title, const char* line2) { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); int titleWidth = strlen(title) * 6; int titleX = (SCREEN_WIDTH - titleWidth) / 2; if (titleX < 0) titleX = 0; display.setCursor(titleX, 20); display.println(title); const char* dots = "..........."; int dotsLen = strlen(dots); int phase = (millis() / 180) % ((dotsLen * 2) - 2); int visibleCount = (phase < dotsLen) ? (phase + 1) : ((dotsLen * 2) - phase - 1); int dotsWidth = visibleCount * 6; int dotsX = (SCREEN_WIDTH - dotsWidth) / 2; if (dotsX < 0) dotsX = 0; display.setCursor(dotsX, 40); for (int i = 0; i < visibleCount; i++) { display.print('.'); } display.display();} void showTotpCodeScreen(const char* title, const char* code, int secondsRemaining) { display.clearDisplay(); // العنوان display.setTextColor(SSD1306_WHITE); display.setTextSize(1); const char* displayTitle = title; if (strcmp(title, "Gmail TOTP") == 0) { displayTitle = "Google"; } int titleWidth = strlen(displayTitle) * 6; int titleX = (SCREEN_WIDTH - titleWidth) / 2; if (titleX < 0) titleX = 0; display.setCursor(titleX, 0); display.println(displayTitle); // كود TOTP (بخط كبير الحجم 2) display.setTextSize(2); int codeWidth = strlen(code) * 12; int codeX = (SCREEN_WIDTH - codeWidth) / 2; if (codeX < 0) codeX = 0; display.setCursor(codeX, 22); display.println(code); // شريط التقدم (الزمن المتبقي) const int period = 30; int barWidth = 96; int barX = 4; int progressWidth = (secondsRemaining * barWidth) / period; if (progressWidth < 0) progressWidth = 0; // رسم إطار الشريط ثم تعبئته بناءً على الوقت المتبقي display.drawRect(barX, 50, barWidth, 10, SSD1306_WHITE); if (progressWidth > 0) { display.fillRect(barX + 2, 52, progressWidth - 4, 6, SSD1306_WHITE); } // رسم الثواني المتبقية كنص بجانب الشريط display.setTextSize(1); display.setCursor(barX + barWidth + 8, 51); display.print(secondsRemaining); display.print("s"); display.display();} String htmlEscape(const char* input) { String s = input ? input : ""; s.replace("&", "&"); s.replace("<", "<"); s.replace(">", ">"); s.replace("\"", """); return s;} String generateApPassword() { const char charset[] = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%^&*"; const int passwordLength = 16; String result = ""; result.reserve(passwordLength); for (int i = 0; i < passwordLength; i++) { result += charset[esp_random() % (sizeof(charset) - 1)]; } return result;} void refreshPasswordMenuItems() { for (int i = 0; i < passwordMenuCount; i++) { passwordMenuItems[i].name = passwordNameValues[i]; passwordMenuItems[i].type = ITEM_TEXT; passwordMenuItems[i].textValue = passwordTextValues[i]; passwordMenuItems[i].totp = nullptr; }} void loadSavedPasswords() { prefs.begin("vault", true); int storedCount = prefs.getInt("count", 4); if (storedCount < 1) storedCount = 1; if (storedCount > MAX_PASSWORD_ITEMS) storedCount = MAX_PASSWORD_ITEMS; passwordMenuCount = storedCount; for (int i = 0; i < passwordMenuCount; i++) { String nameKey = "name" + String(i); String userKey = "user" + String(i); String passKey = "pass" + String(i); String defaultName = passwordNameValues[i]; String defaultUser = passwordUsernameValues[i]; String defaultPass = passwordTextValues[i]; String loadedName = prefs.getString(nameKey.c_str(), defaultName); String loadedUser = prefs.getString(userKey.c_str(), defaultUser); String loadedPass = prefs.getString(passKey.c_str(), defaultPass); loadedName.toCharArray(passwordNameValues[i], sizeof(passwordNameValues[i])); loadedUser.toCharArray(passwordUsernameValues[i], sizeof(passwordUsernameValues[i])); loadedPass.toCharArray(passwordTextValues[i], sizeof(passwordTextValues[i])); } prefs.end(); refreshPasswordMenuItems();} void savePasswordsToPreferences() { prefs.begin("vault", false); prefs.clear(); prefs.putInt("count", passwordMenuCount); for (int i = 0; i < passwordMenuCount; i++) { String nameKey = "name" + String(i); String userKey = "user" + String(i); String passKey = "pass" + String(i); prefs.putString(nameKey.c_str(), passwordNameValues[i]); prefs.putString(userKey.c_str(), passwordUsernameValues[i]); prefs.putString(passKey.c_str(), passwordTextValues[i]); } prefs.end();} void drawSettingsPortalScreen() { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); // العنوان display.setTextSize(1); const char* title = "Settings Portal"; int titleX = (SCREEN_WIDTH - (strlen(title) * 6)) / 2; if (titleX < 0) titleX = 0; display.setCursor(titleX, 0); display.println(title); display.drawLine(0, 10, 128, 10, SSD1306_WHITE); // تفاصيل نقطة الاتصال display.setCursor(0, 18); display.print("SSID: Dr. Passwords"); display.setCursor(0, 32); display.print("PASS: Press OK"); // التعليمات السفلية display.setCursor(0, 50); display.println("Hold DOWN to close"); display.display();} void handlePortalRoot() { int editIndex = -1; if (server.hasArg("edit")) { editIndex = server.arg("edit").toInt(); if (editIndex < 0 || editIndex >= passwordMenuCount) { editIndex = -1; } } String formName = ""; String formUser = ""; String formPass = ""; bool isEditMode = (editIndex >= 0); // Generate default random password for new entries if (!isEditMode) { const char charset[] = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%^&*"; for (int i = 0; i < 16; i++) { formPass += charset[esp_random() % (sizeof(charset) - 1)]; } } if (isEditMode) { formName = htmlEscape(passwordNameValues[editIndex]); formUser = htmlEscape(passwordUsernameValues[editIndex]); formPass = ""; } String html = ""; html += "<!doctype html><html><head><meta name='viewport' content='width=device-width,initial-scale=1'>"; html += "<title>Dr. Passwords</title>"; html += "<style>"; html += "body{margin:0;font-family:Arial,sans-serif;background:#0b0b0b;color:#f5f5f5;padding:22px;}"; html += ".wrap{max-width:980px;margin:0 auto;}"; html += "h1{margin:0 0 18px 0;text-align:center;font-size:28px;font-weight:700;color:#ffffff;}"; html += ".card{background:#161616;border:1px solid rgba(255,255,255,0.08);border-radius:20px;padding:24px;margin-bottom:22px;box-shadow:0 10px 24px rgba(0,0,0,0.35);} "; html += "h2{margin:0 0 18px 0;font-size:18px;color:#ffffff;}"; html += "label{display:block;margin:14px 0 8px 0;font-weight:600;color:#d7d7d7;}"; html += "input{width:100%;padding:14px 16px;border-radius:12px;border:1px solid rgba(255,255,255,0.10);background:#0f0f0f;color:#fff;box-sizing:border-box;font-size:15px;outline:none;}"; html += "input::placeholder{color:#8d8d8d;}"; html += ".actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:22px;}"; html += ".btn{display:inline-block;padding:13px 22px;border:none;border-radius:12px;font-size:15px;font-weight:700;text-decoration:none;cursor:pointer;}"; html += ".btn-primary{background:#4d8ef7;color:#fff;}"; html += ".btn-secondary{background:#4b4b4b;color:#fff;}"; html += ".btn-edit{background:#4d8ef7;color:#fff;padding:10px 18px;border-radius:10px;text-decoration:none;}"; html += ".btn-delete{background:#ef4b3f;color:#fff;padding:10px 18px;border-radius:10px;text-decoration:none;display:inline-block;}"; html += "table{width:100%;border-collapse:collapse;overflow:hidden;border-radius:14px;}"; html += "th,td{padding:16px 14px;border:1px solid rgba(255,255,255,0.08);text-align:left;vertical-align:middle;}"; html += "th{background:#202020;color:#f2f2f2;font-size:15px;}"; html += "td{background:#161616;}"; html += ".table-actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center;}"; html += ".muted{color:#bdbdbd;font-size:14px;margin-top:8px;}"; html += "@media (max-width:700px){body{padding:14px;} .card{padding:18px;} th,td{padding:12px 10px;font-size:14px;} .table-actions{flex-direction:column;align-items:stretch;}}"; html += "</style></head><body><div class='wrap'>"; html += "<h1>Password Management</h1>"; html += "<div class='card'><h2>"; html += isEditMode ? "Edit Saved Password" : "Add New Password"; html += "</h2><form method='POST' action='/save'>"; if (isEditMode) { html += "<input type='hidden' name='edit_index' value='" + String(editIndex) + "'>"; } html += "<label>Name</label>"; html += "<input name='item_name' placeholder='Example: Gmail' value='" + formName + "'>"; html += "<label>Username</label>"; html += "<input name='item_user' placeholder='Enter username' value='" + formUser + "'>"; html += "<label>Password</label>"; html += "<input id='pwd' name='item_pass' type='text' placeholder='Enter new password' value='" + formPass + "'>"; // Password generator UI html += "<div style='margin-top:16px;'>"; html += "<div style='margin-bottom:8px;color:#cfcfcf;'>Password Length: <span id='lenVal'>16</span></div>"; html += "<input id='len' type='range' min='4' max='64' value='16' style='width:100%;'>"; html += "<div style='display:flex;justify-content:space-between;color:#8d8d8d;font-size:12px;'><span>4</span><span>64</span></div>"; html += "<div style='margin-top:10px;'>"; html += "<button type='button' class='btn btn-secondary' onclick='gen()'>Regenerate</button>"; html += "</div></div>"; // Inline JS for generation html += "<script>"; html += "const cs='ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%^&*';"; html += "function gen(){var l=parseInt(document.getElementById('len').value)||16;var s='';for(var i=0;i<l;i++){s+=cs[Math.floor(Math.random()*cs.length)];}document.getElementById('pwd').value=s;document.getElementById('lenVal').textContent=l;}"; html += "document.addEventListener('DOMContentLoaded',function(){var r=document.getElementById('len');var v=document.getElementById('lenVal');if(r&&v){v.textContent=r.value;r.addEventListener('input',function(){v.textContent=this.value;});}});"; html += "</script>"; html += "<div class='actions'>"; html += "<button class='btn btn-primary' type='submit'>"; html += isEditMode ? "Save Changes" : "Add Password"; html += "</button>"; if (isEditMode) { html += "<a class='btn btn-secondary' href="/ku">Cancel</a>"; } html += "</div></form></div>"; html += "<div class='card'><h2>Saved Passwords</h2>"; if (passwordMenuCount == 0) { html += "<p class='muted'>No saved passwords yet.</p>"; } else { html += "<table><tr><th>Name</th><th>Username</th><th>Actions</th></tr>"; for (int i = 0; i < passwordMenuCount; i++) { html += "<tr>"; html += "<td>" + htmlEscape(passwordNameValues[i]) + "</td>"; html += "<td>" + htmlEscape(passwordUsernameValues[i]) + "</td>"; html += "<td><div class='table-actions'>"; html += "<a class='btn-edit' href='/?edit=" + String(i) + "'>Edit</a>"; html += "<a class='btn-delete' href='/delete_now?index=" + String(i) + "&ts=" + String(millis()) + "'>Delete</a>"; html += "</div></td>"; html += "</tr>"; } html += "</table>"; } html += "</div></div></body></html>"; server.sendHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); server.send(200, "text/html", html);} void handlePortalSave() { String itemName = server.arg("item_name"); String itemUser = server.arg("item_user"); String itemPass = server.arg("item_pass"); itemName.trim(); itemUser.trim(); itemPass.trim(); if (itemName.length() == 0) { server.send(200, "text/html", "<!doctype html><html><body style='background:#0b0b0b;color:#fff;font-family:Arial;padding:24px;'><h2>Name is required</h2><p><a href="/ku" style='color:#7fc0ff;'>Back</a></p></body></html>"); return; } int targetIndex = -1; if (server.hasArg("edit_index")) { targetIndex = server.arg("edit_index").toInt(); if (targetIndex < 0 || targetIndex >= passwordMenuCount) { targetIndex = -1; } } if (targetIndex >= 0) { itemName.toCharArray(passwordNameValues[targetIndex], sizeof(passwordNameValues[targetIndex])); itemUser.toCharArray(passwordUsernameValues[targetIndex], sizeof(passwordUsernameValues[targetIndex])); if (itemPass.length() > 0) { itemPass.toCharArray(passwordTextValues[targetIndex], sizeof(passwordTextValues[targetIndex])); } } else { if (itemPass.length() == 0) { server.send(200, "text/html", "<!doctype html><html><body style='background:#0b0b0b;color:#fff;font-family:Arial;padding:24px;'><h2>Password is required for new items</h2><p><a href="/ku" style='color:#7fc0ff;'>Back</a></p></body></html>"); return; } if (passwordMenuCount >= MAX_PASSWORD_ITEMS) { server.send(200, "text/html", "<!doctype html><html><body style='background:#0b0b0b;color:#fff;font-family:Arial;padding:24px;'><h2>Storage full</h2><p>Maximum password items reached.</p><p><a href="/ku" style='color:#7fc0ff;'>Back</a></p></body></html>"); return; } itemName.toCharArray(passwordNameValues[passwordMenuCount], sizeof(passwordNameValues[passwordMenuCount])); itemUser.toCharArray(passwordUsernameValues[passwordMenuCount], sizeof(passwordUsernameValues[passwordMenuCount])); itemPass.toCharArray(passwordTextValues[passwordMenuCount], sizeof(passwordTextValues[passwordMenuCount])); passwordMenuCount++; } refreshPasswordMenuItems(); savePasswordsToPreferences(); handlePortalRoot();} void stopSettingsPortal(); void startSettingsPortal() { stopSettingsPortal(); WiFi.disconnect(true, true); WiFi.softAPdisconnect(true); delay(200); WiFi.mode(WIFI_AP); delay(100); bool apStarted = WiFi.softAP("Dr. Passwords", settingsApPassword.c_str()); delay(300); if (!apStarted) { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(10, 20); display.println("AP Start Failed"); display.setCursor(10, 40); display.println("Check AP Password"); display.display(); delay(1200); currentScreen = SCREEN_MAIN; drawMenu(); return; } server.stop(); dnsServer.stop(); dnsServer.start(DNS_PORT, "*", WiFi.softAPIP()); server.on("/", HTTP_GET, handlePortalRoot); server.on("/generate_204", HTTP_GET, handlePortalRoot); server.on("/hotspot-detect.html", HTTP_GET, handlePortalRoot); server.on("/ncsi.txt", HTTP_GET, handlePortalRoot); server.on("/save", HTTP_POST, handlePortalSave); server.on("/delete_now", HTTP_GET, handlePortalDeleteNow); server.onNotFound(handlePortalRoot); server.begin(); settingsPortalActive = true; drawSettingsPortalScreen();} void handlePortalDeleteNow() { if (!server.hasArg("index")) { handlePortalRoot(); return; } int deleteIndex = server.arg("index").toInt(); if (deleteIndex < 0 || deleteIndex >= passwordMenuCount) { handlePortalRoot(); return; } for (int i = deleteIndex; i < passwordMenuCount - 1; i++) { strlcpy(passwordNameValues[i], passwordNameValues[i + 1], sizeof(passwordNameValues[i])); strlcpy(passwordUsernameValues[i], passwordUsernameValues[i + 1], sizeof(passwordUsernameValues[i])); strlcpy(passwordTextValues[i], passwordTextValues[i + 1], sizeof(passwordTextValues[i])); } passwordMenuCount--; if (passwordMenuCount < 0) passwordMenuCount = 0; if (passwordMenuCount < MAX_PASSWORD_ITEMS) { passwordNameValues[passwordMenuCount][0] = ' '; passwordUsernameValues[passwordMenuCount][0] = ' '; passwordTextValues[passwordMenuCount][0] = ' '; } if (selectedIndex >= passwordMenuCount && passwordMenuCount > 0) { selectedIndex = passwordMenuCount - 1; } if (selectedIndex < 0) selectedIndex = 0; refreshPasswordMenuItems(); savePasswordsToPreferences(); handlePortalRoot();} void stopSettingsPortal() { if (!settingsPortalActive) return; dnsServer.stop(); server.stop(); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_OFF); settingsPortalActive = false;} void processSettingsPortal() { if (!settingsPortalActive) return; dnsServer.processNextRequest(); server.handleClient();} void drawBootScreen() { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); // تصغير الخط ليناسب الشاشة display.setTextSize(1); const char* title = "Dr. Passwords"; int charWidth = 6; int textWidth = strlen(title) * charWidth; int x = (SCREEN_WIDTH - textWidth) / 2; int y = (SCREEN_HEIGHT / 2) - 4; display.setCursor(x, y); display.println(title); display.display(); // تحديث الشاشة} void moveUp() { int itemCount = getCurrentMenuCount(); selectedIndex--; if (selectedIndex < 0) selectedIndex = itemCount - 1; drawMenu();} void moveDown() { int itemCount = getCurrentMenuCount(); selectedIndex++; if (selectedIndex >= itemCount) selectedIndex = 0; drawMenu();} void sendSelectedItem() { MenuItem* items = getCurrentMenuItems(); MenuItem &item = items[selectedIndex]; if (currentScreen == SCREEN_TOTP_VIEW) { time_t now; if (!getCurrentUnixTime(now)) return; char* code = totpMenuItems[activeTotpIndex].totp->getCode(now); Keyboard.print(code); return; } if (settingsPortalActive) { Keyboard.print(settingsApPassword); return; } if (currentScreen == SCREEN_PASSWORD_ACTIONS) { showSendingScreen(passwordMenuItems[activePasswordIndex].name); delay(250); if (selectedIndex == 0) { Keyboard.print(passwordUsernameValues[activePasswordIndex]); } else if (selectedIndex == 1) { Keyboard.print(passwordTextValues[activePasswordIndex]); } else if (selectedIndex == 2) { Keyboard.print(passwordUsernameValues[activePasswordIndex]); Keyboard.write(KEY_TAB); Keyboard.print(passwordTextValues[activePasswordIndex]); } else if (selectedIndex == 1) { Keyboard.print(passwordUsernameValues[activePasswordIndex]); } else if (selectedIndex == 2) { Keyboard.print(passwordUsernameValues[activePasswordIndex]); Keyboard.write(KEY_TAB); Keyboard.print(passwordTextValues[activePasswordIndex]); } delay(400); drawMenu(); return; } if (item.type == ITEM_SUBMENU) { if (currentScreen == SCREEN_MAIN) { if (selectedIndex == 0) { currentScreen = SCREEN_PASSWORDS; selectedIndex = 0; menuScrollOffset = 0; drawMenu(); } else if (selectedIndex == 1) { if (!timeSynced) { showStatusScreen("Connecting WiFi", "TOTP"); syncTimeOverWiFi(); timeSynced = true; } activeTotpIndex = 0; currentScreen = SCREEN_TOTP_VIEW; lastTotpRedraw = 0; } else if (selectedIndex == 2) { selectedIndex = 0; menuScrollOffset = 0; startSettingsPortal(); } } return; } if (item.type == ITEM_INFO) { return; } if (item.type == ITEM_TEXT) { activePasswordIndex = selectedIndex; currentScreen = SCREEN_PASSWORD_ACTIONS; selectedIndex = 0; menuScrollOffset = 0; drawMenu(); return; } if (item.type == ITEM_TOTP) { if (!timeSynced) { showStatusScreen("Connecting WiFi", item.name); syncTimeOverWiFi(); timeSynced = true; } activeTotpIndex = selectedIndex; currentScreen = SCREEN_TOTP_VIEW; lastTotpRedraw = 0; return; }} void setup() { // 1. تعريف الأزرار pinMode(BTN_OK_UP, INPUT_PULLUP); pinMode(BTN_DOWN, INPUT_PULLUP); // 2. تشغيل الشاشة أوووولاً قبل أي شيء آخر! Wire.begin(I2C_SDA, I2C_SCL); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { for(;;); // توقف هنا إذا لم يتم العثور على الشاشة } display.clearDisplay(); // 3. عرض شاشة الإقلاع فوراً لنعرف أن اللوحة تعمل drawBootScreen(); delay(1000); // ننتظر ثانية لنستمتع برؤية الشعار // 4. الآن نقوم بإنشاء كلمة مرور البوابة وقراءة الذاكرة بأمان settingsApPassword = generateApPassword(); //Uncomment For Easy Tests //settingsApPassword = "12345678"; loadSavedPasswords(); // 5. تهيئة رمز الـ TOTP if (!initTotp()) { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(10, 20); display.println("TOTP Error"); display.setCursor(10, 35); display.println("Invalid Base32"); display.display(); while (true) delay(1000); } totpMenuItems[0].totp = gmailTotp; // 6. تشغيل لوحة المفاتيح والـ USB Keyboard.begin(); USB.begin(); delay(USB_STARTUP_DELAY_MS); // 7. أخيراً، عرض القائمة الرئيسية لتكون جاهزة للاستخدام drawMenu();} void loop() { processSettingsPortal(); bool okUpState = digitalRead(BTN_OK_UP); bool downState = digitalRead(BTN_DOWN); unsigned long nowMs = millis(); if (currentScreen == SCREEN_TOTP_VIEW) { time_t now; if (getCurrentUnixTime(now)) { int secondsRemaining = 30 - (now % 30); if (secondsRemaining == 30) secondsRemaining = 0; if (lastTotpRedraw != (unsigned long)now) { char* code = totpMenuItems[activeTotpIndex].totp->getCode(now); showTotpCodeScreen(totpMenuItems[activeTotpIndex].name, code, secondsRemaining); lastTotpRedraw = (unsigned long)now; } } } if (okUpState == LOW) { if (!btnPressed) { btnPressed = true; btnPressStart = nowMs; holdTriggered = false; } else { if (!holdTriggered && (nowMs - btnPressStart >= HOLD_TIME_MS)) { holdTriggered = true; sendSelectedItem(); } } } else { if (btnPressed && !holdTriggered) { if (currentScreen != SCREEN_TOTP_VIEW && !settingsPortalActive) { moveDown(); } } btnPressed = false; holdTriggered = false; } if (downState == LOW) { if (lastDownState == HIGH) { lastDownPress = nowMs; downHoldHandled = false; } if (!downHoldHandled && (nowMs - lastDownPress >= HOLD_TIME_MS)) { downHoldHandled = true; if (currentScreen == SCREEN_TOTP_VIEW) { currentScreen = SCREEN_TOTP; selectedIndex = 0; menuScrollOffset = 0; drawMenu(); } else if (currentScreen == SCREEN_PASSWORD_ACTIONS) { currentScreen = SCREEN_PASSWORDS; selectedIndex = activePasswordIndex; drawMenu(); } else if (settingsPortalActive) { stopSettingsPortal(); currentScreen = SCREEN_MAIN; selectedIndex = 0; menuScrollOffset = 0; drawMenu(); } else if (currentScreen != SCREEN_MAIN) { currentScreen = SCREEN_MAIN; selectedIndex = 0; menuScrollOffset = 0; drawMenu(); } } } else { if (lastDownState == LOW && !downHoldHandled && (nowMs - lastDownPress < HOLD_TIME_MS)) { if (currentScreen != SCREEN_TOTP_VIEW && !settingsPortalActive) { moveUp(); } } downHoldHandled = false; } lastDownState = downState; delay(20);}
200,000 IQD
-
Smart obstacle-avoiding robot
مشروع روبوت ذكي متكامل لتجنب العقبات، مصمم للطلاب والهواة في مجالات الروبوتات والإلكترونيات. يعتمد الروبوت على شريحة Arduino Nano لتوجيه المحركات بدقة واتخاذ القرارات البرمجية في الوقت الفعلي بناءً على بيانات مسح المساحة المزدوجة.أبرز المميزات:نظام رؤية مزدوج: مزود بمستشعرين UltraSonic (HC-SR04) لقراءة المسافات والزوايا بشكل دقيق (يمين ويسار).تحكم قوي بالمحركات: يعتمد على وحدة القيادة L298N Dual H-Bridge للتحكم في السرعة والاتجاه والدوران الذاتي.تنبيه صوتي ذكي: يحتوي على جرس تنبيه (Buzzer) يعمل تلقائياً عند الاقتراب من أي حاجز.خوارزمية هروب متطورة: يتخذ القرار آلياً (دوران لليمين، اليسار، أو الالتفاف الكامل عند الحصار).المكونات الأساسية المستخدمة:لوحة Arduino Nano.وحدة قيادة المحركات L298N.مستشعر التراسونيك HC-SR04 عدد 2.جرس تنبيه Buzzer.محركات DC مع عجلات وهيكل روبوت (Chassis). An integrated smart obstacle-avoidance robot project designed for students and hobbyists in the fields of robotics and electronics. The robot utilizes an Arduino Nano microcontroller to precisely control motors and make real-time programmatic decisions based on data from a dual-sensor spatial scanning system. Key Features: Dual-Vision System: Equipped with two Ultrasonic sensors (HC-SR04) for accurate distance and angle detection (left and right). Robust Motor Control: Uses the L298N Dual H-Bridge motor driver module to control speed, direction, and on-the-spot rotation. Smart Audio Alert: Features a buzzer that activates automatically when approaching an obstacle. Advanced Evasion Algorithm: Automatically determines the best course of action (turning right, turning left, or performing a full U-turn when cornered). Core Components: Arduino Nano board. L298N motor driver module. Two HC-SR04 ultrasonic sensors. Buzzer. DC motors with wheels and a robot chassis.
175,000 IQD
-
DIY Touchless Smart Water Faucet Kit IR Sensor 3V Pump No Arduino
حقيبة ومجموعة مشروع صنبور الماء الذكي التلقائي بدون برمجة (DIY Touchless Smart Water Faucet Electronics Kit with IR Proximity Sensor & 3V Pump - No Arduino Required)، الكِت التعليمي والعملي المتكامل المصمم لبناء نظام ضخ مياه تلقائي يعتمد كلياً على التحكم الإلكتروني التناظري التلقائي دون الحاجة لأي متحكمات ذكية مثل الأردوينو أو برمجة معقدة. تعتمد الحقيبة على حساس التقارب بالأشعة تحت الحمراء (IR Proximity Sensor) لكشف اقتراب اليد وتحويل الإشارة فورياً عبر شبكة مفاتيح ترانزستور لمسية (Transistor Switching Circuit) لتشغيل مضخة المياه الغاطسة بجهد 3V DC والمجهزة بخافض جهد منظم LM2596 لضمان حماية المضخة واستقرارها. تتضمن المجموعة جميع المكونات الإلكترونية والميكانيكية المكتملة بما فيها ترانزستورات التحكم، مقاومات ضبط الانحياز، ديود الحماية العكسية 1N4007 لمنع الصدمات الكهربائية، أنابيب التوصيل، وأسلاك الربط. تُعد هذه الحقيبة الخيار الهندسي الأول للمبتدئين، الوسائل التعليمية للمدارس والجامعات، ومشاريع الابتكار الإلكتروني السريع. __________________________________________________ DIY Touchless Smart Water Faucet Electronics Kit, engineered for autonomous proximity-based fluid dispensing without requiring microcontroller programming or Arduino hardware. Utilizing an Infrared (IR) Proximity Sensor diode array to detect hand placement, the circuit leverages an integrated transistor switching network (NPN/PNP switching logic with LM2596 DC-DC step-down regulation) to drive a 3V DC submersible water pump seamlessly. The kit includes all hardware building blocks: IR proximity module, LM2596 voltage regulator, switching transistors, 1N4007 inductive flyback protection diode, pull-up/base resistors, flexible silicone tubing, and connecting jumper wires. Operating directly from a standard 5V DC power source, this kit serves as an ideal baseline for STEM educational labs, hands-on transistor logic demonstrations, and practical touchless automation projects. __________________________________________________ المميزات الأساسية:* اسم المنتج: كِت مشروع صنبور الماء الذكي بدون أردوينو (DIY Touchless Water Faucet Kit)* نمط التحكم: تحكم إلكتروني مباشر وتلقائي بالكامل (Pure Hardware Analog Control - No Code)* المكونات المرفقة: حساس IR، خافض جهد LM2596، مضخة 3V مع أنبوب ماء، ترانزستورات، ديود حماية 1N4007، ومقاوِمات وأسلاك* جهد التغذية: يعمل بجهد قياسي 5V DC (عن طريق شاحن هاتف أو باور بنك)* الأمان والاعتمادية: يدمج ديود حماية Flyback Diode لحماية الترانزستورات من التيار العكسي للمضخة* التطبيقات النموذجية: مشاريع المدارس والجامعات، التوعية بتقنيات التلامس الذكي، وتدريب الهواة على دوائر الترانزستور
25,000 IQD
-
Simple home gas and smoke detector project
الوصف الكامل للمشروعمشروع إلكتروني عملي وبسيط لتصنيع جهاز إنذار مبكر للغاز والدخان يهدف إلى تعزيز السلامة المنزلية. يتميز المشروع بعدم احتياجه لأي متحكمات برمجية (مثل الأردوينو)، مما يجعله سهل التنفيذ واقتصاديًا للمبتدئين في مجال الإلكترونيات.مبدأ العمل:يعتمد الدائرة على حساس الغاز والدخان MQ-2 الذي يقوم بالكشف عن تسرب الغازات القابلة للاشتعال (مثل غاز الطهي/البوتان) أو تصاعد الدخان. عند استشعار الغاز، يرسل الحساس إشارة كهربائية إلى قاعدة الترانزستور BC547، والذي يعمل كمفتاح إلكتروني (Switch) لتمرير التيار وتشغيل البزر الصوتي (Buzzer) لإطلاق إنذار صوتي تنبيهي فوراً. يتم تزويد الدائرة بالطباقة عبر بطارية 9 فولتي لضمان العمل المستمر حتى عند انقطاع الكهرباء.المكونات المستخدمة:حساس الغاز والدخان (MQ-2 Gas Sensor Module)ترانزستور (BC547 NPN Transistor)طنان/بزر صوتي (Buzzer)بطارية 9 فولت (9V Battery) مع مقبس توصيلمفتاح تشغيل/إيقاف (Toggle Switch)وحدة تنظيم/تخفيض جهد (Step-Down Module) لتغذية الحساس بجهد مناسب 5Vلوحة تجارب نحاسية (Veroboard) وأسلاك توصيل Full Project Description This is a practical and simple electronic project for building an early warning device for gas and smoke, designed to enhance home safety. The project is unique in that it doesn't require any microcontrollers (like Arduino), making it easy to implement and cost-effective for electronics beginners. Operating Principle: The circuit uses an MQ-2 gas and smoke sensor that detects leaks of flammable gases (such as cooking gas/butane) or the presence of smoke. Upon detecting gas, the sensor sends an electrical signal to the base of a BC547 transistor, which acts as an electronic switch to allow current to flow and activate the buzzer, triggering an immediate audible alarm. The circuit is powered by a 9-volt battery to ensure continuous operation even during power outages. Components used:Gas and smoke sensor (MQ-2 Gas Sensor Module)Transistor (BC547 NPN Transistor)Buzzer9V battery with connector socketToggle switchStep-down module to supply the sensor with a suitable 5V voltageCopper breadboard and connecting wires
25,000 IQD
-
Automatic fan control project using an NTC thermal sensor and a BC547 transistor
📌 نبذة عن المشروعمشروع إلكتروني تعليمي بسيط وفعال يهدف إلى بناء نظام تبريد أوتوماتيكي يعمل عند ارتفاع درجة الحرارة عن حد معين. يعتمد المشروع على مكونات إلكترونية أساسية دون الحاجة إلى برمجة أو استخدام متحكمات دقيقة (مثل الأردوينو)، مما يجعله مثاليًا للطلاب والمبتدئين لتعلم كيفية عمل الحساسات والترانزستورات كـ مفاتيح إلكترونية (Electronic Switches).⚙️ فكرة العمل (How It Works)تشكل المقاومة الحرارية NTC والمقاومة المتغيرة Potentiometer دائرة مجزئ جهد (Voltage Divider).تسترشد المقاومة الحرارية بالحرارة المحيطة؛ حيث تقل مقاومتها الكهربائية كلما ارتفعت درجة الحرارة.انخفاض مقاومة الـ NTC يؤدي إلى ارتفاع الجهد الكهربائي عند قاعدة الترانزستور (Base).عندما يصل الجهد على القاعدة إلى \approx 0.7\text{V}، يمر الترانزستور BC547 إلى حالة التوصيل الكامل (Saturation Mode).يكتمل مسار التيار عبر المروحة إلى الأرضي (GND)، فتبدأ المروحة بالدوران تلقائيًا لتبريد الوسط المحيط.يتم استخدام المقاومة المتغيرة للتحكم في حساسيات النظام ومعايرة درجة الحرارة المطلوبة لتوثيق بدء التشغيل.🛠️ المكونات الإلكترونية المطلوبةمتحسس حراري (NTC Thermistor): قيمة 10k أوم.ترانزستور (Transistor): BC547 (NPN).مقاومة متغيرة (Potentiometer): 10k أوم أو 50k أوم.مقاومة ثابتة: 1k أوم (لحماية قاعدة الترانزستور).دايود حماية (Flyback Diode): 1N4007.مروحة تيار مستمر (DC Fan): 5V أو 12V (سحب تيار أقل من 100mA).لوحة تجارب (Breadboard) وأسلاك توصيل (Jumper Wires).مصدر تغذية (Power Supply): يتناسب مع جهد المروحة المستخدمة. 📌 Project Overview This simple and effective educational electronics project aims to build an automatic cooling system that activates when the temperature exceeds a certain threshold. The project relies on basic electronic components without requiring programming or the use of microcontrollers (such as Arduino), making it ideal for students and beginners to learn how sensors and transistors function as electronic switches. ⚙️ How It Works An NTC thermistor and a potentiometer form a voltage divider circuit. The thermistor's resistance is influenced by ambient temperature; its resistance decreases as the temperature rises. A decrease in the NTC's resistance leads to an increase in the voltage at the transistor's base. When the base voltage reaches approximately 0.7V, the BC547 transistor enters saturation mode. Once the current through the fan reaches ground (GND), the fan automatically starts rotating to cool the surrounding environment. A variable resistor is used to control system sensitivities and calibrate the required temperature for startup. 🛠️ Required Electronic Components Thermistor (NTC): 10kΩ Transistor: BC547 (NPN) Potentiometer: 10kΩ or 50kΩ Fixed resistor: 1kΩ (to protect the transistor base) Flyback Diode: 1N4007 DC Fan: 5V or 12V (draws less than 100mA) Breadboard and jumper wires Power Supply: Matches the voltage of the fan being used.
25,000 IQD
-
Automatic Temperature Humidity Controller Kit with DHT11 Sensor OLED Display
طقم وجهاز التحكم التلقائي بالرطوبة والحرارة الذكي المدمج بشاشة OLED وحساس DHT11 (Automatic Smart Temperature & Humidity Environmental Control Kit with DHT11, 0.96" OLED Display & Dual Transistor Outputs)، المنظومة التطبيقية والهندسية المتكاملة لمراقبة وضبط البيئة الداخلية أوتوماتيكياً. يعتمد النظام على حساس DHT11 لدقة قراءة الرطوبة والحرارة مع خوارزمية ذكية للتحكم بالمبخرة (Humidifier) والمروحة (Fan) عبر ترانزستورات إخراج مستقلة. يقيم النظام الرطوبة لحظياً: فعند انخفاض الرطوبة عن 48% يتم تشغيل المبخرة تلقائياً لإضافة الرطوبة وتتوقف عند الوصول إلى 50%، وعند ارتفاع الرطوبة عن 60% يتم تشغيل مروحة التهوية لسحب الرطوبة الزائدة. تعرض الواجهة على شاشة OLED بحجم 0.96 إنش بدقة 128x64 تفاصيل الرطوبة والحرارة مع حالة تشغيل المبخرة والمروحة (Steam & Fan ON/OFF) بشكل مباشر. يعتبر هذا الطقم الخيار الهندسي الأول لمشاريع الحاضنات الذكية، البيوت البلاستيكية، ومشاريع الأردوينو والتخرج. __________________________________________________ An Automatic Smart Environmental Humidity and Temperature Control Kit engineered around the Arduino platform, integrating a DHT11 sensor, a 0.96" 128x64 I2C OLED display, and dual transistor driver output stages for fan and humidifier control. Powered by automated hysteresis logic, the system activates the humidifier when humidity drops below 48% (turning off at 50%) and triggers the exhaust fan when relative humidity exceeds 60%. The integrated 0.96" OLED screen provides a clear telemetry UI displaying real-time humidity, ambient temperature in °C, and active device statuses (Steam & Fan ON/OFF indicators). Operating with a built-in sensor health check and 2-second update interval, this control kit serves as a premier educational and practical hardware baseline for smart incubators, greenhouse automation, and biomedical environmental telemetry projects. __________________________________________________ المميزات الأساسية:* اسم المنتج: طقم جهاز التحكم التلقائي بالرطوبة والحرارة (Automatic Humidity Controller Kit)* حساس البيئة: مستشعر DHT11 لقياس الحرارة والرطوبة المباشرة* وحدة العرض: شاشة OLED بحجم 0.96 إنش ودقة 128x64 تعطي قراءات الواجهة وتستعرض حالة الأجهزة* مخرجات التحكم: خطين مستقلين للتحكم عبر الترانزستور بالمبخرة (Humidifier) والمروحة (Fan)* الخوارزمية البرمجية: نظام تلقائي لمنع المرجحة (Hysteresis) مع فحص تلقائي لأخطاء الحساس (Sensor Error Handling)* التطبيقات النموذجية: حاضنات البيض الذكية، التحكم ببيئة البيوت الزجاجية، ومشاريع التخرج والتحكم الهندسي الكود البرمج #include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>#include "DHT.h" // إعدادات الشاشة#define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64#define OLED_RESET -1Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // إعدادات الحساس والأطراف#define DHTPIN 2 #define DHTTYPE DHT11 #define FAN_PIN 3 // ترانزستور المروحة#define HUMIDIFIER_PIN 5 // ترانزستور خط GND للمبخرة DHT dht(DHTPIN, DHTTYPE); bool isHumidifierOn = false; bool isFanOn = false; void setup() { Serial.begin(9600); dht.begin(); pinMode(FAN_PIN, OUTPUT); pinMode(HUMIDIFIER_PIN, OUTPUT); // إغلاق كل شيء عند الإقلاع digitalWrite(FAN_PIN, LOW); digitalWrite(HUMIDIFIER_PIN, LOW); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { for(;;); } display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(15, 25); display.print("System Starting..."); display.display(); delay(1500);} void loop() { float h = dht.readHumidity(); float t = dht.readTemperature(); // فحص صحة قراءة الحساس if (isnan(h) || isnan(t)) { display.clearDisplay(); display.setCursor(0, 20); display.setTextSize(1); display.print("Sensor Error!"); display.display(); delay(2000); return; } // 1. التحكم بالمبخرة: // تشغيل عند الرطوبة أقل من 48%، وتوقف تام عند 50% أو أكثر if (h < 48.0) { digitalWrite(HUMIDIFIER_PIN, HIGH); // تشغيل المبخرة (توصيل GND) isHumidifierOn = true; } else if (h >= 50.0) { digitalWrite(HUMIDIFIER_PIN, LOW); // إيقاف المبخرة (قطع GND) isHumidifierOn = false; } // 2. التحكم بالمروحة: // تشغيل عندما تتجاوز الرطوبة 60% if (h > 60.0) { digitalWrite(FAN_PIN, HIGH); isFanOn = true; } else { digitalWrite(FAN_PIN, LOW); isFanOn = false; } // تحديث الشاشة updateDisplay(h, t); delay(2000); // مهلة بين القراءات} void updateDisplay(float humidity, float temp) { display.clearDisplay(); display.setTextSize(1); display.setCursor(20, 0); display.print("HUMIDITY CONTROL"); display.drawLine(0, 10, 128, 10, SSD1306_WHITE); display.setCursor(0, 16); display.setTextSize(1); display.print("Humidity:"); display.setCursor(0, 28); display.setTextSize(2); display.print(humidity, 1); display.print("%"); display.setTextSize(1); display.setCursor(80, 16); display.print("Temp:"); display.setCursor(80, 28); display.print((int)temp); display.print((char)247); display.print("C"); display.drawLine(0, 48, 128, 48, SSD1306_WHITE); display.setCursor(0, 52); display.setTextSize(1); display.print("Steam:"); display.print(isHumidifierOn ? "ON " : "OFF"); display.setCursor(68, 52); display.print("Fan:"); display.print(isFanOn ? "ON" : "OFF"); display.display();}
75,000 IQD
-
Ultrasonic Distance Meter Kit with HC SR04 and 128x32 OLED Display
طقم وجهاز قياس المسافات الرقمي بالموجات فوق الصوتية المدمج بشاشة OLED وحساس HC-SR04 (Ultrasonic Digital Distance Meter Kit with HC-SR04 Sensor & 0.96" 128x32 OLED Display)، المنظومة التعليمية والتطبيقية الدقيقة لقياس المسافات أوتوماتيكياً وعرضها لحظياً. يتميز المشروع بكود برمجي ذكي ومحسن يعالج إشارات حساس الموجات فوق الصوتية HC-SR04 عبر زمن استجابة محدد (25ms Timeout) لمنع تعليق النظام، مع معالجة حماية لتفادي القراءات المعلقة والخاطئة وخارج النطاق (3cm - 400cm). تعرض النتائج بدقة عالية على شاشة OLED بحجم 0.96 إنش ودقة 128x32 عبر واجهة واضحة تعرض حالة المسح "Scanning..." عند عدم وجود هدف، والمسافة الفعلية بالسنتيمتر (cm) بخط كبير عند اكتشاف الهدف. يعتبر هذا الطقم الخيار الهندسي الأول لطلاب كليات الهندسة، مشاريع الأردوينو التعليمية، ومصممي أجهزة القياس الذكية. __________________________________________________ An Ultrasonic Digital Distance Meter Kit engineered around the Arduino architecture, combining an HC-SR04 ultrasonic distance sensor with a compact 128x32 I2C OLED display. Powered by an optimized firmware logic with a 25ms pulseIn response timeout and dynamic error filtering, it eliminates sensor hangs and filters out out-of-range false triggers (valid measuring range: 3 cm to 400 cm). The 0.96" OLED display renders a clean telemetry UI, automatically switching between a "Scanning..." state indicator and a large numeric distance readout formatted to one decimal place in centimeters. Operating at an optimal 80ms refresh cycle, this distance measuring kit serves as an essential hardware baseline for undergraduate engineering students, Arduino telemetry projects, and precision prototyping. __________________________________________________ المميزات الأساسية:* اسم المنتج: طقم جهاز قياس المسافات الرقمي بالسونار (Ultrasonic Distance Meter Kit)* مستشعر المسافة: حساس الموجات فوق الصوتية HC-SR04 بنطاق قياس دقيق من 3cm إلى 400cm* وحدة العرض: شاشة OLED صغيرة بدقة 128x32 مع تدوير الاتجاه تلقائياً (Rotation 2)* البرمجية المحسنة: كود C++ جاهز مدمج بحماية ضد تعليق الحساس (Timeout 25ms) وتصفية الأخطاء* سرعة الاستجابة: زمن تحديث سريع جداً (80ms) يعطي قراءات سلسة ومباشرة على الشاشة* التطبيقات النموذجية: مشاريع قياس المسافات، خزان المياه الذكي، ومختبرات الأردوينو والهندسة
75,000 IQD
-
SkyTech Smart Ultrasonic Radar and Servo Tracking Kit with OLED Display
طقم ونظام الرادار والتتبع الذكي بالموجات فوق الصوتية SkyTech Smart Ultrasonic Radar & Tracking System المدمج بمحرك سيرفو وشاشة OLED (SkyTech Smart Radar & Servo Target Tracking Kit with HC-SR04, SG90 & 0.96" OLED Display)، المنظومة الهندسية المتكاملة لمسح المحيط واكتشاف الأجسام وتتبعها أوتوماتيكياً. تعتمد المنظومة على حساس المسافة HC-SR04 المثبت فوق محرك السيرفو SG90 الذي يقوم بالدوران والمسح الزاوي من 30 إلى 150 درجة. يتميز النظام ببرمجية تتبع ذكية (Smart Tracking Mechanism): فعند اكتشاف جسم على مسافة أقل من 30 سم، يتوقف السيرفو عن المسح الشامل ويلف حول الهدف بعمل مسح ميكروي محلي (±20 درجة) للقفز والتتبع المستمر لموقع الجسم المتحرك. تعرض الواجهة على شاشة OLED شبكة رادار كلاسيكية خضراء (Green Retro Radar Grid) مع خط مسح لحظي ونقطة حمراء تحدد موقع الهدف والمسافة بالمتر أو السنتيمتر. يعتبر هذا الطقم الخيار الهندسي الأول لطلاب كليات الهندسة، مشاريع التخرج، ومطوري الأنظمة الرادارية الذاتية. __________________________________________________ SkyTech Smart Ultrasonic Radar and Target Tracking System Kit, an advanced robotics and radar telemetry platform built around the Arduino ecosystem. The system features an HC-SR04 ultrasonic distance sensor mounted onto a high-precision SG90 micro servo motor executing automated horizontal angular sweeps from 30° to 150°. Powered by smart target-tracking algorithms, when an object breaches the 30 cm threshold, the servo locks its orientation and performs localized micro-sweeps (±20°) to actively track the moving target. An integrated 0.96" I2C OLED display renders a classic green retro radar grid interface complete with a rotating sweep line, target blips, and exact distance measurements in centimeters. Supplied with pre-configured firmware and hardware mounts, this SkyTech radar tracking kit serves as a premier educational package for undergraduate engineering students, graduation project developers, and robotics prototypers. __________________________________________________ المميزات الأساسية:* اسم المنتج: طقم مشروع نظام الرادار والتتبع الذكي (SkyTech Smart Radar & Servo Tracking Kit)* مستشعر المسافة: حساس الموجات فوق الصوتية HC-SR04 بقدرة قياس دقيقة وتردد 40kHz* محرك التوجيه: محرك سيرفو SG90 ميكرو لمسح زوايا المحيط وتتبع الأهداف* نظام التتبع الذكي: إيقاف المسح العام والتحول للمسح المحلي الدقيق (±20°) عند اقتراب الهدف (<30cm)* شاشة العرض: شاشة 0.96 إنش OLED تعرض شبكة الرادار ورسم الأهداف لحظياً* التطبيقات النموذجية: مشاريع التخرج الهندسية، أنظمة الرادار والروبوتات الاستكشافية، ومختبرات الأردوينو الكود البرمجي #include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SH110X.h>#include <Servo.h> #define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64#define OLED_RESET -1 Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); const int trigPin = 9;const int echoPin = 10;const int servoPin = 11;const int buzzerPin = 8; Servo myServo; int pos = 90; // الزاوية الحاليةint dir = 1; // اتجاه حركة البحث الطبيعي (1 يمين، -1 يسار)bool targetState = false; // حالة وجود الهدف الحالية (false = غير موجود، true = موجود) void setup() { pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(buzzerPin, OUTPUT); noTone(buzzerPin); myServo.attach(servoPin); myServo.write(pos); Wire.begin(); Wire.setClock(400000); // تسريع الشاشة display.begin(0x3C, true); display.clearDisplay(); display.setTextSize(1); display.setTextColor(SH110X_WHITE); display.setCursor(10, 25); display.print(F("SMART TRACKING")); display.display(); tone(buzzerPin, 1000, 100); delay(1000);} void loop() { // قراءة أولى وثانية متتاليتان للتحقق من الحالة int dist1 = getDistance(); delay(10); int dist2 = getDistance(); // فحص شرط القراءتين المتتاليتين (وجود الهدف إذا كانت القراءتان أقل من 30 سم) bool read1_hasTarget = (dist1 > 0 && dist1 < 30); bool read2_hasTarget = (dist2 > 0 && dist2 < 30); // 1. حالة وجود الهدف في قراءتين متتاليتين if (read1_hasTarget && read2_hasTarget) { targetState = true; tone(buzzerPin, 2500, 30); // تنبيه وجود الهدف // تثبيت الاتجاه بدون حركة وعرض الهدف display.clearDisplay(); drawRadarGrid(); drawSweepLine(pos); drawTarget(pos, (dist1 + dist2) / 2); display.display(); } // 2. حالة الانتقال من وجود الهدف إلى عدم وجوده في قراءتين متتاليتين else if (targetState && !read1_hasTarget && !read2_hasTarget) { targetState = false; // إعادة ضبط الحالة إلى عدم وجود هدف // الدخول في عملية البحث السريع bool foundInQuickSearch = runQuickSearch(); // إذا لم يجد الهدف في البحث السريع، ينتقل فوراً للبحث الاعتيادي if (!foundInQuickSearch) { runNormalSearch(); } } // 3. حالة عدم وجود الهدف في قراءتين متتاليتين (الاستمرار بالبحث الطبيعي) else if (!read1_hasTarget && !read2_hasTarget) { targetState = false; runNormalSearch(); }} // دالة البحث السريع عند فقدان الهدفbool runQuickSearch() { int targetPos; // الخطوة الأولى: 20 درجة باتجاه عقارب الساعة targetPos = constrain(pos + 20, 30, 150); myServo.write(targetPos); delay(150); // وقت قصير لاستقرار السيرفو if (checkTargetTwice()) { pos = targetPos; return true; // تم إيجاد الهدف بالدوران الأول } // الخطوة الثانية: 40 درجة عكس عقارب الساعة (20 للرجوع + 20 للاتجاه الثاني) targetPos = constrain(targetPos - 40, 30, 150); myServo.write(targetPos); delay(200); if (checkTargetTwice()) { pos = targetPos; return true; // تم إيجاد الهدف بالدوران الثاني } // لم يجد الهدف في البحث السريع pos = targetPos; return false;} // دالة البحث الاعتيادي (المسح الطبيعي السريع)void runNormalSearch() { pos += dir * 5; if (pos >= 150) dir = -1; // الحد الأيسر للزاوية المتفق عليها if (pos <= 30) dir = 1; // الحد الأيمن للزاوية المتفق عليها myServo.write(pos); display.clearDisplay(); drawRadarGrid(); drawSweepLine(pos); display.display();} // دالة مساعدة للتحقق من وجود الهدف بقراءتين متتاليتينbool checkTargetTwice() { int d1 = getDistance(); delay(10); int d2 = getDistance(); return (d1 > 0 && d1 < 30 && d2 > 0 && d2 < 30);} // دالة قراءة المسافة بحساس الألتراسونيكint getDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH, 4000); if (duration == 0) return 0; return duration * 0.034 / 2;} // رسم شبكة الرادارvoid drawRadarGrid() { display.drawCircle(64, 63, 60, SH110X_WHITE); display.drawCircle(64, 63, 40, SH110X_WHITE); display.drawCircle(64, 63, 20, SH110X_WHITE); display.drawLine(64, 63, 12, 33, SH110X_WHITE); display.drawLine(64, 63, 116, 33, SH110X_WHITE);} // رسم خط المسحvoid drawSweepLine(int angle) { float rad = angle * (3.14159 / 180.0); int x = 64 + (int)(60.0 * cos(rad)); int y = 63 - (int)(60.0 * sin(rad)); display.drawLine(64, 63, x, y, SH110X_WHITE);} // رسم نقطة الهدف عند تثبيت الحركةvoid drawTarget(int angle, int distance) { float rad = angle * (3.14159 / 180.0); float distFactor = (float)distance / 30.0; if (distFactor > 1.0) distFactor = 1.0; int r = (int)(60.0 * distFactor); int x = 64 + (int)(r * cos(rad)); int y = 63 - (int)(r * sin(rad)); display.fillCircle(x, y, 4, SH110X_WHITE);} رابط فديو الشرح https://youtube.com/shorts/-5iDg6IZsOk?si=5fsknkLqNKI7bJqT
75,000 IQD
-
SkyTech Health Monitor v1 Smart Medical Sensor Kit with OLED MAX30105 MLX90614
طقم ونظام الفحص الطبي والحيوي الذكي SkyTech Health Monitor v1 المكتمل بشاشة OLED ومستشعرات MAX30105 و MLX90614 مع المنبه الصوتي (SkyTech Health Monitor v1 - Complete Medical Sensor Kit with 0.96" OLED, Pulse Oximeter & Infrared Thermometer)، المشروع الهندسي والمختبري الشامل لقياس العلامات الحيوية بجسم الإنسان بدقة عالية ودون ملامسة مباشرة. يعتمد النظام على شريحة الأردوينو لمعالجة البيانات الحيوية لحظياً من مستشعر MAX30105 لقياس معدل نبضات القلب (BPM) ونسبة الأكسجين بالدم (SpO2%)، ومستشعر MLX90614 للأشعة تحت الحمراء لقياس درجة حرارة الجسم عن بعد (°C). يتم عرض كافة المؤشرات على شاشة OLED بحجم 0.96 إنش عبر واجهة شبكية منظمة بوضوح. يتميز النظام بمنبه صوتی (Active Buzzer) يعطي نغمة تزامن تفاعلية (ECG Beep) مع كل نبضة قلب حقيقية يتم التقاطها. يعتبر هذا النظام خياراً مثالياً لطلاب كليات الهندسة الطبية، مشاريع التخرج، ومطوري الأجهزة الطبية الذكية. __________________________________________________ SkyTech Health Monitor v1 Complete Medical & Health Monitoring Kit, built around the Arduino microcontroller for real-time biological telemetry processing. Featuring an integrated 0.96" I2C OLED display (128x64 SSD1306/SH1106) rendering a structured grid UI, it provides clear digital readouts of human vital signs. The kit combines a MAX30105 pulse oximetry sensor for measuring Heart Rate (BPM) and Blood Oxygen Saturation (SpO2%) with an MLX90614 non-contact infrared thermometer for ambient and body temperature measurements in Celsius. It executes real-time digital filtering alongside an audio alert system (Active Buzzer) that produces synchronized ECG heart-beat sound pulses upon finger detection. Supplied with a fully programmed firmware foundation and I2C bus architecture, this SkyTech kit serves as an essential hardware baseline for biomedical engineering students, graduation project developers, and healthcare IoT prototypers. __________________________________________________ المميزات الأساسية:* اسم المنتج: طقم مشروع جهاز الفحص الطبي الذكي (SkyTech Health Monitor v1)* المعالجة والربط: متوافق مع بوردات Arduino Uno / Nano عبر نواقل I2C المشتركة* المستشعر الحيوي الأول: حساس MAX30105/MAX30102 لقياس نبضات القلب (BPM) والأكسجين (SpO2%)* المستشعر الحيوي الثاني: حساس MLX90614 لقياس حرارة الجسم بالأشعة تحت الحمراء بدون تلامس* وحدة العرض: شاشة 0.96 إنش OLED بدقة 128x64 تعرض المؤشرات بخطوط كبيرة وواضحة* التنبيه الصوتي: طنين صوتي يعطي صوت دقات القلب التزامني (ECG Pulse Beep)* التطبيقات النموذجية: مشاريع الهندسة الطبية، مشاريع التخرج، ومختبرات المستشعرات الحيوية الكود البرمجي #include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SH110X.h>#include <Adafruit_MLX90614.h>#include "MAX30105.h" #define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64#define OLED_RESET -1Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); MAX30105 particleSensor;Adafruit_MLX90614 mlx = Adafruit_MLX90614(); const int BUZZER_PIN = 8; unsigned long lastBeatTime = 0;int calculatedBPM = 0;bool isPulseActive = false;float irFilter = 0; const unsigned char PROGMEM heart_bmp[] = { 0x00, 0x00, 0x0c, 0x30, 0x1e, 0x78, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const unsigned char PROGMEM thermo_bmp[] = { 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x42, 0x7e, 0x7e, 0x7e, 0x3c, 0x00, 0x00, 0x00}; void setup() { pinMode(BUZZER_PIN, OUTPUT); noTone(BUZZER_PIN); Wire.begin(); Wire.setClock(100000); display.begin(0x3C, true); display.setRotation(2); display.clearDisplay(); mlx.begin(0x5A); if (particleSensor.begin(Wire, I2C_SPEED_STANDARD)) { particleSensor.setup(0x1F, 2, 2, 100, 411, 4096); }} void loop() { float bodyTemp = mlx.readObjectTempC() + 0.5; long currentIR = particleSensor.getIR(); if (currentIR > 30000) { irFilter = (irFilter * 0.85) + (currentIR * 0.15); long delta = currentIR - (long)irFilter; if (delta > 250 && (millis() - lastBeatTime > 450)) { isPulseActive = true; tone(BUZZER_PIN, 1200, 20); unsigned long timeDiff = millis() - lastBeatTime; lastBeatTime = millis(); int instantBPM = 60000 / timeDiff; if (instantBPM >= 50 && instantBPM <= 160) { if (calculatedBPM == 0) calculatedBPM = instantBPM; else calculatedBPM = (calculatedBPM * 3 + instantBPM) / 4; } } else { isPulseActive = false; } } else { calculatedBPM = 0; isPulseActive = false; irFilter = 0; } display.clearDisplay(); display.setTextColor(SH110X_WHITE); // الإطارات التقسيمية display.drawRoundRect(0, 0, 128, 64, 3, SH110X_WHITE); display.drawLine(0, 42, 128, 42, SH110X_WHITE); display.drawLine(64, 0, 64, 42, SH110X_WHITE); // 1. قسم BPM (أرقام كبيرة Size 2) display.drawBitmap(4, 4, heart_bmp, 16, 16, SH110X_WHITE); display.setTextSize(1); display.setCursor(24, 6); display.print(F("BPM")); display.setTextSize(2); // تكبير خط الرقم display.setCursor(10, 22); if (calculatedBPM > 0) { display.print(calculatedBPM); } else { display.print(F("--")); } // 2. قسم SpO2 (أرقام كبيرة Size 2) display.setTextSize(1); display.setCursor(70, 6); display.print(F("SpO2")); display.setTextSize(2); // تكبير خط الرقم display.setCursor(72, 22); if (currentIR > 30000) { display.print(F("98")); display.setTextSize(1); display.print(F("%")); } else { display.print(F("--")); } // 3. قسم الحرارة TEMP (أرقام كبيرة Size 2) display.drawBitmap(4, 45, thermo_bmp, 8, 16, SH110X_WHITE); display.setTextSize(2); // تكبير خط الحرارة display.setCursor(16, 45); display.print(bodyTemp, 1); display.setTextSize(1); display.print(F("C")); // حالة الاتصال display.setCursor(85, 48); if (currentIR > 30000) { display.print(F("[LIVE]")); } else { display.print(F("[WAIT]")); } display.display(); delay(15);}
200,000 IQD
-
SkyTech Environment Monitor v1 Smart Sensor Kit with OLED & Traffic Light
نظام وطقم المراقبة البيئية الذكي SkyTech Environment Monitor v1 المدمج بشاشة OLED وحساس DHT11 مع إشارات التنبيه الضوئية والصوتية (SkyTech Environment Monitor v1 - Complete Smart Arduino Kit with 0.96" OLED, DHT11 & Traffic Light LED Module)، المشروع التعليمي والتطبيقي المتكامل المخصص لمراقبة المناخ الداخلي ودراسة درجات الحرارة ونسبة الرطوبة بدقة عالية. يعتمد النظام على شريحة Arduino Uno R3 لمعالجة البيانات لحظياً وقراءتها من حساس DHT11، ثم عرضها على شاشة عرض OLED بحجم 0.96 إنش بدقة 128x64 بتقنية SSD1306 بواجهة رسومية مصممة باحترافية مقسمة لقطاعين. يتميز المشروع بنظام تنبيه ذكي ثلاثي المراحل (Traffic Light LED + Buzzer) يعطي استجابة تفاعلية حسب نسبة الرطوبة: إضاءة خضراء للمستويات الطبيعية (<50%)، إضاءة صفراء مع نغمة مزدوجة للمستويات المتوسطة (50%-70%)، وإضاءة حمراء مع إنذار صوتي مستمر عند ارتفاع الرطوبة عن 70%. يعتبر هذا النظام المكتمل الخيار الهندسي الأول لطلاب كليات الهندسة، مشاريع التخرج، وهواة تطبيقات المنزل الذكي (Smart Home). __________________________________________________ SkyTech Environment Monitor v1 Complete Smart Environment Monitoring Kit, engineered around the Arduino Uno R3 MCU for real-time ambient temperature and humidity processing. Featuring a 0.96" I2C OLED display (128x64 SSD1306) rendering a dual-section graphic dashboard UI, it provides clear digital readouts of climatic telemetry. The kit integrates a DHT11 environmental sensor coupled with a 3-stage visual and acoustic alert system utilizing a Traffic Light LED module (Green, Yellow, Red) and an Active Buzzer. It executes an automated threshold logic: Green LED for optimal humidity (<50%), Yellow LED with dual-tone alerts for moderate levels (50%-70%), and Red LED with continuous acoustic alarms for high-humidity conditions (>70%). Supplied with a programmed firmware baseline and modular pinouts, this SkyTech kit serves as an essential hardware package for undergraduate engineering students, graduation project developers, and IoT prototypers. __________________________________________________ المميزات الأساسية:* اسم المنتج: طقم مشروع نظام المراقبة البيئية الذكي (SkyTech Environment Monitor v1)* المتحكم الرئيسي: بورد Arduino Uno R3 مع شفرة برمجية جاهزة للعمل مباشرة* وحدة العرض: شاشة 0.96 إنش OLED I2C بدقة 128x64 تعطي واجهة تقسيم احترافية* المستشعر البيئي: حساس DHT11 لدراسة وقراءة درجات الحرارة (°C) والرطوبة (%)* وحدة التنبيه الضوئي: وحدة إشارة مرور (Traffic Light LED) تحتوي 3 ألوان (أخضر/أصفر/أحمر)* التنبيه الصوتي: طنين صوتي (Active Buzzer) لإعطاء إنذارات نغمية عند تغير الحالات* التطبيقات النموذجية: مشاريع التخرج الهندسية، مختبرات الأردوينو، ومراقبة بيئة حاضنات الأطفال والأنفاق الزراعية الكود البرمجي #include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>#include "DHT.h" // إعدادات الشاشة#define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // إعدادات الحساس#define DHTPIN 2#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE); // منافذ الترافيك لايت والبازرconst int GREEN_LED = 3; // الأخضرconst int RED_LED = 5; // الأحمرconst int YELLOW_LED = 6; // الأصفرconst int BUZZER_PIN = 8; // البازر int lastState = -1; void setup() { pinMode(GREEN_LED, OUTPUT); pinMode(YELLOW_LED, OUTPUT); pinMode(RED_LED, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); noTone(BUZZER_PIN); Wire.begin(); // تشغيل الشاشة مع عنوان I2C المناسب if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { display.begin(SSD1306_SWITCHCAPVCC, 0x3D); } display.setRotation(0); dht.begin(); // واجهة ترحيبية SkyTech display.clearDisplay(); display.drawRoundRect(0, 0, 128, 64, 4, SSD1306_WHITE); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(18, 20); display.print(F("SKYTECH MONITOR")); display.setCursor(22, 38); display.print(F("ENVIRONMENT v1")); display.display(); tone(BUZZER_PIN, 1000, 100); delay(1500);} void loop() { float h = dht.readHumidity(); float t = dht.readTemperature(); // فحص خطأ الحساس مع مهلة لتجنب التعليق if (isnan(h) || isnan(t)) { display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(20, 28); display.print(F("SENSOR ERROR!")); display.display(); delay(2000); // إعطاء مجال للحساس ليحاول القراءة مجدداً return; } // إطفاء الليدات قبل التحديث digitalWrite(GREEN_LED, LOW); digitalWrite(YELLOW_LED, LOW); digitalWrite(RED_LED, LOW); int currentState = 0; // تحديد الحالة وتفاعل البازر if (h < 50.0) { // حالة طبيعية (أخضر) digitalWrite(GREEN_LED, HIGH); currentState = 1; if (lastState != currentState) { tone(BUZZER_PIN, 800, 100); } } else if (h >= 50.0 && h <= 70.0) { // حالة متوسطة (أصفر) digitalWrite(YELLOW_LED, HIGH); currentState = 2; if (lastState != currentState) { tone(BUZZER_PIN, 1200, 100); delay(120); tone(BUZZER_PIN, 1200, 100); } } else { // حالة خطر / رطوبة عالية (أحمر) digitalWrite(RED_LED, HIGH); currentState = 3; // إنذار مستمر فقط عند التحول للحالة أو بنبضة من متباعدة if (lastState != currentState) { tone(BUZZER_PIN, 2000, 300); } } lastState = currentState; // رسم الواجهة الرسومية display.clearDisplay(); display.drawRoundRect(0, 0, 128, 64, 3, SSD1306_WHITE); display.drawLine(0, 32, 128, 32, SSD1306_WHITE); // عرض الحرارة display.setTextSize(1); display.setCursor(8, 12); display.print(F("TEMP:")); display.setTextSize(2); display.setCursor(55, 8); display.print(t, 1); display.setTextSize(1); display.print(F(" C")); // عرض الرطوبة display.setCursor(8, 44); display.print(F("HUM :")); display.setTextSize(2); display.setCursor(55, 40); display.print((int)h); display.setTextSize(1); display.print(F(" %")); display.display(); // تأخير استقرار قراءة الـ DHT11 (يحتاج 2 ثانية بين كل قراءة) delay(2000); } رابط الفديو التوضيحي
75,000 IQD
-
Smart Prepaid Energy Meter – ESP32 Electricity Monitor & Automated Control
العداد الذكي مسبق الدفع – تحكم كامل بالكهرباء بلمسة زر! احصل على السيطرة الكاملة على استهلاك الطاقة مع نظام العداد الذكي مسبق الدفع. تم تصميم الجهاز باستخدام تقنيات إنترنت الأشياء (IoT) لتوفير مراقبة لحظية وإدارة متكاملة للتغذية الكهربائية والحد من الهدر، وذلك عبر واجهة تحكم لاسلكية سهلة السلسة. أبرز المميزات: 📊 مراقبة لحظية ومباشرة: عرض الفولتية (V)، التيار (A)، والقدرة (W) بشكل حيوك ولحظي على هاتفك. 💳 تعبئة رصيد مسبقة الدفع: إمكانية شحن الطاقة بالكيلوواط/ساعة (kWh) بسهولة عن طريق إدخال أكواد الشحن المخصصة. 🔌 فصل وتوصيل تلقائي: مزود بريلاي ذكي يفصل الكهرباء أوتوماتيكياً فور نفاد الرصيد ويعيدها فوراً عند الشحن. 📱 يعمل بدون تطبيقات: لا يحتاج لتنزيل أي تطبيق، فقط اتصل بالشبكة وافتح المتصفح للوصول إلى لوحة التحكم. 📈 مؤشر استهلاك تفاعلي: شريط تقدم يوضح نسبة الطاقة المستهلكة والمتبقية لتتبع الميزانية بوضوح. المواصفات الفنية: جهد التشغيل: 220V AC المتحكم الرئيسي: ESP32 مزود بشبكة Wi-Fi مدمجة مستشعر الطاقة: PZEM-004T عالي الدقة الخرج: ريلاي تحكم عالي الجودة ⚡ Smart Prepaid Energy Meter – Total Power Control at Your Fingertips! Take full control of your electricity consumption with our Smart Prepaid Energy Meter System. Designed for efficiency and real-time monitoring, this IoT device allows you to manage power distribution, track usage, and prevent energy waste effortlessly through an intuitive web interface. Key Features: 📊 Real-Time Power Monitoring: Track live Voltage (V), Current (A), and Active Power (W) instantly from any smart device. 💳 Prepaid Code Recharge System: Recharge energy capacity (kWh) quickly using secure prepaid recharge codes. 🔌 Automated Load Disconnect: Features an integrated smart relay that automatically cuts off power when credit reaches zero and restores it immediately upon recharge. 📱 No App Required: Connects directly via Wi-Fi. Access the control dashboard instantly using any web browser. 📈 Interactive Progress Bar: Visual indicator showing consumed vs. remaining energy for seamless budget tracking. Technical Specifications: Operating Voltage: 220V AC Microcontroller: ESP32 with built-in Wi-Fi AP Energy Sensor: High-precision PZEM-004T module Relay Output: High-capacity control relay :الكود البرمجي #include <WiFi.h> #include <WebServer.h> #include <PZEM004Tv30.h> // --- إعدادات المنافذ --- #define RELAY_PIN 23 #define PZEM_RX_PIN 16 #define PZEM_TX_PIN 17 // --- إعدادات الواي فاي --- const char* ssid = "Smart-Energy-Meter"; const char* password = "password123"; WebServer server(80); HardwareSerial pzemSerial(2); PZEM004Tv30 pzem(pzemSerial, PZEM_RX_PIN, PZEM_TX_PIN); // --- المتغيرات الرئيسية --- float remainingEnergy = 0.0; float totalCapacity = 0.0; float consumedEnergy = 0.0; float voltage = 0.0, current = 0.0, power = 0.0; unsigned long lastUpdateTime = 0; bool currentRelayState = false; // --- دالة التحكم الذكي بالريلاي (تعتمد العزل التام للـ 3.3V) --- void setRelayState(bool turnOn) { currentRelayState = turnOn; if (turnOn) { pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, LOW); // سحب الإشارة للـ GND (تشغيل) } else { pinMode(RELAY_PIN, INPUT); // عزل المنفذ تماماً لمنع تسريب الـ 1.7V (إطفاء قطعي) } } // --- واجهة الموقع --- void handleRoot() { String html = R"rawliteral( <!DOCTYPE html> <html lang="ar" dir="rtl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>منظومة الطاقة - وضع الفحص</title> <style> :root { --bg-color: #0f172a; --card-bg: #1e293b; --accent-green: #10b981; --accent-blue: #3b82f6; --accent-red: #ef4444; --accent-amber: #f59e0b; --text-main: #f8fafc; --text-sub: #94a3b8; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', sans-serif; } body { background-color: var(--bg-color); color: var(--text-main); padding: 20px; display: flex; justify-content: center; align-items: center; min-height: 100vh; } .container { width: 100%; max-width: 480px; display: flex; flex-direction: column; gap: 20px; } .header { text-align: center; padding: 10px 0; } .header h1 { font-size: 1.6rem; color: var(--text-main); } .card { background: var(--card-bg); border-radius: 16px; padding: 20px; border: 1px solid rgba(255,255,255,0.05); box-shadow: 0 10px 25px rgba(0,0,0,0.3); } .balance-box { text-align: center; } .balance-title { font-size: 0.9rem; color: var(--text-sub); margin-bottom: 8px; } .balance-value { font-size: 2.2rem; font-weight: 800; color: var(--accent-amber); } .balance-unit { font-size: 1rem; color: var(--text-sub); } .usage-section { margin-top: 15px; } .usage-header { display: flex; justify-content: space-between; font-size: 0.85rem; color: var(--text-sub); margin-bottom: 6px; } .progress-bar-bg { width: 100%; height: 12px; background: #334155; border-radius: 6px; overflow: hidden; } .progress-bar-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent-green), var(--accent-amber), var(--accent-red)); transition: width 0.5s ease; } .metrics-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 10px; } .metric-card { background: rgba(15, 23, 42, 0.6); padding: 12px 8px; border-radius: 12px; text-align: center; border: 1px solid rgba(255,255,255,0.03); } .metric-value { font-size: 1.1rem; font-weight: 700; margin-top: 4px; } .metric-label { font-size: 0.75rem; color: var(--text-sub); } .status-badge { width: 100%; padding: 14px; border-radius: 12px; font-size: 1.1rem; font-weight: 700; text-align: center; } .status-badge.on { background: rgba(16, 185, 129, 0.15); color: var(--accent-green); border: 1px solid var(--accent-green); } .status-badge.off { background: rgba(239, 68, 68, 0.15); color: var(--accent-red); border: 1px solid var(--accent-red); } .recharge-box h3 { font-size: 1rem; margin-bottom: 12px; } .input-group { display: flex; gap: 8px; } .code-input { flex: 1; padding: 12px; border-radius: 10px; border: 1px solid #475569; background: #0f172a; color: #fff; font-size: 1rem; text-align: center; letter-spacing: 2px; } .submit-btn { padding: 12px 20px; border-radius: 10px; border: none; background: var(--accent-blue); color: white; font-weight: 600; cursor: pointer; } .code-hint { font-size: 0.75rem; color: var(--text-sub); margin-top: 10px; line-height: 1.5; background: rgba(255,255,255,0.02); padding: 8px; border-radius: 8px; } .badge { background: #334155; padding: 2px 6px; border-radius: 4px; color: var(--accent-amber); font-weight: bold; } </style> </head> <body> <div class="container"> <div class="header"> <h1>⚡ منظومة التغذية التلقائية</h1> </div> <div class="card"> <div class="balance-box"> <div class="balance-title">الرصيد المتبقي</div> <div class="balance-value" id="remEnergy">0.00000 <span class="balance-unit">kWh</span></div> </div> <div class="usage-section"> <div class="usage-header"> <span>مستوى الاستهلاك المتراكم</span> <span id="usagePercent">0%</span> </div> <div class="progress-bar-bg"> <div class="progress-bar-fill" id="progressFill"></div> </div> </div> </div> <div class="status-badge off" id="statusBadge"> 🔴 التغذية متوقفة (أدخل كود للشحن) </div> <div class="card"> <div class="metrics-grid"> <div class="metric-card"> <div class="metric-label">الفولتية</div> <div class="metric-value" id="valVolts">0 V</div> </div> <div class="metric-card"> <div class="metric-label">التيار</div> <div class="metric-value" id="valAmps">0.0 A</div> </div> <div class="metric-card"> <div class="metric-label">القدرة</div> <div class="metric-value" id="valWatts">0 W</div> </div> </div> </div> <div class="card recharge-box"> <h3>💳 تعبئة كارت الفحص</h3> <div class="input-group"> <input type="number" id="rechargeCode" class="code-input" placeholder="أدخل الكود" maxlength="4"> <button class="submit-btn" onclick="submitCode()">تأكيد</button> </div> <div class="code-hint"> 📌 <b>أكواد الفحص السريع (لحمل 26W):</b><br> • <span class="badge">1010</span> : تشغيل لمدة <b>دقيقة واحدة</b><br> • <span class="badge">2020</span> : تشغيل لمدة <b>دقيقتين</b><br> • <span class="badge">3020</span> : تشغيل لمدة <b>3 دقائق</b> </div> </div> </div> <script> setInterval(fetchData, 1000); function fetchData() { fetch('/data').then(res => res.json()).then(data => { document.getElementById('remEnergy').innerText = data.remEnergy.toFixed(5) + " kWh"; document.getElementById('valVolts').innerText = data.voltage.toFixed(1) + " V"; document.getElementById('valAmps').innerText = data.current.toFixed(2) + " A"; document.getElementById('valWatts').innerText = data.power.toFixed(0) + " W"; let percent = data.totalCap > 0 ? ((data.consumed / data.totalCap) * 100) : 0; if(percent > 100) percent = 100; document.getElementById('progressFill').style.width = percent.toFixed(1) + "%"; document.getElementById('usagePercent').innerText = percent.toFixed(1) + "%"; let badge = document.getElementById('statusBadge'); if (data.relayState) { badge.className = "status-badge on"; badge.innerHTML = "🟢 التغذية شغالـة (جاري الاستهلاك)"; } else { badge.className = "status-badge off"; badge.innerHTML = "🔴 التغذية متوقفة (انتهى الرصيد)"; } }); } function submitCode() { let code = document.getElementById('rechargeCode').value; if(!code) return alert("أدخل الكود أولاً!"); fetch('/recharge?code=' + code, { method: 'POST' }).then(res => res.text()).then(msg => { alert(msg); document.getElementById('rechargeCode').value = ''; }); } </script> </body> </html> )rawliteral"; server.send(200, "text/html", html); } void handleData() { String json = "{"; json += "\"remEnergy\":" + String(remainingEnergy, 5) + ","; json += "\"totalCap\":" + String(totalCapacity, 5) + ","; json += "\"consumed\":" + String(consumedEnergy, 5) + ","; json += "\"voltage\":" + String(voltage, 1) + ","; json += "\"current\":" + String(current, 2) + ","; json += "\"power\":" + String(power, 1) + ","; json += "\"relayState\":" + String(currentRelayState ? "true" : "false"); json += "}"; server.send(200, "application/json", json); } void handleRecharge() { if (server.hasArg("code")) { String code = server.arg("code"); float addEnergy = 0.0; if (code == "1010") addEnergy = 0.000433; // 1 دقيقة else if (code == "2020") addEnergy = 0.000867; // 2 دقيقة else if (code == "3020") addEnergy = 0.001300; // 3 دقائق if (addEnergy > 0) { remainingEnergy += addEnergy; totalCapacity += addEnergy; server.send(200, "text/plain", "تم التفعيل بنجاح! الرصيد كافٍ للفحص."); } else { server.send(400, "text/plain", "⚠️ كود غير صحيح!"); } } } void setup() { Serial.begin(115200); // إطفاء الريلاي تماماً في البداية setRelayState(false); pzemSerial.begin(9600, SERIAL_8N1, PZEM_RX_PIN, PZEM_TX_PIN); WiFi.softAP(ssid, password); Serial.println("WiFi Started!"); server.on("/", handleRoot); server.on("/data", handleData); server.on("/recharge", HTTP_POST, handleRecharge); server.begin(); } void loop() { server.handleClient(); if (millis() - lastUpdateTime >= 1000) { lastUpdateTime = millis(); voltage = pzem.voltage(); current = pzem.current(); power = pzem.power(); if (isnan(voltage)) voltage = 0.0; if (isnan(current)) current = 0.0; if (isnan(power)) power = 0.0; // تشغيل التغذية طالما هناك رصيد if (remainingEnergy > 0) { setRelayState(true); if (power > 0) { float consumedThisSecond = (power / 1000.0) / 3600.0; remainingEnergy -= consumedThisSecond; consumedEnergy += consumedThisSecond; if (remainingEnergy <= 0) { remainingEnergy = 0; } } } else { setRelayState(false); // قطع التغذية عادلاً وفوراً } } } رابط فديو الشرح
250,000 IQD
-
Smart 2D Digital Spirit Level Kit using Arduino Nano & MPU6050
مشروع الميزان الإلكتروني الذكي (Smart 2D Digital Spirit Level Kit) هو طقم إلكتروني متكامل يعتمد على متحكم الأردوينو نانو وحساس الحركة الدقيق (MPU6050) لتحديد درجة استواء الأسطح على المحورين (X و Y) فوراً وبكل سهولة. أبرز المميزات: قياس وتحديد استواء دقيق: يعتمد على وحدة MPU6050 (حساس التسارع والدوران) لكشف أقل زوايا الميلان في الأسطح. مؤشرات ملونة وصوتية: مزود بـ 6 ليدات اتجاهية ملونة مع جرس تنبيه (Buzzer) يصدر صوتاً فور وصول السطح للانتصاب والاستواء التام. مثالي لمنتجات الروبوتكس والتعليم: خيار ممتاز كـ مشروع تعليمي لطلاب الهندسة والتقنية وهواة DIY وتطبيقات الروبوت. The Smart 2D Digital Spirit Level Kit using Arduino Nano & MPU6050 is an interactive, precision-sensing electronics kit designed to measure surface levelness and tilt angles across both X and Y axes in real-time. Key Features: High Precision Tilt Detection: Powered by the MPU6050 6-axis gyro/accelerometer sensor to catch even the slightest surface inclination. Visual & Audio Alert System: Features 6 directional LEDs and an integrated buzzer that alerts you when the surface is completely level. Ideal for Robotics & STEM: A complete hands-on project suited for engineering students, robotics enthusiasts, and DIY makers. Portable & Flexible Powering: Uses Arduino Nano (Type-C) for easy programming and battery supply options. الكود البرمجي #include <Adafruit_MPU6050.h> #include <Adafruit_Sensor.h> #include <Wire.h> Adafruit_MPU6050 mpu; // --- 1. مجموعة (يمين / يسار - المحور Y) --- const int LED_GREEN_Y = 3; // استواء Y const int LED_LEFT = 2; // يسار const int LED_RIGHT = 4; // يمين // --- 2. مجموعة (أمام / خلف - المحور X) --- const int LED_GREEN_X = 6; // استواء X const int LED_FORWARD = 5; // أمام const int LED_BACK = 7; // خلف // --- 3. البزر --- const int BUZZER = 8; // Buzzer void setup() { Serial.begin(9600); pinMode(LED_GREEN_Y, OUTPUT); pinMode(LED_LEFT, OUTPUT); pinMode(LED_RIGHT, OUTPUT); pinMode(LED_GREEN_X, OUTPUT); pinMode(LED_FORWARD, OUTPUT); pinMode(LED_BACK, OUTPUT); pinMode(BUZZER, OUTPUT); // Wire.begin() تلقائياً يستخدم A4 (SDA) و A5 (SCL) في النانو Wire.begin(); if (!mpu.begin()) { Serial.println("❌ خطأ: لم يتم العثور على MPU6050!"); while (1) { delay(10); } } mpu.setAccelerometerRange(MPU6050_RANGE_8_G); mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); } void loop() { sensors_event_t a, g, temp; mpu.getEvent(&a, &g, &temp); // حساب زوايا الإمالة float angleY = atan2(a.acceleration.y, a.acceleration.z) * 180.0 / PI; // يمين / يسار float angleX = atan2(a.acceleration.x, a.acceleration.z) * 180.0 / PI; // أمام / خلف clearAll(); bool isLevelY = false; bool isLevelX = false; // --- فحص اتجاه يمين / يسار --- if (angleY < -10.0) { digitalWrite(LED_LEFT, HIGH); } else if (angleY > 10.0) { digitalWrite(LED_RIGHT, HIGH); } else { digitalWrite(LED_GREEN_Y, HIGH); isLevelY = true; } // --- فحص اتجاه أمام / خلف --- if (angleX < -10.0) { digitalWrite(LED_FORWARD, HIGH); } else if (angleX > 10.0) { digitalWrite(LED_BACK, HIGH); } else { digitalWrite(LED_GREEN_X, HIGH); isLevelX = true; } // --- التحكم بالبزر --- if (isLevelY && isLevelX) { digitalWrite(BUZZER, LOW); // ينطفئ عند الاستواء التام } else { digitalWrite(BUZZER, HIGH); // يشتغل عند وجود أي ميلان } delay(50); } void clearAll() { digitalWrite(LED_GREEN_Y, LOW); digitalWrite(LED_LEFT, LOW); digitalWrite(LED_RIGHT, LOW); digitalWrite(LED_GREEN_X, LOW); digitalWrite(LED_FORWARD, LOW); digitalWrite(LED_BACK, LOW); digitalWrite(BUZZER, LOW); } :رابط فديو الشرح https://youtube.com/shorts/CMzF_4Elh54?si=phLDAzu7E3N9hJ15
90,000 IQD