Inkbird IBS-M1 with IBS-P01

Hi. I would be a little off the main topic (but there are few forums talking about the IBS M2…) I thought it would be possible to integrate this thermometer with Google Home (and not HA) just to ask the temperature vocally… And I realize that it is not possible. It’s sad… Inkbird should update with the assistants (Alexa, google…) ! Sorry, I’m french…

Thanks I have the script working now… Excellent. :wave: :pray:

$ sh inkbird_query.sh 
{"result":[{"id":"12000140e8db84ba4f78","status":[{"code":"app_add_device_cmd","value":"MA=="},{"code":"g_scan_device","value":"MA=="},{"code":"ch_para","value":"AQgA0GIAAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//w=="},{"code":"ch_cfg1","value":"WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAFgCIANYAgAAnP9kAJz/AAAAAAAAAAAAAAFYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="},{"code":"ch_cfg2","value":"WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="},{"code":"ch_cfg3","value":"WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="},{"code":"ch_cfg4","value":"WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="},{"code":"ch_cfg5","value":"WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="},{"code":"ch_alarm","value":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},{"code":"ch_alarm_trig1","value":0},{"code":"alarm_notify_status","value":false},{"code":"ch_scene1","value":"AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfw=="},{"code":"ch_scene2","value":"AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfw=="},{"code":"ch_rtd1","value":"CBEB////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA=="},{"code":"his_ask_cmd","value":"MA=="},{"code":"his_answer","value":"MA=="},{"code":"his_data","value":"MA=="},{"code":"ch_name1","value":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},{"code":"ch_name2","value":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},{"code":"ch_name3","value":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},{"code":"ch_name4","value":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},{"code":"ch_name5","value":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},{"code":"ch_rtd2","value":"AP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA=="},{"code":"his_data_time","value":"MA=="},{"code":"ch_alarm_trig2","value":0},{"code":"his_alarm1","value":"/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w=="},{"code":"his_alarm2","value":"/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w=="}]}],"success":true,"t":1685149286818,"tid":"01d52378fc2a11eda795ce4cada2c678"}
pool temp is 27.3
2 Likes

Yes, they are quite useless with external integrations. I contacted them about it and they were not very helpful.

1 Like

Hello @Nir,

thank you for your help.

Yesterday I have tried the ch_rtd1.
Interesting was, that the value was changing according to the thermometer (IBS-P01B). So I have found a magic coeficient:

coef = 86.4
pool_temp = round((temp_by_ten/10) - coef, 1)

