Skip to content

Instantly share code, notes, and snippets.

@uucidl
Last active August 27, 2023 22:21
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save uucidl/b9c60b6d36d8080d085a8e3310621d64 to your computer and use it in GitHub Desktop.
Save uucidl/b9c60b6d36d8080d085a8e3310621d64 to your computer and use it in GitHub Desktop.
ibbq-thermometer-protocol

Example devices

  • Inkbird IBT-2X
  • Inkbird IBT-4XS
  • EasyBBQ FCCID: FCC ID 2AI4MPRO3 (SHENZHEN HYPERSYNES CO.,LTD Smart Wireless Thermometer PRO3)

Properties

  • @ConnectTimeout: 60 seconds
  • @BatteryPollingInterval: 5 minutes

The iBBQ is a Bluetooth LE Gatt Device

@DeviceName: iBBQ

Standard Descriptor:

  • @ClientCharacteristicConfigurationDescriptor: @uuid16{0x2902}

Its main service at @uuid16{0xfff0} contains the following characteristics:

  • @SettingsResult: @uuid16{0xfff1} @notify returns results from control messages
  • @AccountAndVerify: @uuid16{0xfff2} @write deals with the pairing process
  • @HistoryData: @uuid16{0xfff3} @notify is not yet properly documented
  • @RealtimeData: @uuid16{0xfff4} @notify returns the results from probes
  • @SettingsData: @uuid16{0xfff5} @write is where control messages are sent

Some messages

Here are some hardcoded messages:

  • @CredentialsMessage: (:byte[]) { 0x21, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0xb8, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00}
  • @RealtimeDataEnableMessage: (:byte[]) { 0x0B, 0x01, 0x00, 0x00, 0x00, 0x00}
  • @UnitsFahrenheitMessage: (:byte[]) { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00}
  • @UnitsCelsiusMessage: (:byte[]) { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}
  • @RequestBatteryLevelMessage: (:byte[]) { 0x08, 0x24, 0x00, 0x00, 0x00, 0x00 }

A message exists to set target temperatures (low and high, the closest of which will be displayed on the screen)

  • @SetTargetTempMessage: (:byte[]) { 0x01, probe-nr, low[0:7bits], low[8:15bits], high[0:7bits], high[8:15bits] }
    • probe-nr is the probe to select, from 0 onwwards
    • low is a int16 signed integer for the lower temperature, in 10^-1 Celsius
    • high is a int16 signed integer for the higher temperature, in 10^-1 Celsius
initiate-login :: 
  write @CredentialsMessage to characteristic @AccountAndVerify
enable-realtime-data ::
  enable notifications on @ClientCharacteristicConfigurationDescriptor
  write @RealtimeDataEnableMessage to characteristic @SettingsData
set-unit :: Fahrenheit or Celsius
  when Fahrenheit write @UnitsFahrenheitMessage to characteristic @SettingsData
  when Celsius    write @UnitsCelsiusMessage to characteristic @SettingsData
request-battery-level ::
  write @RequestBatteryLevelMessage to characteristic @SettingsData
set-target-temp ::
  write @SetTargetTempMessage to characteristic @SettingsData

When settings are written to @SettingsData, results are received on @SettingsResult

When request-battery-level has been sent, @SettingsResult will receive data which can be parsed as:

struct BatteryLevels {
  header: uint8 = data[0], // header == 0x24
  currentVoltage: uint16 = data[1] | data[2] << 8, // up to maxVoltage
  maxVoltage: uint16 = data[3] | data[4] << 8, // if 0 maxVoltage is 6550
}

When enable-realtime-data has been sent, @RealtimeData will receive data which can be parsed as:

  num_probes = sizeof(data)/sizeof(uint16)
  probes: uint16[num_probes]
  with 0 < i < num_probes:  
    probes[i] : uint16 = data[2*i] | data[2*i + 1] << 8

There's an history data end-point, but the format is unknown.

Alarm
  • Device: IBT-4XS
  • @SilenceAlarmMessage: (:byte[]) { 0x04, 0xff, 0x00, 0x00, 0x00, 0x00 }

Device alarm can be silenced by sending @SilenceAlarmMessage to the @SettingsData characteristic.

When an alarm is silenced by the user pressing the device's button, @SilenceAlarmMessage is received on @SettingsResult

@pmn1966
Copy link

pmn1966 commented Jun 9, 2020

Is there anything special to do to receive data on FFF0/FFF4 and FFF0/FFF1 ?
I dont receive any data on these two. All others are working fine. eg. 1800/2A00.

I can change from °C to °F, but i cant read any responce for e.g. Barttery on FFF0/FFF1 and probe data on FFF0/FFF4.

(by the way im using Labview BLE toolkit)

Br

@uucidl
Copy link
Author

uucidl commented Jun 9, 2020

The device is very strict, you need to follow the procedure of sending initiate-login and then enable-realtime-data

I have a working Android App that tracks temperature but the android API is really bad and hard to use as reference. It's not on github for that reason.

However I remember there's a go project that exists out there which is very easy to read:

https://github.com/sworisbreathing/go-ibbq/blob/master/ibbq.go

@p1ng0o
Copy link

p1ng0o commented Jun 24, 2020

Same here, sending initiate login seems to keep the connexion open, but I didn't receive realtime data at all.
I have a 6 channel device.

@pmn1966
Copy link

pmn1966 commented Jun 24, 2020

@p1ng0o

I found the solution:

You need to subscribe to the probe data by sending x0001 to FFF0/FFF4
To unsubscribe send x0000 to FFF0/FFF4

For Control Message e.g. Battery level subscribe by sending x0001 to FFF0/FFF1
To unsubscribe send x0000 to FFF0/FFF1

Let me know if you manage to figure it out.
I made a Labview program that show the probe temperatures and the Battery level :-)
Capture

@p1ng0o
Copy link

p1ng0o commented Jun 24, 2020

Ok, fixed.

the client caracteristics configuration descriptior has to be configured in order to read the data.

Writing 0x0100 in 0x2902 let me received notifications.

Thanks

@uucidl
Copy link
Author

uucidl commented Jun 27, 2020

Yes indeed, I did not document that because I understood this as standard bluetooth le!

@non-programmer
Copy link

I would like to ask you for help with the iBBQ thermometer.
I'm trying to use HM-10 BLE 4.0 serial module to connect to the iBBQ and read temperature.
What is the actual code sent when you say "writing 0x0100 in 0x2902" or
"CredentialsMessage: (:byte[]) { 0x21, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0xb8, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00}
to AccountAndVerify: @uuid16{0xfff2}"
I don't use Arduino, I don't know C-language. I need to see the actual HEX numbers sent in the order they are sent including any hidden commands sent by compiler.
I'm a non programmer. My programming comes down to copy and paste or monkey see monkey do.

@non-programmer
Copy link

My question may not be as clear as I think. I can connect to BBQ thermometer from HM-10 BLE 4.0
After the OK+CONN message I need to send the verification and notification characteristics and that's the part I can't figure out.
In simple term I need to specify I want to send data 0x100 to address 0x2902.
I would like to see the byte stream that has to be sent. Can you help? Thanks.

@july1206
Copy link

Hi.
Evry time I try to start I receive this error:
pls little bit of help?
Tnx!

sudo LOGXI=main=INF ./datalogger
14:09:45.913929 FTL main Error creating iBBQ
err: can't init hci: no devices available: (hci0: can't down device: device or resource busy)
goroutine 1 [running]:
runtime..z2fdebug.Stack
../../../src/libgo/go/runtime/debug/stack.go:24
github.com..z2fmgutz..z2flogxi..z2fv1.HappyDevFormatter.getLevelContext
/home/io/go/pkg/mod/github.com/mgutz/logxi@v0.0.0-20161027140823-aebf8a7d67ab/v1/happyDevFormatter.go:223
github.com..z2fmgutz..z2flogxi..z2fv1.HappyDevFormatter.Format
/home/io/go/pkg/mod/github.com/mgutz/logxi@v0.0.0-20161027140823-aebf8a7d67ab/v1/happyDevFormatter.go:307
github.com..z2fmgutz..z2flogxi..z2fv1.DefaultLogger.Log
/home/io/go/pkg/mod/github.com/mgutz/logxi@v0.0.0-20161027140823-aebf8a7d67ab/v1/defaultLogger.go:117
github.com..z2fmgutz..z2flogxi..z2fv1.DefaultLogger.extractLogError
/home/io/go/pkg/mod/github.com/mgutz/logxi@v0.0.0-20161027140823-aebf8a7d67ab/v1/defaultLogger.go:98
github.com..z2fmgutz..z2flogxi..z2fv1.DefaultLogger.Fatal
/home/io/go/pkg/mod/github.com/mgutz/logxi@v0.0.0-20161027140823-aebf8a7d67ab/v1/defaultLogger.go:107
main.main
/home/io/Downloads/go-ibbq-master/examples/datalogger/main.go:64

panic: Exit due to fatal error:

goroutine 1 [running]:
github.com..z2fmgutz..z2flogxi..z2fv1.DefaultLogger.Fatal
/home/io/go/pkg/mod/github.com/mgutz/logxi@v0.0.0-20161027140823-aebf8a7d67ab/v1/defaultLogger.go:109
main.main
/home/io/Downloads/go-ibbq-master/examples/datalogger/main.go:64

@uucidl
Copy link
Author

uucidl commented Sep 13, 2020

Hi.
Evry time I try to start I receive this error:
pls little bit of help?
Tnx!

sudo LOGXI=main=INF ./datalogger
14:09:45.913929 FTL main Error creating iBBQ
err: can't init hci: no devices available: (hci0: can't down device: device or resource busy)
goroutine 1 [running]:

Hi. Your question should be directed at the source project, not here. See https://github.com/sworisbreathing/go-ibbq

@p1ng0o
Copy link

p1ng0o commented Nov 7, 2020

Hi, is someone have more informations regarding SetTargetTempMessage ?
I would like to:

  • Reset the target temp
  • Set only a target to reach, not a zone

@SerpikoIT
Copy link

hi I also have an Inkbird IBT-2X and I would like to read the temperatures online from a site or app from my mobile, is it possible ???

@qwandor
Copy link

qwandor commented Jan 9, 2021

Has anyone had any luck figuring out how SetTargetTemp works? It doesn't seem to work for me if I pass a value higher than 360 (36°) for the second temperature, and I haven't figured out how the first one works.

@qwandor
Copy link

qwandor commented Jan 10, 2021

Okay, answering my own question:

The second byte of the SetTargetTemp message is the probe number, counting from 0.

Bytes 3-4 are the lower end of the target temperature range, as a little-endian signed integer of the temperature in degrees Celcius multiplied by 10. If just a single target temperature is desired then -3000 is passed (i.e. -300°C).
Bytes 5-6 are the top end of the target temperature range, encoded in the same way.
The screen of the device will display whichever end of the range is closest to the current temperature, hence my earlier confusion.

@uucidl
Copy link
Author

uucidl commented Jan 10, 2021

Okay, answering my own question:

The second byte of the SetTargetTemp message is the probe number, counting from 0.

Bytes 3-4 are the lower end of the target temperature range, as a little-endian signed integer of the temperature in degrees Celcius multiplied by 10. If just a single target temperature is desired then -3000 is passed (i.e. -300°C).
Bytes 5-6 are the top end of the target temperature range, encoded in the same way.
The screen of the device will display whichever end of the range is closest to the current temperature, hence my earlier confusion.

Thanks, this made me realize that the gist had bad syntax, the second byte was documented as the probe number but it wasn't showing up because I typed it as <probe-nr> and it wasn't showing on github. Fixed it. I've added your note about the units being in decacelsius decicelsius.

@p1ng0o
Copy link

p1ng0o commented Jan 10, 2021

Here what is working for me:

    async def ack_alarm(self):
        await self.__write(self.settings_handle, b'\x04\xff\x00\x00\x00\x00')

    async def write_target(self, channel, high = None, low = None):
        if low:
            low = low*10
        else:
            low = 0xf448

        if high:
            high = high*10
        else:
            high = 0xbcc

        m = bytes([1, channel, low & 0xFF, low >> 8, high & 0xFF, high >> 8])
        await self.__write(self.settings_handle, m)

There is a magic trick regarding these numbers.

write_target can ether clean the target temp, set only a temp target (meat), setup a min/max space (pit watcher).

@lukepighetti
Copy link

Would love to know if anyone has the history dump working.

@kernel610
Copy link

I have set the measurement unit using @UnitsFahrenheitMessage which sets the monitoring device appropriately; however the temp reported back is still in Celsius. Is this expected?

@atessmer
Copy link

Device: IBT-4XS

Device alarm can be silenced by sending @SilenceAlarmMessage: (:byte[]) { 0x04, 0xff, 0x00, 0x00, 0x00, 0x00 } to the @SettingsData characteristic.

Similarly, when an alarm is silenced by pressing the button on the device, it sends the same @SilenceAlarmMessage to the client via the @SettingsResult characteristic

@Pelicans-git
Copy link

Would it be possible to see a hex dump of a trace from start to receiving first temperature? That will be incredibly helpful.

@arjfca
Copy link

arjfca commented Nov 4, 2021

Hello

IBBQ & ESP32

The goal is to be able to access my Bluetooth thermometer using WIFI instead of Bluetooth BLE.

I'm loss... So many interogation. Never worked with these new protocols.

  • I did apply for a MQTT server (HiveMQ Websocket Client)

What should I look for once the code has been uploaded to a ESP32?

Once loaded, how do I confirm

  • the code is working and the thermometer is linked to my ESP32?
  • How do I access information from my phone or tablet?

For the credential.h
Do I use my actual home WIFI SSID and password or create a new one

Do I modify the code line
#include "C:\Users\Utilisateur\Documents\Arduino\libraries\InkBird_BLE2MQTT-master\src\credentials.example.h"
for
#include "C:\Users\Utilisateur\Documents\Arduino\libraries\InkBird_BLE2MQTT-master\src\credentials.h"


I had some compiling error with the original code for a ESP32. I resolved them by replacing
//#include "BLEDevice.h"
with
#include <NimBLEDevice.h> //Seem to use less memory to run the BLE

Any help will be appreciated

Martin

@Kerrdog01
Copy link

Has anyone worked this out in python? I have been trying for days and have looked up so many other examples but can't get it working. Any help would be amazing please

@Kerrdog01
Copy link

After spending just about the whole day looking for a solution I have found a working solution written by a genius!
https://github.com/8none1/pybq/blob/master/bbq.py
Just don't use the MQTT part if you don't need it. It worked the first time for me. I need to learn what they did but hopefully, it helps others!

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