Şifreli BLE ile Kimlik Doğrulamalı Akıllı Kilit
Proje Amacı
BLE (Bluetooth Low Energy) bonding/pairing ile bir telefonun kimliğini bir kez eşleştirip, sonraki bağlantılarda ESP32'nin donanımsal AES şifrelemesiyle korunan bir kanaldan 'kilidi aç' komutunu doğrulamayı ve bir servo ile fiziksel kilidi açmayı öğretir. ESP32'nin dahili BLE radyosu, Secure Connections (LE Secure Connections) ile şifreli eşleştirme yapabilecek donanımsal kripto desteğine sahiptir. Bu güvenlik düzeyi Arduino Uno'da kurulamaz: kart hiçbir Bluetooth radyosu (Classic veya BLE) içermez ve kripto hızlandırma donanımı da yoktur; harici bir BLE modülü (HM-10 gibi) eklense bile bu modüller genelde bonding/güvenli eşleştirmeyi tam desteklemez.
Gerekli Malzemeler
- ESP32 DevKit V1 (38 pin)
- SG90 mikro servo motor
- Durum LED'i
- 220Ω direnç
- Breadboard
- Jumper kablolar
- Harici 5V güç kaynağı (servo için önerilir)
Gerekli Kütüphaneler
BLEDevice.h, BLEServer.h, BLEUtils.h, BLE2902.h, BLESecurity.h (hepsi ESP32 Arduino core'un dahili 'ESP32 BLE Arduino' kütüphanesiyle gelir). ESP32Servo (>= 3.0, standart Servo.h yerine ESP32'de bu tercih edilmeli çünkü klasik Servo.h ESP32 ile tam uyumlu değildir).
Pin Bağlantıları
| Bileşen Pini | Bağlantı |
|---|---|
| Servo sinyal | GPIO13 |
| Servo VCC | 5V (VIN, harici kaynak önerilir) |
| Servo GND | GND |
| Durum LED anot (220Ω) | GPIO4 |
| LED katot | GND |
Devre Şeması
ESP32 Kodu
| 1 | #include <BLEDevice.h> |
| 2 | #include <BLEServer.h> |
| 3 | #include <BLEUtils.h> |
| 4 | #include <BLE2902.h> |
| 5 | #include <BLESecurity.h> |
| 6 | #include <ESP32Servo.h> |
| 7 | |
| 8 | #define SERVIS_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" |
| 9 | #define KOMUT_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" |
| 10 | |
| 11 | Servo kilitServo; |
| 12 | const int SERVO_PIN = 13, LED = 4; |
| 13 | bool kilitAcik = false; |
| 14 | |
| 15 | class KomutCallback : public BLECharacteristicCallbacks { |
| 16 | void onWrite(BLECharacteristic* karakteristik) override { |
| 17 | String deger = karakteristik->getValue().c_str(); |
| 18 | // Bağlantı zaten bonding ile şifreli/doğrulanmış olduğu için (aşağıdaki |
| 19 | // güvenlik ayarları sayesinde) buraya sadece eşleşmiş cihazlardan gelen |
| 20 | // komutlar ulaşabilir. |
| 21 | if (deger == "AC") { |
| 22 | kilitServo.write(90); // kilidi aç pozisyonu |
| 23 | kilitAcik = true; |
| 24 | digitalWrite(LED, HIGH); |
| 25 | Serial.println("Kilit AÇILDI (doğrulanmış istemciden)."); |
| 26 | } else if (deger == "KAPAT") { |
| 27 | kilitServo.write(0); // kilitli pozisyon |
| 28 | kilitAcik = false; |
| 29 | digitalWrite(LED, LOW); |
| 30 | Serial.println("Kilit KAPATILDI."); |
| 31 | } |
| 32 | } |
| 33 | }; |
| 34 | |
| 35 | class SunucuCallback : public BLEServerCallbacks { |
| 36 | void onConnect(BLEServer* sunucu) override { Serial.println("İstemci bağlandı, eşleştirme bekleniyor..."); } |
| 37 | void onDisconnect(BLEServer* sunucu) override { |
| 38 | Serial.println("İstemci ayrıldı, tekrar reklam (advertising) başlatılıyor."); |
| 39 | BLEDevice::startAdvertising(); |
| 40 | } |
| 41 | }; |
| 42 | |
| 43 | void setup() { |
| 44 | Serial.begin(115200); |
| 45 | pinMode(LED, OUTPUT); |
| 46 | kilitServo.attach(SERVO_PIN); |
| 47 | kilitServo.write(0); // başlangıçta kilitli |
| 48 | |
| 49 | BLEDevice::init("DevreAI-AkilliKilit"); |
| 50 | |
| 51 | // --- Güvenlik: bonding + MITM koruması ZORUNLU kılınıyor --- |
| 52 | BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); |
| 53 | BLESecurity* guvenlik = new BLESecurity(); |
| 54 | guvenlik->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND); // Secure Connections + bonding |
| 55 | guvenlik->setCapability(ESP_IO_CAP_NONE); // "Just Works" eşleştirme (ekransız cihazlar için) |
| 56 | guvenlik->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); |
| 57 | |
| 58 | BLEServer* sunucu = BLEDevice::createServer(); |
| 59 | sunucu->setCallbacks(new SunucuCallback()); |
| 60 | |
| 61 | BLEService* servis = sunucu->createService(SERVIS_UUID); |
| 62 | BLECharacteristic* karakteristik = servis->createCharacteristic( |
| 63 | KOMUT_UUID, |
| 64 | BLECharacteristic::PROPERTY_WRITE |
| 65 | ); |
| 66 | // ENCRYPTED bayrağı: bu karakteristiğe yazma İŞLEMİ şifreli bağlantı |
| 67 | // olmadan REDDEDİLİR — sahte/eşleşmemiş bir cihaz komut gönderemez. |
| 68 | karakteristik->setAccessPermissions(ESP_GATT_PERM_WRITE_ENCRYPTED); |
| 69 | karakteristik->setCallbacks(new KomutCallback()); |
| 70 | |
| 71 | servis->start(); |
| 72 | BLEDevice::startAdvertising(); |
| 73 | Serial.println("BLE akıllı kilit hazır, eşleştirme bekleniyor..."); |
| 74 | } |
| 75 | |
| 76 | void loop() { |
| 77 | delay(1000); // tüm mantık callback'lerde, loop() boş kalabilir |
| 78 | } |
Çalışma Açıklaması
ESP_IO_CAP_NONE 'Just Works' eşleştirme yöntemidir — kullanıcıdan PIN girmesi istemez ama yine de trafiği şifreler; PIN korumalı gerçek kimlik doğrulama için ESP_IO_CAP_OUT ile 6 haneli bir kod üretip kullanıcıya (örn. bir ekran veya Serial üzerinden) gösterecek şekilde genişletilebilir. setAccessPermissions(ESP_GATT_PERM_WRITE_ENCRYPTED) satırı bu projenin güvenlik temelidir — kaldırılırsa herkes şifrelemesiz olarak komut yazabilir hale gelir, bu yüzden üretimde asla çıkarılmamalıdır.
Test Bilgisi
Kodu yükleyin. Telefonda 'nRF Connect' (Android/iOS) uygulamasıyla 'DevreAI-AkilliKilit' cihazını tarayıp bağlanın; telefon ilk bağlantıda eşleştirme (pairing/bonding) isteği göstermeli, onaylayın. Bağlandıktan sonra KOMUT_UUID karakteristiğine 'AC' yazın; servo dönmeli ve LED yanmalı. Telefonu eşleştirmeden (bonding yapmadan) veya farklı, eşleşmemiş bir telefondan yazmaya çalıştığınızda işlemin reddedildiğini de ayrıca doğrulayarak güvenlik katmanının gerçekten çalıştığından emin olun.
Olası Sorunlar ve Çözümleri
Eşleştirme sürekli başarısız oluyorsa: telefonun Bluetooth ayarlarından ESP32 ile önceki eşleştirme kayıtlarını silip (unpair) yeniden deneyin, bozuk bir bonding kaydı bağlantıyı takılı bırakabilir. Servo titriyor veya güç kesiliyor gibi davranıyorsa: servo'yu ESP32'nin 5V pininden değil harici bir 5V kaynaktan besleyin, ESP32'nin dahili regülatörü servo çekiş akımına yetmez. 'onWrite hiç tetiklenmiyor' sorunu yaşıyorsanız: karakteristik UUID'sinin istemci tarafında (nRF Connect) birebir doğru girildiğinden emin olun, UUID'ler büyük/küçük harfe duyarlı değildir ama tire/karakter hataları sık yapılan bir yazım hatasıdır.
Alternatif Çözümler
Sabit 'AC'/'KAPAT' string komutları yerine, her açılışta değişen zaman damgalı bir HMAC imzası kullanılarak replay-attack (kaydedilmiş komutu tekrar oynatma) saldırılarına karşı ek koruma eklenebilir. Tek bir kilide birden fazla yetkili telefon eklemek isteyenler ESP32 tarafında bir 'yetkili cihaz listesi' (bonded device whitelist) tutabilir. BLE'ye ek olarak proje #01'deki gibi bir uygulama üzerinden uzaktan (WiFi ile) da kilit açma eklenerek, telefon Bluetooth menzilinin dışındayken de erişim sağlayan hibrit bir sistem kurulabilir.
Benzer Projeler
ESPAsyncWebServer ile Bloklamayan Çoklu İstemci REST API
Birden fazla tarayıcı veya istemcinin aynı anda, birbirini bloklamadan bağlanıp iki rölenin durumunu okuyup değiştirebildiği asenkron (event-driven) bir REST API sunmayı öğretir — akıllı ev panelleri ve endüstriyel kontrol arayüzlerinde tercih edilen mimarinin küçük ölçekli bir örneğidir. ESPAsyncWebServer, gelen her isteği ayrı ayrı bekletmeden (non-blocking) LwIP ağ yığınıyla doğrudan çalışır; bunun için ESP32'nin ikinci çekirdeği ve yeterli RAM'i (520KB SRAM) devreye girer. Bu mimari Arduino Uno'da kurulamaz: WiFi donanımı yoktur; harici bir WiFi shield eklense bile klasik senkron 'WiFiServer' modeli her isteği sırayla işler ve 2KB RAM, birden fazla eşzamanlı bağlantı arabelleğini aynı anda tutmaya yetmez.
ESP32-CAM ile Edge AI Yüz/Nesne Tanıma (ESP-WHO)
Kameradan alınan görüntü üzerinde, veriyi buluta göndermeden doğrudan cihaz üzerinde (edge AI) yüz tespiti yapmayı öğretir; Espressif'in ESP-WHO/esp-dl çerçevesi, kamera modülünün PSRAM'ini kullanarak görüntü karelerini tamponlayıp önceden eğitilmiş küçük bir sinir ağı modelini gerçek zamanlı çalıştırır. ESP32-CAM'in özel kamera arayüzü (DVP) ve harici PSRAM çipi, görüntü karelerini ve model ağırlıklarını aynı anda bellekte tutabilecek kapasiteyi sağlar. Bu tür bir işlem Arduino Uno'da gerçekleştirilemez: kamera bağlamak için gereken paralel DVP arayüzü hiç yoktur, PSRAM'i yoktur ve 2KB dahili RAM'i tek bir düşük çözünürlüklü görüntü karesini bile tutmaya yetmez — bir yapay sinir ağı modelini çalıştırmak ise bambaşka bir kapasite gerektirir.
ESP-NOW ile Kendini Onaran (Self-Healing) Mesh Ağı
ESP32'nin WiFi çipi üzerinde çalışan, yönlendiriciye (router) hiç ihtiyaç duymayan özel ve düşük gecikmeli P2P protokolü ESP-NOW ile, bir düğüm arızalanırsa diğer düğümlerin otomatik olarak birbirinin üzerinden veri yönlendirdiği (mesh) bir ağ kurmayı öğretir — router'ın menzili dışındaki alanlara veri ulaştırmak isteyen sensör ağları için pratik ve dayanıklı bir çözümdür. ESP-NOW, Espressif'in WiFi radyosuna gömülü, bağlantısız (connectionless) özel bir protokoldür ve her cihaz aynı anda hem alıcı hem verici (peer) olabilir. Bu iletişim yöntemi Arduino Uno'da kullanılamaz: ESP-NOW, ESP32/ESP8266'nın WiFi radyo çipine gömülü donanımsal bir özelliktir; Uno'da hiçbir radyo çipi bulunmadığından mesh kurmak bir yana, tek bir ESP-NOW paketi bile gönderilip alınamaz.