sworisbreathing / go-ibbq

go-ble library for Inkbird wireless thermometers
Apache License 2.0
41 stars 15 forks source link

battery level question #2

Open pauledd opened 5 years ago

pauledd commented 5 years ago

Hi Sorry, a little bit offtopic. I currently try to find out how to parse the battery level via gatttool. If I understand correctly I need to send a write request to handle 0x0034 with the value 082400000000. char-write-req 0x0034 082400000000 I then get a notification handle with a value back: Notification handle = 0x0025 value: 24 7e 17 96 19 00 I assume that the value is the battery level, right? How did you convert this in percentage?

sworisbreathing commented 5 years ago

Hi @pauledd,

The logic for converting the byte data is in ibbq.go. The first byte (0x24) is what tells you it's a battery level message. The next two bytes are little endian representation of the current voltage, and the following 2 bytes are little endian representation of the max voltage. The 00 I think is just a null terminator, but tbh it's been a while since I've looked at the packet captures in detail.

pauledd commented 5 years ago

thanks! But strange, if I pair the thermometer to my android I read battery is at 59%. If I then connect via gatttool and send: char-write-char-write-req 0x0034 082400000000 I then receive: Notification handle = 0x0025 value: 24 59 17 96 19 00 and that is 0x1759 = 5977 and 0x1996 = 6550 but 5977 cant be 59% of 6550 or do I miss something?

Screenshot_2019-05-10-19-12-45

[edit]: I just managed to build your go application and it shows 91% battery. Hm so something is wrong..

sworisbreathing commented 5 years ago

@pauledd I think you might be right. Looking into it a bit further, I think the issue is the data is in big endian order, not little endian.

Little-endian version:

raw bytes: 24 59 17 96 19 00
actual voltage: 0x1759 (5977)
max voltage: 0x1996 (6550)
percentage: 100 * 5977 / 6550 = 91.25%

Big-endian version:

raw bytes: 24 59 17 96 19 00
actual voltage: 0x5917 (22807)
max voltage: 0x9619 (38425)
percentage: 100 * 22807 / 38425 = 59.35%

I'll push up a fix shortly.

sworisbreathing commented 5 years ago

okay that's fixed. Now the bigger question I have in my mind is, are the temperature readings correct? or are they also big-endian instead of little-endian. I'll need to do some more testing.

pauledd commented 5 years ago

Well, my 1st. sensor shows at 22°C a value of "dc000000" and at 29°C "22010000" that would be 220 and 290 dec in little endian. Quite weird to have little and big endian outputs but why not ;)

sworisbreathing commented 4 years ago

@pauledd how has this update been working for you? I just ran a cook on the new build and the battery levels were all over the place. First 90 then down to 67 then down to 3 then up somewhere above 100 a few minutes later. Whatever these readings are, they don't seem to be big-endian.

jshridha commented 4 years ago

@sworisbreathing @pauledd Have you had any luck with this battery translation issue? I'm having similar problem with some python code I've been working on.

sworisbreathing commented 4 years ago

@jshridha no, I've been looking at it off and on for a while now, and I can't make any headway on it. Neither big-endian nor little-endian interpretation of the data seems to come up with battery levels that match what the android app outputs.

pmn1966 commented 4 years ago

@sworisbreathing @pauledd Did any you found a solution to this? I have exact the same issue with the battery level jumping up and down when using big-endian. I made a test where i ran from full battery level until the Inkbird ran out off power. But no matter how i calculate the battery level i dont get anything similar to the reading in the Iphone BBQ Go App. Could it be somekind of compensation do to a not linear battery discharge?

pmn1966 commented 4 years ago

Here is a screenshot of the discharge curve. (the program is made in LabView:-)

image

Ruben-E commented 4 years ago

I did some investigation by decompiling the Android app.

The current and max voltage are actually little-endian. The current voltage jumps and bit up and down for me as well (first = current, second = max):

6662 6550
6662 6550
6664 6550
6675 6550
6687 6550
6699 6550
6712 6550

After digging a little deeper I found the place where the percentage is calculated. There is an array with different voltage levels belonging to a certain percentage. That seemed a bit weird, why not calculate the percentage based on the current in relation to the min and max voltage. But apparently the voltage levels are not linear:

So this array it used to plot the current voltage against for the actual percentage.

I'm writing a iBBQ library for NodeJS where I implemented this myself: https://github.com/Ruben-E/node-ibbq. It seems to report the correct percentage. Although mine is still 100%, but the app and the device itself are also reporting that.

This is the code used for it (location in the repo here):

let currentVoltage = data.readIntLE(1, 2)
let maxVoltage = data.readIntLE(3, 2)
if (maxVoltage == 0) maxVoltage = 6550;

// const voltages = [5580, 5595, 5609, 5624, 5639, 5644, 5649, 5654, 5661, 5668, 5676, 5683, 5698, 5712, 5727, 5733, 5739, 5744, 5750, 5756, 5759, 5762, 5765, 5768, 5771, 5774, 5777, 5780, 5783, 5786, 5789, 5792, 5795, 5798, 5801, 5807, 5813, 5818, 5824, 5830, 5830, 5830, 5835, 5840, 5845, 5851, 5857, 5864, 5870, 5876, 5882, 5888, 5894, 5900, 5906, 5915, 5924, 5934, 5943, 5952, 5961, 5970, 5980, 5989, 5998, 6007, 6016, 6026, 6035, 6044, 6052, 6062, 6072, 6081, 6090, 6103, 6115, 6128, 6140, 6153, 6172, 6191, 6211, 6230, 6249, 6265, 6280, 6285, 6290, 6295, 6300, 6305, 6310, 6315, 6320, 6325, 6330, 6335, 6340, 6344];
const voltages = [5580, 5595, 5609, 5624, 5639, 5644, 5649, 5654, 5661, 5668, 5676, 5683, 5698, 5712, 5727, 5733, 5739, 5744, 5750, 5756, 5759, 5762, 5765, 5768, 5771, 5774, 5777, 5780, 5783, 5786, 5789, 5792, 5795, 5798, 5801, 5807, 5813, 5818, 5824, 5830, 5830, 5830, 5835, 5840, 5845, 5851, 5857, 5864, 5870, 5876, 5882, 5888, 5894, 5900, 5906, 5915, 5924, 5934, 5943, 5952, 5961, 5970, 5980, 5989, 5998, 6007, 6016, 6026, 6035, 6044, 6052, 6062, 6072, 6081, 6090, 6103, 6115, 6128, 6140, 6153, 6172, 6191, 6211, 6230, 6249, 6265, 6280, 6296, 6312, 6328, 6344, 6360, 6370, 6381, 6391, 6407, 6423, 6431, 6439, 6455];
const percentage = (current: number, max: number) => {
    const factor = max / 6550.0;
    const length = voltages.length;

    if (current > voltages[length - 1] * factor) {
        return 100;
    }

    if (current <= voltages[0] * factor) {
        return 0;
    }

    for (let i = 0; i < length - 1; i++) {
        if (current > voltages[i] * factor && current <= voltages[i + 1] * factor) {
            return i + 1;
        }
    }

    return 100;
}

console.log(percentage(currentVoltage, maxVoltage));

I found two of these voltage arrays, not sure which one to use yet.

jshridha commented 4 years ago

@Ruben-E Thanks for sharing that fix! Can you let me know how you decompiled the APK? I'd like to reproduce for my project and for my education. Thanks!

vondraussen commented 4 years ago
// const voltages = [5580, 5595, 5609, 5624, 5639, 5644, 5649, 5654, 5661, 5668, 5676, 5683, 5698, 5712, 5727, 5733, 5739, 5744, 5750, 5756, 5759, 5762, 5765, 5768, 5771, 5774, 5777, 5780, 5783, 5786, 5789, 5792, 5795, 5798, 5801, 5807, 5813, 5818, 5824, 5830, 5830, 5830, 5835, 5840, 5845, 5851, 5857, 5864, 5870, 5876, 5882, 5888, 5894, 5900, 5906, 5915, 5924, 5934, 5943, 5952, 5961, 5970, 5980, 5989, 5998, 6007, 6016, 6026, 6035, 6044, 6052, 6062, 6072, 6081, 6090, 6103, 6115, 6128, 6140, 6153, 6172, 6191, 6211, 6230, 6249, 6265, 6280, 6285, 6290, 6295, 6300, 6305, 6310, 6315, 6320, 6325, 6330, 6335, 6340, 6344];
const voltages = [5580, 5595, 5609, 5624, 5639, 5644, 5649, 5654, 5661, 5668, 5676, 5683, 5698, 5712, 5727, 5733, 5739, 5744, 5750, 5756, 5759, 5762, 5765, 5768, 5771, 5774, 5777, 5780, 5783, 5786, 5789, 5792, 5795, 5798, 5801, 5807, 5813, 5818, 5824, 5830, 5830, 5830, 5835, 5840, 5845, 5851, 5857, 5864, 5870, 5876, 5882, 5888, 5894, 5900, 5906, 5915, 5924, 5934, 5943, 5952, 5961, 5970, 5980, 5989, 5998, 6007, 6016, 6026, 6035, 6044, 6052, 6062, 6072, 6081, 6090, 6103, 6115, 6128, 6140, 6153, 6172, 6191, 6211, 6230, 6249, 6265, 6280, 6296, 6312, 6328, 6344, 6360, 6370, 6381, 6391, 6407, 6423, 6431, 6439, 6455];
const percentage = (current: number, max: number) => {
    const factor = max / 6550.0;
    const length = voltages.length;

    if (current > voltages[length - 1] * factor) {
        return 100;
    }

    if (current <= voltages[0] * factor) {
        return 0;
    }

    for (let i = 0; i < length - 1; i++) {
        if (current > voltages[i] * factor && current <= voltages[i + 1] * factor) {
            return i + 1;
        }
    }

    return 100;
}

console.log(percentage(currentVoltage, maxVoltage));

I found two of these voltage arrays, not sure which one to use yet.

@Ruben-E I think the right correction array is dependent on the device you are using. I've decompiled an APP I'm using with the iBBQ-2x and in the source they are using the one which ends with 6344 for a device called bbqgo.

Ruben-E commented 4 years ago

@Ruben-E Thanks for sharing that fix! Can you let me know how you decompiled the APK? I'd like to reproduce for my project and for my education. Thanks!

One of the most easiest ways is using a website for that. Grab the .apk file from somewhere and decompile it. Be careful if you download the .apk file from a random place tho. Decompiling should be fine, but I would not run it on the phone. Unfortunately names of classes, variables and methods are obfuscated which makes it hard to find your way around in the decompiled app. Some smart searching for strings will get you started.

Ruben-E commented 4 years ago
// const voltages = [5580, 5595, 5609, 5624, 5639, 5644, 5649, 5654, 5661, 5668, 5676, 5683, 5698, 5712, 5727, 5733, 5739, 5744, 5750, 5756, 5759, 5762, 5765, 5768, 5771, 5774, 5777, 5780, 5783, 5786, 5789, 5792, 5795, 5798, 5801, 5807, 5813, 5818, 5824, 5830, 5830, 5830, 5835, 5840, 5845, 5851, 5857, 5864, 5870, 5876, 5882, 5888, 5894, 5900, 5906, 5915, 5924, 5934, 5943, 5952, 5961, 5970, 5980, 5989, 5998, 6007, 6016, 6026, 6035, 6044, 6052, 6062, 6072, 6081, 6090, 6103, 6115, 6128, 6140, 6153, 6172, 6191, 6211, 6230, 6249, 6265, 6280, 6285, 6290, 6295, 6300, 6305, 6310, 6315, 6320, 6325, 6330, 6335, 6340, 6344];
const voltages = [5580, 5595, 5609, 5624, 5639, 5644, 5649, 5654, 5661, 5668, 5676, 5683, 5698, 5712, 5727, 5733, 5739, 5744, 5750, 5756, 5759, 5762, 5765, 5768, 5771, 5774, 5777, 5780, 5783, 5786, 5789, 5792, 5795, 5798, 5801, 5807, 5813, 5818, 5824, 5830, 5830, 5830, 5835, 5840, 5845, 5851, 5857, 5864, 5870, 5876, 5882, 5888, 5894, 5900, 5906, 5915, 5924, 5934, 5943, 5952, 5961, 5970, 5980, 5989, 5998, 6007, 6016, 6026, 6035, 6044, 6052, 6062, 6072, 6081, 6090, 6103, 6115, 6128, 6140, 6153, 6172, 6191, 6211, 6230, 6249, 6265, 6280, 6296, 6312, 6328, 6344, 6360, 6370, 6381, 6391, 6407, 6423, 6431, 6439, 6455];
const percentage = (current: number, max: number) => {
    const factor = max / 6550.0;
    const length = voltages.length;

    if (current > voltages[length - 1] * factor) {
        return 100;
    }

    if (current <= voltages[0] * factor) {
        return 0;
    }

    for (let i = 0; i < length - 1; i++) {
        if (current > voltages[i] * factor && current <= voltages[i + 1] * factor) {
            return i + 1;
        }
    }

    return 100;
}

console.log(percentage(currentVoltage, maxVoltage));

I found two of these voltage arrays, not sure which one to use yet.

@Ruben-E I think the right correction array is dependent on the device you are using. I've decompiled an APP I'm using with the iBBQ-2x and in the source they are using the one which ends with 6344 for a device called bbqgo.

Looks like it indeed. Same for the app I decompiled (same package name I see, but different developer name).

vondraussen commented 4 years ago

Looks like it indeed. Same for the app I decompiled (same package name I see, but different developer name).

I think this is one and the same "example app" from the original hardware manufacturer and the resellers (like inkbird) just do slight adaptations.