averyhome/quicklink

1.0.2

Latest
uploaded 1 day ago
Simple BLE WiFi Provisioning Component for ESP32. Enables secure WiFi credential provisioning via Bluetooth Low Energy with ECDH key exchange and AES-GCM encryption. Supports BLE-only mode for WiFi-less ESP32 variants.

readme

# QuickLink - Simple BLE WiFi Provisioning Component

QuickLink is a lightweight, easy-to-use BLE WiFi provisioning component for ESP32 family microcontrollers. It enables simple and secure WiFi credential provisioning through Bluetooth Low Energy (BLE).

## Features

- **BLE-based WiFi Provisioning** - Configure WiFi credentials via BLE without needing pre-configured credentials
- **ECDH Encryption** - Secure credential transmission with ECDH key exchange and AES-GCM encryption
- **BLE-Only Mode** - Works on WiFi-less ESP32 variants (ESP32-C2, etc.)
- **Multi-device Support** - Handle multiple device connections simultaneously
- **Battery Service** - Built-in BLE Battery Service support
- **Real-time Logging** - Stream device logs via BLE to mobile clients
- **Device Information Service** - Standard BLE device info (manufacturer, model, firmware, etc.)
- **Minimal Dependencies** - Only requires NimBLE, mbedTLS, and NVS Flash

## Air Link iOS App - Quick WiFi Provisioning via BLE

<p align="center">
  <img src="images/6-5%20Template%2054.png" width="250" alt="App Screenshot 1"/>
  <img src="images/6-5%20Template%2055.png" width="250" alt="App Screenshot 2"/>
  <img src="images/6-5%20Template%2056.png" width="250" alt="App Screenshot 3"/>
</p>

Use the Air Link iOS app to easily provision WiFi credentials to your ESP32 device via BLE. Simply scan for your device, connect, and configure WiFi settings securely.

## Supported Targets

- ESP32
- ESP32-S2
- ESP32-S3
- ESP32-C2
- ESP32-C3
- ESP32-C6

## Installation

Add QuickLink to your project's `idf_component.yml`:

```yaml
dependencies:
  quicklink:
    git: "https://github.com/averyhome/quicklink.git"
    version: "^1.0.2"
```

Then rebuild your project:

```bash
idf.py build
```

## Quick Start

### 1. Basic Example

```c
#include "quicklink.h"

static void event_handler(quicklink_event_t event, void *data, void *ctx)
{
    switch (event) {
        case QUICKLINK_EVENT_STARTED:
            ESP_LOGI(TAG, "QuickLink started");
            break;
        case QUICKLINK_EVENT_BLE_CONNECTED:
            ESP_LOGI(TAG, "BLE client connected");
            break;
        case QUICKLINK_EVENT_CRED_RECEIVED:
            ESP_LOGI(TAG, "WiFi credentials received");
            break;
        case QUICKLINK_EVENT_WIFI_CONNECTED:
            ESP_LOGI(TAG, "WiFi connected successfully");
            break;
        case QUICKLINK_EVENT_WIFI_FAILED:
            ESP_LOGE(TAG, "WiFi connection failed");
            break;
        case QUICKLINK_EVENT_STOPPED:
            ESP_LOGI(TAG, "QuickLink stopped");
            break;
        default:
            break;
    }
}

void app_main(void) {
    quicklink_config_t config = {
        .device_name = "MyDevice",
        .enable_wifi_provisioning = true,
        .ble_auto_stop = false,
        .event_cb = event_handler,
        .user_ctx = NULL,
    };
    
    quicklink_status_t ret = quicklink_start(&config);
    if (ret != QUICKLINK_OK) {
        ESP_LOGE(TAG, "Failed to start QuickLink: %d", ret);
        return;
    }
}
```

### 2. Full-Featured Example

With Device Info, Battery Service, and Custom GATT Service:

```c
#include "quicklink.h"
#include "host/ble_uuid.h"
#include "host/ble_gatt.h"

/* Custom Service UUID: 12345678-1234-1234-1234-123456789abc */
static const ble_uuid128_t custom_svc_uuid =
    BLE_UUID128_INIT(0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x34, 0x12,
                     0x34, 0x12, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);

/* Custom Characteristic UUID: 12345678-1234-1234-1234-123456789abd */
static const ble_uuid128_t custom_chr_uuid =
    BLE_UUID128_INIT(0xbd, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x34, 0x12,
                     0x34, 0x12, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);

static uint8_t custom_data[20] = "Hello QuickLink!";

/* Custom characteristic access callback */
static int custom_chr_access(uint16_t conn_handle, uint16_t attr_handle,
                             struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
        return os_mbuf_append(ctxt->om, custom_data, sizeof(custom_data)) == 0 
               ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
    } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
        uint16_t len = OS_MBUF_PKTLEN(ctxt->om);
        if (len > sizeof(custom_data)) len = sizeof(custom_data);
        ble_hs_mbuf_to_flat(ctxt->om, custom_data, len, NULL);
        ESP_LOGI(TAG, "Custom data written: %s", custom_data);
        return 0;
    }
    return BLE_ATT_ERR_UNLIKELY;
}

/* Define custom GATT service */
static const struct ble_gatt_svc_def custom_services[] = {
    {
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = &custom_svc_uuid.u,
        .characteristics = (struct ble_gatt_chr_def[]) {
            {
                .uuid = &custom_chr_uuid.u,
                .access_cb = custom_chr_access,
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
            },
            {0}
        }
    },
    {0}
};

void app_main(void)
{
    /* Define device information */
    static const quicklink_device_info_t device_info = {
        .manufacturer = "YourCompany",
        .model = "YourModel",
        .serial = "SN20240101001",
        .hw_version = "1.0",
        .fw_version = "1.0.0"
    };

    /* Configure QuickLink with all features */
    quicklink_config_t config = {
        .device_name = "MyDevice",
        .event_cb = event_handler,
        .user_ctx = NULL,
        .ble_auto_stop = false,
        .enable_wifi_provisioning = true,
        .device_info = &device_info,        /* Enable Device Info Service */
        .custom_services = custom_services  /* Add custom GATT services */
    };

    quicklink_status_t ret = quicklink_start(&config);
    if (ret != QUICKLINK_OK) {
        ESP_LOGE(TAG, "Failed to start QuickLink: %d", ret);
        return;
    }

    /* Update battery level periodically */
    uint8_t battery = 100;
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10000));
        battery = (battery > 20) ? (battery - 5) : 100;
        quicklink_set_battery_level(battery);
    }
}
```

### 3. Configuration Options

Enable/disable features via `menuconfig`:

```bash
idf.py menuconfig
# Navigate to Component Config → QuickLink
```

**QUICKLINK_ENABLE_WIFI** (default: enabled)
- Enable WiFi provisioning functionality
- Disable for BLE-only builds on WiFi-less chips

**QUICKLINK_STRIP_DEBUG** (default: enabled)
- Strip debug symbols to reduce binary size and protect code

**QUICKLINK_WIFI_MAX_RETRY** (default: 5)
- Maximum WiFi connection retry attempts

## API Reference

### Configuration

```c
typedef struct {
    const char *device_name;                    // BLE device name (required)
    quicklink_event_cb_t event_cb;              // Event callback
    void *user_ctx;                             // User context
    bool ble_auto_stop;                         // Auto-stop BLE after WiFi connected
    bool enable_wifi_provisioning;              // Enable WiFi provisioning
    const quicklink_device_info_t *device_info; // Optional device info
    const void *custom_services;                // Optional custom GATT services
} quicklink_config_t;
```

### Core Functions

```c
// Start QuickLink service
quicklink_status_t quicklink_start(const quicklink_config_t *config);

// Stop both BLE and WiFi
quicklink_status_t quicklink_stop(void);

// Stop only BLE (keep WiFi connected)
quicklink_status_t quicklink_stop_ble(void);

// Check if running
bool quicklink_is_running(void);

// Check WiFi connection status
bool quicklink_is_wifi_connected(void);

// Set battery level (0-100%)
void quicklink_set_battery_level(uint8_t level);

// Send log message via BLE
void quicklink_send_log(const char *message);

// Reset BLE identity
quicklink_status_t quicklink_reset_ble_identity(void);
```

## Events

```c
typedef enum {
    QUICKLINK_EVENT_STARTED,         // Service started
    QUICKLINK_EVENT_STOPPED,         // Service stopped
    QUICKLINK_EVENT_BLE_STOPPED,     // BLE stopped (WiFi continues)
    QUICKLINK_EVENT_BLE_CONNECTED,   // BLE client connected
    QUICKLINK_EVENT_BLE_DISCONNECTED,// BLE client disconnected
    QUICKLINK_EVENT_CRED_RECEIVED,   // WiFi credentials received
    QUICKLINK_EVENT_WIFI_CONNECTING, // WiFi connecting
    QUICKLINK_EVENT_WIFI_CONNECTED,  // WiFi connected
    QUICKLINK_EVENT_WIFI_FAILED,     // WiFi failed
} quicklink_event_t;
```

## BLE Services and Characteristics

### QuickLink Provisioning Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)

| UUID | Type | Direction | Purpose |
|------|------|-----------|---------|
| 6e400002 | WRITE | Client → Device | WiFi SSID |
| 6e400003 | WRITE | Client → Device | WiFi Password (plaintext, deprecated) |
| 6e400004 | READ/NOTIFY | Device → Client | Connection Status |
| 6e400005 | READ | Device → Client | Server Public Key (ECDH) |
| 6e400006 | WRITE | Client → Device | Client Public Key (ECDH) |
| 6e400007 | WRITE | Client → Device | Encrypted Password |
| 6e400008 | NOTIFY | Device → Client | Log Output |

### Standard Services

- **Device Information Service (0x180A)** - Manufacturer, model, serial, hardware/firmware version
- **Battery Service (0x180F)** - Battery level reporting

## Examples

See the `examples/` folder for complete example projects:

- **basic** - Simple WiFi provisioning example
- **advanced** - Full-featured example with logging and device info

## Troubleshooting

### "WiFi provisioning disabled by Kconfig" warning

WiFi support is disabled. Set `CONFIG_QUICKLINK_ENABLE_WIFI=y` in menuconfig for WiFi functionality, or use BLE-only mode by setting it to `n`.

### Device not appearing in BLE scan

Ensure:
1. BLE is enabled: `CONFIG_BT_ENABLED=y`
2. NimBLE is enabled: `CONFIG_BT_NIMBLE_ENABLED=y`
3. Device has sufficient free heap memory
4. Bluetooth permissions are granted on mobile device

### WiFi connection fails

1. Check SSID and password are correct
2. Verify WiFi network is 2.4GHz (most ESP32s don't support 5GHz)
3. Check WiFi signal strength at device location
4. Review logs: `idf.py monitor`

## License

Proprietary - See LICENSE file for details

## Support

For issues, questions, or feedback, please visit:
- GitHub Issues: https://github.com/averyhome/quicklink/issues
- Documentation: https://github.com/averyhome/quicklink/wiki

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for version history and updates.

Links

Supports all targets

License: Custom

To add this component to your project, run:

idf.py add-dependency "averyhome/quicklink^1.0.2"

download archive

Stats

  • Archive size
    Archive size ~ 749.81 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

averyhome/quicklink version: 1.0.2
|