Giter Site home page Giter Site logo

orbital-systems / react-native-esp-idf-provisioning Goto Github PK

View Code? Open in Web Editor NEW
18.0 6.0 6.0 2.68 MB

ESP IDF provisioning and custom data library for react-native

License: MIT License

Java 5.24% JavaScript 2.57% Ruby 4.89% C 0.05% Swift 12.02% Objective-C 2.89% Objective-C++ 4.28% TypeScript 41.65% Kotlin 26.41%
ble esp32 esp32-idf provisioning softap wifi-configuration

react-native-esp-idf-provisioning's People

Contributors

dependabot[bot] avatar grasmash avatar mateogianolio avatar robbeman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-native-esp-idf-provisioning's Issues

`capabilities` and `versionInfo` are always `undefined`

I noticed this when testing yesterday. They should be defined as getters instead of statically defined in JS land because they are always undefined until the device is connected. Also, I don't think they make much sense in SoftAP mode.

Use factory pattern for ESPDevice making calls to connect cleaner

If we rewrite ESPDevice to a factory class returning subclasses based on input params for transport and security, we can get cleaner method calls to connect (instead of passing null for unused params):

// security 0, ble
device.connect();

// security 0, softAP
device.connect(softAPPassword);

// ... etc

Support SoftAP mode

We currently do not have a device to test SoftAP provisioning with so any help appreciated!

scanWifiList never succeed if proofOfPossession is used

Our app follows the example app. searchESPDevices works, we can see list of devices.

On a found device, we call await espDevice.connect(proofOfPossession);

Then call await device.scanWifiList(); This always fails with message Failed to create session.

Logcat show onCharacteristicWrite, status : 4
And stack trace

java.lang.Exception: Write to BLE failed
at com.espressif.provisioning.transport.BLETransport$1.onCharacteristicWrite(BLETransport.java:377)
at android.bluetooth.BluetoothGatt$1$7.run(BluetoothGatt.java:562)
at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:959)
at android.bluetooth.BluetoothGatt.-$$Nest$mrunOrQueueCallback(Unknown Source:0)
at android.bluetooth.BluetoothGatt$1.onCharacteristicWrite(BluetoothGatt.java:557)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:279)
at android.os.Binder.execTransactInternal(Binder.java:1351)
at android.os.Binder.execTransact(Binder.java:1310)

I found that the android native property ESPDevice.proofOfPossession is always an empty string which make it unable to create BLE session with the device, hence the error above.

The reason is:

  • in method onPeripheralFound, whenever a device is found (via searchESPDevices), it is added to the espDevices cache. But it that time, there is no PoP, thus no thing is set. Here is the line.
  • then in method createESPDevice, if the device exist in the espDevices cache, it returns immediately without filling the Pop. And the result is that PoP is never used.

I made a patch and it seems to work for my case. Not know if there is any other cases. I don't check the property android.bluetooth.BluetoothDevice.uuids because it always null in my case: the bluetooth device is not null by its uuids is null.
fix_proofOfPossession_is_never_set_patch.txt

Unit tests

It's difficult to unit test this as practically all code needs a real device to test with.

Suggestions on methodology are welcome.

Error in iOS release build: The Swift pod `react-native-esp-idf-provisioning` depends upon `glog`

when building iOS in release mode (to submit to appstore), we got the following error

The Swift pod `react-native-esp-idf-provisioning` depends upon `glog`, which does not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries), you may set `use_modular_headers!` globally in your Podfile, or specify `:modular_headers => true` for particular dependencies.

Are we missing anything causing the error?

`connected` is required in ESPDeviceInterface

The following code

const espDevice = new ESPDevice({
  name,
  transport: ESPTransport.ble,
  security: ESPSecurity.secure,
});

... results in...

Argument of type '{ name: string; transport: ESPTransport.ble; security: ESPSecurity.secure; }' is not assignable to parameter of type 'ESPDeviceInterface'.
  Property 'connected' is missing in type '{ name: string; transport: ESPTransport.ble; security: ESPSecurity.secure; }' but required in type 'ESPDeviceInterface'.ts(2345)