And the value was OK during the evening (the temperature was about 28 - 29°C.
Unfortunatly today the values are:

With magic coeficient: -113.8
Without magic coeficient (so the original script): -27.4
Real value: 25.4

ch_rtd1:

{
	"code": "ch_rtd1",
	"value": "A/4AAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA=="
}

I have tried to change index to

raw_temp_first_charecter = raw_temp[0:1]
raw_temp_second_charecter = raw_temp[1:2]
raw_temp_third_charecter = raw_temp[3:4]

but it fails on error it is not able to find key “/”.

I think I am close to solution but still unsuccessful.

OK, now the real value is 26.1 and the magic constant with original code starts working.
The original code value is 112.5.


{
			"code": "ch_rtd1",
			"value": "AwUBAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA=="
		}

I don’t know if it can help somehow to find the right solution. This looks like there is some boundery…

Amazing @Nir , I have been trying to get pool temp for the last 18 months and here it is:

I have been looking around for an inexpensive option for pool temp, but most solutions were very expensive, except for InkBird, which had had some success with HA. I purchased 2x IBS-M1 on the hope of getting a gen 1 version, but I ended up with two gen 2 :frowning: I purchased an RTL dongle but couldn’t get that integrated either. Thank you…

I didn’t want to head down the complexity of ssh and the MQTT route, so I combined your two scripts into one python script that returns the value and then setup a simple command_line sensor.

- platform: command_line
  name: Pool Temperature
  command: 'python3 /config/scripts/get_pool_temp.py'
  unit_of_measurement: "°C"
  scan_interval: 60
#!/usr/bin/env python3
import json
import requests
import hmac
import hashlib
import time

# Declare constants
ClientID="<<ENTER CLIENT ID HERE>>"
ClientSecret="<<ENTER CLIENT SECRET HERE>>"
DeviceID = "<<ENTER DEVICE ID HERE>>"
ChannelID = "<<ENTER DEVICE CHANNEL HERE e.g. ch_1 or 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_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)

2 Likes

I did exactly the same :slight_smile:

But you are more lucky your code works for you :frowning:

For me only with my magic constant and only if the temp is > 26 (cca).

@keeema, this is strange. Generally the way Inkbird represents the temp is via 3 characters:

1st character is a capital letter between A and P. They use the unicode for the letter minus 65, times 16. Unicode of A is 65 so A is 0, B is 16, C is 32, etc.

2nd character is a letter or number, which is one of - A, E, I, M, Q, U, Y, c, g, k, o, s, w, 0, 4, 8. Each has a specific value, from 0 to 15 which is added to the first value. so AA is 0, AE is 1, AI is 2 to P8 which is 255. You divide this by 10 to get the temp, so P8 is 25.5

3rd character is either A or B - if it is A, you don’t need to change the number, if it is B, you need to add 256, which will give you tempt above 25.5. So AAB is 256 (25.6), AEB is 257 (25.7), etc. all the way to P8B - 511 (51.1)

In your first post, ch_rtd1 data was Aw8BAAAAAAAAXAD, so I used the AwB, which gives 0 + 12 + 256 = 268 (26.8). I am not sure what the 8 is doing there.

In your second post, ch_rtd1 is A/4AAAAAAAAAWwD, which doesn’t make sense to me because I have never seen the character “/” used.

In your last post, ch_rtd1 is AwUBAAAAAAAAWwD. Using AwB (ignoring the 3rd character) gives is 268.

[in retrospect, the above is incorrect - the leading A shouldn’t be used directly in the calculation, the 1st character (“w”, “/”) is used but in a different way that is described above, while the 2nd (“8”, “4”, “U”) and 3rd characters (“A” or “B”) seem to be used as described above]

What thermometer are you using? I am using a pool thermometer and the conversion may be different, especially given that you have a character in the 3rd place which I don’t have. It will be useful if you could record ch_rtd1 data and what is the corresponding temp systemically. What I did was to put the thermometer in a warm glass of water and let it cool, recording the data every time the temp changed. This is how I worked out the conversion. But I was able to do that because I am using a pool thermometer…

@markpurcell, your way makes much more sense! Can run straight from HA and is much much simpler. I am not a programmer - I just use examples I find on the internet to build what I need. I knew there is a simpler way to do it, and thought it can all run in python, but wasn’t sure how to convert the sh script I found to python (i.e. express the tuyatime and other strings in python, use the requests command instead of curl, etc), and didn’t want to spend more time after it was working. Great job - this will be easier to implement.

@marcel510, use the script and sensor markpurcell posted, it is much easier to implement than my scripts.

1 Like

My setup is IBS-P01B + IBS-M1 gen2.

I have a working solution.

Guys, don’t laugh and don’t ask me why…
@Nir what you wrote about how data are read and decoded on inkbird devices is completly right. My script is using it. BUT… I need to use two magic constants :man_facepalming::

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

debug = True

# Declare constants

ClientID = "clientid"
ClientSecret = "secret"
DeviceID = "deviceid"
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

# if debug: 
#     print(f'RequestResponse is now {RequestResponse}')

# 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"]

if debug:      
    print(raw_temp)
# 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

if(debug):
    print("Original value:" , Pool_temp)

# Magic constant assign
if Pool_temp > 0:
    coef = 86.4
else:
    coef = -52.8
Pool_temp = round((temp_by_ten/10) - coef, 1)

print(Pool_temp)

This gives me real values:

A/YAAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: -28.2
24.6
A/UAAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: -28.3
24.5
A/QAAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: -28.4
24.4
AwYBAAAAAAAAXAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: 112.6
26.2
AxIBAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: 113.8
27.4
AxYBAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: 114.2
27.8
AxwBAAAAAAAAWwD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA==
Original value: 114.8
28.4

@Nir if you figure out how is this possible or if there is something we are missing (e.g. some ref. value in other part the whole string)
I would be really curious… :slight_smile: :slight_smile: :slight_smile:

It looks like your device doesn’t use A to P as the first character. It seems that it uses other characters, depending if temp is 25.5 or under, or if it is 25.6 and above. In that case there should be two conditions (as you found out). According to the examples you sent me, it appears that there will be two for formulas:

In cases where the temps is 25.5 or lower:

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

In cases where the temp is 25.6 or higher:

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

It looks like you have an “A” before your value, while I have a “C”, perhaps indicating what type of first character calculation to use. However, there is one problem with this system - if you start counting from w (unicode 119) for temp above 25.5, there are only 8 further increments you can do before getting to unicode 127, which doesn’t have a letter assigned. This means that the highest temp that can be expressed will be 38.3, which doesn’t make sense. It will be useful to have more examples from your readings for temps < 23.9 and > 38.3. The second and third characters in your example seem to work like mine.

The following script should work for both cases (yours and mine) with the information we have so far:

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

# Declare constants
ClientID="<<ENTER CLIENT ID HERE>>"
ClientSecret="<<ENTER CLIENT SECRET HERE>>"
DeviceID = "<<ENTER DEVICE ID HERE>>"
ChannelID = "<<ENTER DEVICE CHANNEL HERE e.g. ch_1 or 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 ord(raw_temp_first_charecter) <= 47:
        temp_by_ten = (ord(raw_temp_first_charecter) - 32)*16 + charcter_conversion[raw_temp_second_charecter]
    if ord(raw_temp_first_charecter) >= 119:
        temp_by_ten = (ord(raw_temp_first_charecter) - 119)*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)  
