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

No stats after firmware update #86

Open
jj05y opened this Issue Nov 17, 2018 · 128 comments

Comments

Projects
None yet
@jj05y
Copy link

jj05y commented Nov 17, 2018

Hey,
I just cloned the repo and while the app connects fine, there's no stats available. It may be the firmware update. Can you repro?

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 17, 2018

To me it looks like the Onewheel now requires some kind of initialistaion to send values.
Else it will just report 0 as value for each characteristic.

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 17, 2018

grafik

@COM8 COM8 referenced this issue Nov 17, 2018

Closed

Gemini support #3

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 17, 2018

Just noticed the same thing with Onewheel Community Edition app. I only get firmware and hardware revision.

Almost all properties in LightBlue are also unnamed now.

Going to investigate today with a phantom board and will let you know if I find anything useful.

@kwatkins

This comment has been minimized.

Copy link
Collaborator

kwatkins commented Nov 18, 2018

Hmm well that's a bit annoying. If not solved I'll tackle in a few days, my XR is out as I change to a new treaded tire (currently stuck at the dismount step, it isn't easy as YouTube peeps show). I doubt the GUIDS changed but hard to say ... Likely will just reverse the official app.

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 18, 2018

GUIDs are the same. Only firmware and hardware revisions have values via LightBlue.

The latest official app doesn’t detect my phantom board for doing the reverse engineering of their BLE anymore. Previous app versions still work fine.

Another thing is the URL path for the new firmware has changed. And a few other things about the apps are different. I wonder if all of this is FM trying to prevent these 3rd party apps existing?

EDIT: I updated my Android device to the latest OW app. I enabled HCI logging and then connected to the board and then sent the log to my computer and am stepping through it with Wireshark. I can see the app fetching ride mode fine and on the correct characteristic uuid. I am looking up back further to see if the board is sending any specific data to allow it to send the other data. Will update when I know more.

@jj05y

This comment has been minimized.

Copy link
Author

jj05y commented Nov 18, 2018

Using gatttool its reading 0 for alot of handles, some have data but how is one to map them to meaningful names?

@jj05y jj05y closed this Nov 18, 2018

@jj05y jj05y reopened this Nov 18, 2018

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 18, 2018

Inspecting a bluetooth log, I am 99% confident the uuids have not changed and don’t need to be renamed.

The board is doing something else.

Should also be noted the old OW app can’t connect to the new OW board, much like the same issue we are in.

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 18, 2018

Yes I can confirm this. The characteristics are still the same.
Never the less they added 4:
e659f31d-ea98-11e3-ac10-0800200c9a66 labeled Data29
e659f31e-ea98-11e3-ac10-0800200c9a66 labeled Data30
e659f31f-ea98-11e3-ac10-0800200c9a66 labeled Data31
e659f320-ea98-11e3-ac10-0800200c9a66 labeled Data32
Guess they are for the custom riding mode.

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 18, 2018

Inspecting a bluetooth log, I am 99% confident the uuids have not changed and don’t need to be renamed.

The board is doing something else.

Should also be noted the old OW app can’t connect to the new OW board, much like the same issue we are in.

Do you mind uploading your HCI log?
Don't have an Adroid device on hand, only Android x86 😉 and it's not letting me log traffic.

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 18, 2018

e659f31d through to e659f320 are not new. LightBlue used to have named properties and it would call them unknown 1 to unknown 4. I don't believe I've ever seen them change value, but they could very we be used now though.

Log is attached, it can be opened by Wireshark. It also shows my device picking up a bunch of other devices so need to double check for service UUID and then compare it. From memory board connects in frame 117.
btsnoop_hci.log.zip

EDIT: There is also bluetooth logging for iOS. I didn't know it was a thing otherwise I probably would have tried this. https://developer.apple.com/bug-reporting/profiles-and-logs/

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 18, 2018

Ok thanks, maybe I can spot something new.

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 18, 2018

So that's what I've discovered:
The app based on your logs provided sends the following data to the board:

  1. Write 00 to e659f319-ea98-11e3-ac10-0800200c9a66 // Set live time odometer to 0
  2. Write 0fc2 to e659f311-ea98-11e3-ac10-0800200c9a66 // Set firmware revision to 4034 (BASE10)
  3. Write 43:52:58:d8:82:11:d1:26:96:5f:9f:aa:72:fc:de:92:f3:25:3d:20 to e659f3ff-ea98-11e3-ac10-0800200c9a66 // Write Q1JYw5jCghHDkSbCll/Cn8KqcsO8w57CksOzJT0g (BASE64) to serial write
  4. Write 00 to e659f319-ea98-11e3-ac10-0800200c9a66 // Set live time odometer to 0
  5. Write 007 to e659f302-ea98-11e3-ac10-0800200c9a66 // Sets ride mode to 7
  6. Write 00 to e659f319-ea98-11e3-ac10-0800200c9a66 // Set live time odometer to 0
  7. Write 00 to e659f319-ea98-11e3-ac10-0800200c9a66 // Set live time odometer to 0
  8. Write 00 to e659f319-ea98-11e3-ac10-0800200c9a66 // Set live time odometer to 0
  9. Write 00 to e659f319-ea98-11e3-ac10-0800200c9a66 // Set live time odometer to 0

The interresting one is the serial data. I couldn't make sence of it, but it's probably just in a wrong endian right now.

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 18, 2018

Could you please provide a few more log files with connection establishments so I can validate my theory?

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 18, 2018

The serial write one is interesting. I've only seen the board do serial write for firmware deploying.
I won't be able to get more logs until after work.

I'd be interested to know:

  • Is that thing sent to serial phone unique
  • Is that thing sent to serial device unique (data generated on the board device ID or something)
  • Is that thing sent to serial static everywhere
  • if the iOS bluetooth logs can display the same thing

For other people to get the data its really easy on Android if you have dev mode unlocked. http://www.fte.com/WebHelp/BPA600/Content/Documentation/WhitePapers/BPA600/Encryption/GettingAndroidLinkKey/RetrievingHCIlog.htm

Ill go check on Facebook if I can get anyone else to generate a log.

EDIT: In case anyone comes across this thread, that above link shows how to enable HCI logging. Here is an app that can open that log file and allow you to share it.
https://play.google.com/store/apps/details?id=com.github.akinaru.hcidebugger

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 19, 2018

Here is another log. Here is what I have found so far. This could just be an order of operations in a multi threaded app, or it could be how it triggers the board to send some sort of data as a key. But on frame 342 it enabled read notifications on E659F3EE which is interesting because that IS a new characteristic which isn't exposed when we can the boards characteristics.

Once notifications are enabled it writes the boards firmware revision back to itself. After that 20 bytes of data is received as notifications from the previous subscription (below as each notification)

43:52
58:7f:8e
0c
4c:17
7a:22
a2:b2
32
e2:e2
e2:e2:f8:77:ca

After that 20 bytes of data is sent back to the board on E659F3FE (which as you said was serial read previously (its odd that the first 3 bytes match, they would be the characters CRX if that means anything to anyone? Some of the other bytes are in the string, others are not found. Also note it is ).

43:52:58:4a:8d:4c:93:ca:9c:75:bc:ba:73:87:53:e9:10:4b:49:28

Also note it is slightly different from the value in my last log. Its the same length and starts with the same 3 bytes.

43:52:58:d8:82:11:d1:26:96:5f:9f:aa:72:fc:de :92:f3:25:3d:20

And for reference, from scan 1, here is the 20 bytes that where sent from the board to the phone.

43:52
58:7f
9e:5c
14
df:42
e2:62
82:62
62
62:62:62:77:f6:9c

After that the E659F3EE characteristic which I believe is the new serial read starts spitting out the gibberish it used to. I reckognise it because it'd keep saying "One" and some data between it. I never did figure out what it all meant. At frame 382 the notification for E659F3EE is disabled and then it seems that the board communicates as usual with its reads and writes how our apps used to.

After work tomorrow I am going to double check these values along with the endianness and see what they could possibly be.

btsnoop_hci-2.log.zip

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 19, 2018

I will try to reverse engineer the .apk. Maybe I can spot something there.

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 19, 2018

I had tried that a few days ago, but It appears to be obfuscated very differently to how it used to be. Either that or my new dev setup isn't working right.

@jj05y

This comment has been minimized.

Copy link
Author

jj05y commented Nov 19, 2018

Yeah, it's been minified :( Makes it very hard to read.

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 19, 2018

All this makes me think they really don't want 3rd party apps. Surely this wasn't all on accident :P

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 19, 2018

A little bit more "security" is not wrong. They had some really big flaws, because everybody was able to connect to your oneweel and for example change light mode or change riding mode during the ride.
Still not great. Would have hoped for some kind of pairing mechanism instead...

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 19, 2018

*had and still have

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 19, 2018

You're right, extra security is never a bad thing.

If only there was a bug bounty program or similar to receive free XRs.

@kwatkins

This comment has been minimized.

Copy link
Collaborator

kwatkins commented Nov 19, 2018

Awesome everyone here is tackling this... I just did an initial look at the APK (using jadx for decompilation) and looks like they are doing some encoding/decoding with the chars on the top layer. I take it the messages are still coming through, just garbage until we figure out the seed and key values.

They also moved a lot of the methods handling sensitive and private data to native, just making it slightly more annoying to reverse, including MainActivity.getChallengeResponsePassword below.

com.rideonewheel.onewheel.OnewheelService
public void onCharacteristicChanged(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic bluetoothGattCharacteristic) { this.a.a(bluetoothGattCharacteristic, 0); if (bluetoothGattCharacteristic.getUuid().equals(g.y) != null) { bluetoothGatt = e.a(); if (!bluetoothGatt.G()) { bluetoothGattCharacteristic.getStringValue(0); bluetoothGatt.a(bluetoothGattCharacteristic.getValue()); if (bluetoothGatt.I().length == 20) { String str = new String(Arrays.copyOfRange(bluetoothGatt.I(), 0, 3)); bluetoothGatt = Arrays.copyOfRange(bluetoothGatt.I(), 3, 19); byte[] decode = BaseEncoding.base16().decode(MainActivity.getChallengeResponsePassword(p.a(this.a.getApplicationContext()))); decode = Bytes.concat(bluetoothGatt, decode); bluetoothGattCharacteristic = Bytes.concat(bluetoothGattCharacteristic, com.rideonewheel.onewheel.shared.a.a(decode)); decode = new byte[]{(byte) 0}; for (byte b : bluetoothGattCharacteristic) { decode[0] = (byte) (b ^ decode[0]); } this.a.a(Bytes.concat(bluetoothGattCharacteristic, decode)); this.a.D(); } } } }

@COM8

This comment has been minimized.

Copy link

COM8 commented Nov 19, 2018

Going to continue tomorrow, here's what I've found out so far:
Used dex-tools and jd-gui.
If you take a look into OnewheelService.java Line 1745 (if they are the same :D)

 public void a(byte[] paramArrayOfByte)
  {
    if (this.D != null) {
      a(this.D, paramArrayOfByte);
    }
  }

this.D is the serial write characteristic instance and we write an array of bytes to it.
Thats the only time I found, that D really gets used for something.
The only time this method gets called (no external call found) is in line 280:

  private e.a af = new e.a()
  {
    public void a()
    {
      OnewheelService.b(OnewheelService.this);
    }
    
    public void a(byte[] paramAnonymousArrayOfByte)
    {
      OnewheelService.this.a(paramAnonymousArrayOfByte);
    }
  };
@jj05y

This comment has been minimized.

Copy link
Author

jj05y commented Nov 19, 2018

The reading/writing of firmware version is interesting. I thought It may be so each device knows the protocol to communicate with (because it changed with gemini). I tried this:

[0C:AE:7D:ED:07:xx][LE]> char-read-hnd 0059
Characteristic value/descriptor: 10 26
[0C:AE:7D:ED:07:xx][LE]> char-write-req 0059 1026
Characteristic value was written successfully

but still get 0 values for 45, 49 (roll, yaw) (and others)
[0C:AE:7D:ED:07:xx][LE]> char-read-hnd 0045
Characteristic value/descriptor: 00 00
[0C:AE:7D:ED:07:xx][LE]> char-read-hnd 0049
Characteristic value/descriptor: 00 00

I can see in wireshark the equivalant of com8's step three above,
some crazy value gets written. I think this is the key to the handshake,
image

from the decomiled src of gemini ap:
public static final UUID c = UUID.fromString("E659F300-EA98-11E3-AC10-0800200C9A66");
public static final UUID x = UUID.fromString("E659F3FF-EA98-11E3-AC10-0800200C9A66");

c is a brand new UUID, not ref'd in ponewheel src,
x is ref'd as OnewheelCharacteristicUartSerialWrite

I'm at a loss at this point,

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Nov 19, 2018

E659F300-EA98-11E3-AC10-0800200C9A66 is the service UUID.
I have E659F3FF-EA98-11E3-AC10-0800200C9A66 in OWCE listed as SerialWrite which is a named value via LightBlue, which is named by someone in the community I think... Maybe its named from the board itself.

I just got sent someone elses log and I got the same thing, read 20 bytes, did something and then sent those 20 bytes off.

Could you find E659F3EE-EA98-11E3-AC10-0800200C9A66 anywhere?

EDIT: @jj05y yeah I think writing of the board firmware version back is triggering the board to then send us the password for the device. And yeah reading it is for figuring out what flow we want to then follow makes sense.

@kwatkins Can we able to see the contents of the getChallengeResponsePassword like your above code or does it not get decompiled?

@kwatkins

This comment has been minimized.

Copy link
Collaborator

kwatkins commented Nov 19, 2018

fyi, just trying to work out the flow of what the official app is doing, may/may not help the research going on now. let me know if there are places to zero on and i can continue the dive.

11-19 14:54:47.931 29257 29329 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:47.934 29257 29708 [com.rideonewheel.onewheel][com.rideonewheel.onewheel.MainActivity.getFirmwareFolderUrl] EjPXmbUBIJfrTYgBCw4AKPZMuzA=->https://s3-us-west-1.amazonaws.com/1wheel/fw_10-24-18/
11-19 14:54:47.937 29257 29328 [com.rideonewheel.onewheel][android.os.Parcel.writeString] com.rideonewheel.onewheel
11-19 14:54:47.939 29257 29329 [com.rideonewheel.onewheel][android.os.Parcel.writeString] 50:33:8B:6C:XX:XX
11-19 14:54:47.942 29257 29708 [com.rideonewheel.onewheel][java.net.HttpURLConnection] https://s3-us-west-1.amazonaws.com/1wheel/fw_10-24-18/version_XR.txt
11-19 14:54:47.942 29257 29708 [com.rideonewheel.onewheel][java.net.HttpURLConnection] https://s3-us-west-1.amazonaws.com/1wheel/fw_10-24-18/version_XR.txt
11-19 14:54:47.952 29257 29328 [com.rideonewheel.onewheel][android.os.Parcel.writeString] com.google.android.wearable.app.cn
11-19 14:54:47.996 29257 29268 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f311-ea98-11e3-ac10-0800200c9a66,length=2,setValue==ECY=
11-19 14:54:47.996 29257 29268 [com.rideonewheel.onewheel][android.os.Parcel.writeString] 50:33:8B:6C:61:XX
11-19 14:54:47.998 29257 29268 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.writeCharacteristic] UUID=e659f311-ea98-11e3-ac10-0800200c9a66,getStringValue=&
11-19 14:54:48.131 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==CR
11-19 14:54:48.223 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==WH8=
11-19 14:54:48.223 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==nTk=
11-19 14:54:48.224 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==HwA=
11-19 14:54:48.225 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=1,setValue==q
11-19 14:54:48.226 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==efk=
11-19 14:54:48.227 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==GZk=
11-19 14:54:48.228 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==mZk=
11-19 14:54:48.229 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==mZk=
11-19 14:54:48.230 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=2,setValue==Dow=
11-19 14:54:48.231 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,length=1,setValue==~
11-19 14:54:48.239 29257 29269 [com.rideonewheel.onewheel][android.os.Parcel.writeString] com.rideonewheel.onewheel
11-19 14:54:48.242 29257 29269 [com.rideonewheel.onewheel][com.rideonewheel.onewheel.MainActivity.getChallengeResponsePassword] in:EjPXmbUBIJfrTYgBCw4AKPZMuzA=,out:D9255F0F23354E19BA739CCDC4A91765
11-19 14:54:48.248 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGattCharacteristic.setValue] UUID=e659f3ff-ea98-11e3-ac10-0800200c9a66,length=20,setValue==Q1JYh0FDe+slyo8GHPTpqE7VzcU=
11-19 14:54:48.250 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.writeCharacteristic] UUID=e659f3ff-ea98-11e3-ac10-0800200c9a66,getStringValue=CRX�AC{�%ʏ��N���
11-19 14:54:48.252 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f3fe-ea98-11e3-ac10-0800200c9a66,enabled=false
11-19 14:54:48.259 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f302-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.263 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f30c-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.266 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f303-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.270 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f30a-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.273 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f314-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.280 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f316-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.284 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f313-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.288 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f307-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.292 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f319-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.296 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f30b-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.300 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f312-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.303 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f30f-ea98-11e3-ac10-0800200c9a66,enabled=true
11-19 14:54:48.364 29257 29269 [com.rideonewheel.onewheel][android.bluetooth.BluetoothGatt.setCharacteristicNotification] UUID=e659f31e-ea98-11e3-ac10-0800200c9a66,enabled=true
@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

I feel like I'm going crazy right now, but the play store page for ponewheel says it was last updated April 8th 2018 and after downloading it just now it wouldn't connect. Is there a beta channel or a new store page I'm missing?

Thanks for the update @mherfurt

Sorry for any duplicate alerts, accidently posted from my school GitHub account.

@hammer-is

This comment has been minimized.

Copy link

hammer-is commented Feb 2, 2019

@Nanoux See screenshot from my OnePlus about the 14th January release:
image
As far as I know both the April 8th release and the current release targets API21 (Android 5.0+) so I don't undestand why you can't see latest release. Btw. I've not joined the "beta" option.

UPDATE;
Something is odd. Play Store in a PC browser shows current version is 3.3 - on my mobile it shows 3.4! However they both show 14th January as last update. And the "WHAT'S NEW" shows "Finally added Gemini firmware support!" both on PC and mobile.

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

Huh, maybe it's a staged release or something, we'll have to ask @kwatkins I guess.

@hammer-is

This comment has been minimized.

Copy link

hammer-is commented Feb 2, 2019

@Nanoux app is on Github if you don't want to build yourself (Gemini support is in master branch). https://github.com/ponewheel/android-ponewheel/releases/tag/gemini_support

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

I'm aware @hammer-is but thank you.

On second thought I think the build Target is the problem, according to this page Google stopped allowing app updates targeting below API level 26 last fall. https://developer.android.com/distribute/best-practices/develop/target-sdk

What Android version is your OnePlus running?

@hammer-is

This comment has been minimized.

Copy link

hammer-is commented Feb 2, 2019

@Nanoux my phone is on Android 8.0 but I think it's only minsdkversion that limits what phones can install app/update. If it was targetsdkversion that was causing the limit then no phones with <Android 8.0 would have been able to update any app since last fall and that does not make sense.
Targetsdkversion is at 26 daddd3b

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

I misunderstood your original comment then, I have no idea.

@COM8

This comment has been minimized.

Copy link

COM8 commented Feb 2, 2019

What do you guys think about the following:
Instead of just sitting here and wondering about their next steps, why don't we proactively try to get in touch with FM?
I don't think Facebook is the right way to go there.
We should draft a letter/email to them and ASK them why they are doing what they are doing and maybe even suggest some better ways (open sourcing the official app(s), ...) so we both can get along.

Fact is they are trying to lock down the Onewheel to first party apps only.
So maybe in the future they actually manage to lock out all third party apps and we can't get around it.
At this point it might be to late to get in touch with them.

@muellergit

This comment has been minimized.

Copy link

muellergit commented Feb 2, 2019

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

@COM8 I was planning on doing that, but I can't find a good way outside of the customer support system. Any ideas?

@COM8

This comment has been minimized.

Copy link

COM8 commented Feb 2, 2019

One way would be creating a thread in the forum.

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

Last time I did that just mentioning my app existed they deleted my thread, there's no way they would leave that up.

@COM8

This comment has been minimized.

Copy link

COM8 commented Feb 2, 2019

If they delete our post we know they wouldn't answer us via mail/support.
I think if enough of us would comment the initial post with something like:

I'm the dev of XYZ and I would like to know what's up (or so).

The thread has to get some attention form normal people and staff

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

Forum Moderators and policy makers at FM are probably not the same people, they may just not want drama in their forums.

Does anyone know if the OWBuddy guys still work at FM and how to contact them? They seem like the perfect people to ask

@hammer-is

This comment has been minimized.

Copy link

hammer-is commented Feb 2, 2019

Next chapter as I try to solve the Play store version mystery using an old Galaxy S4 on Android 5.0.1.

Factory reset + sign in with my own Google account = access to newest 3.4/Gemini version according to the Play store page. I verified that it could connect to my OW+ successfully.
Factory reset and + sign in with another Google account = access to the old 3.3 version! I verified that it did not work with the OW+ (as I don't know how to see the version inside pOnewheel).

So bottom line is that using Android 5.0(.1) pOnewheel can be retrieved from the Play store IF the Google account have access to it...

@kwatkins any idea why only some Google accounts can access version 3.4 of pOnewheel?

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 2, 2019

If I had to guess, he used the staged rollout feature, whether he intended to or not, which just rolls out the update to a select % of users. It's used mostly by big apps who only want to have 5% of their users experience horrible undiscovered bugs instead of all 100% :p

@kwatkins

This comment has been minimized.

Copy link
Collaborator

kwatkins commented Feb 3, 2019

@kwatkins

This comment has been minimized.

Copy link
Collaborator

kwatkins commented Feb 3, 2019

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 3, 2019

Looking through it really quick, I might know why its happening. In your OnServicesDiscovered function, you setNotify & read every bluetooth characteristic you want, and then do the gemini thing as you get the value for the firmware version. In my experience, the values you setNotify initially will work, but anytime you try to setNotify or un-setNotify (not great with the lingo, sorry), or try to read a characteristic, you get null values.

Heres the flow in my app:
I setNotify to all the characteristics I want in a seprate function, because Gemini & Andromeda do it at different times.
Step 1: In OnServicesDiscovered, JUST read the firmware version.
Step 2: In OnCharacteristicRead, if the value is of the char firmware version, parse it's value. If its >= 4034, JUST write the descriptor for the Serial Read characteristic to Enable notifications, and set notify to true with gatt. Otherwise its Andromeda or lower and we can call the method to read & notify all the characteristics we want. (Although I learned doing this that some android devices have a max of 12 notify characteristics at once for some reason. At least I'm pretty sure.) I also set a class-wide boolean value isGemini to true here so I don't have to keep checking if its Andromeda or Gemini later on.
Step 3: In OnDescriptorWrite, if isGemini and the characteristic descriptor that was written was Serial Write, then trigger the byte stream by writing the firmware version onto itself.
Step 4: In OnCharacteristicChanged, if isGemini and characteristic is serial read, do the gemini hash crap and stuff and setNotify for serial read to false.
Step 5: In OnCharacteristicWrite, if isGemini & characteristic is Serial Write, NOW setNotify and read all the characteristics you want. its also only now that I start the repeated handshake clock thing, but I don't think it really matters, this all happens pretty quick.

That will get you connected, but if you want to do it reliably theres a few tips I found. If you try to reconnect within 24 seconds of the last handshake, for some reason the onewheel sends more than 20 bytes. Like, a lot more. If you do the same hash thing with the first 20 bytes it sends it will still connect, but you have to do something like (inkey.toByteArray().length >= 20) in you gemini function, and put in some logic so that it only executes once and not every time you recieve a byte after the first 20. Also in this case, writing the characteristic usually fails. gatt.writeCharacteristic returns a boolean to tell you if it worked, and when you try to reconnect in this window it usually fails. I just wait a bit and then keep trying, over and over, until it works, but there may be a better solution.

Also, I had a super weird bug on my Pie Pixel where if I tried to read the firmware version immediately in OnServicesDiscovered, the connection would sometimes instantly time out, so I used a Handler thread to delay it 500 ms and that makes it a lot more stable, so do with that what you will.

Anyway, I hope this helps @kwatkins , if you have questions or want a flowchart or something lemme know :P

EDIT: If i can find the time I'll try and add these myself, but between college, work, and trying to save my own app I don't know if that'll happen. But I'll try.

@mherfurt

This comment has been minimized.

Copy link

mherfurt commented Feb 3, 2019

@Nanoux Thanks for this helpful insight!

@kwatkins

This comment has been minimized.

Copy link
Collaborator

kwatkins commented Feb 3, 2019

@Nanoux +1 to the thanks, super helpful. I'll implement this workflow when cycles open up, have a newborn/little dude and dirty diapers to change before changing my dirty code ;)

As always appreciate the help from everywhere here, and definitely open to others implementing this, I can help test and roll out the changes.

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 4, 2019

I was thinking, does Bluetooth the company have any rules about restricting access to a Bluetooth device in order to get licensed? I can't find anything but that seems like it should be a thing.

@mherfurt

This comment has been minimized.

Copy link

mherfurt commented Feb 4, 2019

@Nanoux About 10 years ago, I attended several so-called UPF events (UnPlugFest) organized by the Bluetooth SIG. The Bluetooth SIG itself is an association of different Bluetooth device/chip manufacturers that drive the development of new features of this manufacturer-independent forward.

Back then, it was obligatory for every manufacturer of Bluetooth enabled devices to have their product/platform certified by the Bluetooth SIG. Each platform was certified for implementing a minimum set of Bluetooth functionality so that it is entitled to wear the Bluetooth brand... (Fee for this was about 10k$ per platform)

FM uses a Bluetooth SoC that was developed by TexasInstruments. In this case - I believe - it is sufficient that the SoC module is certified.

The Bluetooth SIG itself does not enforce rules that guarantee a safe/secure use of the Bluetooth wireless technology. Due to the high segmentation, it is almost impossiblke for them to monitor all use-cases of Bluetooth technology.

Long answer short: I do not think so.

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 4, 2019

Alright, thanks, that's quite helpful. I'll probably write a message to FM customer support sometime in the next few days and hope for the best, really not much else I can do it seems.

@Nanoux

This comment has been minimized.

Copy link

Nanoux commented Feb 8, 2019

Update:

Customer Support ticket has been sent, I couldn't find any other way of contacting FM

I open sourced the free version of Onewave and put a built, unsigned APK in a release for anyone desperate. This class may be of interest to you guys, Its diverged quite a bit from when I got it from the pOnewheel source but it should be quite useful nonetheless. https://github.com/Nanoux/Onewave/blob/master/app/src/main/java/com/nanowheel/nanoux/nanowheel/util/BluetoothUtilImpl.java

EDIT: Just wanted to thank @kwatkins and anyone whos worked on this project, reverse engineering it taught me so much about Android Development and specifically how to connect to BLE.

@COM8

This comment has been minimized.

Copy link

COM8 commented Feb 10, 2019

Has anybody tested the unlock mechanism with a OW+XR?
Since the XR might have a slightly different FW revision.
COM8/UWP-Onewheel#5

@COM8

This comment has been minimized.

Copy link

COM8 commented Feb 11, 2019

Ok, yes confirmed: To unlock an OW+XR we need to listen for and write back the 4134 (0x1026) FW revision instead of the 4034 (0x0fc2) FW revision of an OW+.

Thanks to @TomasHubelbauer.

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Feb 12, 2019

5686... That is a huge firmware jump, and odd that it isn't 5086 or something. I assume it's via analytics? Any idea of rough location, like California maybe?

@TomasHubelbauer

This comment has been minimized.

Copy link

TomasHubelbauer commented Feb 12, 2019

@beeradmoore My bad, that was a messup on my part! I was looking at a wrong buffer 🙄

@beeradmoore

This comment has been minimized.

Copy link

beeradmoore commented Feb 12, 2019

Damn, got me excited for a new OW being discovered in the wild :p (I guess they wouldn't use 3rd party apps to test the new OWs for this very reason).

@jj05y this can probably all be closed now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment