### ESPDevice Initialization Example Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Demonstrates how to create an ESPDevice instance using the secure2 scheme and BLE transport. ```swift let device = ESPDevice( name: "ESP32-Device", security: .secure2, transport: .ble, proofOfPossession: "12345678", username: "admin" ) ``` -------------------------------- ### Install via CocoaPods Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/README.md Add the library to your project using the Podfile. ```ruby pod 'ESPProvision' ``` -------------------------------- ### Install CocoaPods dependencies Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/Example/ESPProvisionSample/README.md Run this command in the ESPProvisionSample directory to install the required ESPProvision dependency. ```bash pod install ``` -------------------------------- ### Install via Swift Package Manager Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/README.md Add the library as a dependency in your Package.swift file. ```swift dependencies: [ .package(url: "https://github.com/espressif/esp-idf-provisioning-ios.git", from: "2.1.1") ] ``` -------------------------------- ### ESPBleTransport Initialization Example Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Demonstrates how to initialize an ESPBleTransport instance with scan timeout, device name prefix, and optional proof of possession. ```swift let bleTransport = ESPBleTransport( scanTimeout: 5.0, deviceNamePrefix: "ESP-", proofOfPossession: "1234" ) ``` -------------------------------- ### Example: Scan and Print Wi-Fi Networks Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/04-types.md Demonstrates how to use `ESPDevice.scanWifiList()` to discover Wi-Fi networks and print their details. Ensure the device object is available and initialized. ```swift device.scanWifiList { networks, error in guard let networks = networks else { return } for network in networks { print("SSID: \(network.ssid)") print("Signal: \(network.rssi) dBm") print("Auth: \(network.auth)") print("Channel: \(network.channel)") } } ``` -------------------------------- ### HTTP Exchange Example Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Illustrates a typical HTTP POST request and response exchange for session data over SoftAP. Includes headers and body content. ```http POST /prov-session HTTP/1.1 Host: 192.168.4.1 Content-Type: application/x-www-form-urlencoded [encrypted handshake data] HTTP/1.1 200 OK Content-Type: text/plain Set-Cookie: [encrypted response data] ``` -------------------------------- ### Info.plist WifiBaseUrl Setting Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Example of how to configure the WifiBaseUrl in the Info.plist file. This setting determines the default base URL for connecting to an ESP device. ```xml WifiBaseUrl 192.168.4.1:80 ``` -------------------------------- ### Handling ESPProvisionError during Wi-Fi Provisioning Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/05-errors.md Demonstrates how to handle specific ESPProvisionError cases when provisioning a device over Wi-Fi. This example shows how to differentiate between common Wi-Fi related errors like authentication and network not found. ```swift device.provision(ssid: "MyNetwork", passPhrase: "password") { status in switch status { case .success: print("Device connected successfully") case .configApplied: print("Configuration sent; waiting for connection...") case .failure(let error): if let provError = error as? ESPProvisionError { switch provError { case .wifiStatusAuthenticationError: print("Invalid password - please verify credentials") case .wifiStatusNetworkNotFound: print("Network not found - check SSID spelling") case .configurationError(let underlyingError): print("Config failed: \(underlyingError)") default: print("Provisioning failed: \(error.description)") } } } } ``` -------------------------------- ### Example QR Code JSON Format Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/04-types.md Illustrates the expected JSON format for QR code data used in device provisioning. This format includes essential parameters for connecting to a device. ```json { "name": "ESP-Device", "transport": "ble", "security": 2, "pop": "abcd1234", "username": "admin", "network": "wifi" } ``` -------------------------------- ### Handling ESPSessionError during Session Initialization Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/05-errors.md Example of how to handle various ESPSessionError cases when initializing a session with a device. This includes checking for specific errors like noPOP, securityMismatch, and versionInfoError. ```swift device.initialiseSession(sessionPath: nil) { status in switch status { case .connected: print("Session established") case .failedToConnect(let error): if let sessionError = error as? ESPSessionError { switch sessionError { case .noPOP: print("Proof of Possession required") case .securityMismatch: print("Security scheme mismatch - check device configuration") case .versionInfoError(let underlyingError): print("Failed to get device info: \(underlyingError)") default: print("Session failed: \(error.description)") } } case .disconnected: print("Device disconnected") } } ``` -------------------------------- ### Verify Wi-Fi Connection and Get IP Address Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/09-wifi-provisioning.md After provisioning, this code checks for successful connection and retrieves the device's IP address. The IP address can then be used for direct communication with the device. ```swift device.provision(ssid: "MyNetwork", passPhrase: "secret") { status in if status == .success { if let ipAddress = device.wifiConnectedIp4Addr() { print("Device is now connected at: \(ipAddress)") // Can use ipAddress for direct HTTP communication } } } ``` -------------------------------- ### Provide Proof of Possession Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/09-wifi-provisioning.md Implement the `getProofOfPossesion` delegate method to return the Proof of Possession, typically from a QR code or stored value. This example returns a hardcoded string. ```swift func getProofOfPossesion( forDevice: ESPDevice, completionHandler: @escaping (String) -> Void ) { // Return the PoP from QR code or stored value completionHandler("1234") } ``` -------------------------------- ### Scan QR Code for Device Info Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/02-espprovisionmanager.md Starts a QR code scan using the device's camera, displaying the preview within a provided UIView. It extracts device information from the QR code and provides status updates during the scanning process. Requires camera permissions in Info.plist. ```swift let scanView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300)) self.view.addSubview(scanView) ESPProvisionManager.shared.scanQRCode( scanView: scanView, completionHandler: { device, error in if let error = error { print("QR scan failed: \(error.description)") return } guard let device = device else { return } print("Scanned device: \(device.name)") // Proceed to connect }, scanStatus: { status in switch status { case .scanStarted: print("Camera started") case .readingCode: print("Reading QR code...") case .searchingBLE(let name): print("Searching for BLE device: \(name)") case .joiningSoftAP(let name): print("Joining SoftAP: \(name)") } } ) ``` -------------------------------- ### Complete Provisioning Flow with Error Handling Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/05-errors.md This snippet demonstrates a complete provisioning flow including device discovery, connection, session initialization, and provisioning, with comprehensive error handling at each step. It also includes the implementation of the ESPDeviceConnectionDelegate for handling security credentials. ```swift ESPProvisionManager.shared.searchESPDevices( devicePrefix: "ESP-", transport: .ble, security: .secure2 ) { devices, error in guard let device = devices?.first else { if let error = error { print("Discovery failed: \(error.description)") } return } // 2. Connect device.delegate = self device.connect { status in guard case .connected = status else { if case .failedToConnect(let error) = status { print("Connection failed: \(error.description)") } return } // 3. Initialize session device.initialiseSession(sessionPath: nil) { status in guard case .connected = status else { if case .failedToConnect(let error) = status { print("Session failed: \(error.description)") } return } // 4. Provision device.provision(ssid: "HomeNetwork", passPhrase: "password123") { status in switch status { case .success: print("Provisioning successful") case .configApplied: print("Configuration applied; connecting...") case .failure(let error): print("Provisioning error: \(error.description)") } } } } } // Implement delegate for credentials extension MyViewController: ESPDeviceConnectionDelegate { func getProofOfPossesion( forDevice: ESPDevice, completionHandler: @escaping (String) -> Void ) { // Return PoP from user input or stored value completionHandler("1234") } func getUsername( forDevice: ESPDevice, completionHandler: @escaping (String?) -> Void ) { // Return username for Security 2 completionHandler("admin") } } ``` -------------------------------- ### scan Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Starts scanning for BLE devices matching a specified name prefix. ```APIDOC ## scan ### Description Initiates a Bluetooth Low Energy scan to discover devices whose names start with a given prefix. The scan results are delivered via the provided delegate. ### Method `func scan(delegate: ESPBLETransportDelegate)` ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - **delegate** (`ESPBLETransportDelegate`) - Required - The delegate that will receive scan results. ### Request Example ```swift bleTransport.scan(delegate: self) ``` ### Response - None (scan results are delivered asynchronously to the delegate) ### Delegate Callbacks - `peripheralsFound(peripherals:)`: Called when one or more devices matching the name prefix are found. The `peripherals` parameter is a dictionary mapping device names to `ESPD`evice objects. - `peripheralsNotFound(serviceUUID:)`: Called if no devices matching the criteria are found. ``` -------------------------------- ### ESP Device Security Property Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Gets or sets the security scheme configured for the device. This can be modified before establishing a connection. ```swift public var security: ESPSecurity ``` -------------------------------- ### Provision Device via QR Code Scan Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/11-quick-reference.md This pattern shows how to initiate device provisioning by scanning a QR code. It handles the QR code scanning process, device connection, session establishment, and subsequent Wi-Fi provisioning. ```swift ESPProvisionManager.shared.scanQRCode( scanView: scanView, completionHandler: { device, error in guard let device = device else { return } device.delegate = self device.connect { status in guard case .connected = status else { return } device.initialiseSession(sessionPath: nil) { status in guard case .connected = status else { return } device.provision(ssid: "MyWifi", passPhrase: "pass") { status in if case .success = status { print("✓ Provisioned") } } } } }, scanStatus: { status in switch status { case .scanStarted: print("Camera started") case .readingCode: print("Reading QR...") case .searchingBLE(let name): print("Searching \(name)") case .joiningSoftAP(let ssid): print("Joining \(ssid)") } } ) ``` -------------------------------- ### ESPDevice Initialization Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Initializes a new ESPDevice instance with specified parameters for connection and security. ```swift public init( name: String, security: ESPSecurity, transport: ESPTransport, proofOfPossession: String? = nil, username: String? = nil, network: ESPNetworkType? = nil, softAPPassword: String? = nil, advertisementData: [String: Any]? = nil ) ``` -------------------------------- ### Get Username for Device Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/10-thread-provisioning.md Implements the ESPDeviceConnectionDelegate method to provide a hardcoded username. This is called during the provisioning process to establish a user session. ```swift func getUsername( forDevice: ESPDevice, completionHandler: @escaping (String?) -> Void ) { completionHandler("admin") } ``` -------------------------------- ### scan Method Signature Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Starts a BLE scan for devices matching a specific name prefix. Requires a delegate to receive scan results. ```swift func scan(delegate: ESPBLETransportDelegate) ``` -------------------------------- ### Initialize ESPSecurity2 Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/08-security.md Instantiate ESPSecurity2 with username, password, and an optional flag for device firmware patch version support. ```swift init(username: String, password: String, useCounterFlag: Bool = false) ``` ```swift let security = ESPSecurity2( username: "admin", password: "12345678", useCounterFlag: true ) ``` -------------------------------- ### ESPScanStatus Enumeration Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/04-types.md Represents intermediate stages of QR code scanning, including scan started, reading code, searching BLE, and joining SoftAP. ```APIDOC ## ESPScanStatus ### Description Represents intermediate stages of QR code scanning. ### Enum ```swift public enum ESPScanStatus { case scanStarted case readingCode case searchingBLE(String) case joiningSoftAP(String) } ``` ### Cases - `.scanStarted`: Camera initialization started. - `.readingCode`: QR code being parsed. - `.searchingBLE(String)`: Searching for BLE device by name. Associated value is the device name. - `.joiningSoftAP(String)`: Connecting to SoftAP Wi-Fi network. Associated value is the SSID. ### Usage Used in optional `scanStatus` callback in `ESPProvisionManager.scanQRCode()`. ``` -------------------------------- ### ESPDevice Initialization Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Initializes a new ESPDevice instance with specified security, transport, and optional parameters. ```APIDOC ## init(name:security:transport:proofOfPossession:username:network:softAPPassword:advertisementData:) ### Description Initializes a new ESPDevice instance. ### Parameters #### Path Parameters - #### Query Parameters - #### Request Body - ### Parameters - **name** (`String`) - Required - Device name or SSID - **security** (`ESPSecurity`) - Required - Security scheme: `.unsecure`, `.secure`, or `.secure2` - **transport** (`ESPTransport`) - Required - Transport type: `.ble` or `.softap` - **proofOfPossession** (`String?`) - Optional - Proof of Possession (required for secure schemes) - **username** (`String?`) - Optional - Username (used with Security 2) - **network** (`ESPNetworkType?`) - Optional - Network type: `.wifi` or `.thread` - **softAPPassword** (`String?`) - Optional - SoftAP network password - **advertisementData** (`[String:Any]?`) - Optional - BLE advertisement data dictionary ### Request Example ```swift let device = ESPDevice( name: "ESP32-Device", security: .secure2, transport: .ble, proofOfPossession: "12345678", username: "admin" ) ``` ### Response #### Success Response (200) - #### Response Example - ``` -------------------------------- ### Provision Device on Thread Network Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/11-quick-reference.md This pattern illustrates provisioning an ESP device onto a Thread network using a pre-loaded Thread Operational Dataset. It follows the standard connection and session establishment steps before initiating Thread provisioning. ```swift // Load dataset let dataset = try Data(contentsOf: datasetURL) // Connect device (same as Wi-Fi) device.connect(delegate: self) { status in guard case .connected = status else { return } device.initialiseSession(sessionPath: nil) { status in guard case .connected = status else { return } // Provision with Thread device.provision( ssid: nil, passPhrase: "", threadOperationalDataset: dataset ) { status in if case .success = status { print("✓ Attached to Thread network") } } } } ``` -------------------------------- ### Provide Username for Security 2 Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/09-wifi-provisioning.md Implement the `getUsername` delegate method for Security 2 authentication, returning the username. This example returns a hardcoded username. ```swift func getUsername( forDevice: ESPDevice, completionHandler: @escaping (String?) -> Void ) { // For Security 2 completionHandler("admin") } ``` -------------------------------- ### ESPSession Integration Pattern Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/06-session.md Illustrates the typical workflow for establishing and using an ESPSession for device provisioning. This includes selecting the security scheme, creating the session, initializing the handshake, and performing encrypted data transfer. ```swift // 1. Create session with appropriate security layer switch securityScheme { case .secure2: securityLayer = ESPSecurity2(username: username, password: pop) case .secure: securityLayer = ESPSecurity1(proofOfPossession: pop) case .unsecure: securityLayer = ESPSecurity0() } // 2. Create session session = ESPSession(transport: selectedTransport, security: securityLayer) // 3. Initialize handshake session.initialize(response: nil, sessionPath: nil) { error in if error == nil && session.isEstablished { // Session ready for provisioning } } // 4. Use session for encrypted communication let encryptedData = session.securityLayer.encrypt(data: configData) session.transportLayer.SendConfigData(path: path, data: encryptedData) { response, error in let decryptedResponse = session.securityLayer.decrypt(data: response) } ``` -------------------------------- ### initialiseSession Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Establishes a secure session with the device via a security handshake. This method must be called after `connect()` completes successfully. ```APIDOC ## initialiseSession ### Description Establishes a secure session with the device via security handshake. ### Method `initialiseSession` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **sessionPath** (`String?`) - Optional - Custom session endpoint path (nil uses default) - **completionHandler** (closure) - Required - Called when session initialization completes ### Returns None (completion handler called asynchronously) ### ESPSessionStatus values - `.connected` — Session established - `.failedToConnect(ESPSessionError)` — Session initialization failed - `.disconnected` — Unexpected disconnection ### Possible ESPSessionError values - `.sessionInitError` — Handshake failed - `.securityMismatch` — Security scheme mismatch - `.noPOP` — Proof of Possession not provided - `.noUsername` — Username not provided (Security 2) - `.versionInfoError` — Failed to get device version ### Example ```swift device.initialiseSession(sessionPath: nil) { status in switch status { case .connected: print("Session established") // Now safe to call provision() or sendData() case .failedToConnect(let error): print("Session failed: \(error.description)") default: break } } ``` ### Notes - Must be called after `connect()` completes successfully - Determines the actual security scheme from device version info - Automatically selects appropriate security layer (Security 0, 1, or 2) ``` -------------------------------- ### Get Proof of Possession for Device Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/10-thread-provisioning.md Implements the ESPDeviceConnectionDelegate method to provide a hardcoded proof of possession string. This is called during the provisioning process to authenticate the device. ```swift func getProofOfPossesion( forDevice: ESPDevice, completionHandler: @escaping (String) -> Void ) { completionHandler("1234") } ``` -------------------------------- ### Swift Thread Provisioning Workflow Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/10-thread-provisioning.md This Swift class implements the full Thread provisioning workflow for an ESP device. It handles loading the Thread dataset, discovering and connecting to the device via BLE, initializing a secure session, checking for Thread support, scanning for existing Thread networks, and provisioning the device with a provided dataset. Ensure the 'thread_dataset.bin' file is present in the app's bundle. ```swift class ThreadProvisioningViewController: UIViewController, ESPDeviceConnectionDelegate { var device: ESPDevice? var threadDataset: Data? @IBOutlet weak var statusLabel: UILabel! // MARK: - User Actions @IBAction func startThreadProvisioning() { loadThreadDataset() searchDevice() } // MARK: - Step 1: Load Dataset private func loadThreadDataset() { guard let datasetPath = Bundle.main.path(forResource: "thread_dataset", ofType: "bin") else { updateStatus("❌ Thread dataset file not found") return } do { threadDataset = try Data(contentsOf: URL(fileURLWithPath: datasetPath)) updateStatus("✓ Dataset loaded (\(threadDataset?.count ?? 0) bytes)") } catch { updateStatus("❌ Failed to load dataset: \(error.localizedDescription)") } } // MARK: - Step 2-3: Device Discovery & Connection private func searchDevice() { guard threadDataset != nil else { updateStatus("❌ No Thread dataset loaded") return } updateStatus("Searching for devices...") ESPProvisionManager.shared.searchESPDevices( devicePrefix: "ESP-", transport: .ble, security: .secure2 ) { devices, error in guard let device = devices?.first else { self.updateStatus("❌ No devices found") return } self.device = device self.connectToDevice() } } private func connectToDevice() { updateStatus("Connecting to device...") device?.delegate = self device?.connect { status in switch status { case .connected: self.initializeSession() case .failedToConnect(let error): self.updateStatus("❌ Connection failed: \(error.description)") case .disconnected: self.updateStatus("❌ Device disconnected") } } } private func initializeSession() { updateStatus("Establishing secure session...") device?.initialiseSession(sessionPath: nil) { status in switch status { case .connected: self.checkThreadCapability() case .failedToConnect(let error): self.updateStatus("❌ Session failed: \(error.description)") case .disconnected: self.updateStatus("❌ Device disconnected") } } } // MARK: - Step 4: Check Thread Capability private func checkThreadCapability() { guard let capabilities = device?.capabilities else { self.updateStatus("❌ Could not read device capabilities") return } if capabilities.contains("thread_scan") { updateStatus("✓ Device supports Thread") scanThreadNetworks() } else { updateStatus("❌ Device does not support Thread provisioning") } } private func scanThreadNetworks() { updateStatus("Scanning for Thread networks...") device?.scanThreadList { networks, error in if let error = error { self.updateStatus("❌ Scan failed: \(error.description)") return } guard let networks = networks, !networks.isEmpty else { self.updateStatus("⚠ No Thread networks found") self.provisionWithDataset() return } // Display found networks self.updateStatus("✓ Found \(networks.count) Thread networks") for network in networks { print("Network: \(network.networkName), Channel: \(network.channel), RSSI: \(network.rssi)") } // Proceed with provisioning using our dataset self.provisionWithDataset() } } // MARK: - Step 5: Provision with Dataset private func provisionWithDataset() { guard let dataset = threadDataset else { updateStatus("❌ Thread dataset not loaded") return } updateStatus("Provisioning device with Thread dataset...") device?.provision( ssid: nil, passPhrase: "", threadOperationalDataset: dataset ) { status in switch status { case .success: self.provisioningSucceeded() case .configApplied: self.updateStatus("Configuration applied, waiting for attachment...") case .failure(let error): self.handleThreadError(error) } } } // MARK: - Error Handling private func updateStatus(_ message: String) { // Update UI with status message print(message) // Placeholder for actual UI update statusLabel.text = message } private func provisioningSucceeded() { updateStatus("✅ Thread provisioning successful!") } private func handleThreadError(_ error: ESPThreadError) { updateStatus("❌ Thread provisioning failed: \(error.description)") } // MARK: - ESPDeviceConnectionDelegate func onDeviceConnectionLost(_ device: ESPDevice!, with error: Error!) { updateStatus("❌ Connection lost: \(error.localizedDescription)") } } ``` -------------------------------- ### Get Device IPv4 Address Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Retrieves the IPv4 address assigned to the device after successful Wi-Fi provisioning. Returns the IP address as a string or nil if the device is not connected. ```swift public func wifiConnectedIp4Addr() -> String? ``` ```swift device.provision(ssid: "MyNetwork", passPhrase: "password") { status in if status == .success { if let ipAddr = device.wifiConnectedIp4Addr() { print("Device IP: \(ipAddr)") } } } ``` -------------------------------- ### ESP Provisioning Capability Strings Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/11-quick-reference.md Lists common capability strings indicating device features for provisioning. ```swift "wifi_scan" // Device supports Wi-Fi network scanning "thread_scan" // Device supports Thread network scanning "no_pop" // Device doesn't require Proof of Possession "no_sec" // Device supports unsecured communication (Security 0) "thread_prov" // Device supports Thread provisioning ``` -------------------------------- ### ESPProvisionManager Methods Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/11-quick-reference.md Provides a list of available methods for managing ESP devices and provisioning. Use these for direct interaction with the provisioning manager. ```swift // Search devices searchESPDevices(devicePrefix:transport:security:completionHandler:) // Scan QR code scanQRCode(scanView:completionHandler:scanStatus:) // Stop scanning stopScan() stopESPDevicesSearch() // Refresh list refreshDeviceList(completionHandler:) // Manual create createESPDevice(deviceName:transport:security:...) // Logging enableLogs(_:) ``` -------------------------------- ### Initialize ESPSecurity0 Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/08-security.md Initializes the unsecured security implementation. Use this when no encryption is needed and the environment is trusted. ```swift let security = ESPSecurity0() ``` -------------------------------- ### Search and Provision Wi-Fi Device Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/11-quick-reference.md This pattern demonstrates the complete workflow for finding a Wi-Fi enabled ESP device, connecting to it, establishing a session, scanning for Wi-Fi networks, and provisioning the device with network credentials. ```swift // 1. Search ESPProvisionManager.shared.searchESPDevices( devicePrefix: "ESP-", transport: .ble, security: .secure2 ) { devices, error in let device = devices?.first // 2. Connect device?.connect(delegate: self) { status in guard case .connected = status else { return } // 3. Session device?.initialiseSession(sessionPath: nil) { status in guard case .connected = status else { return } // 4. Scan networks device?.scanWifiList { networks, error in // Show networks to user... // 5. Provision device?.provision(ssid: "MyWifi", passPhrase: "pass") { status in if case .success = status { print("✓ Provisioned") } device?.disconnect() } } } } } // Implement delegate extension ViewController: ESPDeviceConnectionDelegate { func getProofOfPossesion(forDevice: ESPDevice, completionHandler: @escaping (String) -> Void) { completionHandler("1234") } func getUsername(forDevice: ESPDevice, completionHandler: @escaping (String?) -> Void) { completionHandler("admin") } } ``` -------------------------------- ### Provisioning Success Handler Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/09-wifi-provisioning.md Handles the success case of provisioning, updating the status with the device's IP address if available, or a general success message. Includes a cleanup step to disconnect the device after a delay. ```swift private func provisioningSucceeded() { if let ipAddr = device?.wifiConnectedIp4Addr() { updateStatus("✓ Success! Device connected at \(ipAddr)") } else { updateStatus("✓ Device provisioning complete") } // Cleanup DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { self.device?.disconnect() } } ``` -------------------------------- ### connect Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Initiates a connection to a specific BLE peripheral. ```APIDOC ## connect ### Description Initiates a connection to a BLE peripheral. The connection attempt has a timeout of 20 seconds. ### Method `func connect(peripheral: CBPeripheral, withAdvertisementData advertisementData: [String: Any]?, withOptions options: [String: Any]?, delegate: ESPBLEStatusDelegate)` ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - **peripheral** (`CBPeripheral`) - Required - The BLE peripheral to connect to. - **withAdvertisementData** (`[String:Any]?`) - Optional - Advertisement data obtained during device discovery. - **withOptions** (`[String:Any]?`) - Optional - Connection options, passed directly to `CBCentralManager`. - **delegate** (`ESPBLEStatusDelegate`) - Required - Delegate to receive connection status callbacks. ### Request Example ```swift let options: [String: Any]? = nil bleTransport.connect(peripheral: discoveredPeripheral, withAdvertisementData: advData, withOptions: options, delegate: self) ``` ### Response - None (connection is asynchronous and status is reported via delegate callbacks) ### Delegate Callbacks - `peripheralConnected()`: Called when the connection is successfully established. - `peripheralFailedToConnect(peripheral:error:)`: Called if the connection attempt fails. - `peripheralDisconnected(peripheral:error:)`: Called if the connection is lost after being established. ``` -------------------------------- ### provision Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Sends Wi-Fi or Thread network credentials to the device. The completion handler is called when provisioning completes, indicating success, configuration applied, or failure with a specific error. ```APIDOC ## provision ### Description Sends Wi-Fi or Thread network credentials to the device. ### Method Signature ```swift public func provision( ssid: String?, passPhrase: String? = "", threadOperationalDataset: Data? = nil, completionHandler: @escaping (ESPProvisionStatus) -> Void ) ``` ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None (parameters are passed directly to the function) ### Parameters Details - **ssid** (`String?`) - Optional - SSID of Wi-Fi network to connect to. - **passPhrase** (`String?`) - Optional, defaults to `""` - Password for Wi-Fi network. - **threadOperationalDataset** (`Data?`) - Optional, defaults to `nil` - Thread dataset binary for Thread provisioning. - **completionHandler** (`closure`) - Required - Called when provisioning completes. ### Returns None (completion handler called asynchronously) ### ESPProvisionStatus Values - `.success` — Device successfully connected to network - `.configApplied` — Configuration sent, awaiting connection status - `.failure(ESPProvisionError)` — Provisioning failed with specific error ### Possible ESPProvisionError Values - `.sessionError` — Session not established - `.configurationError(Error)` — Failed to send config - `.wifiStatusError(Error)` — Failed to query Wi-Fi status - `.wifiStatusDisconnected` — Device Wi-Fi disconnected - `.wifiStatusAuthenticationError` — Invalid credentials - `.wifiStatusNetworkNotFound` — SSID not found - `.wifiStatusUnknownError` — Unknown Wi-Fi error - `.threadStatusError(Error)` — Thread status query failed - `.threadStatusDettached` — Thread not attached - `.threadDatasetInvalid` — Invalid Thread dataset - `.threadStatusNetworkNotFound` — Thread network not found - `.threadStatusUnknownError` — Unknown Thread error ### Request Example - Wi-Fi Provisioning ```swift device.provision(ssid: "MyNetwork", passPhrase: "password123") { status in switch status { case .success: print("Device successfully connected to Wi-Fi") case .configApplied: print("Configuration sent, waiting for connection") case .failure(let error): print("Provisioning failed: \(error.description)") } } ``` ### Request Example - Thread Provisioning ```swift let datasetBytes = Data([/* Thread dataset bytes */]) device.provision(ssid: nil, threadOperationalDataset: datasetBytes) { status in switch status { case .success: print("Device successfully attached to Thread network") case .failure(let error): print("Thread provisioning failed: \(error.description)") } } ``` ### Notes - Session must be established first (call `initialiseSession()`) - For Wi-Fi: Pass `ssid` and `passPhrase` - For Thread: Pass `threadOperationalDataset` instead - Automatically polls device for connection status after applying configuration - Retries connection once if network disconnection is detected during provisioning ``` -------------------------------- ### Provision Wi-Fi and Thread Network Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/10-thread-provisioning.md A device can simultaneously support both Wi-Fi and Thread. Provision the Wi-Fi network first, then provision the Thread network using the operational dataset. ```swift // Device can run both Wi-Fi and Thread simultaneously device.provision(ssid: "HomeWifi", passPhrase: "password") { wifiStatus in // Wi-Fi provisioning... } // And later... device.provision(ssid: nil, threadOperationalDataset: threadDataset) { threadStatus in // Thread provisioning... } ``` -------------------------------- ### createESPDevice Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/02-espprovisionmanager.md Manually creates an ESPDevice instance without discovery. ```APIDOC ## createESPDevice ### Description Manually creates an ESPDevice instance without discovery. ### Method public func createESPDevice( deviceName: String, transport: ESPTransport, security: ESPSecurity = .secure2, proofOfPossession: String? = nil, softAPPassword: String? = nil, username: String? = nil, network: ESPNetworkType? = nil, completionHandler: @escaping (ESPDevice?, ESPDeviceCSSError?) -> Void ) ### Parameters #### Path Parameters (none) #### Query Parameters (none) #### Request Body - **deviceName** (String) - Required - Name of the ESP device - **transport** (ESPTransport) - Required - Transport type: `.ble` or `.softap` - **security** (ESPSecurity) - Optional - Security scheme (defaults to `.secure2`) - **proofOfPossession** (String?) - Optional - Proof of Possession string (required for secure schemes) - **softAPPassword** (String?) - Optional - SoftAP network password (if transport is `.softap`) - **username** (String?) - Optional - Username for Security 2 - **network** (ESPNetworkType?) - Optional - Network type: `.wifi` or `.thread` ### Response #### Success Response (200) None (completion handler called asynchronously) ### Response Example ```swift // Create SoftAP device ESPProvisionManager.shared.createESPDevice( deviceName: "ESP-DEVICE", transport: .softap, security: .secure2, proofOfPossession: "1234", softAPPassword: "espressif", username: "admin" ) { device, error in if let error = error { print("Device creation failed: \(error.description)") return } guard let device = device else { return } print("Device created: \(device.name)") // Proceed to connect } // Create BLE device ESPProvisionManager.shared.createESPDevice( deviceName: "ESP-BLE-001", transport: .ble, security: .secure, proofOfPossession: "abcd1234" ) { device, error in if let device = device { print("BLE device created: \(device.name)") } } ``` **Notes**: - For BLE transport, the device will be searched for by name - For SoftAP, the device is created immediately - The SoftAP password should be empty string if the network is open ``` -------------------------------- ### connect Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Establishes a connection with the ESP device. This method can be used for both BLE and SoftAP connections. The completion handler is called on the main thread. ```APIDOC ## connect ### Description Establishes a connection with the ESP device. ### Method `connect` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **delegate** (`ESPDeviceConnectionDelegate?`) - Optional - Delegate for security credentials - **completionHandler** (closure) - Required - Called when connection completes ### Returns None (completion handler called asynchronously) ### ESPSessionStatus values - `.connected` — Connection successful - `.failedToConnect(ESPSessionError)` — Connection failed with specific error - `.disconnected` — Device disconnected ### Example ```swift device.connect { status in switch status { case .connected: print("Device connected successfully") device.initialiseSession(sessionPath: nil) { sessionStatus in // Handle session initialization } case .failedToConnect(let error): print("Connection failed: \(error.description)") case .disconnected: print("Device disconnected") } } // Implement delegate methods extension MyClass: ESPDeviceConnectionDelegate { func getProofOfPossesion(forDevice: ESPDevice, completionHandler: @escaping (String) -> Void) { completionHandler("1234") } func getUsername(forDevice: ESPDevice, completionHandler: @escaping (String?) -> Void) { completionHandler("admin") } } ``` ### Notes - For BLE: Initiates Bluetooth connection to peripheral - For SoftAP: Connects to Wi-Fi network using system APIs - Completion handler is called on main thread ``` -------------------------------- ### connect Method Signature Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/07-transport.md Initiates a connection to a BLE peripheral. Requires a delegate for connection status callbacks. Connection timeout is 20 seconds. ```swift func connect( peripheral: CBPeripheral, withAdvertisementData advertisementData: [String: Any]?, withOptions options: [String: Any]?, delegate: ESPBLEStatusDelegate ) ``` -------------------------------- ### Connect to ESP Device Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/03-espdevice.md Establishes a connection with the ESP device. Implement the ESPDeviceConnectionDelegate for security credentials. The completion handler is called on the main thread. ```swift open func connect( delegate: ESPDeviceConnectionDelegate? = nil, completionHandler: @escaping (ESPSessionStatus) -> Void ) ``` ```swift device.delegate = self device.connect { status in switch status { case .connected: print("Device connected successfully") device.initialiseSession(sessionPath: nil) { sessionStatus in // Handle session initialization } case .failedToConnect(let error): print("Connection failed: \(error.description)") case .disconnected: print("Device disconnected") } } ``` ```swift extension MyClass: ESPDeviceConnectionDelegate { func getProofOfPossesion(forDevice: ESPDevice, completionHandler: @escaping (String) -> Void) { completionHandler("1234") } func getUsername(forDevice: ESPDevice, completionHandler: @escaping (String?) -> Void) { completionHandler("admin") } } ``` -------------------------------- ### Complete Wi-Fi Provisioning Workflow in Swift Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/09-wifi-provisioning.md This Swift code implements a full Wi-Fi provisioning flow for ESP-IDF devices on iOS. It handles device searching, connection, session establishment, Wi-Fi network scanning, user network selection (including manual entry), and the final provisioning step. ```swift class WiFiProvisioningViewController: UIViewController, ESPDeviceConnectionDelegate { var device: ESPDevice? @IBOutlet weak var statusLabel: UILabel! // MARK: - User Actions @IBAction func startProvisioning() { searchDevice() } // MARK: - Provisioning Steps private func searchDevice() { updateStatus("Searching for devices...") ESPProvisionManager.shared.searchESPDevices( devicePrefix: "ESP-", transport: .ble, security: .secure2 ) { devices, error in guard let device = devices?.first else { self.updateStatus("No devices found") return } self.device = device self.connectToDevice() } } private func connectToDevice() { updateStatus("Connecting to device...") device?.delegate = self device?.connect { status in switch status { case .connected: self.initializeSession() case .failedToConnect(let error): self.updateStatus("Connection failed: \(error.description)") case .disconnected: self.updateStatus("Device disconnected") } } } private func initializeSession() { updateStatus("Establishing secure session...") device?.initialiseSession(sessionPath: nil) { status in switch status { case .connected: self.showNetworkSelection() case .failedToConnect(let error): self.updateStatus("Session failed: \(error.description)") case .disconnected: self.updateStatus("Device disconnected") } } } private func showNetworkSelection() { updateStatus("Scanning for Wi-Fi networks...") device?.scanWifiList { networks, error in if let error = error { self.updateStatus("Scan failed: \(error.description)") return } guard let networks = networks else { self.updateStatus("No networks found") return } // Display picker or list for user to select self.displayNetworkPicker(networks: networks) } } private func displayNetworkPicker(networks: [ESPWifiNetwork]) { let controller = UIAlertController( title: "Select Network", message: "Choose Wi-Fi network", preferredStyle: .actionSheet ) for network in networks { controller.addAction(UIAlertAction(title: network.ssid, style: .default) { _ in self.showPasswordPrompt(for: network.ssid) }) } controller.addAction(UIAlertAction(title: "Other Network", style: .default) { _ in self.showManualNetworkEntry() }) present(controller, animated: true) } private func showPasswordPrompt(for ssid: String) { let controller = UIAlertController( title: "Password", message: "Enter Wi-Fi password for \(ssid)", preferredStyle: .alert ) controller.addTextField { field in field.placeholder = "Password" field.isSecureTextEntry = true } controller.addAction(UIAlertAction(title: "Provision", style: .default) { _ in if let password = controller.textFields?.first?.text { self.provisionDevice(ssid: ssid, password: password) } }) present(controller, animated: true) } private func showManualNetworkEntry() { let controller = UIAlertController( title: "Manual Entry", message: "Enter network SSID and password", preferredStyle: .alert ) controller.addTextField { field in field.placeholder = "Network SSID" } controller.addTextField { field in field.placeholder = "Password" field.isSecureTextEntry = true } controller.addAction(UIAlertAction(title: "Provision", style: .default) { _ in if let fields = controller.textFields, let ssid = fields[0].text, let password = fields[1].text { self.provisionDevice(ssid: ssid, password: password) } }) present(controller, animated: true) } private func provisionDevice(ssid: String, password: String) { updateStatus("Provisioning device with Wi-Fi credentials...") device?.provision(ssid: ssid, passPhrase: password) { status in switch status { ``` -------------------------------- ### Create ESPDevice Instance Source: https://github.com/espressif/esp-idf-provisioning-ios/blob/master/_autodocs/02-espprovisionmanager.md Manually creates an ESPDevice instance without performing discovery. Requires specifying device name, transport, and optionally security, proof of possession, and SoftAP password. The completion handler is invoked with the created device or an error. ```swift public func createESPDevice( deviceName: String, transport: ESPTransport, security: ESPSecurity = .secure2, proofOfPossession: String? = nil, softAPPassword: String? = nil, username: String? = nil, network: ESPNetworkType? = nil, completionHandler: @escaping (ESPDevice?, ESPDeviceCSSError?) -> Void ) ``` ```swift // Create SoftAP device ESPProvisionManager.shared.createESPDevice( deviceName: "ESP-DEVICE", transport: .softap, security: .secure2, proofOfPossession: "1234", softAPPassword: "espressif", username: "admin" ) { device, error in if let error = error { print("Device creation failed: \(error.description)") return } guard let device = device else { return } print("Device created: \(device.name)") // Proceed to connect } ``` ```swift // Create BLE device ESPProvisionManager.shared.createESPDevice( deviceName: "ESP-BLE-001", transport: .ble, security: .secure, proofOfPossession: "abcd1234" ) { device, error in if let device = device { print("BLE device created: \(device.name)") } } ```