Meshtastic

Meshtastic Android Integration + setDeviceAddress API

I’m developing a plugin (https://github.com/paulmandal/atak-forwarder/) for ATAK (Android Team Awareness Kit - a very feature rich mapping software) to allow hikers and other outdoorspeople to coordinate while in the backcountry.

I’ve got a decent integration with the Meshtastic Android API going that works for almost all of my needs. However, I am trying to use the MeshService.setDeviceAddress(String) method from my plugin/application but I cannot. Whenever I call this I get an exception like:

23130-23147/com.geeksville.mesh E/toRemoteExceptions: Uncaught exception, returning to remote client
    java.lang.RuntimeException: Can't create handler inside thread Thread[Binder:23130_1,5,main] that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:207)
        at android.os.Handler.<init>(Handler.java:119)
        at com.geeksville.mesh.service.SafeBluetooth.<init>(SafeBluetooth.kt:100)
        at com.geeksville.mesh.service.BluetoothInterface.<init>(BluetoothInterface.kt:210)
        at com.geeksville.mesh.service.RadioInterfaceService.startInterface(RadioInterfaceService.kt:234)
        at com.geeksville.mesh.service.RadioInterfaceService.setBondedDeviceAddress(RadioInterfaceService.kt:304)
        at com.geeksville.mesh.service.RadioInterfaceService.access$setBondedDeviceAddress(RadioInterfaceService.kt:37)
        at com.geeksville.mesh.service.RadioInterfaceService$binder$1$setDeviceAddress$1.invoke(RadioInterfaceService.kt:312)
        at com.geeksville.mesh.service.RadioInterfaceService$binder$1$setDeviceAddress$1.invoke(RadioInterfaceService.kt:309)
        at com.geeksville.util.ExceptionsKt.toRemoteExceptions(Exceptions.kt:56)
        at com.geeksville.mesh.service.RadioInterfaceService$binder$1.setDeviceAddress(RadioInterfaceService.kt:311)
        at com.geeksville.mesh.service.MeshService$binder$1$setDeviceAddress$1.invoke(MeshService.kt:1538)
        at com.geeksville.mesh.service.MeshService$binder$1$setDeviceAddress$1.invoke(MeshService.kt:1533)
        at com.geeksville.util.ExceptionsKt.toRemoteExceptions(Exceptions.kt:56)
        at com.geeksville.mesh.service.MeshService$binder$1.setDeviceAddress(MeshService.kt:1535)
        at com.geeksville.mesh.IMeshService$Stub.onTransact(IMeshService.java:274)
        at android.os.Binder.execTransactInternal(Binder.java:1021)
        at android.os.Binder.execTransact(Binder.java:994)

I know the method documentation states “Users should not call this directly, only used internally by the MeshUtil activity” but I need this method for my use case: assigning a callsign, map marker color/symbol (used in ATAK), and reporting interval to devices that do not have phone + ATAK to control them so that they can be shown on the map in ATAK.

Is there any way to work around this?

Just some quick feedback – integrating with the Meshtastic API has been easy and device performance has been good. Really nice work on the software/hardware!

2 Likes

DId you try to call the method from another thread than the main ?

I’m calling from the main thread, do I need to do this in a background thread?

It has to be run in a coroutines in kotlin.
I guess it is the problem, i need to google from the computer to verify that

Can you try to call it like :

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
         MeshService.setDeviceAddress(String);
    }
});

This didn’t work for me, I am connecting to the MeshService as a service so I don’t know if the callers thread will have any impact here.

I was able to get this working by modifying SafeBluetooth.kt:L101 to read:

private val mHandler: Handler = Handler(Looper.getMainLooper())

Not sure if that is an appropriate solution though.