Inkbird BBQ4T Local Control

I’ve been working on a way to take local control of the Inkbird BBQ4T as well as integrate into Home Assistant.

This works with a native Inkbird/ SmartLife app as well as the BBQ4T app. As shown in the pics, it does utilize the TuyaMCU.

My first go at this was with tuya-convert. It was successful, but (after some back and forth on taking the plunge), I decided to flash it via TTL. Tasmota done! Problem: unable to enable all 4 probes at the same time. Next step: ESPHome!

After installing ESPHome, I was able to identify the following:

[tuya:036]: Datapoint 110: int value (value: 655350) Probe 4
[tuya:036]: Datapoint 101: int value (value: 100000) Battery
[tuya:034]: Datapoint 1: switch (value: ON) ?Power Button
[tuya:040]: Datapoint 19: enum (value: 1) ?
[tuya:036]: Datapoint 102: int value (value: 30) ?Backlight timer
[tuya:034]: Datapoint 104: switch (value: OFF) ?Alarm Enable/ Mute
[tuya:036]: Datapoint 105: int value (value: 0) ?Timer or Target Temp
[tuya:036]: Datapoint 107: int value (value: 7120) Probe 1
[tuya:036]: Datapoint 108: int value (value: 7211) Probe 2
[tuya:036]: Datapoint 109: int value (value: 7181) Probe 3
[tuya:050]: Product: ‘{“p”:“x6oarivkdgru1upf”,“v”:“1.0.0”,“m”:0}’

Successful on simultaneously capturing individually reporting probes, however I get a value of 65000 when a probe is disconnected. I want to be able to register a null or designate a disconnect status. Not sure if (and how) I could include this with the ESP yaml, or if it would be better to handle that in HA.

The other issue I’m trying to work out is there is an alarm set point function. Basically, you would be able to assign a temperature limit in the app. Once a designated probe reached that temp, the unit would alarm. I appear to have access to some portion of that: DP105 accepts 0 or 10. When the value is 10 and DP104 is ON, the alarm will sound. 105 will timer out and revert to 0 (haven’t been able to lock down the time yet), however I can control the audio willingly by toggling 104 while 105 remains in the 10 state.

DP 1 -appears to be associated with the single button on the unit. Unit is either on (fully connected) or off (disconnected from WiFi). No remote capabilities.

DP19 -no clue

DP102 -appears to be associated with the backlight timeout on the display. Default value is 30 and the backlight turns off after 30 seconds. This was a configurable option within the app iir. Not certain how to provide a configurable input and if that value can be modified via ESPHome.

DP106 -not reported via ESP but regognized via Tasmota. Output can be seen here:
http://paste.ubuntu.com/p/Q8h98MRdq7/plain/

Hoping to make additional progress with some guidance.

1 Like

Hi @kcraig73, interesting work! Not sure if you’ve seen this post? Several of us have had success by getting the secret key and using the Tuya or LocalTuya integration, might help in your investigations.

@kcraig73 curious if you ever got this fully working?

Unfortunately, this one took a backseat to other projects when I hit the above roadblocks. I am still able to use the unit as a live temp read (did so recently through HA and even set up automations), but I have not been able to configure the additional DPs.

You’ve got me beat. I can’t even figure out how to open the thing. No external screws, and doesn’t seem to snap apart.

Screws are located under the face plate which is held down with adhesive. Just carefully pry from the edges. I heated mine slightly to loosen.

I guessed that but thought it kind of odd so stopped prying. Thank you for the quick reply.

I have setup serial sniffing and I am trying to uncover some more Datapoints before switching to Tasmota/ESPHome. I will post further progress here.

Edit: Started a Google sheet to keep everything in order as I tinker with this. @kcraig73 was off to a great start.

Here is what I believe to be a first final version of my current yaml. If there is anyone actually following this thread feel free to critique.

I have exposed most useful datapoints in the way I think works best.

C/F toggle is not included because 'Merica, but actually since the device seems to use Fahrenheit as its default any conversion to Celsius can be done in HA instead. Temperatures values for probe alerts need to be set in F not C.

Along the lines of C/F, I didn’t expose the probe calibration datapoint. As of yet my probes seem good enough for the use case that this just isn’t worth the return.

For probe alerts, a low temp is only used if setting a range. Otherwise you only need to set the high temp.

Still working on a decent Lovelace config for all the information as well.

Edit 1: Added C/F toggle, and restoring of that preference. Also corrected charging status and battery %

Edit 2: Updated names to increase uniqueness, I manually gave everything a friendly name without the bbq4t prefix. Refactored some things.

esphome:
  name: "bbq4t"

esp8266:
  board: esp01_1m
  restore_from_flash: true

logger:
  baud_rate: 0