README Corrections

A few suggested changes to the README:

  1. Missing arguments in example code
    In the example in the README, this is shown:
    const devices = ESPProvisionManager.searchESPDevices('prefix');
    However, running this causes the following error:
    Argument 2 (NSInteger) of EspIdfProvisioning.searchESPDevices must not be null
    At least 2 arguments must be passed to searchESPDevices() for it to work.

  2. Undocumented iOS permissions.
    It is undocumented that the app.json for the module must provide a string for NSBluetoothAlwaysUsageDescription. Failing to add it causes this error:

This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSBluetoothAlwaysUsageDescription key with a string value explaining to the user how the app uses this data.

This error is a bit tough to find because it doesn't appear in the react native or expo loggers, only the xcode debug panel.

Bluetooth permission check in Android <= 30

The BLUETOOTH_CONNECT permission does not exist on Android <= 30, so this will always fail.

if (ContextCompat.checkSelfPermission(reactApplicationContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {

In fact permission checks seem a bit inconsistent in general. 🤔


Sidenote: It seems you do not need to grant permissions on lower android version, but maybe the permission checks are usefull to ensure bluetooth is enabled in general?

cfr. zoontek/react-native-permissions#468

variable name typo leads to unable to create device session

Both our app and the example app in this repo could't pass the wifi scan after connecting to a device. In the example app, we can scan for the list of devices; we can select a device; but after selecting BLE, Secure1 and entering PoP, we're unable to scan Wifi.

The error message that toasted on the screen was Failed to create session

The native log in logcat was onCharacteristicWrite, status : 4
The native stack trace was

java.lang.Exception: Write to BLE failed
at com.espressif.provisioning.transport.BLETransport$1.onCharacteristicWrite(BLETransport.java:377)
at android.bluetooth.BluetoothGatt$1$7.run(BluetoothGatt.java:562)
at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:959)
at android.bluetooth.BluetoothGatt.-$$Nest$mrunOrQueueCallback(Unknown Source:0)
at android.bluetooth.BluetoothGatt$1.onCharacteristicWrite(BluetoothGatt.java:557)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:279)
at android.os.Binder.execTransactInternal(Binder.java:1351)
at android.os.Binder.execTransact(Binder.java:1310)

After much of debugging, I found the cause at file NativeEspIdfProvisioning.ts, method createESPDevice. The argument proofOfPossesion is misspelled (missing one s), here is it. While its koltlin counterpart in class EspIdfProvisioningModule is proofOfPossession. That make the PoP always passed to the native code as empty string which cause the session creation fails.

Could you help fix this and pump a new version? Otherwise, the plugin won't work with any secured BLE devices

[ios] Errors in `scanWifiList` should not always reject promise?

Hi, I'm back, sorry.

Not 100% sure if this is an issue for this package, but I want to share what I am facing and maybe hear your thoughts on this.

Here you reject the promise when an error occurs in scanWifiList:

if error != nil {
reject("error", error?.description, nil)
invoked = true
return
}

Which is great, but apparently that does not always mean it's the end.

The espressif sample app does not handle errors, it just ignores them and waits for another call of the completionHandler, as you can see in this issue. And with my device, which always returns a malformedProtobuf error before resolving this means the scan always rejects prematurely.

Possible solutions:

For testing purposes I just updated the above handler like this:

                if error != nil {
-                    reject("error", error?.description, nil)
-                    invoked = true
                    return
                }

And voila, results are coming in! Feels dirty, though.


Another possible solution would be to not use a promise, but a subscription-like strategy, so we can receive errors and still a successful response afterwards. This seems to be what the sample app is doing as well, keep the connection open and just update whenever results come in.

The error and success do seem to follow up very closely, so maybe the error will not even be visible to end users if you choose to output them.

(That would be a breaking change, I suppose.)

Reconnecting to a device that has been unpaired from Android bluetooth menu throws error on onCharacteristicWrite

This is an edge-case bug, but I found out that if I

  1. Connect to a device
  2. Remove the device from Android bluetooth menu
  3. Reconnect to the device
  4. Try to scan wifi

I get error 133 on writing characteristic and immediately after I get disconnected from GATT with status code 19, which indicates that the device initiated the disconnection for some reason.

I found out that if I call disconnectDevice() in createESPDevice when the bond state of bluetoothDevice is BOND_NONE, this error does not occur anymore and scanning works again. Will fix in PR

[Android] `userName` property is never set

Problem

When calling device.scanWifiList (or sendData) on a connected device that requires a username the following error occurs:

java.lang.IllegalArgumentException: The user identity 'I' must not be null or empty
	at com.espressif.provisioning.srp6a.SRP6ClientSession.step1
	at com.espressif.provisioning.security.Security2.<init>(Security2.java:84)
	at com.espressif.provisioning.ESPDevice.initSession(ESPDevice.java:640)
	at com.espressif.provisioning.ESPDevice.scanNetworks(ESPDevice.java:503)
	at com.espidfprovisioning.EspIdfProvisioningModule.scanWifiList
	at java.lang.reflect.Method.invoke(Native Method)
	at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.
	at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.
	at com.facebook.jni.NativeRunnable.run(Native Method)
	at android.os.Handler.handleCallback(Handler.java:938)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage
	at android.os.Looper.loopOnce(Looper.java:226)
	at android.os.Looper.loop(Looper.java:313)
	at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run
	at java.lang.Thread.run(Thread.java:1012)

This is caused by the espDevices in EspIdfProvisioningModule not retaining the username used to connect to the device.

Proposed solution

I'm not sure if it is as simple as that, but this is what I think should work does seem to work in my local setup:

espDevice.userName = username

espDevices[deviceName]?.proofOfPossession = proofOfPossession

espDevices[deviceName]?.userName = username

Thank you for the time and effort you put into this package. I will continue debugging and let you know if I find anything substantial. 🙏

Calling searchESPDevices() returns no devices, XPC connection invalid

Hi,

I'm trying to get a simple implementation of this library working:

import {
  ESPProvisionManager,
  ESPDevice,
  ESPTransport,
  ESPSecurity,
} from '@orbital-systems/react-native-esp-idf-provisioning';

const ConnectToPedalAccessPoint = async () => {
  try {
    let prefix = '';
    let transport = ESPTransport.ble;
    const devices = ESPProvisionManager.searchESPDevices(prefix, transport);
    console.log('devices', devices);
  } catch (err) {
    console.error(err);
  }
}

await ConnectToPedalAccessPoint();

Running this returns an empty object

{"_h": 0, "_i": 0, "_j": null, "_k": null}

and produces the following error:
XPC connection invalid

Any suggestions on resolving this? I'd like to start with list all nearby BLE devices regardless of prefix. However, I've also tried this with values of prefix that I know have matching nearby devices.

Unable to scan for wifi list on iOS

Hello,

I've successfully used this library to find and connect to an ESP32 device. However, I'm not able to scan for a wifi list using the device connection. It returns the error:

[Error: Request for returning Wi-Fi network list failed with error: The operation couldn’t be completed. (SwiftProtobuf.BinaryDecodingError error 3.)]

Very simple implemenation:

#  This line works. Confirmed connection by monitoring ESP32 output.
await device.connect(proofOfPosession, null, username);
# This line produces an error.
const espWifiList = await device.scanWifiList();

Device stuck after provision wifi data

Hi,
I run the example application and when I provision the wifi data I get {"status": "success"} response but nothing happens: the device doesn't try to connect to wifi and is no more visible in the devices screen. To reappear and make it connectable via ble, I have to disconnect it from the power supply.

Where am I wrong?

Thanks, Vincenzo

Failed to apply plugin 'kotlin-android' on AGP 8.2.0

In an app project which uses Android Gradle plugin 8.2.0, it fails to build with the following error at this plugin

> Task :gradle-plugin:inspectClassesForKotlinIC UP-TO-DATE

FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* Where:
Build file '/..../node_modules/@orbital-systems/react-native-esp-idf-provisioning/android/build.gradle' line: 1

* What went wrong:
A problem occurred evaluating project ':orbital-systems_react-native-esp-idf-provisioning'.
> Failed to apply plugin 'kotlin-android'.
   > Extension of type 'JavaPluginExtension' does not exist. Currently registered extension types: [ExtraPropertiesExtension, KotlinAndroidProjectExtension, KotlinTestsRegistry]

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating project ':orbital-systems_react-native-esp-idf-provisioning'.
	at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:93)
	at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.lambda$apply$0(DefaultScriptPluginFactory.java:135)
	at org.gradle.configuration.ProjectScriptTarget.addConfiguration(ProjectScriptTarget.java:79)
	at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:138)
	at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
	at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:44)
	at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62)
	a...
	... 

==============================================================================

2: Task failed with an exception.
-----------
* What went wrong:
A problem occurred configuring project ':orbital-systems_react-native-esp-idf-provisioning'.
> 'kotlin-android' plugin requires one of the Android Gradle plugins.
  Please apply one of the following plugins to ':orbital-systems_react-native-esp-idf-provisioning' project:
  - com.android.application
  	- com.android.library
  	- com.android.dynamic-feature
  	- com.android.test
  	- com.android.instantapp
  	- com.android.feature

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
...

The reason is at file android/build.gradle. It currently looks like

apply plugin: "kotlin-android"

buildscript {
  repositories {
    google()
    mavenCentral()
  }

  dependencies {
    classpath "com.android.tools.build:gradle:7.2.1"
  }
}

def isNewArchitectureEnabled() {
  return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
}

apply plugin: "com.android.library"
.....

The line apply plugin: "kotlin-android" is on the top, then, on the way down, there is the apply plugin: "com.android.library".
If I move the apply plugin: "com.android.library" on the very first line, the build succeed

apply plugin: "com.android.library"
apply plugin: "kotlin-android"
... then the rest of the file

Issue with connect(pop) Method Not Showing Expected Logs for Security2 Connection

Hello react-native-esp-idf-provisioning team,

I would like to extend my deepest gratitude for developing such a niche yet incredibly useful toolkit for React Native developers interested in working with ESP32 devices.