1 Like

Hi @markpurcell . How did you manage to put the IBS M1S to DP mode?
On the tuya iot dashboard, it looks like that after switching it to DP mode it always rejects it.

I did have a similar issue, every time I switched to DP it switched back :frowning:

I gave up in the end and then came back to it a couple of days later and it was in DP mode!

I can only think it may take a little while for the change to stick.

We should check if DP state is actually necessary. I wonder if the script will work anyway.

Nir, Please check out GitHub - richierockskool/homebridge-inkbird-wifi-gateway: homebridge Inkbird wifi gateway and try to help us fit this into our code and where to put it? Thank you, we are stuck and can not get this working. This could be the solution. Rich

I am sorry but I wouldn’t even know where to start. I am not familiar with homebridge and have never worked with Java. Do you have the same problem with getting the temp in code (i.e. “CAwB////////”)? If so, you can just use the logic I described above to convert it to temperature in Celsius.

Hey guys, I wanna try the python scripts but my curL response has the status empty. Anyone saw this before? I guess my sensor is the second version too because the Tuya shows everything in chinese.

I thought this is happening because it can’t find the sensor but I have no way to check if it’s connected and to connect to Tuya you have to remove it from the Inkbird app.

image

Have you changed to DP instruction on Tuya IoT?

And check that you have the correct server. You can find a list of servers here: tuya-home-assistant/regions_dataCenters.md at 363bca835c7297c89f751bcc84f93c42b081d647 · tuya/tuya-home-assistant · GitHub

Yes, i’ve changed to DP instruction and it’s on the correct server. But, i’ve tried the query again right now and returned the status. Let’s check if the python script works now.

EDIT: I’m having this python error:

Traceback (most recent call last):
  File "/home/lgnunes/teste.py", line 66, in <module>
    temp_by_ten = (ord(raw_temp_first_charecter) - 65)*16 + charcter_conversion[raw_temp_second_charecter]
KeyError: '/'

Heres my status response, my channel is 1 or 2? Didn’t work for both.

    "status": [
      {
        "code": "app_add_device_cmd",
        "value": "MA=="
      },
      {
        "code": "g_scan_device",
        "value": "MA=="
      },
      {
        "code": "ch_para",
        "value": "AQMAPFoCAwBnEQMBAIgnBAMAihkFAwBKJgYDAdbfAAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//wAAAP//AAAA//8AAAD//w=="
      },
      {
        "code": "ch_cfg1",
        "value": "WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="
      },
      {
        "code": "ch_cfg2",
        "value": "WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="
      },
      {
        "code": "ch_cfg3",
        "value": "WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="
      },
      {
        "code": "ch_cfg4",
        "value": "WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="
      },
      {
        "code": "ch_cfg5",
        "value": "WAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAlgCIANYAiADnP9kAJz/ZAAAAAAAAAAAAAJYAiADWAIgA5z/ZACc/2QAAAAAAAAAAAACWAIgA1gCIAOc/2QAnP9kAAAAAAAAAAAAAg=="
      },
      {
        "code": "ch_alarm",
        "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
      },
      {
        "code": "ch_alarm_trig1",
        "value": 0
      },
      {
        "code": "alarm_notify_status",
        "value": false
      },
      {
        "code": "ch_scene1",
        "value": "AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfw=="
      },
      {
        "code": "ch_scene2",
        "value": "AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfwAAAAAAAAAAAH8AAAAAAAAAAAB/AAAAAAAAAAAAfw=="
      },
      {
        "code": "ch_rtd1",
        "value": "AP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAD1QAUBRQF//9kAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA=="
      },
      {
        "code": "his_ask_cmd",
        "value": "MA=="
      },
      {
        "code": "his_answer",
        "value": "MA=="
      },
      {
        "code": "his_data",
        "value": "MA=="
      },
      {
        "code": "ch_name1",
        "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
      },
      {
        "code": "ch_name2",
        "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
      },
      {
        "code": "ch_name3",
        "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
      },
      {
        "code": "ch_name4",
        "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
      },
      {
        "code": "ch_name5",
        "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
      },
      {
        "code": "ch_rtd2",
        "value": "AP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AAD//////////wAA//////////8AAP//////////AA=="
      },
      {
        "code": "his_data_time",
        "value": "MA=="
      },
      {
        "code": "ch_alarm_trig2",
        "value": 0
      },
      {
        "code": "his_alarm1",
        "value": "/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w=="
      },
      {
        "code": "his_alarm2",
        "value": "/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w=="
      }
    ],