Inkbird IBS-M1 with IBS-P01 via Tuya local doesn't provide temperature data

Continuing the discussion from Inkbird IBS-M1 with IBS-P01:

Hi all,

I am trying to integrate my pool thermometer IBS-P01B on gateway IBS-M1 into the Home Assistant by Local Tuya.

I am able to add the device to Tuya Smart, I can see the device in Tuya IoT platform, I can get the device basic info by API explorer and status, but it doesn’t contain the temperature data. Even in the Tuya Smart App are not visible temperature data.

Did I miss some part of configuration?

Tuya IoT Device Debugg:

Device log:

Status:

Additional info:
Home Assistant integration can read only such data:

1 Like

I have the same setup IBS-M1S (2nd gen) and two thermometers connected to inkbird app.

My gateway doesn’t work with Tuya SmartLife. I get the same screen with all Chinese characters. I need to use inkbird app to connect to the gateway and have access to the temperature data.

Would be super if we could connect it to HA and have all temp in one dashboard.

Hi, issue there,

i add IBS-M1 working with tuya cloud and pool thermometer

I unlink the IBS-M1 with tuya app, and try to make it again.

I can’t find anymore IBS-M1 icon in tuya app to make the link !!!

Does anyone what happened ? I can only link with inkbird app, but no way to poll the cloud…

Thanks

I just got the IBS-M2 with the pool thermometer (IBS-P02). I can get both to work in Tuya, where Tuya will control the IBS-M2; can switch temperature from F to C, as well can add the pool thermometer. However, the temperature displayed in Tuya is -20, not the real temperature of either devices.
When I look under Tuya in HA, I can see the device, but with only 1 entity and it shows -20 as well.

Has anyone else gotten any further?

Hello,

I would like to integrate my IBS-P01B Bluetooth thermometer,
linked to my IBS-M1 BT/Wi-Fi gateway, into the Home Assistant.
Did someone made progress on this matter ? Thanks in advance.

S@M

Hi, you can find interesting discussion in the link mentioned in the first comment.

In short…my final and working solution was tuya iot and the python script:

#!/usr/bin/env python3
import json
import requests
import hmac
import hashlib
import time

debug = False

# Declare constants

ClientID = "ddd"
ClientSecret = "ddd"
DeviceID = "ddd"
ChannelID = "ch_rtd1"
BaseUrl = "https://openapi.tuyaeu.com"
EmptyBodyEncoded = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

# Character conversion dictionary for decoding the temperature value
charcter_conversion = {
    "A": 0, "E": 1, "I": 2, "M": 3, "Q": 4, "U": 5, "Y": 6, "c": 7,
    "g": 8, "k": 9, "o": 10, "s": 11, "w": 12, "0": 13, "4": 14, "8": 15
}

# Get current time in milliseconds
tuyatime = int(time.time()) * 1000

