Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#44, #45): add getters and setters and cleanup #47

Merged
merged 11 commits into from
Jun 10, 2024
232 changes: 198 additions & 34 deletions android/src/main/java/com/espidfprovisioning/EspIdfProvisioningModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,17 @@ import com.facebook.react.bridge.WritableMap
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONException
import org.json.JSONObject
import java.lang.Exception
import java.util.ArrayList
import java.util.Base64


inline fun<T> T?.guard(nullClause: () -> Nothing): T {
return this ?: nullClause()
}

fun BluetoothDevice.isAlreadyConnected(): Boolean {
return try {
javaClass.getMethod("isConnected").invoke(this) as? Boolean? ?: false
Expand Down Expand Up @@ -235,18 +242,19 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon
searchESPDevices(deviceName, transport, security, object : Promise {
override fun resolve(p0: Any?) {
// If search does not find the device, consider it not found
if (espDevices[deviceName] == null) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("Device not found."))
return
}

// Configure proof of possession
espDevices[deviceName]?.proofOfPossession = proofOfPossession
espDevice.proofOfPossession = proofOfPossession
if (username != null) {
espDevices[deviceName]?.userName = username
espDevice.userName = username
}

val result = Arguments.createMap()
result.putString("name", espDevices[deviceName]?.deviceName)
result.putString("name", espDevice.deviceName)
result.putString("transport", transport)
result.putInt("security", security)

Expand Down Expand Up @@ -299,12 +307,12 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon
@SuppressLint("MissingPermission")
@ReactMethod
override fun connect(deviceName: String, promise: Promise?) {
if (espDevices[deviceName] == null) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

if (espDevices[deviceName]?.transportType == ESPConstants.TransportType.TRANSPORT_SOFTAP) {
if (espDevice.transportType == ESPConstants.TransportType.TRANSPORT_SOFTAP) {
// Permission checks
if (!hasWifiPermission() || !hasFineLocationPermission()) {
promise?.reject(Error("Missing one of the following permissions: CHANGE_WIFI_STATE, ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE, ACCESS_FINE_LOCATION"))
Expand All @@ -313,15 +321,15 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon
}

// If device is already connected, exit early
if (espDevices[deviceName]?.transportType == ESPConstants.TransportType.TRANSPORT_BLE &&
espDevices[deviceName]?.bluetoothDevice?.isAlreadyConnected() == true) {
if (espDevice.transportType == ESPConstants.TransportType.TRANSPORT_BLE &&
espDevice.bluetoothDevice?.isAlreadyConnected() == true) {
val result = Arguments.createMap()
result.putString("status", "connected")
promise?.resolve(result)
return
}

espDevices[deviceName]?.connectToDevice()
espDevice.connectToDevice()

EventBus.getDefault().register(object {
@Subscribe(threadMode = ThreadMode.MAIN)
Expand All @@ -348,13 +356,13 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon

@ReactMethod
override fun sendData(deviceName: String, path: String, data: String, promise: Promise?) {
if (espDevices[deviceName] == null) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

val decodedData = Base64.getDecoder().decode(data)
espDevices[deviceName]?.sendDataToCustomEndPoint(path, decodedData, object : ResponseListener {
espDevice.sendDataToCustomEndPoint(path, decodedData, object : ResponseListener {
override fun onSuccess(returnData: ByteArray?) {
val encodedData = Base64.getEncoder().encode(returnData).toString(Charsets.UTF_8)
promise?.resolve(encodedData)
Expand All @@ -366,24 +374,14 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon
})
}

@ReactMethod
override fun getProofOfPossession(deviceName: String, promise: Promise?) {
if (espDevices[deviceName] == null) {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

promise?.resolve(espDevices[deviceName]?.proofOfPossession)
}

@ReactMethod
override fun scanWifiList(deviceName: String, promise: Promise?) {
if (espDevices[deviceName] == null) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

espDevices[deviceName]?.scanNetworks(object : WiFiScanListener {
espDevice.scanNetworks(object : WiFiScanListener {
override fun onWifiListReceived(wifiList: ArrayList<WiFiAccessPoint>?) {
val resultArray = Arguments.createArray()

Expand Down Expand Up @@ -411,12 +409,12 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon

@ReactMethod
override fun provision(deviceName: String, ssid: String, passphrase: String, promise: Promise?) {
if (espDevices[deviceName] == null) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

espDevices[deviceName]!!.provision(ssid, passphrase, object : ProvisionListener {
espDevice.provision(ssid, passphrase, object : ProvisionListener {
override fun createSessionFailed(e: Exception?) {
promise?.reject(e)
}
Expand Down Expand Up @@ -454,21 +452,187 @@ class EspIdfProvisioningModule internal constructor(context: ReactApplicationCon
}

@ReactMethod
override fun initializeSession(deviceName: String, sessionPath: String, promise: Promise?) {
if (espDevices[deviceName] == null) {
override fun getProofOfPossession(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

espDevices[deviceName]?.initSession(object : ResponseListener {
override fun onSuccess(returnData: ByteArray?) {
val encodedData = Base64.getEncoder().encode(returnData)
promise?.resolve(encodedData)
promise?.resolve(espDevice.proofOfPossession)
}

@ReactMethod
override fun setProofOfPossession(deviceName: String, proofOfPossession: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

espDevice.proofOfPossession = proofOfPossession
promise?.resolve(proofOfPossession)
}

@ReactMethod
override fun getUsername(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

promise?.resolve(espDevice.userName)
}

@ReactMethod
override fun setUsername(deviceName: String, username: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

espDevice.userName = username
promise?.resolve(username)
}

@ReactMethod
override fun getDeviceName(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

promise?.resolve(espDevice.deviceName)
}

@ReactMethod
override fun setDeviceName(deviceName: String, newDeviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

if (newDeviceName == "") {
promise?.reject(Error("Cannot set empty device name."))
return
}

// Not sure what this does
espDevice.deviceName = newDeviceName

promise?.resolve(newDeviceName)
}

override fun getPrimaryServiceUuid(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

promise?.resolve(espDevice.primaryServiceUuid)
}

@ReactMethod
override fun setPrimaryServiceUuid(deviceName: String, primaryServiceUuid: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

espDevice.primaryServiceUuid = primaryServiceUuid
promise?.resolve(primaryServiceUuid)
}

@ReactMethod
override fun getSecurityType(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

promise?.resolve(espDevice.securityType.ordinal)
}

@ReactMethod
override fun setSecurityType(deviceName: String, security: Int, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

val securityEnum = when (security) {
0 -> ESPConstants.SecurityType.SECURITY_0
1 -> ESPConstants.SecurityType.SECURITY_1
2 -> ESPConstants.SecurityType.SECURITY_2
else -> ESPConstants.SecurityType.SECURITY_2
}

espDevice.securityType = securityEnum

promise?.resolve(securityEnum.ordinal)
}

@ReactMethod
override fun getTransportType(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

promise?.resolve(espDevice.transportType.toString())
}

@ReactMethod
override fun getVersionInfo(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

val result = Arguments.createMap()

if (espDevice.versionInfo !== null) {
try {
val protoVersion = JSONObject(espDevice.versionInfo).getJSONObject("prov")

val prov = Arguments.createMap()
if (protoVersion.has("sec_ver")) {
prov.putInt("sec_ver", protoVersion.optInt("sec_ver"))
}
if (protoVersion.has("ver")) {
prov.putString("ver", protoVersion.optString("ver"))
}
if (protoVersion.has("cap")) {
val capabilities = Arguments.createArray()
val cap = protoVersion.getJSONArray("cap")
for (i in 0..<cap.length()) {
capabilities.pushString(cap.getString(i))
}
prov.putArray("cap", capabilities)
}

result.putMap("prov", prov)
} catch (e: JSONException) {
// Ignore error
}
}

override fun onFailure(e: Exception?) {
promise?.reject(e)
promise?.resolve(result)
}

@ReactMethod
override fun getDeviceCapabilities(deviceName: String, promise: Promise?) {
val espDevice = espDevices[deviceName].guard {
promise?.reject(Error("No ESP device found. Call createESPDevice first."))
return
}

val capabilities = Arguments.createArray()

if (espDevice.deviceCapabilities != null) {
for (capability in espDevice.deviceCapabilities!!) {
capabilities.pushString(capability)
}
})
}

promise?.resolve(capabilities)
}
}
15 changes: 13 additions & 2 deletions android/src/oldarch/EspIdfProvisioningSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@ abstract class EspIdfProvisioningSpec(context: ReactApplicationContext?) : React
abstract fun createESPDevice(deviceName: String, transport: String, security: Int, proofOfPossession: String?, softAPPassword: String?, username: String?, promise: Promise?)
abstract fun connect(deviceName: String, promise: Promise?)
abstract fun sendData(deviceName: String, path: String, data: String, promise: Promise?)
abstract fun getProofOfPossession(deviceName: String, promise: Promise?)
abstract fun scanWifiList(deviceName: String, promise: Promise?)
abstract fun disconnect(deviceName: String)
abstract fun provision(deviceName: String, ssid: String, passphrase: String, promise: Promise?)
abstract fun initializeSession(deviceName: String, sessionPath: String, promise: Promise?)
abstract fun getProofOfPossession(deviceName: String, promise: Promise?)
abstract fun setProofOfPossession(deviceName: String, proofOfPossession: String, promise: Promise?)
abstract fun getUsername(deviceName: String, promise: Promise?)
abstract fun setUsername(deviceName: String, username: String, promise: Promise?)
abstract fun getDeviceName(deviceName: String, promise: Promise?)
abstract fun setDeviceName(deviceName: String, newDeviceName: String, promise: Promise?)
abstract fun getPrimaryServiceUuid(deviceName: String, promise: Promise?)
abstract fun setPrimaryServiceUuid(deviceName: String, primaryServiceUuid: String, promise: Promise?)
abstract fun getSecurityType(deviceName: String, promise: Promise?)
abstract fun setSecurityType(deviceName: String, security: Int, promise: Promise?)
abstract fun getTransportType(deviceName: String, promise: Promise?)
abstract fun getVersionInfo(deviceName: String, promise: Promise?)
abstract fun getDeviceCapabilities(deviceName: String, promise: Promise?)
}
26 changes: 20 additions & 6 deletions example/src/DeviceScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@
) {
const insets = useSafeAreaInsets();
const [device, setDevice] = React.useState<ESPDevice | undefined>();
const [versionInfo, setVersionInfo] = React.useState<Record<string, any>>();
const [deviceCapabilities, setDeviceCapabilities] =
React.useState<string[]>();

React.useEffect(() => {
async function getVersionInfo() {
setVersionInfo(await device?.getVersionInfo());
}

async function getDeviceCapabilities() {
setDeviceCapabilities(await device?.getDeviceCapabilities());
}

if (device) {
getVersionInfo();
getDeviceCapabilities();
}
}, [device]);

useFocusEffect(
React.useCallback(() => {
Expand Down Expand Up @@ -69,18 +87,14 @@
<Text style={styles.text} h4>
Capabilities
</Text>
<Text style={styles.text}>{device?.capabilities?.toString()}</Text>
<Text style={styles.text} h4>
Advertisement data
</Text>
<Text style={styles.text}>
{JSON.stringify(device?.advertisementData)}
{JSON.stringify(deviceCapabilities ?? [])}
</Text>
<Text style={styles.text} h4>
Version info
</Text>
<Text style={styles.text}>{device?.versionInfo?.toString()}</Text>
<Text style={styles.text}>{JSON.stringify(versionInfo ?? {})}</Text>
<View style={{ marginBottom: 8 }}>

Check warning on line 97 in example/src/DeviceScreen.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { marginBottom: 8 }
<Button
title="Scan Wi-Fi list"
onPress={() => {
Expand All @@ -102,8 +116,8 @@
</View>
</ScrollView>
) : (
<View style={{ flex: 1 }}>

Check warning on line 119 in example/src/DeviceScreen.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { flex: 1 }
<ActivityIndicator style={{ height: '100%' }} />

Check warning on line 120 in example/src/DeviceScreen.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { height: '100%' }
</View>
)}
<View style={{ paddingBottom: insets.bottom }}>
Expand Down
Loading
Loading