Cannot get Tuya Integration to work

seems like LocalTuya and 2023.5.2 doesnt want to save the last entity change, regadless of the type - i thought it was the °F & °C turns out it was any change and wouldnt commit the last ID change - i rolled back to 2023.4.6 and it was ok.

On the “missing” entities IDs 107,108,109,110… I added uting the manual DPS option and now have probe_one (107) showing a string of all sensors rather than individual probes as i expected to see when i got all 11 known entities to show up. I dont have the protocol or have searched much on using this string.

I have been investigiating the changing of instruction from standard to DP instruction - although looked like I was getting somewhere…doesnt seem to make much difference to whats being accessed in LocalTuya

Hi @DJL9999 , did you have any luck with resolving this? Mine seems to be doing a similar thing with the 107 DPS except it’s showing a value of ‘aBoAAZYeAAH2/wkB9v8JAQ==’. I can’t seem to get any temperatures out of the device via the localtuya integration.

1 Like

Hey all! This thread seems to be the best source of information on how this thermometer is set up, so I thought I’d add some information on how DPS/datapoints 120 through 123 function.

These are the thermometer alarm mode and setpoints set in hex, with a bit of rearranging. I’ll do my best to explain…

Datapoints 120-123 format: XX.YY.YY.ZZ.ZZ

XX: Temp Alarm Mode
  00 = Alarm Disabled
  10 = Max Temp Alarm
  11 = Temp Range Alarm
YY.YY: High/Max Temp (bytes flipped)
ZZ.ZZ: Low Temp (bytes flipped)

Flip the first and second byte values to get the temp value in HEX

Example: Set a Temp Range of Min 32F to Max 590F

  • Use an alarm mode of Temp Range (11)
  • 32F
    • Decimal integer x10 is 320
    • Hex is 0140
    • Flip the 01 and 40 byte values: 40.01
  • 590F
    • Decimal integer x10 is 5900
    • Hex is 170C
    • Flip the 17 and 0C byte values: 0C.17
  • Resulting datapoint value: 11.0C.17.40.01

I’ve been busy converting all my Tuya devices over to ESPHome (both native esp8266 and BK7231-based libretiny), and this thermometer is one of my last remaining devices to convert. When I finish setting up the ESPHome yaml for it, I’ll dump the config here.

1 Like

I don’t have “custom:template-entity-row”. Where do I get that from?

HACS is your friend. Or dive into Github:

thomasloven/lovelace-template-entity-row: :small_blue_diamond: Display whatever you want in an entities card row. (github.com)

Hi @DJL9999. I’m not sure if you already have found a solution however I received a response from Inkbird (after many back and forwards).

They stated “The following is the engineer’s explanation:
ZBoAAIAbAACUGwAAHBsAAA== <— Value held in DPs107
Base64 decoding obtained
CC 1A 00 00 80 1B 00 00 94 1B 00 00 1C 1B 00 00 00
4 bytes per temperature.
CC 1A 00 00 Probe 1 Temperature 80 1B 00 00 Probe 2 Temperature, and so on
The transmission data is in small end mode and converted to decimal.
00001ACC converted to decimal to 6860
6860/100=68.6 F Fahrenheit”

Based on that information, I have used NodeRed to decode the Base64 string and output 4 temperature values to HomeAssistant. Below is the flow which you can import. It is in Celsius as the entity state, but also outputs Fahrenheit as an attribute. I thought I would share this in case it helps you or others.

NodeRed Flow:

[
    {
        "id": "7066186d409631ab",
        "type": "tab",
        "label": "IBBQ Temp",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "8b23198e06f322f9",
        "type": "server-state-changed",
        "z": "7066186d409631ab",
        "name": "Get temp from Probe 1 field",
        "server": "56676c55.140b84",
        "version": 3,
        "exposeToHomeAssistant": false,
        "haConfig": [
            {
                "property": "name",
                "value": ""
            },
            {
                "property": "icon",
                "value": ""
            }
        ],
        "entityidfilter": "sensor.ibbq_probe_1",
        "entityidfiltertype": "exact",
        "outputinitially": true,
        "state_type": "str",
        "haltifstate": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "outputs": 1,
        "output_only_on_state_change": false,
        "for": 0,
        "forType": "num",
        "forUnits": "minutes",
        "ignorePrevStateNull": false,
        "ignorePrevStateUnknown": false,
        "ignorePrevStateUnavailable": false,
        "ignoreCurrentStateUnknown": false,
        "ignoreCurrentStateUnavailable": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "eventData"
            },
            {
                "property": "topic",
                "propertyType": "msg",
                "value": "",
                "valueType": "triggerId"
            }
        ],
        "x": 120,
        "y": 200,
        "wires": [
            [
                "76400e190d0614fe"
            ]
        ]
    },
    {
        "id": "76400e190d0614fe",
        "type": "function",
        "z": "7066186d409631ab",
        "name": "Calc Base64 values into 4 temp values",
        "func": "// Output 'Not Connected' if the device is unavailable\nif (msg.payload === 'unavailable') {\n    for (let i = 0; i < 4; i++) {\n        msg[`ibbq_temp${i + 1}`] = \"Not Connected\";\n        msg[`ibbq_temp${i + 1}_fahrenheit`] = \"Not Connected\";\n    }\n    return msg;\n}\n\n// Decode the payload from base64 format\nconst decodedBytes = Buffer.from(msg.payload, 'base64');\nconst temperatureBytes = [];\n\n// Split the decoded payload into temperature bytes\nfor (let i = 0; i < decodedBytes.length; i += 4) {\n    temperatureBytes.push(decodedBytes.slice(i, i + 4));\n}\n\nconst celsiusTemperatures = [];\nconst fahrenheitTemperatures = [];\nlet allNotConnected = true;\n\n// Convert temperature bytes to Celsius and Fahrenheit and store in the message\nfor (let i = 0; i < 4; i++) {\n    const sensorName = `ibbq_temp${i + 1}`;\n    \n    if (i < temperatureBytes.length) {\n        const fahrenheit = temperatureBytes[i].readInt32LE(0) / 100;\n        const celsius = (fahrenheit - 32) * 5 / 9;\n            //If the result is greater than 1000, then the probe isn't connected\n        if (celsius <= 1000) {\n            msg[sensorName] = Math.round(celsius * 100) / 100; // Output Celsius as integer\n            msg[`${sensorName}_fahrenheit`] = Math.round(fahrenheit * 100) / 100; // Output Fahrenheit as integer\n            celsiusTemperatures.push(Math.round(celsius * 100) / 100);\n            fahrenheitTemperatures.push(Math.round(fahrenheit * 100) / 100);\n            allNotConnected = false;\n        } else {\n            msg[sensorName] = \"Not Connected\";\n            msg[`${sensorName}_fahrenheit`] = \"Not Connected\";\n            celsiusTemperatures.push(\"Not Connected\");\n            fahrenheitTemperatures.push(\"Not Connected\");\n        }\n    } else {\n        msg[sensorName] = \"Not Connected\";\n        msg[`${sensorName}_fahrenheit`] = \"Not Connected\";\n        celsiusTemperatures.push(\"Not Connected\");\n        fahrenheitTemperatures.push(\"Not Connected\");\n    }\n}\n\n// If all sensors are 'Not Connected', drop the message\nif (allNotConnected) {\n    return null;\n}\n\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 450,
        "y": 200,
        "wires": [
            [
                "849ca070314689ca",
                "ef9821e26f3e8b18",
                "6de16712f21ab4ee",
                "05c988feb9705ac2"
            ]
        ]
    },
    {
        "id": "849ca070314689ca",
        "type": "ha-api",
        "z": "7066186d409631ab",
        "name": "Set Probe 1",
        "server": "56676c55.140b84",
        "version": 1,
        "debugenabled": false,
        "protocol": "http",
        "method": "post",
        "path": "/states/sensor.ibbq_temp1",
        "data": "{\"state\":\"{{ibbq_temp1}}\",\"attributes\":{\"icon\":\"mdi:temperature-celsius\",\"friendly_name\":\"IBBQ Probe 1\",\"fahrenheit\":\"{{ibbq_temp1_fahrenheit}}\"}}",
        "dataType": "json",
        "responseType": "json",
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "results"
            }
        ],
        "x": 750,
        "y": 140,
        "wires": [
            []
        ]
    },
    {
        "id": "ef9821e26f3e8b18",
        "type": "ha-api",
        "z": "7066186d409631ab",
        "name": "Set Probe 2",
        "server": "56676c55.140b84",
        "version": 1,
        "debugenabled": false,
        "protocol": "http",
        "method": "post",
        "path": "/states/sensor.ibbq_temp2",
        "data": "{\"state\":\"{{ibbq_temp2}}\",\"attributes\":{\"icon\":\"mdi:temperature-celsius\",\"friendly_name\":\"IBBQ Probe 2\",\"fahrenheit\":\"{{ibbq_temp2_fahrenheit}}\"}}",
        "dataType": "json",
        "responseType": "json",
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "results"
            }
        ],
        "x": 750,
        "y": 200,
        "wires": [
            []
        ]
    },
    {
        "id": "6de16712f21ab4ee",
        "type": "ha-api",
        "z": "7066186d409631ab",
        "name": "Set Probe 3",
        "server": "56676c55.140b84",
        "version": 1,
        "debugenabled": false,
        "protocol": "http",
        "method": "post",
        "path": "/states/sensor.ibbq_temp3",
        "data": "{\"state\":\"{{ibbq_temp3}}\",\"attributes\":{\"icon\":\"mdi:temperature-celsius\",\"friendly_name\":\"IBBQ Probe 3\",\"fahrenheit\":\"{{ibbq_temp3_fahrenheit}}\"}}",
        "dataType": "json",
        "responseType": "json",
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "results"
            }
        ],
        "x": 750,
        "y": 260,
        "wires": [
            []
        ]
    },
    {
        "id": "05c988feb9705ac2",
        "type": "ha-api",
        "z": "7066186d409631ab",
        "name": "Set Probe 4",
        "server": "56676c55.140b84",
        "version": 1,
        "debugenabled": false,
        "protocol": "http",
        "method": "post",
        "path": "/states/sensor.ibbq_temp4",
        "data": "{\"state\":\"{{ibbq_temp4}}\",\"attributes\":{\"icon\":\"mdi:temperature-celsius\",\"friendly_name\":\"IBBQ Probe 4\",\"fahrenheit\":\"{{ibbq_temp4_fahrenheit}}\"}}",
        "dataType": "json",
        "responseType": "json",
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "results"
            }
        ],
        "x": 750,
        "y": 320,
        "wires": [
            []
        ]
    },
    {
        "id": "56676c55.140b84",
        "type": "server",
        "name": "Home Assistant",
        "version": 1,
        "legacy": false,
        "addon": false,
        "rejectUnauthorizedCerts": false,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": false,
        "cacheJson": true
    }
]