# Prepare signing for Access Token
URL = "/v1.0/token?grant_type=1"
StringToSign = f"{ClientID}{tuyatime}GET\n{EmptyBodyEncoded}\n\n{URL}"
AccessTokenSign = hmac.new(ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()

# Get Access Token
headers = {
    'client_id': ClientID,
    'sign_method': 'HMAC-SHA256',
    't': str(tuyatime),
    'sign': AccessTokenSign
}
response = requests.get(f"{BaseUrl}{URL}", headers=headers)
AccessToken = response.json()['result']['access_token']

# Send Device status request
URL = f"/v1.0/iot-03/devices/status?device_ids={DeviceID}"
StringToSign = f"{ClientID}{AccessToken}{tuyatime}GET\n{EmptyBodyEncoded}\n\n{URL}"
RequestSign = hmac.new(ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()

headers.update({
    'sign': RequestSign,
    'access_token': AccessToken
})

response = requests.get(f"{BaseUrl}{URL}", headers=headers)
RequestResponse = response.text

# Parse and process the request response
device_param = json.loads(RequestResponse)
number_of_status = len(device_param["result"][0]["status"])

for i in range(number_of_status):
    if device_param["result"][0]["status"][i]["code"] == ChannelID:
        raw_temp = device_param["result"][0]["status"][i]["value"]

# Decode the temperature value
raw_temp_lead_charecter = raw_temp[0:1]
raw_temp_first_charecter = raw_temp[1:2]
raw_temp_second_charecter = raw_temp[2:3]
raw_temp_third_charecter = raw_temp[3:4]

if raw_temp_lead_charecter == "C":
    temp_by_ten = (ord(raw_temp_first_charecter) - 65)*16 + charcter_conversion[raw_temp_second_charecter]

if raw_temp_lead_charecter == "A":
    if debug:
        print(ord(raw_temp_first_charecter))
    if ord(raw_temp_first_charecter) <= 43:
        temp_by_ten = (ord(raw_temp_first_charecter) - 29)*16 + charcter_conversion[raw_temp_second_charecter]
    else:
        if ord(raw_temp_first_charecter) <= 47:
            temp_by_ten = (ord(raw_temp_first_charecter) - 32)*16 + charcter_conversion[raw_temp_second_charecter]
        else:
            if ord(raw_temp_first_charecter) >= 119:
                temp_by_ten = (ord(raw_temp_first_charecter) - 119)*16 + charcter_conversion[raw_temp_second_charecter]
            else:
                temp_by_ten = (ord(raw_temp_first_charecter) - 44)*16 + charcter_conversion[raw_temp_second_charecter]    


if raw_temp_third_charecter == "B":
    temp_by_ten = temp_by_ten + 256

# Calculate and print the pool temperature
Pool_temp = temp_by_ten / 10
print(Pool_temp)

The conditions with raw_temp_lead_charecter are still little bit mysterious but working…

Maybe there is some update on tuya or ha tuya local side which allows to communicate directly, but I did not tried it in this part of the year… pool is empty :slight_smile:

1 Like

Excellent work @keeema !
I did some rework in your script to include all the parameter that my IBS-M2 and P02R are sending via tuya in one api call. Additionally, I add the configuration.yaml part to include all attributes in one sensor below. To use the attributes in dashboards you might have to create helper templates - works fine for me. When there is more time, I might start working on a real integration via HACS.

#!/usr/bin/env python3
import json
import requests
import hmac
import hashlib
import time
import base64

debug = False

# Declare constants

ClientID = "xxx"
ClientSecret = "xx"
DeviceID = "xxx"

ChannelID_M2 = "ch_1"
ChannelID_TH2 = "ch_0"

BaseUrl = "https://openapi.tuyaeu.com"
EmptyBodyEncoded = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

IBS_Values = { "pool_temperature": 99, "pool_battery": 99, "display_temperature": 99, "display_humidity": 99, "display_battery": 99}


# Get current time in milliseconds
tuyatime = int(time.time()) * 1000

# Prepare signing for Access Token
URL = "/v1.0/token?grant_type=1"
StringToSign = f"{ClientID}{tuyatime}GET\n{EmptyBodyEncoded}\n\n{URL}"
AccessTokenSign = hmac.new(ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()

# Get Access Token
headers = {
    'client_id': ClientID,
    'sign_method': 'HMAC-SHA256',
    't': str(tuyatime),
    'sign': AccessTokenSign
}
response = requests.get(f"{BaseUrl}{URL}", headers=headers)
AccessToken = response.json()['result']['access_token']

# Send Device status request
URL = f"/v1.0/iot-03/devices/status?device_ids={DeviceID}"
StringToSign = f"{ClientID}{AccessToken}{tuyatime}GET\n{EmptyBodyEncoded}\n\n{URL}"
RequestSign = hmac.new(ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()

headers.update({
    'sign': RequestSign,
    'access_token': AccessToken
})

response = requests.get(f"{BaseUrl}{URL}", headers=headers)
RequestResponse = response.text

# Parse and process the request response
device_param = json.loads(RequestResponse)
number_of_status = len(device_param["result"][0]["status"])
if debug:
    print ("device_param:",device_param)
    print ("number_of_status:",number_of_status)

for i in range(number_of_status):
    if device_param["result"][0]["status"][i]["code"] == ChannelID_M2:
        raw_th2 = base64.b64decode(device_param["result"][0]["status"][i]["value"])
    if device_param["result"][0]["status"][i]["code"] == ChannelID_TH2:
        raw_m2 = base64.b64decode(device_param["result"][0]["status"][i]["value"])

# Decode the temperature value

r0 = raw_m2[0:1]
r1 = raw_m2[1:2]
r2 = raw_m2[2:3]
r3 = raw_m2[3:4]
r4 = raw_m2[4:5]
r5 = raw_m2[5:6]
r6 = raw_m2[6:7]
r7 = raw_m2[7:8]
r8 = raw_m2[8:9]
r9 = raw_m2[9:10]

temp1=(int.from_bytes(r2)*64+int.from_bytes(r1))/10
hum1=(int.from_bytes(r4)*256+int.from_bytes(r3))/10
batt1=int.from_bytes(r9)

IBS_Values["display_temperature"]=temp1
IBS_Values["display_humidity"]=hum1
IBS_Values["display_battery"]=batt1

r0 = raw_th2[0:1]
r1 = raw_th2[1:2]
r2 = raw_th2[2:3]
r3 = raw_th2[3:4]
r4 = raw_th2[4:5]
r5 = raw_th2[5:6]
r6 = raw_th2[6:7]
r7 = raw_th2[7:8]
r8 = raw_th2[8:9]
r9 = raw_th2[9:10]

temp1=(int.from_bytes(r2)*64+int.from_bytes(r1))/10
batt1=int.from_bytes(r9)

IBS_Values["pool_temperature"]=temp1
IBS_Values["pool_battery"]=batt1

print (json.dumps(IBS_Values))


configuration.yaml:

command_line:
  - sensor:
      name: ###your fav name here ###
      command: "python3 python_scripts/get_data.py"
      json_attributes:
        - pool_temperature
        - pool_battery
        - display_temperature
        - display_humidity
        - display_battery
2 Likes

Hello,
That would be great.
Let us know if/when
you release this :slight_smile:

Hi @mhirsch47, I’ve been experimenting with your python script and have it running, but the response I’m getting from the Tuya API is as below, which obviously doesn’t contain the elements the script is expected.

device_param: {‘result’: [{‘id’: ‘bff16e3df4905d454ez2tz’, ‘status’: [{‘code’: ‘va_temperature’, ‘value’: -200}, {‘code’: ‘temp_unit_convert’, ‘value’: ‘c’}]}], ‘success’: True, ‘t’: 1708885524975, ‘tid’: ‘3e44489ed40b11eeb54b123cb993baaf’}

My background is I have recently bought a IBS-M2 WiFi Gateway and IBS-P02R Floating Pool Thermometer. I added the IBS-M2 to the inkbird app and added the IBS-P02R as a child sensor. I then removed the IBS-M2 from the inkbird app and added the IBS-M2 to the Tuya app. It was then also visible in the Tuya IoT Portal.

I then ran your script and got the above response, so I feel like I’ve missed something somewhere. Can you happen to see where I’ve gone wrong?

Don’t worry @mhirsch47, I managed to answer my own question! I needed to enable DP Mode in the Tuya IoT Protal for the IBS-M2. Working now as expected and I can see the temperatures in HA.

I have some progress you may be interested in: Inkbird IBS-M1 with IBS-P01 - #181 by EvanSchalton

Hello,

can somebody tell me how to use / place the python script?

Firstly, thanks so much to everyone that’s contributed to this thread, I’ve learned a huge amount from it.
After a very long night getting the script to successfully return the pool temperature, and then running that in appdaemon to have the temperature present as a sensor I thought my work was done. However, I found in the morning that the temperature value hadn’t updated.
Is there another call I have to make to refresh the data? Or should that be happening on it’s own?
This is the code I’m running (special thanks to @keeema):

#!/usr/bin/env python3
import json
import requests
import hmac
import hashlib
import time
import sys

# Declare constants
ClientID="<<ClientID>>"
ClientSecret="<<ClientSecret>>"
DeviceID = "<<DeviceID>>"
ChannelID = "ch_2"
BaseUrl = "https://openapi.tuyaeu.com"
EmptyBodyEncoded = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

# If there is an argument, override ChannelID with it
if len( sys.argv ) > 1:
    ChannelID = sys.argv[1]

# Character conversion dictionary for decoding the temperature value
charcter_conversion = {
    "A": 0, "E": 1, "I": 2, "M": 3, "Q": 4, "U": 5, "Y": 6, "c": 7,
    "g": 8, "k": 9, "o": 10, "s": 11, "w": 12, "0": 13, "4": 14, "8": 15
}

# Get current time in milliseconds
tuyatime = int(time.time()) * 1000

# Prepare signing for Access Token
URL = "/v1.0/token?grant_type=1"
StringToSign = f"{ClientID}{tuyatime}GET\n{EmptyBodyEncoded}\n\n{URL}"
AccessTokenSign = hmac.new(ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()

# Get Access Token
headers = {
    'client_id': ClientID,
    'sign_method': 'HMAC-SHA256',
    't': str(tuyatime),
    'sign': AccessTokenSign
}
response = requests.get(f"{BaseUrl}{URL}", headers=headers)
AccessToken = response.json()['result']['access_token']

# Send Device status request
URL = f"/v2.0/cloud/thing/{DeviceID}/shadow/properties"
StringToSign = f"{ClientID}{AccessToken}{tuyatime}GET\n{EmptyBodyEncoded}\n\n{URL}"
RequestSign = hmac.new(ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()

headers.update({
    'sign': RequestSign,
    'access_token': AccessToken
})

response = requests.get(f"{BaseUrl}{URL}", headers=headers)
RequestResponse = response.text

# Parse and process the request response
device_param = json.loads(RequestResponse)
number_of_status = len(device_param["result"]["properties"])

for i in range(number_of_status):
    # print(device_param["result"]["properties"][i]["code"])
    if device_param["result"]["properties"][i]["code"] == ChannelID:
        raw_temp = device_param["result"]["properties"][i]["value"]

# Decode the temperature value
raw_temp_first_charecter = raw_temp[1:2]
raw_temp_second_charecter = raw_temp[2:3]
raw_temp_third_charecter = raw_temp[3:4]

temp_by_ten = (ord(raw_temp_first_charecter) - 65)*16 + charcter_conversion[raw_temp_second_charecter]

if raw_temp_third_charecter == "B":
    temp_by_ten = temp_by_ten + 256

# Calculate and print the pool temperature
Pool_temp = temp_by_ten / 10
print(Pool_temp)

I’m using an IBS-P02R with the IBS-M2 gateway