Jump to content
Paco Gorina

Unraveling Ninebot One E+ BLE Protocol - Success?

Recommended Posts

1 hour ago, Richard.D said:

@Paco Gorina, great job dude! 

While seems the dropbox page( https://www.dropbox.com/sh/2dcadhphgktqlgs/AADmFLuGryUfKKd5O90h0oSea?dl=0 ) says "This folder is empty"...

Sorry, my Dropbox is quit clogged syncing some Gb

I post them in this message

Now the Dropbox link must be full, Anyway here are the files

Protocol Good.txt

Decoding Fields.xlsx

BLENinebotMessage.swift

Edited by Paco Gorina

Share this post


Link to post
Share on other sites

Added a new file with all the decoded fields I Know, formats and units.

Decoded Fields.xlsx

I have now a very simple client that works in iOS and allows logging data to a File and presenting it graphically.

Hope to have it clean a ready for the Apple Store. Anyway once clean will post a project in Github

IMG_0825.jpg

IMG_0828.jpg

IMG_0829.jpg

Share this post


Link to post
Share on other sites

To have a log of current intensity and power would be very useful. It would allow a rider to know whether he plays with limits or drives safely.

Impressive work. Thank you.

Share this post


Link to post
Share on other sites
5 hours ago, Paco Gorina said:

Following decoding of NB protocol fields I upload a log with current (variable #80) and field #74 (for the moment unknown) to see if anybody might find a meaning for #74

9B_20160211_224018.xlsx

9B_20160211_224018.txt

Looking at the data, it appears that the current has a range of 817A to -235A which is a bit outside the range of abilities for the EU.  Any ideas about why it is so far out?  Could the positive and negative ranges may need another divisor applied to represent the actual current?

The pattern I see in the #74 data is a cycling up and down.  It may be gyro data.  Can you align this data with speed to see if when you are stopped when it is around the 675 range? 

Share this post


Link to post
Share on other sites

Looking at the data, it appears that the current has a range of 817A to -235A which is a bit outside the range of abilities for the EU.  Any ideas about why it is so far out?  Could the positive and negative ranges may need another divisor applied to represent the actual current?

Actually  current must be divided by 100 to get Amperes. That is between 8.17 to -2.35 A which is much more reasonable. All the protocol uses ints and one must scale to get the units.

I will get more varied logs of #74 but or it is. A discrete level variable or it seems to saturate but at different levels depending the moment.

Share this post


Link to post
Share on other sites

I have found following code that suggest variable 74 is electric_voltage_12V. (scaled by 100)

Also could be information about the lights (taken by bits)

private class C1158c extends TimerTask {
    final /* synthetic */ jm f5976a;
    private C1158c(jm jmVar) {
        this.f5976a = jmVar;
    }
    public void run() {
        if (this.f5976a.f5987k != null) {
            Message message = new Message();
            message.what = 0;
            Bundle bundle = new Bundle();
            bundle.putInt("electric_voltage", this.f5976a.f5987k.m5787c(71));
            bundle.putInt("electric_voltage_bat1", this.f5976a.f5987k.m5787c(72));
            bundle.putInt("electric_voltage_bat2", this.f5976a.f5987k.m5787c(73));
            bundle.putInt("electric_voltage_12V", this.f5976a.f5987k.m5787c(74));
            bundle.putInt("electric_voltage_5V", this.f5976a.f5987k.m5787c(75));
            bundle.putInt("electric_current", this.f5976a.f5987k.m5787c(80));
            bundle.putInt("electric_current_moto1", this.f5976a.f5987k.m5787c(81));
            bundle.putInt("electric_current_moto2", this.f5976a.f5987k.m5787c(82));
            bundle.putInt("electric_current_phase_moto1", this.f5976a.f5987k.m5787c(83));
            bundle.putInt("electric_current_phase_moto2", this.f5976a.f5987k.m5787c(84));
            message.setData(bundle);
            this.f5976a.f5990n.sendMessage(message);
        }
    }
}

Share this post


Link to post
Share on other sites
34 minutes ago, Paco Gorina said:

I have found following code that suggest variable 74 is electric_voltage_12V. (scaled by 100)

 

Interesting find but a confusing one as well.  The Ninebot uses a step down buck regulator to get the voltage to 13.46V using an LM5005.  This voltage can vary slightly based on load on the 13.46V rail but should be pretty constant.  I don't see how the "74" would map to this voltage.  If we wanted to force it in, you can use "74" = x  Where Voltage = 12+ x / 1000.  This would provide a range from 12.041 to 13.632 in your spreadsheet but I don't like forcing a value into meeting expectations.  Do you have the ability to measure the voltages directly to see if there is a correlation?  

What are you using to connect to make your BLE connection?  I was going to order a BLE sniffer but Adafruit is currently out of stock.

 

 

Share this post


Link to post
Share on other sites

I am not using a sniffer, I built a program that simulates a client (a client for the Ninebot) and a server (that simulates the Ninebot).

I connect the client part to the ninebot and the Ninebot application to the server.

Every write to the variable done by the Application I pass to the ninebot and every variable update from the Ninebot I pass to the server.

That way I may look at all the communication between the Ninebot and the applications.

Hope to have the sources online in one or two days, now cleaning a little. They are for iOS.

I have the pure client part that logs directly the data from the wheel and presents it graphically, stores it into a file and updates a mini application in the Apple Watch with the Speed, time and distance and battery level and remaining distance.

Finishing some details and making them AppleStore suitable.

Share this post


Link to post
Share on other sites

Sending data

Seems similar than asking for values but the 0x09 0x01 are changed to 0x09 and 0x03

So to write the “riding mode” (variable 210, 0xd2 ) to 3 (hexa 0x0003)we shoud send

55 aa 04 09 03 d2 0300 1aff

When setting speed limit its units must be m/h. For example for setting speed (variable 116 = 0x74) limit to 7 km/h

7 km/h = 7000 m/h = 0x1B58

55 aa 04 09 03 74 581b 08ff

Must see what gets changed or not. 

Share this post


Link to post
Share on other sites

Fantastic work, Paco!

I am working on a project to autonomously drive the Ninebot Mini (just ordered one, hope it arrives soon), and plan to reverse engineer the BLE protocol. I hope it will be quite similar to what you've found here. I've got an Adafruit Bluefruit LE sniffer on the way, but have no idea when the Ninebot Mini will arrive...

Edited by bdonkey

Share this post


Link to post
Share on other sites

I think the official client program is the same so protocol must be the same and some of the variables which have no use in Ninebot One may have a use in Ninebot mini, for example there are right wheel and left wheel speeds etc.

I don't believe you need the sniffer as you may use a man in the middle approach if it uses Bluetooth LTE.

I am finishing to clean a bit the code of the MiM and the client to publish it in the Apple Store and it should work the same with the Ninebot mini but I have not way to checking it but I am  bit delayed.

Will see if I may add some additional fields from the disassembled Android code and will publish the findings in the protocol excel in a separate speculative section.

As controlling the mini from an application I have no idea if it is possible. The One only has the maximum speed and som flags that may be set but I have not tried to change anything.

Share this post


Link to post
Share on other sites

The Mini is supposed to be controllable from their app; I would expect it should use the same protocol, but we will see.

 

Share this post


Link to post
Share on other sites

Sent application to the Apple Store *9BMetrics"., will see if it passes the review.

 

Share this post


Link to post
Share on other sites

Cool, Paco!

I only have an Android, unfortunately, but have been able to capture some wireshark packet traces of the BLE between the Ninebot Mini and the Ninebot app. The packet format looks similar to what you described, but I have not figured out the mapping from the handles to the specific characteristic UUIDs yet.

ninebot-advertise-enterapp-enterremote-exitremote-exitapp.pcapng.gz

ninebot-advertise-enterapp-exitapp.pcapng.gz

nrfmastercontrolpanel-gatt-discovery.pcapng.gz

ninebot-advertise-enterapp-enterremote-foward-backward-left-right-exitremote-exitapp.pcapng.gz

Share this post


Link to post
Share on other sites

I would look at the following variable/values as they seem related to two wheel or two battery devices.

Especifically 33 handler angle should apply.

Speed left and right should be speed of left and right wheel

33        handler_angle
63        T Bat 1
64        T Bat 2
38        speed average?
39        speed left
40        speed right
167        angle left
168        angle right

Angle no idea what means

 

Edited by Paco Gorina

Share this post


Link to post
Share on other sites

This is excellent work @Paco Gorina.

Next time it rains all weekend I will try cooking something up for Android (and hopefully Android Wear).

Share this post


Link to post
Share on other sites

Great work. This can be used also for an App for Open Source Boards using BLE communication.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...