In summary, NodeRed uses an Event State node to watch for changes of [sensor.ibbq_probe_1 - which is DPS 107] which connects to the function node which processes using the following:

// Output 'Not Connected' if the device is unavailable
if (msg.payload === 'unavailable') {
    for (let i = 0; i < 4; i++) {
        msg[`ibbq_temp${i + 1}`] = "Not Connected";
        msg[`ibbq_temp${i + 1}_fahrenheit`] = "Not Connected";
    }
    return msg;
}

// Decode the payload from base64 format
const decodedBytes = Buffer.from(msg.payload, 'base64');
const temperatureBytes = [];

// Split the decoded payload into temperature bytes
for (let i = 0; i < decodedBytes.length; i += 4) {
    temperatureBytes.push(decodedBytes.slice(i, i + 4));
}

const celsiusTemperatures = [];
const fahrenheitTemperatures = [];
let allNotConnected = true;

// Convert temperature bytes to Celsius and Fahrenheit and store in the message
for (let i = 0; i < 4; i++) {
    const sensorName = `ibbq_temp${i + 1}`;
    
    if (i < temperatureBytes.length) {
        const fahrenheit = temperatureBytes[i].readInt32LE(0) / 100;
        const celsius = (fahrenheit - 32) * 5 / 9;
            //If the result is greater than 1000, then the probe isn't connected
        if (celsius <= 1000) {
            msg[sensorName] = Math.round(celsius * 100) / 100; // Output Celsius as integer
            msg[`${sensorName}_fahrenheit`] = Math.round(fahrenheit * 100) / 100; // Output Fahrenheit as integer
            celsiusTemperatures.push(Math.round(celsius * 100) / 100);
            fahrenheitTemperatures.push(Math.round(fahrenheit * 100) / 100);
            allNotConnected = false;
        } else {
            msg[sensorName] = "Not Connected";
            msg[`${sensorName}_fahrenheit`] = "Not Connected";
            celsiusTemperatures.push("Not Connected");
            fahrenheitTemperatures.push("Not Connected");
        }
    } else {
        msg[sensorName] = "Not Connected";
        msg[`${sensorName}_fahrenheit`] = "Not Connected";
        celsiusTemperatures.push("Not Connected");
        fahrenheitTemperatures.push("Not Connected");
    }
}

