Note: This project is actively maintained and supports both iOS and Android platforms! 🛠️
-
Cross-Platform Support 📱
- Full support for both iOS and Android
- Consistent API across platforms
- Unified error handling and reporting
-
Robust Error Handling 🛡️
- Detailed error messages and codes
- Platform-specific error details
- Easy error recovery mechanisms
- Comprehensive error documentation
-
Fully Async API 🔄
- Wraps closures and handles multiple callback invocations
- Clean and modern Swift-based implementation
-
Nitro Architecture ⚡
- Direct Swift execution without Objective-C intermediaries
- Optimized performance and reduced overhead
-
New Architecture Compatible 🏗️
- Supports synchronous JS execution
- Future-proof design
-
Layered API Design 🎯
- Direct native API access for maximum control
- Separated hooks for modular usage
- High-level hooks for quick implementation
- Documentation coming soon
-
Multiple Provisioning Methods 📡
- SoftAP support
- BLE support
- Security levels 0, 1, and 2
-
Enhanced Stability 🛡️
- Patches and workarounds for Espressif library limitations
- Improved reliability and performance
- React Native 0.78.0 or higher
- iOS: Xcode 14.0 or higher
- Android: Android Studio with NDK support
- Node.js 16 or higher
yarn add react-native-esp-prov-toolkit
# or
npm install react-native-esp-prov-toolkit
yarn add react-native-nitro-modules@^0.25.2
# or
npm install react-native-nitro-modules@^0.25.2
- Run pod install:
cd ios && pod install
-
Add the following capabilities to your Xcode project:
- Hotspot Configuration
- Access WiFi Information
-
Add the following keys to your
Info.plist
:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Connect with BLE Compatible devices for Provisioning</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Connect with BLE Compatible devices for Provisioning</string>
<key>NSLocalNetworkUsageDescription</key>
<string>This app needs access to your local network to discover ESP devices</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need this to access WiFi iface</string>
- Add the following to your
android/build.gradle
:
allprojects {
repositories {
// ... other repositories
maven { url 'https://jitpack.io' }
}
}
- Add the following permissions to your
AndroidManifest.xml
:
<!-- Request legacy Bluetooth permissions on older devices. -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- BLE -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Needed for SSID monitoring and Wifi Scanning & Configuring -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
import { useSoftapProvisioning, PTSecurity } from 'react-native-esp-prov-toolkit';
// Define your device prefix (e.g., "ESP_")
const DEVICE_PREFIX = "ESP_";
// Helper function to handle location permission denial
const alertForLocationPermissions = () => {
Alert.alert(
'Location Permission',
'This app needs location services to work.',
[
{ text: 'Settings', onPress: () => Linking.openSettings() },
{ text: 'OK', style: 'default' }
]
);
};
function ProvisionScreen() {
const {
provState: currentState,
provError,
wifiList,
provisionDevice,
} = useSoftapProvisioning(
10000, // scanInterval (ms)
10000, // promptTimeoutMs
DEVICE_PREFIX, // devicePrefix
PTSecurity.SECURITY_0, // security level
undefined, // username (optional)
undefined, // proofOfPossession (optional)
undefined, // softAPPassword (optional)
alertForLocationPermissions // onLocationPermDenied callback
);
const handleProvision = async (ssid: string, password: string) => {
try {
await provisionDevice(ssid, password);
// Handle success
} catch (error) {
// Handle error
}
};
// Render different states based on currentState:
// - 'searching': Initial state, waiting for device
// - 'connecting': Connecting to device
// - 'connected': Connected, ready to provision
// - 'provisioning': Currently provisioning
// - 'success': Provisioning successful
// - 'failure': Provisioning failed
}
The provisioning process follows these steps:
- Connect to the ESP device's SoftAP network from your phone's WiFi settings
- The library will automatically detect and connect to the device
- Once connected, you can scan for available WiFi networks
- Select a network and provide credentials
- The device will be provisioned with the selected network
// Search for ESP devices with given prefix
searchForESPDevices(
devicePrefix: string,
transport: PTTransport,
security: PTSecurity
): Promise<string[]>
// Create a new ESP device instance
createESPDevice(
deviceName: string,
transport: PTTransport,
security: PTSecurity,
proofOfPossession?: string,
softAPPassword?: string,
username?: string
): Promise<void>
// Check if a device exists
doesESPDeviceExist(deviceName: string): boolean
// Get device information
getESPDevice(deviceName: string): PTDevice | undefined
// Connect to an ESP device
connectToESPDevice(deviceName: string): Promise<PTSessionStatus>
// Disconnect from an ESP device
disconnectFromESPDevice(deviceName: string): void
// Check if session is established
isESPDeviceSessionEstablished(deviceName: string): boolean
// Scan for available WiFi networks
scanWifiListOfESPDevice(deviceName: string): Promise<PTWifiEntry[]>
// Provision device with WiFi credentials
provisionESPDevice(
deviceName: string,
ssid: string,
password: string
): Promise<PTProvisionStatus>
// Get current network SSID
getCurrentNetworkSSID(): string | undefined
// Get device's IPv4 address
getIPv4AddressOfESPDevice(deviceName: string): string | undefined
// Request location permission
requestLocationPermission(): void
// Get current location permission status
getCurrentLocationStatus(): PTLocationAccess
// Register callback for location status changes
registerLocationStatusCallback(
callback: (access: PTLocationAccess) => boolean
): number
// Remove location status callback
removeLocationStatusCallback(id: number): boolean
enum PTSecurity {
SECURITY_0 = 0,
SECURITY_1 = 1,
SECURITY_2 = 2
}
enum PTTransport {
TRANSPORT_SOFTAP = 0,
TRANSPORT_BLE = 1
}
enum PTSessionStatus {
CONNECTED = 0,
DISCONNECTED = 1,
CHECK_MANUALLY = 2
}
enum PTProvisionStatus {
SUCCESS = 0,
CONFIG_APPLIED = 1
}
enum PTLocationAccess {
DENIED = 0,
GRANTED = 1,
LIMITED = 2
}
All API functions throw PTException
with specific error codes that can be translated to human-readable messages using getErrorDescription(error: PTError): string
.
- ✅ iOS support available
- ✅ Android support available
- 🔄 Active maintenance and updates
The Espressif libraries present some architectural challenges:
- Limited access to internal components (private/fileprivate)
- Architectural limitations that prevent direct fixes
- No ability to extend certain critical components
We've implemented workarounds to ensure stability and functionality. However, if there's community interest, we're open to creating a new branch where we can:
- Rewrite the iOS/Android libraries from scratch
- Implement proper fixes at the root level
- Create a more maintainable and extensible solution
-
Bluetooth Adapter Issues 📱
- Hangs when Bluetooth adapter is killed from settings during operation (both iOS and Android)
- iOS: Prompts and hangs if Bluetooth is off in settings
- Android: Fails with native error if Bluetooth is off in settings
- Connect → Disconnect → Connect cycles can cause failures due to Bluetooth adapter object reuse
-
Prevent Hangs ⏱️
- Race every operation's promise with a timeout to prevent hanging
- Example:
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Operation timed out')), 5000) ); await Promise.race([operation, timeout]);
-
Device Instance Management 🔄
- Create new device instances for each provisioning cycle
- Follow this pattern: Create → Connect → Scan → Provision
- Do not reuse device instances after completing operations
- Always include the create step in each cycle
-
CI/CD Improvements 🔄
- Fix iOS CI pipeline
- Add CI jobs for example project testing
- Install and run example project on iOS
- Install and run example project on Android
-
Bluetooth Enhancements 📱
- Add BLE adapter status check
- Raise appropriate exceptions when adapter is off
- Improve BLE permission error handling in iOS
- Fix permission annotations on Android
- Add BLE adapter status check
- Community-driven improvements
- Potential ground-up rewrite based on community interest
This project is licensed under the MIT License - see the LICENSE file for details.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is actively maintained and developed. Stay tuned for updates! 🎉