uart:
  rx_pin: GPIO3
  tx_pin: GPIO1
  baud_rate: 115200

tuya:
  id: mcu
  time_id: homeassistant_time
  on_datapoint_update:
    - sensor_datapoint: 111
      datapoint_type: bitmask
      then:
        lambda: |-
          std::bitset<4> probes(x);
          probes.flip();
          id(probe_1_present).publish_state(probes.test(0));
          id(probe_2_present).publish_state(probes.test(1));
          id(probe_3_present).publish_state(probes.test(2));
          id(probe_4_present).publish_state(probes.test(3));
    - sensor_datapoint: 105
      datapoint_type: int
      then:
        lambda: |-
          std::bitset<4> alerts(x);
          id(probe_1_alert).publish_state(alerts.test(0));
          id(probe_2_alert).publish_state(alerts.test(1));
          id(probe_3_alert).publish_state(alerts.test(2));
          id(probe_4_alert).publish_state(alerts.test(3));
    
  
time:
  - platform: homeassistant
    id: homeassistant_time
     
button:
  - platform: template
    name: "BBQ4T Clear Alerts"
    id: clear_alerts
    icon: "mdi:alert-remove"
    on_press:
      - lambda: |-
          id(mcu).set_integer_datapoint_value(105,0);
      
  - platform: template
    name: "BBQ4T Set Probe Alert"
    id: set_probe_alerts
    icon: "mdi:thermometer-check"
    on_press:
      - lambda: |-
          std::vector<uint8_t> raw(30,0);
          int p1l = (int)id(probe_1_low_temp).state * 10;
          int p1h = (int)id(probe_1_high_temp).state* 10;
          int p2l = (int)id(probe_2_low_temp).state * 10;
          int p2h = (int)id(probe_2_high_temp).state * 10;
          int p3l = (int)id(probe_3_low_temp).state * 10;
          int p3h = (int)id(probe_3_high_temp).state * 10;
          int p4l = (int)id(probe_4_low_temp).state * 10;
          int p4h = (int)id(probe_4_high_temp).state * 10;
          
          //Setup Probe 1
          if (id(probe_1_alerts).state) {
            if (id(probe_1_range).state){
              raw.at(0) = 17;
              raw.at(3) = p1l >> 8;
              raw.at(4) = p1l & 0xFF;
            } else {
              raw.at(0) = 16;
              raw.at(3) = p1h >> 8;
              raw.at(4) = p1h & 0xFF;
            }
            raw.at(1) = p1h >> 8;
            raw.at(2) = p1h & 0xFF;
          } else {
            raw.at(0) = 0;
            raw.at(1) = 0;
            raw.at(2) = 0;
            raw.at(3) = 0;
            raw.at(4) = 0;
          }
          //Setup Probe 2
          if (id(probe_2_alerts).state) {
            if (id(probe_2_range).state){
              raw.at(5) = 17;
              raw.at(8) = p2l >> 8;
              raw.at(9) = p2l & 0xFF;
            } else {
              raw.at(5) = 16;
              raw.at(8) = p2h >> 8;
              raw.at(9) = p2h & 0xFF;
            }
            raw.at(6) = p2h >> 8;
            raw.at(7) = p2h & 0xFF;
          } else {
            raw.at(5) = 0;
            raw.at(6) = 0;
            raw.at(7) = 0;
            raw.at(8) = 0;
            raw.at(9) = 0;
          }
          //Setup Probe 3
          if (id(probe_3_alerts).state) {
            if (id(probe_3_range).state){
              raw.at(10) = 17;
              raw.at(13) = p3l >> 8;
              raw.at(14) = p3l & 0xFF;
            } else {
              raw.at(10) = 16;
              raw.at(13) = p3h >> 8;
              raw.at(14) = p3h & 0xFF;
            }
            raw.at(11) = p3h >> 8;
            raw.at(12) = p3h & 0xFF;
          } else {
            raw.at(10) = 0;
            raw.at(11) = 0;
            raw.at(12) = 0;
            raw.at(13) = 0;
            raw.at(14) = 0;
          }
          //Setup Probe 4
          if (id(probe_4_alerts).state) {
            if (id(probe_4_range).state){
              raw.at(15) = 17;
              raw.at(18) = p4l >> 8;
              raw.at(19) = p4l & 0xFF;
            } else {
              raw.at(15) = 16;
              raw.at(18) = p4h >> 8;
              raw.at(19) = p4h & 0xFF;
            }
            raw.at(16) = p4h >> 8;
            raw.at(17) = p4h & 0xFF;
          } else {
            raw.at(15) = 0;
            raw.at(16) = 0;
            raw.at(17) = 0;
            raw.at(18) = 0;
            raw.at(19) = 0;
          }
          //Send data
          id(mcu).set_raw_datapoint_value(106,raw);
          
switch:
  - platform: "tuya"
    name: "BBQ4T Mute"
    id: mute
    switch_datapoint: 104
    icon: "mdi:volume-mute"

  - platform: template
    name: "BBQ4T Probe 1 Alerts"
    id: probe_1_alerts
    icon: "mdi:thermometer-alert"
    optimistic: true
  - platform: template
    name: "BBQ4T Probe 1 Max/Range"
    id: probe_1_range
    optimistic: true

  - platform: template
    name: "BBQ4T Probe 2 Alerts"
    id: probe_2_alerts
    icon: "mdi:thermometer-alert"
    optimistic: true
  - platform: template
    name: "BBQ4T Probe 2 Max/Range"
    id: probe_2_range
    optimistic: true

  - platform: template
    name: "BBQ4T Probe 3 Alerts"
    id: probe_3_alerts
    icon: "mdi:thermometer-alert"
    optimistic: true
  - platform: template
    name: "BBQ4T Probe 3 Max/Range"
    id: probe_3_range
    optimistic: true
    
  - platform: template
    name: "BBQ4T Probe 4 Alerts"
    id: probe_4_alerts
    icon: "mdi:thermometer-alert"
    optimistic: true
  - platform: template
    name: "BBQ4T Probe 4 Max/Range"
    id: probe_4_range
    optimistic: true

number:
  - platform: template
    name: "BBQ4T Probe 1 Low Temperature"
    id: probe_1_low_temp
    unit_of_measurement: "°F"
    icon: "mdi:snowflake-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1
  - platform: template
    name: "BBQ4T Probe 1 High Temperature"
    id: probe_1_high_temp
    unit_of_measurement: "°F"
    icon: "mdi:fire-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1

  - platform: template
    name: "BBQ4T Probe 2 Low Temperature"
    id: probe_2_low_temp
    unit_of_measurement: "°F"
    icon: "mdi:snowflake-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1    
  - platform: template
    name: "BBQ4T Probe 2 High Temperature"
    id: probe_2_high_temp
    unit_of_measurement: "°F"
    icon: "mdi:fire-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1

  - platform: template
    name: "BBQ4T Probe 3 Low Temperature"
    id: probe_3_low_temp
    unit_of_measurement: "°F"
    icon: "mdi:snowflake-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1
  - platform: template
    name: "BBQ4T Probe 3 High Temperature"
    id: probe_3_high_temp
    unit_of_measurement: "°F"
    icon: "mdi:fire-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1
    
  - platform: template
    name: "BBQ4T Probe 4 Low Temperature"
    id: probe_4_low_temp
    unit_of_measurement: "°F"
    icon: "mdi:snowflake-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1
  - platform: template
    name: "BBQ4T Probe 4 High Temperature"
    id: probe_4_high_temp
    unit_of_measurement: "°F"
    icon: "mdi:fire-alert"
    optimistic: true
    min_value: 0
    max_value: 500
    step: 1    
    
sensor:
  - platform: tuya
    name: "BBQ4T Probe 1 Temperature"
    id: probe_1_temperature
    icon: "mdi:thermometer"
    sensor_datapoint: 107
    unit_of_measurement: "°F"
    device_class: "temperature"
    state_class: "measurement"
    filters:
      - lambda: |-
          if (x < 100000) return x * 0.01;
          else return {};
  - platform: tuya
    name: "BBQ4T Probe 2 Temperature"
    id: probe_2_temperature
    icon: "mdi:thermometer"
    sensor_datapoint: 108
    unit_of_measurement: "°F"
    device_class: "temperature"
    state_class: "measurement"
    filters:
      - lambda: |-
          if (x < 100000) return x * 0.01;
          else return {};
  - platform: tuya
    name: "BBQ4T Probe 3 Temperature"
    id: probe_3_temperature
    icon: "mdi:thermometer"
    sensor_datapoint: 109
    unit_of_measurement: "°F"
    device_class: "temperature"
    state_class: "measurement"
    filters:
      - lambda: |-
          if (x < 100000) return x * 0.01;
          else return {};
  - platform: tuya
    name: "BBQ4T Probe 4 Temperature"
    id: probe_4_temperature
    icon: "mdi:thermometer"
    sensor_datapoint: 110
    unit_of_measurement: "°F"
    device_class: "temperature"
    state_class: "measurement"
    filters:
      - lambda: |-
          if (x < 100000) return x * 0.01;
          else return {};
          
  - platform: tuya
    name: "BBQ4T Battery"
    id: battery
    sensor_datapoint: 101
    unit_of_measurement: "%"
    device_class: "battery"
    state_class: "measurement"
    filters:
      - lambda: |-
          if (x > 100) {
            id(charging).publish_state(1);
            return x * 0.001;
          } else {
            id(charging).publish_state(0);
            return x;
          }
    
binary_sensor:
  - platform: template
    name: "BBQ4T Charging"
    id: charging
    icon: "mdi:battery-charging"
  - platform: template
    name: "BBQ4T Probe 1 Presence"
    id: probe_1_present
    icon: "mdi:connection"
  - platform: template
    name: "BBQ4T Probe 2 Presence"
    id: probe_2_present
    icon: "mdi:connection"
  - platform: template
    name: "BBQ4T Probe 3 Presence"
    id: probe_3_present
    icon: "mdi:connection"
  - platform: template
    name: "BBQ4T Probe 4 Presence"
    id: probe_4_present
    icon: "mdi:connection"
  - platform: template
    name: "BBQ4T Probe 1 Alert"
    id: probe_1_alert
    icon: "mdi:alert"
  - platform: template
    name: "BBQ4T Probe 2 Alert"
    id: probe_2_alert
    icon: "mdi:alert"
  - platform: template
    name: "BBQ4T Probe 3 Alert"
    id: probe_3_alert
    icon: "mdi:alert"
  - platform: template
    name: "BBQ4T Probe 4 Alert"
    id: probe_4_alert
    icon: "mdi:alert"

select:
  - platform: tuya
    name: "BBQ4T Units"
    enum_datapoint: 19
    optimistic: true
    options:
      0: Celsius
      1: Fahrenheit
      
  - platform: template
    name: "BBQ4T Screen Timeout"
    id: screen_timeout
    icon: "mdi:power-sleep"
    optimistic: true
    restore_value: true
    options:
      - "15 Seconds"
      - "30 Seconds"
      - "1 Minute"
      - "5 Minutes"
      - "15 Minutes"
      - "30 Mintues"
      - "1 Hour"
      - "Never"
    on_value:
      - lambda: |-
          switch(i) {
            case 0:
              id(mcu).set_integer_datapoint_value(102,15);
              break;
            case 1:
              id(mcu).set_integer_datapoint_value(102,30);
              break;
            case 2:
              id(mcu).set_integer_datapoint_value(102,60);
              break;
            case 3:
              id(mcu).set_integer_datapoint_value(102,300);
              break;
            case 4:
              id(mcu).set_integer_datapoint_value(102,900);
              break;
            case 5:
              id(mcu).set_integer_datapoint_value(102,1800);
              break;
            case 6:
              id(mcu).set_integer_datapoint_value(102,3600);
              break;
            case 7:
              id(mcu).set_integer_datapoint_value(102,3601);
              break;
          }

Brilliant work. I tried this immediately, and it works great so far (of course, I’d have to try it under actual use conditions). I appreciate the diligence and comments about the beginnings. I am not an ESP pro, especially when it comes to lambdas. This needed your strength to complete.

On the discussion of C/F, HA has the temps in F, however the unit is still in C. Did you discover a toggle that would activate or a way to set the unit to convert?

I also noticed we need to define when the unit is plugged-in/ charging. When I have it charging, it shows the battery at 100,000%.

I definitly learned a lot setting this up. I also assume there are more effcient ways to do some of the things I’ve done. But it’s a huge leap over my old igrill <-> bt <-> mqtt <-> HA setup.

Is C set as you default unit in HA? I use F and everything displays as F. There is a datapoint for switching to C, I will play around with it a little. I’m not sure if its better to handle that conversion on unit or in HA. If you use C as your default maybe you can help with the progress on that side. I’ll add the toggle and see how it impacts things.

Ah yes, the battery, I noticed that as well. When charging the percentage is x 1000. I should be able to fix that easily. I just got lazy and assumed it wouldn’t be plugged in too often when using it.

I prefer Temp displayed in F. I see that defined in the YAML, but the physical display still shows C. Not sure if there’s a way to modify that. I seem to recall the original app had a modification for temp unit display.

Alright, I think I’ve solved your issue. Edited the above post to include restoring from flash, this should fix C/F and also restore the LCD timeout. Also added a charging binary and fixed battery output.

1 Like

Works perfectly. Nice MDI additions as well.

Thank you! I am hopeful others find this and can make use of it as well!

This is great work guys, I wonder if I could ask how you went about flashing the unit? I have tried tuya-convert with no luck. Does the USB port do serial? Or will I need to use a serial adapter on the esp itself?

I use localtuya and have it fully integrated.

I used a serial to usb and flashed with ESPHome.

Nice card. I’ll have to use that as inspiration for a custom card. The presets are the only thing we’ll be missing, although I’m sure it’s possible to simulate with a template.

Thanks mate, do you have the pinout for the chip? Do you know the procedure for putting it into flashing mode?