require('dotenv').config(); const express = require('express'); const http = require('http'); const socketIo = require('socket.io'); const cors = require('cors'); const helmet = require('helmet'); const compression = require('compression'); const rateLimit = require('express-rate-limit'); const { SerialPort } = require('serialport'); const { ReadlineParser } = require('@serialport/parser-readline'); const sqlite3 = require('sqlite3').verbose(); const net = require('net'); const WebSocket = require('ws'); const aiAnalyzer = require('./ai-analyzer'); const { decodeVIN, getSystemInfo, getAllSystems, vehicleDatabase, getVehiclesByMake, getElectricVehicles, getBrandInfo } = require('./vehicle-database'); const { getECUInfo, getIssueInfo, getIssueByCode, getIssuesByTag, getECUsByMake, generateFixScript, commonIssues, ecuDatabase } = require('./ecu-database'); const { lookupDTC, searchDTCByKeyword, getAllDTCs, getDTCsBySystem, getDTCsBySeverity } = require('./dtc-database'); const notificationService = require('./notification-service'); // Handle uncaught exceptions (عشان السيرفر ما يقعش) process.on('uncaughtException', (err) => { console.error('Uncaught Exception:', err); }); process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection:', reason); }); const app = express(); const server = http.createServer(app); const io = socketIo(server, { cors: { origin: '*', methods: ['GET', 'POST'] }, transports: ['websocket'] // <-- أضف السطر ده }); // Security Middleware app.use(helmet()); app.use(compression()); app.use(cors()); app.use(express.json({ limit: '10mb' })); // Rate Limiting const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }); app.use('/api/', limiter); // ========== Database ========== const db = new sqlite3.Database(process.env.DB_PATH || './car-data.db'); db.serialize(() => { // جدول القراءات الرئيسي - موسع ليشمل جميع الحساسات db.run(`CREATE TABLE IF NOT EXISTS readings ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, rpm REAL, speed REAL, temp REAL, engine_load REAL, throttle REAL, maf REAL, map REAL, iat REAL, fuel_pressure REAL, o2_b1s1 REAL, o2_b1s2 REAL, o2_b2s1 REAL, o2_b2s2 REAL, timing_advance REAL, intake_temp REAL, ambient_temp REAL, fuel_level REAL, engine_runtime REAL, distance_mil REAL, fuel_rail_pressure REAL, egr_error REAL, evap_vapor REAL, fuel_tank_pressure REAL, battery_voltage REAL, oil_temp REAL, fuel_rate REAL, torque_demanded REAL, torque_actual REAL, throttle_actuator REAL, pedal_position REAL, barometric_pressure REAL, catalyst_temp_b1 REAL, catalyst_temp_b2 REAL, ethanol_percent REAL, abs_evap_vapor REAL, evap_pressure REAL, alternator_current REAL, ac_pressure REAL, ac_clutch REAL, cooling_fan REAL, power_takeoff REAL, engine_high_load REAL, low_fuel REAL, vehicle_speed_limit REAL, transmission_temp REAL, steering_angle REAL, yaw_rate REAL, lateral_accel REAL, wheel_speed_fl REAL, wheel_speed_fr REAL, wheel_speed_rl REAL, wheel_speed_rr REAL, vin TEXT )`); // جدول الأعطال الذكية db.run(`CREATE TABLE IF NOT EXISTS ai_faults ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, code TEXT, name TEXT, description TEXT, solution TEXT, severity TEXT, location_x REAL, location_y REAL, system TEXT, part TEXT, confidence INTEGER, possible_causes TEXT, diagnostic_steps TEXT )`); // جدول معلومات السيارات db.run(`CREATE TABLE IF NOT EXISTS vehicles ( id INTEGER PRIMARY KEY AUTOINCREMENT, vin TEXT UNIQUE, make TEXT, model TEXT, year INTEGER, engine TEXT, power INTEGER, torque INTEGER, transmission TEXT, fuel_type TEXT, ecu TEXT, last_seen DATETIME )`); // جدول الإصلاحات db.run(`CREATE TABLE IF NOT EXISTS repairs ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, vin TEXT, fault_code TEXT, repair_description TEXT, parts_used TEXT, cost REAL )`); // 🆕 جدول جديد لتخزين قراءات الحساسات التفصيلية db.run(`CREATE TABLE IF NOT EXISTS sensor_readings ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, sensor_name TEXT, sensor_value TEXT, sensor_unit TEXT )`); }); // ========== Customer Management ========== // إنشاء جدول العملاء db.run(`CREATE TABLE IF NOT EXISTS customers ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, phone TEXT, car_model TEXT, car_year INTEGER, car_vin TEXT, license_plate TEXT, registration_date DATETIME DEFAULT CURRENT_TIMESTAMP, last_service DATETIME, next_service DATETIME, service_status TEXT DEFAULT 'pending', is_returning BOOLEAN DEFAULT 0, total_visits INTEGER DEFAULT 1, notes TEXT )`); // إنشاء جدول زيارات الصيانة db.run(`CREATE TABLE IF NOT EXISTS service_visits ( id INTEGER PRIMARY KEY AUTOINCREMENT, customer_id INTEGER, visit_date DATETIME DEFAULT CURRENT_TIMESTAMP, service_type TEXT, faults TEXT, repairs TEXT, parts_used TEXT, cost REAL, status TEXT DEFAULT 'in_progress', completion_date DATETIME, FOREIGN KEY (customer_id) REFERENCES customers(id) )`); // ========== Bluetooth Pairing & Connection Helpers ========== const { exec } = require('child_process'); const fs = require('fs'); const util = require('util'); const execPromise = util.promisify(exec); // دالة لفحص إذا كان البلوتوث شغال async function isBluetoothEnabled() { try { const { stdout } = await execPromise('hciconfig'); return stdout.includes('UP RUNNING'); } catch { return false; } } // دالة لربط جهاز Bluetooth مع باسورد (اختياري) async function pairBluetoothDevice(address, password = null, channel = 0) { const rfcommPath = `/dev/rfcomm${channel}`; return new Promise(async (resolve, reject) => { try { // 1. نحرر المنفذ لو كان مستخدم قبل كده await execPromise(`sudo rfcomm release ${channel} 2>/dev/null`).catch(() => {}); // 2. نعمل pairing باستخدام bluetoothctl if (password) { console.log(`🔐 محاولة الاقتران بالجهاز ${address} باستخدام كلمة المرور: ${password}`); // نستخدم bluetoothctl للاقتران const pairingCommands = ` echo "agent on" echo "default-agent" echo "pair ${address}" echo "trust ${address}" echo "connect ${address}" echo "exit" `; const child = exec('bluetoothctl', (error, stdout, stderr) => { if (error) { console.log('⚠️ bluetoothctl warning:', error.message); } }); child.stdin.write(pairingCommands); child.stdin.end(); // نستنى شوية عشان الاقتران يكتمل await new Promise(resolve => setTimeout(resolve, 5000)); } // 3. نربط المنفذ باستخدام rfcomm console.log(`🔗 ربط المنفذ rfcomm${channel} بالجهاز ${address}`); await execPromise(`sudo rfcomm bind ${channel} ${address} 1`); // 4. نستنى عشان المنفذ يظهر await new Promise(resolve => setTimeout(resolve, 1500)); // 5. نتحقق إذا كان المنفذ موجود if (fs.existsSync(rfcommPath)) { console.log(`✅ تم ربط الجهاز ${address} على ${rfcommPath}`); resolve(rfcommPath); } else { reject(new Error(`المنفذ ${rfcommPath} لم يتم إنشاؤه`)); } } catch (err) { console.error('❌ خطأ في ربط البلوتوث:', err.message); reject(err); } }); } // دالة لفحص حالة المنفذ async function checkPortStatus(portPath) { try { const { stdout } = await execPromise(`ls -la ${portPath} 2>/dev/null`); return stdout.includes(portPath); } catch { return false; } } // دالة لمسح أجهزة Bluetooth مع معلومات إضافية async function scanBluetoothDevicesWithInfo() { return new Promise((resolve) => { const devices = []; // نجرب نستخدم bluetoothctl للبحث const child = exec('bluetoothctl scan on', { timeout: 10000 }); setTimeout(() => { exec('bluetoothctl devices', (error, stdout) => { if (error) { console.log('Bluetooth scan error:', error); return resolve([]); } const lines = stdout.split('\n'); for (const line of lines) { const match = line.match(/Device\s+([0-9A-F:]+)\s+(.+)/i); if (match) { devices.push({ address: match[1], name: match[2].trim() || 'Unknown Device', type: 'bluetooth', requiresPairing: true, // افتراضياً محتاج pairing paired: false }); } } resolve(devices); }); }, 2000); }); } // ========== OBD Connection Methods ========== const connectionMethods = { serial: { name: 'USB (Serial)', icon: '🔌', connect: (portPath, onData, onError) => { try { const port = new SerialPort({ path: portPath, baudRate: 9600, autoOpen: false }); const parser = port.pipe(new ReadlineParser({ delimiter: '\r' })); port.open((err) => { if (err) onError(err); else { console.log(`✅ Serial connected on ${portPath}`); port.write('ATZ\r'); } }); parser.on('data', onData); port.on('error', onError); return { close: () => port.close(), send: (data) => port.write(data) }; } catch(e) { onError(e); return null; } } }, bluetooth: { name: 'Bluetooth (RFCOMM)', icon: '📡', connect: (devicePath, onData, onError) => { try { console.log(`🔵 محاولة فتح المنفذ: ${devicePath}`); // نتأكد إن المنفذ موجود قبل محاولة الفتح if (!fs.existsSync(devicePath)) { console.error(`❌ المنفذ ${devicePath} غير موجود`); onError(new Error(`Port ${devicePath} does not exist`)); return null; } const port = new SerialPort({ path: devicePath, baudRate: 9600, autoOpen: false, lock: false }); const parser = port.pipe(new ReadlineParser({ delimiter: '\r' })); let isConnected = false; let retryCount = 0; const maxRetries = 3; // دالة لإعادة المحاولة const attemptReconnect = () => { if (retryCount < maxRetries && port.isOpen) { retryCount++; console.log(`🔄 محاولة إعادة الاتصال (${retryCount}/${maxRetries})...`); setTimeout(() => { if (port.isOpen) { port.write('ATZ\r'); } }, 1000); } }; port.on('open', () => { console.log(`✅ Bluetooth connected on ${devicePath} - المنفذ مفتوح الآن`); isConnected = true; retryCount = 0; // نرسل ATZ لتهيئة ELM327 setTimeout(() => { console.log('📤 إرسال ATZ لتهيئة ELM327...'); port.write('ATZ\r'); // بعد ATZ، نرسل ATE0 لإيقاف echo setTimeout(() => { port.write('ATE0\r'); }, 500); // نضبط البروتوكول على auto setTimeout(() => { port.write('ATSP0\r'); }, 1000); }, 500); }); port.on('error', (err) => { console.error(`❌ Bluetooth error on ${devicePath}:`, err.message); if (err.message.includes('No such file') || err.message.includes('does not exist')) { onError(new Error(`جهاز ELM327 غير متصل. تأكد من تشغيله وربطه`)); } else if (err.message.includes('Permission denied')) { onError(new Error(`صلاحيات المنفذ مطلوبة. جرب: sudo chmod 666 ${devicePath}`)); } else { onError(err); } }); port.on('close', () => { console.log(`🔌 منفذ البلوتوث ${devicePath} تم إغلاقه`); isConnected = false; // نبلغ عن انقطاع الاتصال if (currentConnection === port) { io.emit('status', { connected: false, error: 'انقطع الاتصال بالجهاز' }); } }); // نفتح المنفذ port.open((err) => { if (err) { console.error(`❌ فشل فتح المنفذ ${devicePath}:`, err.message); // نعطي رسالة واضحة للمستخدم if (err.message.includes('Permission denied')) { onError(new Error(`لا توجد صلاحيات للمنفذ ${devicePath}\nالحل: sudo chmod 666 ${devicePath} أو شغل السيرفر ب sudo`)); } else { onError(err); } } else { console.log(`🔓 منفذ ${devicePath} فتح بنجاح، بانتظار التأكيد...`); } }); // التعامل مع البيانات parser.on('data', (data) => { const trimmed = data.toString().trim(); if (trimmed && !trimmed.includes('ERROR')) { console.log(`📥 استقبال: ${trimmed.substring(0, 50)}`); onData(trimmed); } }); // إرسال ping كل 5 ثواني عشان نتأكد إن الاتصال لسه شغال const keepAliveInterval = setInterval(() => { if (port.isOpen && isConnected) { port.write('AT\r'); } }, 5000); return { close: () => { console.log(`🔌 إغلاق المنفذ ${devicePath}`); clearInterval(keepAliveInterval); port.close(); }, send: (data) => { if (port.isOpen && isConnected) { port.write(data); return true; } else { console.warn(`⚠️ محاولة إرسال والمنفذ مغلق: ${data}`); return false; } } }; } catch(e) { console.error('❌ خطأ في إنشاء منفذ البلوتوث:', e); onError(e); return null; } } }, wifi: { name: 'WiFi (TCP/IP)', icon: '🌐', connect: (host, port, onData, onError) => { try { const client = net.createConnection(port, host, () => { console.log(`✅ WiFi connected to ${host}:${port}`); client.write('ATZ\r'); }); client.on('data', (data) => onData(data.toString())); client.on('error', onError); return { close: () => client.destroy(), send: (data) => client.write(data) }; } catch(e) { onError(e); return null; } } }, websocket: { name: 'WebSocket', icon: '🔗', connect: (url, onData, onError) => { try { const ws = new WebSocket(url); ws.on('open', () => { console.log(`✅ WebSocket connected to ${url}`); ws.send('ATZ'); }); ws.on('message', (data) => onData(data.toString())); ws.on('error', onError); return { close: () => ws.close(), send: (data) => ws.send(data) }; } catch(e) { onError(e); return null; } } }, simulator: { name: 'Simulator (Testing)', icon: '🧪', connect: (onData, onError) => { console.log('✅ Simulator mode active'); let rpm = 800, speed = 40, temp = 85, load = 25, throttle = 15, increasing = true; const interval = setInterval(() => { if (increasing) { rpm += Math.floor(Math.random() * 300) + 50; if (rpm > 5500) increasing = false; } else { rpm -= Math.floor(Math.random() * 200) + 30; if (rpm < 800) increasing = true; } speed = Math.floor(rpm / 40) + Math.floor(Math.random() * 10); temp = rpm > 4000 ? temp + 0.3 : temp - 0.1; if (temp > 115) temp = 115; if (temp < 80) temp = 80; load = Math.floor((rpm / 6500) * 80) + 10; throttle = Math.floor((rpm / 5500) * 70) + 5; onData(`41 0C ${((Math.floor(rpm * 4) >> 8) & 0xFF).toString(16).padStart(2,'0')} ${(Math.floor(rpm * 4) & 0xFF).toString(16).padStart(2,'0')}\r>`); setTimeout(() => onData(`41 0D ${Math.floor(speed).toString(16).padStart(2,'0')}\r>`), 50); setTimeout(() => onData(`41 05 ${(Math.floor(temp) + 40).toString(16).padStart(2,'0')}\r>`), 100); setTimeout(() => onData(`41 04 ${Math.floor(load * 255 / 100).toString(16).padStart(2,'0')}\r>`), 150); setTimeout(() => onData(`41 11 ${Math.floor(throttle * 255 / 100).toString(16).padStart(2,'0')}\r>`), 200); }, 2000); return { close: () => clearInterval(interval), send: (data) => console.log('Simulator received:', data) }; } } }; // ========== All OBD-II PIDs (Standard + Extended) ========== const OBD_PIDS = { '04': { name: 'Engine load', unit: '%', formula: (v) => (v * 100) / 255 }, '05': { name: 'Engine coolant temperature', unit: '°C', formula: (v) => v - 40 }, '0A': { name: 'Fuel pressure', unit: 'kPa', formula: (v) => v * 3 }, '0B': { name: 'Intake manifold absolute pressure', unit: 'kPa', formula: (v) => v }, '0C': { name: 'Engine RPM', unit: 'rpm', formula: (v, v2) => (v * 256 + v2) / 4 }, '0D': { name: 'Vehicle speed', unit: 'km/h', formula: (v) => v }, '0E': { name: 'Timing advance', unit: '°', formula: (v) => (v - 128) / 2 }, '0F': { name: 'Intake air temperature', unit: '°C', formula: (v) => v - 40 }, '10': { name: 'MAF air flow rate', unit: 'g/s', formula: (v, v2) => (v * 256 + v2) / 100 }, '11': { name: 'Throttle position', unit: '%', formula: (v) => v * 100 / 255 }, '14': { name: 'O2 Sensor 1 Bank 1 Voltage', unit: 'V', formula: (v) => v / 200 }, '15': { name: 'O2 Sensor 2 Bank 1 Voltage', unit: 'V', formula: (v) => v / 200 }, '18': { name: 'O2 Sensor 1 Bank 2 Voltage', unit: 'V', formula: (v) => v / 200 }, '19': { name: 'O2 Sensor 2 Bank 2 Voltage', unit: 'V', formula: (v) => v / 200 }, '1F': { name: 'Run time since engine start', unit: 'seconds', formula: (v, v2) => v * 256 + v2 }, '22': { name: 'Fuel rail pressure', unit: 'kPa', formula: (v, v2) => (v * 256 + v2) * 0.079 }, '2C': { name: 'EGR commanded', unit: '%', formula: (v) => v * 100 / 255 }, '2D': { name: 'EGR error', unit: '%', formula: (v) => (v - 128) * 100 / 128 }, '2E': { name: 'Evaporative purge commanded', unit: '%', formula: (v) => v * 100 / 255 }, '2F': { name: 'Fuel level input', unit: '%', formula: (v) => v * 100 / 255 }, '33': { name: 'Barometric pressure', unit: 'kPa', formula: (v) => v }, '3C': { name: 'Catalyst temperature Bank 1', unit: '°C', formula: (v, v2) => (v * 256 + v2) / 10 - 40 }, '3D': { name: 'Catalyst temperature Bank 2', unit: '°C', formula: (v, v2) => (v * 256 + v2) / 10 - 40 }, '3E': { name: 'Battery voltage', unit: 'V', formula: (v) => v / 10 }, '42': { name: 'Relative throttle position', unit: '%', formula: (v) => v * 100 / 255 }, '43': { name: 'Ambient air temperature', unit: '°C', formula: (v) => v - 40 }, '46': { name: 'Accelerator pedal position D', unit: '%', formula: (v) => v * 100 / 255 }, '49': { name: 'Throttle actuator control', unit: '%', formula: (v) => v * 100 / 255 }, '4F': { name: 'Ethanol fuel percentage', unit: '%', formula: (v) => v * 100 / 255 }, '59': { name: 'Engine oil temperature', unit: '°C', formula: (v) => v - 40 }, '5B': { name: 'Engine fuel rate', unit: 'L/h', formula: (v, v2) => (v * 256 + v2) / 20 }, '5D': { name: 'Engine torque demanded', unit: '%', formula: (v) => v * 100 / 255 }, '5E': { name: 'Engine torque actual', unit: '%', formula: (v) => v * 100 / 255 }, '5F': { name: 'Engine reference torque', unit: 'Nm', formula: (v, v2) => v * 256 + v2 }, '80': { name: 'Toyota: Steering angle', unit: '°', formula: (v, v2) => (v * 256 + v2) / 10 }, '81': { name: 'Toyota: Yaw rate', unit: '°/s', formula: (v, v2) => ((v * 256 + v2) - 32768) / 10 }, '82': { name: 'Toyota: Lateral acceleration', unit: 'G', formula: (v, v2) => ((v * 256 + v2) - 32768) / 1000 }, '83': { name: 'Toyota: Wheel speed FL', unit: 'km/h', formula: (v, v2) => (v * 256 + v2) / 100 }, '84': { name: 'Toyota: Wheel speed FR', unit: 'km/h', formula: (v, v2) => (v * 256 + v2) / 100 }, '85': { name: 'Toyota: Wheel speed RL', unit: 'km/h', formula: (v, v2) => (v * 256 + v2) / 100 }, '86': { name: 'Toyota: Wheel speed RR', unit: 'km/h', formula: (v, v2) => (v * 256 + v2) / 100 }, '87': { name: 'Toyota: Transmission temperature', unit: '°C', formula: (v) => v - 40 }, '8B': { name: 'Ford: Oil life', unit: '%', formula: (v) => v * 100 / 255 }, '8C': { name: 'Ford: Transmission fluid temp', unit: '°C', formula: (v) => v - 40 }, '8D': { name: 'Ford: Tire pressure FL', unit: 'kPa', formula: (v) => v }, '8E': { name: 'Ford: Tire pressure FR', unit: 'kPa', formula: (v) => v }, '8F': { name: 'Ford: Tire pressure RL', unit: 'kPa', formula: (v) => v }, '94': { name: 'GM: Transmission gear', unit: '', formula: (v) => ['P', 'R', 'N', 'D', 'L'][v] || 'Unknown' }, '95': { name: 'Nissan: CVT temperature', unit: '°C', formula: (v) => v - 40 } }; // ========== Global State ========== let isConnected = false; let connectionType = null; let currentConnection = null; // Store all sensor readings let currentSensors = { rpm: 0, speed: 0, temp: 0, engineLoad: 0, throttle: 0, maf: 0, map: 0, iat: 0, fuelPressure: 0, o2_b1s1: 0, o2_b1s2: 0, o2_b2s1: 0, o2_b2s2: 0, timingAdvance: 0, ambientTemp: 0, fuelLevel: 0, engineRuntime: 0, barometricPressure: 0, batteryVoltage: 0, oilTemp: 0, torqueDemanded: 0, torqueActual: 0, throttleActuator: 0, pedalPosition: 0, catalystTemp_b1: 0, catalystTemp_b2: 0, ethanolPercent: 0, transmissionTemp: 0, steeringAngle: 0, yawRate: 0, lateralAccel: 0, wheelSpeedFL: 0, wheelSpeedFR: 0, wheelSpeedRL: 0, wheelSpeedRR: 0, oilLife: 0, tirePressureFL: 0, tirePressureFR: 0, tirePressureRL: 0, tirePressureRR: 0, transmissionGear: 'N', cvtTemperature: 0, timestamp: null }; let previousSensors = null; let previousData = null; let readInterval = null; let vehicleInfo = null; // OBD Parsers function parseRPM(res) { const m = res?.match(/41 0C ([0-9A-F]{2}) ([0-9A-F]{2})/i); return m ? parseInt(m[1] + m[2], 16) / 4 : null; } function parseSpeed(res) { const m = res?.match(/41 0D ([0-9A-F]{2})/i); return m ? parseInt(m[1], 16) : null; } function parseTemp(res) { const m = res?.match(/41 05 ([0-9A-F]{2})/i); return m ? parseInt(m[1], 16) - 40 : null; } function parseLoad(res) { const m = res?.match(/41 04 ([0-9A-F]{2})/i); return m ? (parseInt(m[1], 16) * 100) / 255 : null; } function parseThrottle(res) { const m = res?.match(/41 11 ([0-9A-F]{2})/i); return m ? (parseInt(m[1], 16) * 100) / 255 : null; } let isReady = false; let commandQueue = []; let waitingForResponse = false; let currentCallback = null; function processQueue() { if (waitingForResponse || commandQueue.length === 0 || !isReady || !currentConnection) return; const { cmd, callback } = commandQueue.shift(); waitingForResponse = true; currentCallback = callback; currentConnection.send(cmd + '\r'); } function sendCommand(cmd, callback) { if (!currentConnection || !isConnected) { if (callback) callback(null); return; } commandQueue.push({ cmd, callback }); processQueue(); } function handleOBDData(trimmed) { if (trimmed === '>') { isReady = true; if (waitingForResponse && currentCallback) { waitingForResponse = false; if (currentCallback) currentCallback(''); currentCallback = null; processQueue(); } } else if (waitingForResponse && currentCallback) { waitingForResponse = false; const callback = currentCallback; currentCallback = null; callback(trimmed); processQueue(); } if (trimmed.includes('ELM327')) { setTimeout(() => { if (currentConnection) currentConnection.send('ATSP0\r'); setTimeout(() => { isReady = true; }, 500); }, 500); } } function parseOBDResponse(response, pid) { if (!response) return null; const pidConfig = OBD_PIDS[pid]; if (!pidConfig) return null; const pattern = new RegExp(`41 ${pid} ([0-9A-F]{2})?([0-9A-F]{2})?([0-9A-F]{2})?([0-9A-F]{2})?`, 'i'); const match = response.match(pattern); if (!match) return null; const bytes = []; for (let i = 1; i <= 4; i++) { if (match[i]) bytes.push(parseInt(match[i], 16)); } if (typeof pidConfig.formula === 'function') { return pidConfig.formula(bytes[0] || 0, bytes[1] || 0, bytes[2] || 0, bytes[3] || 0); } return bytes[0] || 0; } // ========== Read Live Data with AI Analysis ========== // ========== Read Live Data with AI Analysis ========== async function readAllSensors() { if (!currentConnection || !isReady) return; const sensorsToRead = [ '0C', '0D', '05', '04', '11', '10', '0B', '0F', '0A', '14', '15', '18', '19', '0E', '33', '3E', '2F', '1F', '22', '2C', '2D', '2E', '3C', '3D', '42', '46', '49', '43', '59', '5B', '5D', '5E', '5F', '80', '81', '82', '83', '84', '85', '86', '87', '8B', '8C', '8D', '8E', '8F', '94', '95' ]; let delay = 0; for (const pid of sensorsToRead) { setTimeout(() => { sendCommand(`01${pid}`, (response) => { const value = parseOBDResponse(response, pid); if (value !== null && value !== undefined) { const sensorMap = { '0C': 'rpm', '0D': 'speed', '05': 'temp', '04': 'engineLoad', '11': 'throttle', '10': 'maf', '0B': 'map', '0F': 'iat', '0A': 'fuelPressure', '14': 'o2_b1s1', '15': 'o2_b1s2', '18': 'o2_b2s1', '19': 'o2_b2s2', '0E': 'timingAdvance', '33': 'barometricPressure', '3E': 'batteryVoltage', '2F': 'fuelLevel', '1F': 'engineRuntime', '22': 'fuelRailPressure', '2C': 'egrCommanded', '2D': 'egrError', '2E': 'evapPurge', '3C': 'catalystTemp_b1', '3D': 'catalystTemp_b2', '42': 'relativeThrottle', '43': 'ambientTemp', '46': 'pedalPositionD', '49': 'throttleActuator', '59': 'oilTemp', '5B': 'fuelRate', '5D': 'torqueDemanded', '5E': 'torqueActual', '5F': 'referenceTorque', '80': 'steeringAngle', '81': 'yawRate', '82': 'lateralAccel', '83': 'wheelSpeedFL', '84': 'wheelSpeedFR', '85': 'wheelSpeedRL', '86': 'wheelSpeedRR', '87': 'transmissionTemp', '8B': 'oilLife', '8C': 'fordTransTemp', '8D': 'tirePressureFL', '8E': 'tirePressureFR', '8F': 'tirePressureRL', '94': 'transmissionGear', '95': 'cvtTemperature' }; const key = sensorMap[pid]; if (key) currentSensors[key] = value; } }); }, delay); delay += 100; } setTimeout(() => { currentSensors.timestamp = new Date().toISOString(); db.run(`INSERT INTO readings (rpm, speed, temp, engine_load, throttle, maf, map, iat, fuel_pressure, o2_b1s1, o2_b1s2, o2_b2s1, o2_b2s2, timing_advance, ambient_temp, fuel_level, battery_voltage, oil_temp, fuel_rate, torque_demanded, torque_actual, throttle_actuator, pedal_position, barometric_pressure, catalyst_temp_b1, catalyst_temp_b2, ethanol_percent, transmission_temp, steering_angle, yaw_rate, lateral_accel, wheel_speed_fl, wheel_speed_fr, wheel_speed_rl, wheel_speed_rr) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ currentSensors.rpm, currentSensors.speed, currentSensors.temp, currentSensors.engineLoad, currentSensors.throttle, currentSensors.maf, currentSensors.map, currentSensors.iat, currentSensors.fuelPressure, currentSensors.o2_b1s1, currentSensors.o2_b1s2, currentSensors.o2_b2s1, currentSensors.o2_b2s2, currentSensors.timingAdvance, currentSensors.ambientTemp, currentSensors.fuelLevel, currentSensors.batteryVoltage, currentSensors.oilTemp, currentSensors.fuelRate, currentSensors.torqueDemanded, currentSensors.torqueActual, currentSensors.throttleActuator, currentSensors.pedalPosition, currentSensors.barometricPressure, currentSensors.catalystTemp_b1, currentSensors.catalystTemp_b2, currentSensors.ethanolPercent, currentSensors.transmissionTemp, currentSensors.steeringAngle, currentSensors.yawRate, currentSensors.lateralAccel, currentSensors.wheelSpeedFL, currentSensors.wheelSpeedFR, currentSensors.wheelSpeedRL, currentSensors.wheelSpeedRR ]); // ========== 🤖 AI ANALYSIS ON ALL SENSORS ========== const { faults, warnings, recommendations } = aiAnalyzer.analyzeAllSensors(currentSensors, previousSensors, vehicleInfo); const allIssues = [...faults, ...warnings]; for (const issue of allIssues) { db.run(`INSERT INTO ai_faults (code, name, description, solution, severity, location_x, location_y, system, part, confidence, possible_causes, diagnostic_steps) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [issue.code, issue.name, issue.description, issue.solution, issue.severity, issue.location?.x || 50, issue.location?.y || 50, issue.location?.system || 'unknown', issue.location?.part || null, issue.confidence || 80, issue.possibleCauses ? JSON.stringify(issue.possibleCauses) : null, issue.diagnosticSteps ? JSON.stringify(issue.diagnosticSteps) : null]); notificationService.addAlert(issue.code, issue.severity, issue.description, issue.location); } if (allIssues.length > 0) { io.emit('ai-faults', allIssues); console.log(`🤖 AI detected ${allIssues.length} issues from sensors`); } if (recommendations && recommendations.length > 0) { io.emit('recommendations', recommendations); console.log(`💡 AI recommendations: ${recommendations.join(', ')}`); } io.emit('sensors-data', currentSensors); previousSensors = { ...currentSensors }; }, delay + 200); } // ========== Connect Function ========== function connect(method, params) { if (currentConnection) { try { currentConnection.close(); } catch(e) {} currentConnection = null; } if (readInterval) clearInterval(readInterval); const methodConfig = connectionMethods[method]; if (!methodConfig) return false; // معالجة مختلفة حسب نوع الاتصال let connection = null; if (method === 'simulator') { connection = methodConfig.connect( (data) => handleOBDData(data.toString().trim()), (err) => { console.log(`❌ ${method} error:`, err?.message || err); isConnected = false; connectionType = null; io.emit('status', { connected: false }); } ); } else if (method === 'serial' || method === 'bluetooth') { const portPath = params[0] || (method === 'serial' ? '/dev/ttyUSB0' : '/dev/rfcomm0'); connection = methodConfig.connect( portPath, (data) => handleOBDData(data.toString().trim()), (err) => { console.log(`❌ ${method} error:`, err?.message || err); isConnected = false; connectionType = null; io.emit('status', { connected: false }); } ); } else if (method === 'wifi') { const host = params[0] || '192.168.0.10'; const port = params[1] || 35000; connection = methodConfig.connect( host, port, (data) => handleOBDData(data.toString().trim()), (err) => { console.log(`❌ ${method} error:`, err?.message || err); isConnected = false; connectionType = null; io.emit('status', { connected: false }); } ); } else if (method === 'websocket') { const url = params[0] || 'ws://localhost:8080'; connection = methodConfig.connect( url, (data) => handleOBDData(data.toString().trim()), (err) => { console.log(`❌ ${method} error:`, err?.message || err); isConnected = false; connectionType = null; io.emit('status', { connected: false }); } ); } else { return false; } if (connection) { isConnected = true; connectionType = method; isReady = false; commandQueue = []; waitingForResponse = false; currentConnection = connection; readInterval = setInterval(readAllSensors, 3000); io.emit('status', { connected: true, connectionType: method }); return true; } return false; } // ========== API Endpoints ========== app.get('/api/live-data', (req, res) => res.json(currentSensors)); app.get('/api/history', (req, res) => { db.all('SELECT * FROM readings ORDER BY timestamp DESC LIMIT 100', (err, rows) => res.json(rows)); }); app.get('/api/ai-faults', (req, res) => { db.all('SELECT * FROM ai_faults ORDER BY timestamp DESC LIMIT 50', (err, rows) => res.json(rows)); }); app.get('/api/vehicle-info', (req, res) => res.json(vehicleInfo || { message: 'لا توجد معلومات عن السيارة' })); app.get('/api/vehicle-systems', (req, res) => res.json(getAllSystems())); app.get('/api/connection-methods', (req, res) => { res.json(Object.entries(connectionMethods).map(([id, m]) => ({ id, name: m.name, icon: m.icon, available: true }))); }); // ========== DTC Database API Endpoints ========== // البحث عن كود عطل معين app.get('/api/dtc/lookup/:code', (req, res) => { const code = req.params.code.toUpperCase(); const result = lookupDTC(code); res.json(result); }); // البحث عن أعطال بكلمة مفتاحية app.get('/api/dtc/search/:keyword', (req, res) => { const keyword = req.params.keyword; const results = searchDTCByKeyword(keyword); res.json({ keyword, count: results.length, results }); }); // الحصول على جميع أكواد الأعطال app.get('/api/dtc/all', (req, res) => { const all = getAllDTCs(); res.json({ count: all.length, codes: all }); }); // الحصول على أكواد الأعطال حسب النظام app.get('/api/dtc/system/:system', (req, res) => { const system = req.params.system; const results = getDTCsBySystem(system); res.json({ system, count: results.length, codes: results }); }); // الحصول على أكواد الأعطال حسب الخطورة app.get('/api/dtc/severity/:severity', (req, res) => { const severity = req.params.severity; const results = getDTCsBySeverity(severity); res.json({ severity, count: results.length, codes: results }); }); // تحليل أكواد الأعطال باستخدام قاعدة البيانات + AI app.post('/api/dtc/analyze', async (req, res) => { const { codes } = req.body; if (!codes || codes.length === 0) { return res.status(400).json({ error: 'الرجاء إدخال أكواد الأعطال' }); } const analysis = []; const unknownCodes = []; for (const code of codes) { const lookup = lookupDTC(code.toUpperCase()); if (lookup.found) { analysis.push(lookup); } else { unknownCodes.push(code); } } // لو فيه أكواد مش موجودة في القاعدة، استخدم AI let aiAnalysis = null; if (unknownCodes.length > 0) { aiAnalysis = await aiAnalyzer.analyzeDTCCodes(unknownCodes, vehicleInfo); } res.json({ timestamp: new Date().toISOString(), analyzedCodes: analysis, unknownCodes: unknownCodes, aiFallbackAnalysis: aiAnalysis, summary: { total: codes.length, found: analysis.length, unknown: unknownCodes.length } }); }); // تحليل كود عطل باستخدام معيار SAE J2012 app.get('/api/dtc/analyze-sae/:code', (req, res) => { const code = req.params.code.toUpperCase(); const analysis = aiAnalyzer.analyzeDTCBySAEStandard(code, vehicleInfo); res.json(analysis); }); // تحليل عدة أكواد مرة واحدة app.post('/api/dtc/analyze-sae-batch', (req, res) => { const { codes } = req.body; if (!codes || !Array.isArray(codes)) { return res.status(400).json({ error: 'الرجاء إرسال مصفوفة من الأكواد' }); } const results = []; for (const code of codes) { const analysis = aiAnalyzer.analyzeDTCBySAEStandard(code, vehicleInfo); results.push(analysis); } res.json({ count: results.length, results }); }); app.get('/api/sensors/all', (req, res) => res.json(currentSensors)); app.get('/api/sensors/basic', (req, res) => res.json({ rpm: currentSensors.rpm, speed: currentSensors.speed, temp: currentSensors.temp, engineLoad: currentSensors.engineLoad, throttle: currentSensors.throttle })); app.get('/api/sensors/air-fuel', (req, res) => res.json({ maf: currentSensors.maf, map: currentSensors.map, iat: currentSensors.iat, fuelPressure: currentSensors.fuelPressure, fuelLevel: currentSensors.fuelLevel, ethanolPercent: currentSensors.ethanolPercent, fuelRate: currentSensors.fuelRate })); app.get('/api/sensors/o2', (req, res) => res.json({ bank1_sensor1: currentSensors.o2_b1s1, bank1_sensor2: currentSensors.o2_b1s2, bank2_sensor1: currentSensors.o2_b2s1, bank2_sensor2: currentSensors.o2_b2s2 })); app.get('/api/sensors/temperatures', (req, res) => res.json({ coolant: currentSensors.temp, oil: currentSensors.oilTemp, ambient: currentSensors.ambientTemp, transmission: currentSensors.transmissionTemp, catalyst_b1: currentSensors.catalystTemp_b1, catalyst_b2: currentSensors.catalystTemp_b2, cvt: currentSensors.cvtTemperature })); app.get('/api/sensors/electrical', (req, res) => res.json({ batteryVoltage: currentSensors.batteryVoltage, timingAdvance: currentSensors.timingAdvance, barometricPressure: currentSensors.barometricPressure })); app.get('/api/sensors/torque', (req, res) => res.json({ demanded: currentSensors.torqueDemanded, actual: currentSensors.torqueActual, reference: currentSensors.referenceTorque })); app.get('/api/sensors/wheels', (req, res) => res.json({ front_left: currentSensors.wheelSpeedFL, front_right: currentSensors.wheelSpeedFR, rear_left: currentSensors.wheelSpeedRL, rear_right: currentSensors.wheelSpeedRR, steering_angle: currentSensors.steeringAngle, yaw_rate: currentSensors.yawRate, lateral_accel: currentSensors.lateralAccel })); app.get('/api/sensors/tires', (req, res) => res.json({ front_left: currentSensors.tirePressureFL, front_right: currentSensors.tirePressureFR, rear_left: currentSensors.tirePressureRL, rear_right: currentSensors.tirePressureRR, oil_life: currentSensors.oilLife })); app.post('/api/connect', (req, res) => { const { method, params = [] } = req.body; // التحقق من وجود الجهاز قبل محاولة الاتصال if (method === 'serial') { const fs = require('fs'); const portPath = params[0] || '/dev/ttyUSB0'; if (!fs.existsSync(portPath)) { return res.status(404).json({ success: false, error: `❌ المنفذ ${portPath} غير موجود. تأكد من توصيل جهاز ELM327 عبر USB.`, suggestion: 'جرب واحداً من هذه المنافذ: /dev/ttyUSB0, /dev/ttyACM0, COM3, COM4' }); } } if (method === 'bluetooth') { const portPath = params[0] || '/dev/rfcomm0'; const fs = require('fs'); if (!fs.existsSync(portPath)) { return res.status(404).json({ success: false, error: `❌ جهاز Bluetooth غير متصل على ${portPath}. تأكد من إقران جهاز ELM327.`, suggestion: 'شغل: sudo rfcomm bind 0 XX:XX:XX:XX:XX:XX' }); } } if (method === 'wifi') { const host = params[0] || '192.168.0.10'; const port = params[1] || 35000; // سنحاول الاتصال بشكل غير متزامن const net = require('net'); const testSocket = new net.Socket(); const timeout = setTimeout(() => { testSocket.destroy(); return res.status(404).json({ success: false, error: `❌ لا يمكن الاتصال بـ ${host}:${port}. تأكد من أن جهاز ELM327 متصل بالشبكة.`, suggestion: 'تأكد من أن الـ IP صحيح والجهاز مشغل' }); }, 3000); testSocket.connect(port, host, () => { clearTimeout(timeout); testSocket.destroy(); const success = connect(method, params); res.json({ success, message: success ? `✅ تم الاتصال عبر ${method}` : `❌ فشل الاتصال عبر ${method}` }); }); testSocket.on('error', () => { clearTimeout(timeout); res.status(404).json({ success: false, error: `❌ لا يمكن الوصول إلى ${host}:${port}`, suggestion: 'تأكد من أن ELM327 WiFi مشغل ومتصل بنفس الشبكة' }); }); return; } if (method === 'websocket') { const url = params[0] || 'ws://localhost:8080'; const WebSocket = require('ws'); const testWs = new WebSocket(url); const timeout = setTimeout(() => { testWs.close(); return res.status(404).json({ success: false, error: `❌ لا يمكن الاتصال بـ ${url}`, suggestion: 'تأكد من أن خادم WebSocket مشغل' }); }, 3000); testWs.on('open', () => { clearTimeout(timeout); testWs.close(); const success = connect(method, params); res.json({ success, message: success ? `✅ تم الاتصال عبر ${method}` : `❌ فشل الاتصال عبر ${method}` }); }); testWs.on('error', () => { clearTimeout(timeout); res.status(404).json({ success: false, error: `❌ لا يمكن الاتصال بـ ${url}`, suggestion: 'تأكد من صحة عنوان WebSocket' }); }); return; } // Simulator و serial و bluetooth const success = connect(method, params); if (!success) { return res.status(500).json({ success: false, error: `❌ فشل الاتصال عبر ${method}`, suggestion: method === 'serial' ? 'تأكد من توصيل الكابل' : method === 'bluetooth' ? 'تأكد من إقران الجهاز' : 'جرب Simulator للاختبار' }); } res.json({ success: true, message: `✅ تم الاتصال عبر ${method}` }); }); app.get('/api/status', (req, res) => res.json({ connected: isConnected, connectionType, data: currentSensors, vehicleInfo })); app.post('/api/decode-vin', (req, res) => { const { vin } = req.body; if (!vin) return res.status(400).json({ error: 'VIN مطلوب' }); const decoded = decodeVIN(vin); vehicleInfo = decoded; db.run(`INSERT OR REPLACE INTO vehicles (vin, make, model, year, engine, power, torque, transmission, fuel_type, ecu, last_seen) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`, [vin, decoded.make, decoded.model, decoded.year, decoded.engine, decoded.power, decoded.torque, decoded.transmission, decoded.fuelType, decoded.ecu]); res.json(decoded); }); app.post('/api/ai-analyze', async (req, res) => { const { question, context } = req.body; const result = await aiAnalyzer.analyzeWithDeepSeek(question, { vehicleInfo, liveData: currentSensors, ...context }); res.json({ result }); }); app.post('/api/analyze-dtc', async (req, res) => { const { codes } = req.body; const analysis = await aiAnalyzer.analyzeDTCCodes(codes, vehicleInfo); res.json(analysis); }); app.post('/api/generate-fix', (req, res) => { const { issueId } = req.body; const fix = generateFixScript(issueId, vehicleInfo); res.json(fix); }); // ========== Customer APIs ========== // إضافة عميل جديد app.post('/api/customers', async (req, res) => { const { name, email, phone, carModel, carYear, carVin, licensePlate } = req.body; if (!name || !email) { return res.status(400).json({ error: 'الاسم والبريد الإلكتروني مطلوبان' }); } // التحقق من وجود العميل db.get('SELECT * FROM customers WHERE email = ?', [email], async (err, existing) => { if (err) return res.status(500).json({ error: err.message }); const isReturning = !!existing; const totalVisits = existing ? existing.total_visits + 1 : 1; const query = existing ? `UPDATE customers SET name=?, phone=?, car_model=?, car_year=?, car_vin=?, license_plate=?, last_service=CURRENT_TIMESTAMP, total_visits=?, is_returning=1 WHERE email=?` : `INSERT INTO customers (name, email, phone, car_model, car_year, car_vin, license_plate, total_visits, is_returning) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`; const params = existing ? [name, phone, carModel, carYear, carVin, licensePlate, totalVisits, email] : [name, email, phone, carModel, carYear, carVin, licensePlate, totalVisits, 0]; db.run(query, params, async function(err) { if (err) return res.status(500).json({ error: err.message }); const customerId = existing ? existing.id : this.lastID; const customer = { id: customerId, name, email, carModel, isReturning }; // إرسال بريد ترحيب try { const { sendWelcomeEmail } = require('./email-service'); await sendWelcomeEmail({ ...customer, estimatedTime: '2-3 أيام' }); } catch(emailErr) { console.error('Email error:', emailErr); } res.json({ success: true, customer: { id: customerId, name, email, carModel, isReturning: existing ? 1 : 0 }, message: existing ? 'تم تحديث بيانات العميل' : 'تم إضافة عميل جديد' }); }); }); }); // الحصول على جميع العملاء app.get('/api/customers', (req, res) => { db.all('SELECT * FROM customers ORDER BY registration_date DESC', (err, rows) => { if (err) return res.status(500).json({ error: err.message }); res.json(rows); }); }); // الحصول على عميل معين app.get('/api/customers/:id', (req, res) => { db.get('SELECT * FROM customers WHERE id = ?', [req.params.id], (err, row) => { if (err) return res.status(500).json({ error: err.message }); if (!row) return res.status(404).json({ error: 'العميل غير موجود' }); res.json(row); }); }); // تحديث حالة الصيانة app.put('/api/customers/:id/service-status', (req, res) => { const { status, completionNotes } = req.body; db.run('UPDATE customers SET service_status = ? WHERE id = ?', [status, req.params.id], async function(err) { if (err) return res.status(500).json({ error: err.message }); if (status === 'completed') { // جلب بيانات العميل db.get('SELECT * FROM customers WHERE id = ?', [req.params.id], async (err, customer) => { if (!err && customer) { try { const { sendServiceCompleteEmail } = require('./email-service'); await sendServiceCompleteEmail(customer); } catch(emailErr) { console.error('Email error:', emailErr); } } }); } res.json({ success: true }); }); }); // إضافة زيارة صيانة app.post('/api/service-visits', (req, res) => { const { customerId, serviceType, faults, repairs, partsUsed, cost } = req.body; db.run(`INSERT INTO service_visits (customer_id, service_type, faults, repairs, parts_used, cost) VALUES (?, ?, ?, ?, ?, ?)`, [customerId, serviceType, JSON.stringify(faults), JSON.stringify(repairs), JSON.stringify(partsUsed), cost], function(err) { if (err) return res.status(500).json({ error: err.message }); res.json({ success: true, visitId: this.lastID }); }); }); // الحصول على زيارات عميل app.get('/api/customers/:id/visits', (req, res) => { db.all('SELECT * FROM service_visits WHERE customer_id = ? ORDER BY visit_date DESC', [req.params.id], (err, rows) => { if (err) return res.status(500).json({ error: err.message }); res.json(rows); }); }); // إرسال تذكير للعميل app.post('/api/customers/:id/reminder', async (req, res) => { const { nextServiceDate } = req.body; db.get('SELECT * FROM customers WHERE id = ?', [req.params.id], async (err, customer) => { if (err) return res.status(500).json({ error: err.message }); if (!customer) return res.status(404).json({ error: 'العميل غير موجود' }); try { const { sendReminderEmail } = require('./email-service'); await sendReminderEmail({ ...customer, nextServiceDate }); res.json({ success: true, message: 'تم إرسال التذكير' }); } catch(emailErr) { res.status(500).json({ error: 'فشل إرسال الإيميل' }); } }); }); // تحليل العطل وإرسال التقرير تلقائياً app.post('/api/analyze-and-notify', async (req, res) => { const { customerId, faults, recommendations } = req.body; db.get('SELECT * FROM customers WHERE id = ?', [customerId], async (err, customer) => { if (err) return res.status(500).json({ error: err.message }); try { const { sendDiagnosisReport } = require('./email-service'); await sendDiagnosisReport(customer, faults, recommendations); res.json({ success: true, message: 'تم إرسال تقرير التشخيص' }); } catch(emailErr) { res.status(500).json({ error: 'فشل إرسال التقرير' }); } }); }); // إحصائيات العملاء // ========== Customer Statistics (مكتمل) ========== app.get('/api/customers/stats/summary', (req, res) => { db.get(`SELECT COUNT(*) as total_customers, SUM(CASE WHEN is_returning = 1 THEN 1 ELSE 0 END) as returning_customers, SUM(CASE WHEN is_returning = 0 THEN 1 ELSE 0 END) as new_customers, SUM(CASE WHEN service_status = 'pending' THEN 1 ELSE 0 END) as pending_services, SUM(CASE WHEN service_status = 'in_progress' THEN 1 ELSE 0 END) as active_services, SUM(CASE WHEN service_status = 'completed' THEN 1 ELSE 0 END) as completed_services FROM customers`, (err, row) => { if (err) return res.status(500).json({ error: err.message }); res.json(row || { total_customers: 0, returning_customers: 0, new_customers: 0, pending_services: 0, active_services: 0, completed_services: 0 }); }); }); // ========== API لمسح كل الأعطال ========== app.post('/api/clear-dtcs', (req, res) => { db.run('DELETE FROM ai_faults', (err) => { if (err) return res.status(500).json({ error: err.message }); res.json({ success: true, message: 'تم مسح جميع الأعطال بنجاح' }); }); }); // ========== API للحصول على آخر إحصائيات ========== app.get('/api/system-stats', (req, res) => { db.get('SELECT COUNT(*) as total_readings FROM readings', (err, readingsRow) => { if (err) return res.status(500).json({ error: err.message }); db.get('SELECT COUNT(*) as total_faults FROM ai_faults', (err, faultsRow) => { if (err) return res.status(500).json({ error: err.message }); // حساب عدد الأعطال النشطة (غير الممسوحة) db.get('SELECT COUNT(*) as active_faults FROM ai_faults WHERE cleared = 0 OR cleared IS NULL', (err, activeRow) => { res.json({ totalReadings: readingsRow?.total_readings || 0, totalFaults: faultsRow?.total_faults || 0, activeFaults: activeRow?.active_faults || 0, isConnected: isConnected || false }); }); }); }); }); // ========== Scan Available Ports ========== app.get('/api/scan-ports', (req, res) => { const fs = require('fs'); const availablePorts = []; // فحص المنافذ الشائعة على Linux const linuxPorts = ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyACM0', '/dev/ttyACM1', '/dev/rfcomm0']; // فحص المنافذ الشائعة على Windows const windowsPorts = ['COM3', 'COM4', 'COM5', 'COM6', 'COM7']; for (const port of linuxPorts) { if (fs.existsSync(port)) { availablePorts.push(port); } } // محاكاة لاكتشاف Bluetooth (قد يحتاج إذن) try { const { execSync } = require('child_process'); const btOutput = execSync('hcitool dev 2>/dev/null || echo ""', { encoding: 'utf8' }); if (btOutput.includes('hci')) { availablePorts.push('bluetooth:any'); } } catch(e) {} res.json(availablePorts.length > 0 ? availablePorts : ['لا توجد أجهزة متصلة']); }); // ========== Network & Device Scanning ========== const os = require('os'); // Scan WiFi networks app.get('/api/scan-wifi', (req, res) => { const platform = os.platform(); let command = ''; if (platform === 'linux') { command = 'nmcli dev wifi list 2>/dev/null || iwlist wlan0 scan 2>/dev/null | grep -E "ESSID|Quality"'; } else if (platform === 'win32') { command = 'netsh wlan show networks'; } else if (platform === 'darwin') { command = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s'; } else { return res.json([]); } exec(command, (error, stdout) => { if (error) { console.log('WiFi scan error:', error); return res.json([]); } const networks = []; const lines = stdout.split('\n'); for (const line of lines) { // استخراج اسم الشبكة (SSID) const ssidMatch = line.match(/ESSID:"?([^"\n]+)"?/i) || line.match(/([A-Za-z0-9_\-]+)\s+Infra/i) || line.match(/^[\s]*([A-Za-z0-9_\-]+)\s+/); if (ssidMatch && ssidMatch[1] && !ssidMatch[1].includes('--')) { networks.push({ ssid: ssidMatch[1], signal: line.includes('Quality') ? parseInt(line.match(/Quality=(\d+)/)?.[1] || '50') : 50, secure: !line.includes('Open') && !line.includes('unencrypted') }); } } res.json([...new Map(networks.map(n => [n.ssid, n])).values()].slice(0, 20)); }); }); // Scan Bluetooth devices app.get('/api/scan-bluetooth', (req, res) => { exec('hcitool scan 2>/dev/null | tail -n +2', (error, stdout) => { if (error) { console.log('Bluetooth scan error:', error); return res.json([]); } const devices = []; const lines = stdout.split('\n'); for (const line of lines) { if (line.trim()) { const parts = line.trim().split(/\s+/); if (parts.length >= 2) { devices.push({ address: parts[0], name: parts.slice(1).join(' ') || 'Unknown Device', type: 'bluetooth' }); } } } res.json(devices); }); }); // Scan Serial ports app.get('/api/scan-serial', async (req, res) => { try { const { SerialPort } = require('serialport'); const ports = await SerialPort.list(); const availablePorts = ports.map(port => ({ path: port.path, manufacturer: port.manufacturer || 'Unknown', serialNumber: port.serialNumber || '', pnpId: port.pnpId || '', locationId: port.locationId || '', productId: port.productId || '', vendorId: port.vendorId || '' })); res.json(availablePorts); } catch(err) { console.error('Serial scan error:', err); const fs = require('fs'); const commonPorts = ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyACM0', '/dev/ttyACM1', '/dev/rfcomm0']; const available = commonPorts.filter(p => fs.existsSync(p)).map(p => ({ path: p, manufacturer: 'Unknown' })); res.json(available); } }); // Connect to WiFi device (ELM327 WiFi) app.post('/api/connect-wifi', (req, res) => { const { ssid, password, host, port } = req.body; // على Linux، يمكن الاتصال بشبكة WiFi if (password) { exec(`nmcli device wifi connect "${ssid}" password "${password}" 2>/dev/null`, (error) => { if (error) { return res.json({ success: false, error: 'فشل الاتصال بالشبكة' }); } // بعد الاتصال بالشبكة، نحاول الاتصال بـ ELM327 setTimeout(() => { const success = connect('wifi', [host || '192.168.0.10', port || 35000]); res.json({ success, message: success ? '✅ تم الاتصال بالجهاز' : '❌ فشل الاتصال بالجهاز' }); }, 3000); }); } else { const success = connect('wifi', [host || '192.168.0.10', port || 35000]); res.json({ success, message: success ? '✅ تم الاتصال بالجهاز' : '❌ فشل الاتصال' }); } }); // Connect to Bluetooth device // Connect to Bluetooth device with optional password app.post('/api/connect-bluetooth', async (req, res) => { const { address, channel, password } = req.body; if (!address) { return res.status(400).json({ success: false, error: 'عنوان الجهاز مطلوب' }); } try { console.log(`📡 محاولة الاتصال بجهاز البلوتوث: ${address}`); // 1. نتحقق إذا كان البلوتوث شغال const btEnabled = await isBluetoothEnabled(); if (!btEnabled) { return res.status(400).json({ success: false, error: 'البلوتوث ليس شغالاً', suggestion: 'شغل البلوتوث أولاً: sudo hciconfig hci0 up' }); } // 2. نربط الجهاز (مع أو بدون باسورد) const rfcommPath = await pairBluetoothDevice(address, password || null, channel || 0); // 3. نتحقق من المنفذ const portExists = await checkPortStatus(rfcommPath); if (!portExists) { return res.status(400).json({ success: false, error: 'فشل إنشاء المنفذ', suggestion: 'جرب إعادة تشغيل البلوتوث: sudo rfcomm release 0' }); } // 4. نحاول الاتصال setTimeout(() => { const success = connect('bluetooth', [rfcommPath]); if (success) { console.log(`✅ تم الاتصال بجهاز ${address} عبر ${rfcommPath}`); res.json({ success: true, message: `✅ تم الاتصال بجهاز ${address}`, port: rfcommPath }); } else { res.json({ success: false, error: 'فشل الاتصال بالجهاز بعد الربط', suggestion: 'تأكد من أن جهاز ELM327 مشغل ومرتبط بشكل صحيح' }); } }, 2000); } catch (err) { console.error('❌ Bluetooth pairing error:', err); // نعطي رسالة واضحة حسب نوع الخطأ let errorMsg = 'فشل الاتصال بالجهاز'; let suggestion = ''; if (err.message.includes('Permission denied')) { errorMsg = 'صلاحيات المنفذ مطلوبة'; suggestion = 'شغل السيرفر ب sudo: sudo node server.js'; } else if (err.message.includes('No such device')) { errorMsg = 'الجهاز غير موجود'; suggestion = 'تأكد من أن جهاز ELM327 مشغل وفي وضع الـ pairing'; } else if (err.message.includes('password') || err.message.includes('authentication')) { errorMsg = 'كلمة المرور غير صحيحة أو مطلوبة'; suggestion = 'جرب كلمات المرور الشائعة: 1234, 0000, 123456'; } else { suggestion = 'تأكد من تشغيل الجهاز وإعادة المحاولة'; } res.status(400).json({ success: false, error: errorMsg, suggestion: suggestion, originalError: err.message }); } }); // ========== Bluetooth Status API ========== app.get('/api/bluetooth/status', async (req, res) => { try { const btEnabled = await isBluetoothEnabled(); const rfcommExists = fs.existsSync('/dev/rfcomm0'); res.json({ bluetoothEnabled: btEnabled, connected: isConnected, connectionType: connectionType, rfcommExists: rfcommExists, portPath: '/dev/rfcomm0', message: btEnabled ? (rfcommExists ? '✅ البلوتوث جاهز' : '⚠️ لا يوجد جهاز مرتبط') : '❌ البلوتوث معطل' }); } catch (err) { res.status(500).json({ error: err.message }); } }); // API لمسح أجهزة البلوتوث (محدث) app.get('/api/scan-bluetooth-enhanced', async (req, res) => { try { const devices = await scanBluetoothDevicesWithInfo(); res.json(devices); } catch (err) { console.error('Enhanced Bluetooth scan error:', err); res.json([]); } }); // ========== Smart AI Analysis APIs ========== // تحليل ذكي باستخدام DeepSeek app.post('/api/smart-analyze', async (req, res) => { const { question, context = {} } = req.body; const result = await aiAnalyzer.smartAnalyze(question, { vehicleInfo, liveData: currentSensors, voltage: context.voltage, dtcCodes: context.dtcCodes, ...context }); res.json({ result }); }); // تحليل DTCs بطريقة ذكية app.post('/api/smart-analyze-dtc', async (req, res) => { const { codes } = req.body; const analysis = await aiAnalyzer.analyzeDTCCodesSmart(codes, vehicleInfo); res.json(analysis); }); // تحليل البيانات الحية بطريقة ذكية app.post('/api/smart-analyze-live', async (req, res) => { const analysis = await aiAnalyzer.analyzeLiveDataSmart(currentSensors, vehicleInfo); res.json({ analysis }); }); // ========== Dead Car Diagnosis ========== app.post('/api/diagnose-dead-car', async (req, res) => { if (!currentConnection || !isConnected) { return res.status(400).json({ error: 'لا يوجد اتصال بالجهاز', canRetry: true }); } const diagnosis = { timestamp: new Date().toISOString(), batteryVoltage: null, dtcs: [], pendingDtcs: [], smartAnalysis: null }; try { // 1. قراءة فولتية البطارية const voltageResponse = await new Promise((resolve) => { sendCommand('ATRV', (response) => resolve(response)); }); const voltageMatch = voltageResponse?.match(/(\d+\.?\d*)/); if (voltageMatch) diagnosis.batteryVoltage = parseFloat(voltageMatch[1]); // 2. قراءة أكواد الأعطال const dtcResponse = await new Promise((resolve) => { sendCommand('03', (response) => resolve(response)); }); const dtcPattern = /([PBCU][0-9A-F]{4})/gi; let match; while ((match = dtcPattern.exec(dtcResponse)) !== null) { diagnosis.dtcs.push(match[1]); } // 3. قراءة الأكواد المعلقة const pendingResponse = await new Promise((resolve) => { sendCommand('07', (response) => resolve(response)); }); while ((match = dtcPattern.exec(pendingResponse)) !== null) { diagnosis.pendingDtcs.push(match[1]); } // 4. تحليل ذكي باستخدام AI diagnosis.smartAnalysis = aiAnalyzer.analyzeDeadCar(diagnosis.batteryVoltage, diagnosis.dtcs); // 5. استخدام DeepSeek للتحليل العميق (إذا وجدت أكواد) if (diagnosis.dtcs.length > 0 || diagnosis.batteryVoltage < 12) { const deepAnalysis = await aiAnalyzer.smartAnalyze( `سيارة لا تدور. البطارية ${diagnosis.batteryVoltage}V. الأكواد: ${diagnosis.dtcs.join(', ')}`, { vehicleInfo, voltage: diagnosis.batteryVoltage, dtcCodes: diagnosis.dtcs } ); diagnosis.deepAnalysis = deepAnalysis; } res.json(diagnosis); } catch (err) { console.error('Dead car diagnosis error:', err); res.status(500).json({ error: 'فشل تشخيص العربية', details: err.message }); } }); // ========== NEW API Endpoints for ECUs and Issues ========== // الحصول على جميع ECUs app.get('/api/ecus/all', (req, res) => { const ecus = Object.entries(ecuDatabase).map(([name, data]) => ({ name, manufacturer: data.manufacturer, country: data.country, vehicles: data.vehicles, protocols: data.protocols, flashingSupported: data.flashingSupported, softwareVersions: data.softwareVersions, isElectric: data.isElectric || false, fixesCount: data.fixes?.length || 0 })); res.json(ecus); }); // الحصول على معلومات ECU معين app.get('/api/ecus/:name', (req, res) => { const ecuName = req.params.name; const ecuInfo = getECUInfo(ecuName); res.json(ecuInfo); }); // الحصول على ECUs حسب الماركة app.post('/api/ecus/by-make', (req, res) => { const { make } = req.body; if (!make) { return res.status(400).json({ error: 'الرجاء إدخال اسم الماركة' }); } const ecus = getECUsByMake(make); res.json(ecus); }); // الحصول على جميع المشاكل الشائعة app.get('/api/issues/all', (req, res) => { const issues = Object.entries(commonIssues).map(([id, data]) => ({ id, name: data.name, code: data.code, severity: data.severity, symptoms: data.symptoms, estimatedTime: data.estimatedTime, estimatedCost: data.estimatedCost, tags: data.tags })); res.json(issues); }); // الحصول على مشكلة معينة app.get('/api/issues/:id', (req, res) => { const issueId = req.params.id; const issue = getIssueInfo(issueId); if (!issue) { return res.status(404).json({ error: 'المشكلة غير موجودة' }); } res.json({ id: issueId, ...issue }); }); // البحث عن مشكلة حسب كود العطل app.get('/api/issues/by-code/:code', (req, res) => { const code = req.params.code.toUpperCase(); const issue = getIssueByCode(code); if (!issue) { return res.status(404).json({ error: `لا توجد معلومات للكود ${code}` }); } res.json(issue); }); // البحث عن مشاكل حسب التصنيف app.get('/api/issues/by-tag/:tag', (req, res) => { const tag = req.params.tag; const issues = getIssuesByTag(tag); res.json(issues); }); // توليد سكربت إصلاح لمشكلة معينة app.post('/api/generate-fix-script', (req, res) => { const { issueId, vehicleInfo } = req.body; if (!issueId) { return res.status(400).json({ error: 'الرجاء إدخال معرف المشكلة' }); } const fixScript = generateFixScript(issueId, vehicleInfo || {}); if (!fixScript) { return res.status(404).json({ error: 'المشكلة غير موجودة' }); } res.json(fixScript); }); // تحليل متقدم باستخدام قاعدة بيانات ECUs app.post('/api/advanced-diagnosis', async (req, res) => { const { dtcCodes, vehicleInfo, liveData } = req.body; const diagnosis = { timestamp: new Date().toISOString(), dtcCodes: dtcCodes || [], vehicleInfo: vehicleInfo || {}, liveData: liveData || {}, issues: [], recommendedActions: [], ecuRecommendations: [] }; // تحليل كل كود عطل if (dtcCodes && dtcCodes.length > 0) { for (const code of dtcCodes) { const issue = getIssueByCode(code); if (issue) { diagnosis.issues.push({ code: code, issue: issue.name, severity: issue.severity, symptoms: issue.symptoms, causes: issue.causes, solutions: issue.solutions, estimatedTime: issue.estimatedTime, estimatedCost: issue.estimatedCost, requiredTools: issue.requiredTools }); } else { // استخدام AI لتحليل الكود غير المعروف diagnosis.issues.push({ code: code, issue: `كود ${code} - يتطلب تحليل متخصص`, severity: 'unknown', recommendation: 'استخدم فني متخصص أو تحليل DeepSeek' }); } } } // توصيات ECUs بناءً على السيارة if (vehicleInfo && vehicleInfo.make) { const ecus = getECUsByMake(vehicleInfo.make); if (ecus.length > 0) { diagnosis.ecuRecommendations = ecus.map(ecu => ({ name: ecu.name, manufacturer: ecu.manufacturer, flashingSupported: ecu.flashingSupported, softwareVersions: ecu.softwareVersions })); } } // توصيات عامة if (diagnosis.issues.length > 0) { const criticalIssues = diagnosis.issues.filter(i => i.severity === 'critical'); if (criticalIssues.length > 0) { diagnosis.recommendedActions.push('🚨 توجد أعطال حرجة - يفضل إيقاف السيارة فوراً'); } const highIssues = diagnosis.issues.filter(i => i.severity === 'high'); if (highIssues.length > 0) { diagnosis.recommendedActions.push('⚠️ توجد أعطال خطيرة - يفضل الفحص العاجل'); } diagnosis.recommendedActions.push('🔧 استخدم ماسح OBD لقراءة البيانات الحية'); diagnosis.recommendedActions.push('📋 دوّن ملاحظات عن متى تظهر الأعطال'); } res.json(diagnosis); }); // إحصائيات ECUs والمشاكل app.get('/api/diagnostic-stats', (req, res) => { const stats = { totalECUs: Object.keys(ecuDatabase).length, totalIssues: Object.keys(commonIssues).length, issuesBySeverity: { critical: 0, high: 0, medium: 0, low: 0 }, issuesByTag: {}, ecusByCountry: {}, flashingSupported: 0 }; // إحصائيات المشاكل for (const issue of Object.values(commonIssues)) { if (issue.severity) { stats.issuesBySeverity[issue.severity] = (stats.issuesBySeverity[issue.severity] || 0) + 1; } if (issue.tags) { for (const tag of issue.tags) { stats.issuesByTag[tag] = (stats.issuesByTag[tag] || 0) + 1; } } } // إحصائيات ECUs for (const ecu of Object.values(ecuDatabase)) { if (ecu.country) { stats.ecusByCountry[ecu.country] = (stats.ecusByCountry[ecu.country] || 0) + 1; } if (ecu.flashingSupported) { stats.flashingSupported++; } } res.json(stats); }); // أضفهم قبل WebSocket app.get('/api/vehicles/all', (req, res) => { const allVehicles = Object.entries(vehicleDatabase).map(([prefix, info]) => ({ prefix, make: info.make, model: info.model, years: info.years, engine: info.engine, power: info.power, transmission: info.transmission, fuelType: info.fuelType, bodyType: info.bodyType })); res.json(allVehicles); }); app.get('/api/vehicles/make/:make', (req, res) => { const vehicles = getVehiclesByMake(req.params.make); res.json(vehicles); }); app.get('/api/vehicles/electric', (req, res) => { const vehicles = getElectricVehicles(); res.json(vehicles); }); app.get('/api/brand/:make', (req, res) => { const brandInfo = getBrandInfo(req.params.make); res.json(brandInfo); }); app.get('/api/system/:id', (req, res) => { const systemInfo = getSystemInfo(req.params.id); res.json(systemInfo); }); // ========== OBD PIDs API ========== app.get('/api/obd/pids/all', (req, res) => { // ترتيب الـ PIDs حسب المعرف const sortedPids = Object.entries(OBD_PIDS) .sort((a, b) => parseInt(a[0], 16) - parseInt(b[0], 16)) .map(([pid, info]) => ({ pid: pid, name: info.name, unit: info.unit, formula: info.formula.toString() })); res.json({ count: sortedPids.length, pids: sortedPids, supported: currentSensors ? Object.keys(currentSensors).filter(k => currentSensors[k] > 0).length : 0 }); }); // ========== Comprehensive Analysis API ========== app.post('/api/comprehensive-analysis', async (req, res) => { const { dtcCodes, vehicleInfo: inputVehicleInfo } = req.body; const analysis = { timestamp: new Date().toISOString(), vehicleInfo: vehicleInfo || inputVehicleInfo, totalSensors: Object.keys(currentSensors).filter(k => currentSensors[k] > 0).length, activeFaults: aiFaults.length, severity: 'low', summary: '', canDrive: true }; // تحديد مستوى الخطورة const criticalFaults = aiFaults.filter(f => f.severity === 'critical'); const highFaults = aiFaults.filter(f => f.severity === 'high'); if (criticalFaults.length > 0) { analysis.severity = 'critical'; analysis.canDrive = false; analysis.summary = `🚨 توجد ${criticalFaults.length} أعطال حرجة. لا تقم بالقيادة!`; } else if (highFaults.length > 0) { analysis.severity = 'high'; analysis.canDrive = true; analysis.summary = `⚠️ توجد ${highFaults.length} أعطال خطيرة. يفضل الفحص العاجل.`; } else if (aiFaults.length > 0) { analysis.severity = 'medium'; analysis.canDrive = true; analysis.summary = `📌 توجد ${aiFaults.length} أعطال. يمكن القيادة بحذر.`; } else { analysis.severity = 'low'; analysis.canDrive = true; analysis.summary = '✅ جميع الأنظمة تعمل بشكل طبيعي. السيارة بحالة جيدة.'; } res.json(analysis); }); // ========== Generate Report API ========== app.post('/api/generate-report', async (req, res) => { const { dtcCodes } = req.body; const report = []; report.push('╔══════════════════════════════════════════════════════════════╗'); report.push('║ 🔧 Reda CAR - تقرير تشخيص شامل ║'); report.push('╚══════════════════════════════════════════════════════════════╝'); report.push(''); report.push(`📅 التاريخ: ${new Date().toLocaleString('ar-EG')}`); report.push(`🚗 السيارة: ${vehicleInfo?.make || 'غير معروف'} ${vehicleInfo?.model || ''} ${vehicleInfo?.year || ''}`); report.push(`📊 عدد الحساسات النشطة: ${Object.keys(currentSensors).filter(k => currentSensors[k] > 0).length}`); report.push(`🚨 عدد الأعطال النشطة: ${aiFaults.length}`); report.push(''); if (aiFaults.length > 0) { report.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); report.push('🔍 الأعطال المكتشفة:'); for (const fault of aiFaults.slice(0, 10)) { report.push(` 📌 ${fault.code}: ${fault.name}`); report.push(` 💡 الحل: ${fault.solution.substring(0, 100)}...`); report.push(''); } } report.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); report.push('📊 أهم قراءات الحساسات:'); report.push(` 🚗 RPM: ${currentSensors.rpm}`); report.push(` 📊 السرعة: ${currentSensors.speed} km/h`); report.push(` 🌡️ حرارة المحرك: ${currentSensors.temp}°C`); report.push(` 🔋 فولتية البطارية: ${currentSensors.batteryVoltage}V`); report.push(` 💨 MAF: ${currentSensors.maf} g/s`); report.push(` 🦶 دعسة البنزين: ${currentSensors.throttle}%`); report.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); report.push('✨ تم التقرير بواسطة Reda CAR AI'); res.json({ report: report.join('\n') }); }); // الحصول على PID معين app.get('/api/obd/pid/:pid', (req, res) => { const pid = req.params.pid; const pidInfo = OBD_PIDS[pid]; if (!pidInfo) { return res.status(404).json({ error: `PID ${pid} غير موجود` }); } // محاولة قراءة القيمة الحالية const sensorMap = { '0C': 'rpm', '0D': 'speed', '05': 'temp', '04': 'engineLoad', '11': 'throttle', '10': 'maf', '0B': 'map', '0F': 'iat', '0A': 'fuelPressure', '0E': 'timingAdvance', '3E': 'batteryVoltage', '2F': 'fuelLevel', '1F': 'engineRuntime', '33': 'barometricPressure', '59': 'oilTemp', '5B': 'fuelRate', '5D': 'torqueDemanded', '5E': 'torqueActual' }; const sensorKey = sensorMap[pid]; const currentValue = sensorKey ? currentSensors[sensorKey] : null; res.json({ pid: pid, name: pidInfo.name, unit: pidInfo.unit, currentValue: currentValue, formula: pidInfo.formula.toString(), supported: currentValue !== null && currentValue !== 0 }); }); // ========== WebSocket ========== io.on('connection', (socket) => { console.log('✅ Frontend connected'); const interval = setInterval(() => { socket.emit('sensors-data', currentSensors); socket.emit('live-data', { rpm: currentSensors.rpm, speed: currentSensors.speed, temp: currentSensors.temp, engineLoad: currentSensors.engineLoad, throttle: currentSensors.throttle }); socket.emit('status', { connected: isConnected, connectionType, vehicleInfo }); }, 1000); socket.on('disconnect', () => clearInterval(interval)); }); // ========== Start Server ========== const PORT = process.env.PORT || 7860; server.listen(PORT, () => { console.log(`\n${'='.repeat(60)}`); console.log(`🚗 Reda CAR Professional Diagnostic System v5.0`); console.log(`${'='.repeat(60)}`); console.log(`📍 API: http://localhost:${PORT}`); console.log(`📡 WebSocket: ws://localhost:${PORT}`); console.log(`💾 Database: ${process.env.DB_PATH || './car-data.db'}`); console.log(`\n🔌 طرق الاتصال المدعومة:`); Object.entries(connectionMethods).forEach(([id, m]) => console.log(` ${m.icon} ${m.name} (${id})`)); console.log(`\n🤖 AI Features:`); console.log(` - Dynamic Fault Analysis (no static database)`); console.log(` - DeepSeek R1 Integration`); console.log(` - Pattern Recognition`); console.log(` - Confidence Scoring`); console.log(`\n✨ Reda CAR جاهز!\n`); });