// If all sensors are 'Not Connected', drop the message
if (allNotConnected) {
    return null;
}

return msg;

The function node then writes to HomeAssistant via an API node.

1 Like

Do you have the temperature probes pluged into the unit? I spent a few hours trying to figure out how to add the other sensors, until I read someone elses posts about having to have them all plugged in when you start to configure for the first time.
-Patrick

Yep pretty sure I had them all plugged in. Haven’t tried for a while - maybe I will try again this weekend and will doubly make sure they were all plugged in.

You might find that you have the same issue as me and DJL9999. The post above on how to obtain the temperature values of the probes from DPs 107 might help

This is amazing. Wish I had seen this before spending a while figuring out how they were encoding the values by myself!

1 Like

I have not used node red before could someone tell me what I do with that code to get it to work for me?

So I got everything put into node red but when I run it I get this error from the function.
“RangeError [ERR_BUFFER_OUT_OF_BOUNDS]: Attempt to access memory outside buffer bounds”
Any ideas?

My tuya app shows my IBBQ-4T but there are no variables for the 4 probes. Not sure why. I can see some chinese stuff but they don’t seem to show temp values.

I don’t see 107…

image

I have the same issue as you. Did you get it resolved?

Where can I find this “manual DPS option” is this in Tuya app or dev or in Hassio?

Unfortunately not. Though I haven’t checked it since I posted here - Based on you having the same problem, I expect it to be the same. If I get a chance I’ll check it out again and confirm.

1 Like

I think you can add 107 manually within HA config when setting up the tuya - just going off memory so could be wrong.

So managed to see the 107 but it’s a negative number and only displays the probe1 temp.
image

I’m using Tuya Local which identified my Inkbird as “inkbird_bbq4t_thermometerv2.yaml”

In that yaml file I can see that it uses the DP107 and then splits it up to all other probes so not sure why it shows up as a negative number.

From Tuya loT debug of DP107 I see the following:

Time Device Event DP ID Event Details
12/21/2023 8:32 Report 探头温度1 wBwAAMAcAAAQHQAAwBwAAA==
12/21/2023 8:32 Report 探头温度1 wBwAAcAcAAEaHQAB1BwAAQ==
12/21/2023 8:32 Report 探头温度1 1BwAAMAcAAAaHQAA3hwAAA==
12/21/2023 8:31 Report 探头温度1 wBwAAcAcAAEaHQABwBwAAQ==
12/21/2023 8:31 Report 探头温度1 wBwAAMAcAAAaHQAAyhwAAA==
12/21/2023 8:30 Report 探头温度1 wBwAAcAcAAEQHQABwBwAAQ==

Even though it’s in chinese characters it is indeed DP107 as per the inspection of the page:
image

In Tuya.iot in your “project” you’ll find a Device-ID, with this you can “Traverse” the left menu, and find a "Complete list of DP’s for your devices , where there also is a ( Scaling ) Number, which you manually have to set( for various measurements, to get it right in i.e HA), when either setting up your devices, or clicking “Configure Device” in /Settings/Devices-Integrations.

I can’t remember exactly where ( long time since i’ve been in there, from what i know they have changed their site-structure ), but it’s in the bottom of the left Menu, in tuya.iot , and there are a few topis in regards to DP’s in here, with complete links/pic’s, Use the Search function

Or go here and check if this is still valid , the DP-list and other details is among the various sub-menu’s, go through, copy/past your device id, and you’ll see

PS: You just say “it’s not right” , so what is the correct temperature ) ( +1.6 ? +16 ? +160 ? ) this is what the scaling factor is for … In Tuya integrations this has to be "transformed into i.e ( multiply/devide 0,1 or 0,01 or 0.001 ) , or ( 10 or 100 or 1000 )

So I played with the “inkbird_bbq4t_thermometerv2.yaml" file and got the following (all I did is change the probe 2-3-4 from integer to type: base64):

image

Thing is when I test the probes with hot water I notice that the Hassio temp for Probe 4 is actually the Probe 1 of the device, Probe 2 matches Probe 2, the other probes make the negative numbers blink.

1 Like