Skip to content

Instantly share code, notes, and snippets.

@brennanMKE
Created July 19, 2024 18:52
Show Gist options
  • Save brennanMKE/fd7c942bb6881cde44269756b94709a3 to your computer and use it in GitHub Desktop.
Save brennanMKE/fd7c942bb6881cde44269756b94709a3 to your computer and use it in GitHub Desktop.
Passing WiFi credentials over Bluetooth

Passing WiFi credentials over Bluetooth

The following prompt was sent to ChatGPT.

Please help me with networking using an ESP32. I use PlatformIO in VS Code for my IDE and I'd like to give my program WiFi credentials but not include the password in source control. What I'd like to consider doing is leveraging BLE on the device so that I can run a program on my Mac which would scan for BLE devices which need WiFi credentials and share with them. I'd want to write this program in Swift with Xcode on macOS. Can you help me with how to get my ESP32 to use BLE to be discoverable when so it can get WiFi credentials and also the command-line app built in Swift?

Sure, let's break this down into two main parts:

  1. Configuring the ESP32 to use BLE for receiving WiFi credentials.
  2. Creating a command-line application in Swift on macOS to send WiFi credentials to the ESP32 via BLE.

Part 1: Configuring the ESP32 to use BLE for Receiving WiFi Credentials

1.1 Setting Up PlatformIO and ESP32 BLE Library

First, ensure you have the ESP32 and BLE libraries installed in your PlatformIO project. Add these dependencies to your platformio.ini file:

[env:esp32]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps = 
    ESPAsyncWebServer
    NimBLE-Arduino

1.2 Writing the ESP32 Code

Here's an example of how to set up the ESP32 to be discoverable via BLE and receive WiFi credentials:

#include <Arduino.h>
#include <WiFi.h>
#include <NimBLEDevice.h>

#define SERVICE_UUID        "12345678-1234-1234-1234-123456789abc"
#define CHARACTERISTIC_UUID "87654321-4321-4321-4321-cba987654321"

class MyCallbacks : public NimBLECharacteristicCallbacks {
    void onWrite(NimBLECharacteristic* pCharacteristic) {
        std::string value = pCharacteristic->getValue();
        int separator = value.find(":");
        if (separator != std::string::npos) {
            String ssid = value.substr(0, separator).c_str();
            String password = value.substr(separator + 1).c_str();
            Serial.println("Received WiFi credentials:");
            Serial.print("SSID: ");
            Serial.println(ssid);
            Serial.print("Password: ");
            Serial.println(password);
            WiFi.begin(ssid.c_str(), password.c_str());
        }
    }
};

void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);

    // Initialize BLE
    NimBLEDevice::init("ESP32_BLE");
    NimBLEServer *pServer = NimBLEDevice::createServer();
    NimBLEService *pService = pServer->createService(SERVICE_UUID);
    NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                             CHARACTERISTIC_UUID,
                                             NIMBLE_PROPERTY::WRITE);
    pCharacteristic->setCallbacks(new MyCallbacks());
    pService->start();
    NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(SERVICE_UUID);
    pAdvertising->start();
}

void loop() {
    // Keep BLE running
    delay(1000);
}

Part 2: Creating a Command-Line Application in Swift

2.1 Setting Up the Swift Project

Open Xcode and create a new Command Line Tool project in Swift.

2.2 Importing CoreBluetooth

Add the CoreBluetooth framework to your project. In your main.swift, implement the BLE scanning and communication:

import Foundation
import CoreBluetooth

class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
    var centralManager: CBCentralManager!
    var targetPeripheral: CBPeripheral?
    var writeCharacteristic: CBCharacteristic?

    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            centralManager.scanForPeripherals(withServices: [CBUUID(string: "12345678-1234-1234-1234-123456789abc")], options: nil)
        } else {
            print("Bluetooth is not available.")
        }
    }

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        targetPeripheral = peripheral
        centralManager.stopScan()
        centralManager.connect(peripheral, options: nil)
    }

    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices([CBUUID(string: "12345678-1234-1234-1234-123456789abc")])
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        if let services = peripheral.services {
            for service in services {
                peripheral.discoverCharacteristics([CBUUID(string: "87654321-4321-4321-4321-cba987654321")], for: service)
            }
        }
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        if let characteristics = service.characteristics {
            for characteristic in characteristics {
                if characteristic.uuid == CBUUID(string: "87654321-4321-4321-4321-cba987654321") {
                    writeCharacteristic = characteristic
                    let credentials = "Your_SSID:Your_Password"
                    if let data = credentials.data(using: .utf8) {
                        peripheral.writeValue(data, for: characteristic, type: .withResponse)
                    }
                }
            }
        }
    }
}

let manager = BLEManager()
RunLoop.main.run()

Summary

  • The ESP32 code sets up a BLE service and characteristic to receive WiFi credentials.
  • The Swift code scans for the ESP32 BLE device, connects to it, and sends the WiFi credentials.

This setup will help you manage WiFi credentials securely without hardcoding them in your ESP32 source code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment