Skip to content

Instantly share code, notes, and snippets.

@uucidl
Last active August 27, 2023 22:21
Show Gist options
  • 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

@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