I have successfully used the connect(pop, null, username) method to establish a connection to an ESP32 device, which worked flawlessly. The logs displayed on the ESP32 terminal were as expected, including security2 connection initiation and public key creation, among others.

However, when attempting to provide an alternative connection method in my app through the use of connect(pop) (without the second and third parameters), I noticed that the ESP32 terminal did not display the same logs as when connecting with the connect(pop, null, username) method. Specifically, I didn't observe the logs related to security2 connection initiation or public key creation.

This led me to wonder if this behavior is related to the security settings configured within the connect() API. Could it be possible that the connect(pop) method currently only supports secure1 connections? Or is there another explanation for the difference in log output when using connect(pop) compared to connect(pop, null, username)?

This is my react native code

const search = async () => {
    let prefix = 'PROV_'
    let transport = ESPTransport.ble
    let security = ESPSecurity.secure2
    try {
      const devices = await ESPProvisionManager.searchESPDevices(
        prefix,
        transport,
        security,
      )
      setDevice(devices[0])
      console.log(devices[0])
    } catch (e) {
      console.log(e)
    }
  }
  const handlePressConnection = async () => {
    console.log('Pressed')
    setIsLoading(true)
    try {
      const newDevice = new ESPDevice({
        name: device.name,
        transport: ESPTransport.ble,
        security: ESPSecurity.secure2,
      })
      await newDevice.connect(pop)
      console.log('connected')
      await newDevice.scanWifiList().then((res) => {
        dispatch(setWifiList(res))
      })
      setIsLoading(false)
      navigation.navigate('WifiListScreen')
    } catch (e) {
      setIsLoading(false)
      console.log(e)
    }
  }

I could not see console.log('connected') on handlepressConnection method.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.