ESP32 ile akıllı akü şarj sistemi-BLE

👤 Yazar: ozcan 📅 Tarih: 01.06.2026 22:07 👁️ Görüntüleme: 14

ESP32 ile Akıllı Akü Şarj Kontrolü (Donanım Seviyesi BLE Şifrelemeli)

Windows 11 mimarisinde Bluetooth LE cihazları eşleştirilirken, işletim sistemi sürücü seviyesinde otomatik doğrulama ("Just Works") yaparak şifre sorma ekranını bypass edebilmektedir. Bu projede, Windows'un otomatik şifre onaylama açıklarını doğrudan ESP32'nin Bluetooth register (kayıtçı) seviyesinde kapatan, kullanıcıyı donanımsal olarak altı haneli sabit şifre (passkey) girmeye mecbur bırakan ve tarama esnasında çift cihaz görünmesini engelleyen kararlı şarj kontrol sistemini ele alıyoruz.

DONANIMSAL GÜVENLİK NOTU: Cihaza bilgisayarınızdan veya akıllı telefonunuzdan ilk kez bağlanmaya çalıştığınızda işletim sistemi otomatik eşleşmeyi durduracak ve sizden boş bir PIN kutusuna şifre girmenizi isteyecektir. Bu projenin donanıma kazınmış sabit eşleşme kodu 123456 olarak belirlenmiştir.

Öne Çıkan Özellikler

Bağlantı ve Test Nasıl Yapılır?

  1. Aşağıdaki kaynak kodu Arduino IDE üzerinden ESP32 kartınıza yükleyin.
  2. Windows 11 cihazınızda Ayarlar, Bluetooth ve Cihazlar, Cihaz Ekle menüsüne gidin. (Eğer eski başarısız denemeler varsa listeden mutlaka kaldırın).
  3. Listede tek bir tane net olarak görünen Yenidir_BMS_BLE cihazına tıklayın.
  4. Ekrana zorla getirilen boş şifre kutusuna 123456 yazarak donanımsal eşleşmeyi tamamlayın.
  5. Verileri izlemek ve komut göndermek için Bluetooth LE Explorer veya herhangi bir BLE Terminal yazılımı kullanarak Servis UUID ve Karakteristik kanallarına abone (Subscribe) olun.

Projenin ESP32 Kaynak Kodu

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

#define SERVICE_UUID           "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID_RX "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define CHARACTERISTIC_UUID_TX "d2a21e42-cb31-4ee5-bc95-0e6e76cf0e33"

BLEServer* pServer = NULL;
BLECharacteristic* pTxCharacteristic = NULL;
bool cihazBagli = false;

const int voltajPin = 34; 
const int akimPin   = 35; 
const int pwmPin    = 25; 

const int pwmFrekans = 5000;
const int pwmCozunurluk = 8; 
int pwmDuty = 0;

const int filtreKatsayisi = 10;
float voltajDizi[filtreKatsayisi] = {0};
float akimDizi[filtreKatsayisi] = {0};
int filtreIndex = 0;

int aktifMod = 1;              
float hedonSarjAkimi = 3.0;    
float limitUstVolt = 14.4;     
float limitAltVolt = 12.3;     
float limitDevamVolt = 13.8;   

bool mod1DolduMu = false;
bool mod2BeklemedeMi = false;

String gelenVeri = "";

float gercekVoltajOku() {
  int hamDeger = analogRead(voltajPin);
  float analogVolt = (hamDeger * 3.3) / 4095.0;
  return analogVolt * 5.0; 
}

float gercekAkimOku() {
  int hamDeger = analogRead(akimPin);
  float analogVolt = (hamDeger * 3.3) / 4095.0;
  return (analogVolt - 2.5) / 0.066; 
}

class YenidirServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      cihazBagli = true;
      Serial.println("Sistem: Bir cihaz BLE ile baglandi.");
    }
    void onDisconnect(BLEServer* pServer) {
      cihazBagli = false;
      Serial.println("Sistem: Cihaz baglantisi kesildi. Tekrar yayin yapiliyor...");
      pServer->getAdvertising()->start();
    }
};

class KomutYakalayici: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      String rxDeger = pCharacteristic->getValue();
      if (rxDeger.length() > 0) {
        gelenVeri = rxDeger;
        gelenVeri.trim();
        Serial.print("BLE'den Gelen: "); Serial.println(gelenVeri);
      }
    }
};

class BLEGuvenlikYoneticisi : public BLESecurityCallbacks {
    uint32_t onPassKeyRequest() {
        Serial.println("BLE Donanim Guvenligi: Passkey talep edildi!");
        return 123456; 
    }
    void onPassKeyNotify(uint32_t pass_key) {
        Serial.print("BLE Donanim Guvenligi: Ekranda gosterilmesi gereken PIN: ");
        Serial.println(pass_key);
    }
    bool onSecurityRequest() { 
        return true; 
    }
    void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) {
        if (cmpl.success) {
            Serial.println("BLE Donanim Guvenligi: DONANIMSAL ESLESME BASARILI!");
        } else {
            Serial.println("BLE Donanim Guvenligi: DONANIMSAL SIFRE HATALI VEYA REDDEDILDI!");
        }
    }
};

void setup() {
  Serial.begin(115200);
  
  BLEDevice::init("Yenidir_BMS_BLE");
  BLEDevice::setSecurityCallbacks(new BLEGuvenlikYoneticisi());

  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new YenidirServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);

  pTxCharacteristic = pService->createCharacteristic(
                        CHARACTERISTIC_UUID_TX,
                        BLECharacteristic::PROPERTY_READ | 
                        BLECharacteristic::PROPERTY_NOTIFY |
                        BLECharacteristic::PROPERTY_READ_ENC
                      );
  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
                        CHARACTERISTIC_UUID_RX,
                        BLECharacteristic::PROPERTY_WRITE |
                        BLECharacteristic::PROPERTY_WRITE_ENC
                      );
  pRxCharacteristic->setCallbacks(new KomutYakalayici());

  pService->start();

  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false); 
  
  BLESecurity *pSecurity = new BLESecurity();
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
  pSecurity->setCapability(ESP_IO_CAP_OUT);
  pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);

  uint32_t sabitSifre = 123456;
  esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &sabitSifre, sizeof(uint32_t));

  BLEDevice::startAdvertising();
  Serial.println("Yenidir BMS Baslatildi. Donanimsal Kilit Kodu 123456 olarak sabitlendi!");

  ledcAttach(pwmPin, pwmFrekans, pwmCozunurluk);
}

void loop() {
  if (gelenVeri != "") {
    if (gelenVeri.startsWith("MOD:")) {
      aktifMod = gelenVeri.substring(4).toInt();
      mod1DolduMu = false; mod2BeklemedeMi = false; pwmDuty = 0;
      Serial.print("Sistem: MOD DEGISTI -> "); Serial.println(aktifMod);
    }
    else if (gelenVeri.startsWith("AKIM:")) {
      hedonSarjAkimi = gelenVeri.substring(5).toFloat();
    }
    else if (gelenVeri.startsWith("UST:")) {
      limitUstVolt = gelenVeri.substring(4).toFloat();
    }
    else if (gelenVeri.startsWith("ALT:")) {
      limitAltVolt = gelenVeri.substring(4).toFloat();
    }
    else if (gelenVeri.startsWith("DEVAM:")) {
      limitDevamVolt = gelenVeri.substring(6).toFloat();
    }
    gelenVeri = ""; 
  }

  voltajDizi[filtreIndex] = gercekVoltajOku();
  akimDizi[filtreIndex] = gercekAkimOku();
  filtreIndex = (filtreIndex + 1) % filtreKatsayisi;

  float filtreliVolt = 0; float filtreliAkim = 0;
  for (int i = 0; i < filtreKatsayisi; i++) {
    filtreliVolt += voltajDizi[i]; filtreliAkim += akimDizi[i];
  }
  filtreliVolt /= filtreKatsayisi; filtreliAkim /= filtreKatsayisi;

  if (aktifMod == 1) {
    if (!mod1DolduMu) {
      if (filtreliVolt >= limitUstVolt) mod1DolduMu = true; 
      else {
        if (filtreliAkim < hedonSarjAkimi && pwmDuty < 255) pwmDuty++;
        if (filtreliAkim > hedonSarjAkimi && pwmDuty > 0)   pwmDuty--;
      }
    } else {
      if (filtreliVolt < limitDevamVolt && pwmDuty < 255) pwmDuty++;
      if (filtreliVolt > limitDevamVolt && pwmDuty > 0)   pwmDuty--;
    }
  }
  else if (aktifMod == 2) {
    if (!mod2BeklemedeMi) {
      if (filtreliVolt >= limitUstVolt) { mod2BeklemedeMi = true; pwmDuty = 0; } 
      else {
        if (filtreliAkim < hedonSarjAkimi && pwmDuty < 255) pwmDuty++;
        if (filtreliAkim > hedonSarjAkimi && pwmDuty > 0)   pwmDuty--;
      }
    } else {
      pwmDuty = 0; 
      if (filtreliVolt <= limitAltVolt) mod2BeklemedeMi = false; 
    }
  }
  else if (aktifMod == 3) {
    if (filtreliVolt < limitDevamVolt && pwmDuty < 255) pwmDuty++;
    if (filtreliVolt > limitDevamVolt && pwmDuty > 0)   pwmDuty--;
  }

  ledcWrite(pwmPin, pwmDuty);

  static unsigned long sonRaporZamani = 0;
  if (millis() - sonRaporZamani >= 2000) {
    sonRaporZamani = millis();
    
    String rapor = "V:" + String(filtreliVolt, 2) + 
                   " A:" + String(filtreliAkim, 2) + 
                   " M:" + String(aktifMod) + 
                   " P:" + String(pwmDuty) + "\n";
    
    Serial.print(rapor);
    
    if (cihazBagli) {
      pTxCharacteristic->setValue(rapor.c_str());
      pTxCharacteristic->notify(); 
    }
  }
  delay(10); 
}
    

💬 Yorumlar

Henüz yorum yapılmamış. İlk yorumu siz yapın!

Bir Yorum Bırakın

Güvenlik Kontrolü:

Yenidir.com
Sayfa Başı
Yenidir CMS V0.1