I am having an hard time calling the Tuya API while using curl.
Tuya requires to generate a signature as following: HMAC-SHA256(client_id + t, secret). I built a small script that does exactly what Tuya asks. I have also double checked by trying to generate the signature using the same client_id, t and secret that are in their documentation as example, and the generated signature matches what the documentation says.
client_id is a pre-assigned value t is the timestamp in 13 digits (and here I think is where the error is) secret is a pre-assigned value
Once the signature is built it needs to be used via curl in a POST call, but Tuya keeps refusing the signature with the following error:
{"code":1004,"msg":"sign invalid","success":false,"t":1664314067553}
Now, I think that the issue is the timing. In order for my script to generate the signature few milliseconds are required and when the value of t gets passed to curl it won't match with the execution of curl (of course). Here's my code:
t=($(($(date +%s%N)/1000000))); sign1=$(echo -n "yyr8hxxxxxxxxd4mji$t" | openssl dgst -sha256 -hmac "cc75fd7xxxxxxxxx63d032b" | awk '{print$2}') && sign2=$(echo ${sign1^^}) ; curl --request POST "https://openapi.tuyaeu.com/v1.0/iot-03/devices/717715xxxxxxx520/commands" --header "sign_method: HMAC-SHA256" --header "client_id: yyr8hxxxxxxxxd4mji" --header "t: t" --header "mode: cors" --header "sign: $sign2" --header "access_token: cc75fd7xxxxxxxxx63d032b" --data "{"commands":[{"code":"switch_1","value":true}]}"
I've of course already tried to use && to execute all commands together but there has been no change. Does someone have any idea?
Your sign
is invalid.
Here are the steps you need (in bash) to call the Tuya API correctly.
Declare your variables:
ClientID="replace_with_you_client_Id yyr8hxxxxxxxxd4mji"
ClientSecret="replace_with_you_client_secret cc75fd7xxxxxxxxx63d032b"
Device="replace_with_your_device 717715xxxxxxx520"
First you have to get an access_token
:
AccessToken=$(t=$(date +%s%N |sed "s/......$//g"); curl -sSLkX GET "https://openapi.tuyaeu.com/v1.0/token?grant_type=1" -H "sign_method: HMAC-SHA256" -H "client_id: $ClientID" -H "t: $t" -H "mode: cors" -H "Content-Type: application/json" -H "sign: $(echo -en "${ClientID}${t}GET\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n\n/v1.0/token?grant_type=1" | openssl dgst -sha256 -hmac "$ClientSecret" | tr '[:lower:]' '[:upper:]' |sed "s/.* //g")" -H "access_token: " | sed "s/.*\"access_token\":\"//g" |sed "s/\".*//g")
Then you need to calculate the good "sign". You need you ClientId
, the timestamp, the access_token
, the method, the encoded_body
, the url
:
TimeStamp=$(date +%s%N |sed "s/......$//g")
METHOD='POST'
BODY='{"commands":[{"code":"switch_1","value":true}]}'
encodedBody=$(echo -n "$BODY" | openssl dgst -sha256 | sed "s/.*[ ]//g")
URL="/v1.0/iot-03/devices/$Device/commands"
Calculate sign
:
SIGN=$(echo -n "$ClientID${AccessToken}${TimeStamp}${METHOD}
$encodedBody
$URL" | openssl dgst -sha256 -hmac "$ClientSecret" | tr '[:lower:]' '[:upper:]' |sed "s/.* //g")`
Or in one line:
SIGN=$(echo -en "$ClientID${AccessToken}${TimeStamp}${METHOD}\n$encodedBody\n\n$URL" | openssl dgst -sha256 -hmac "$ClientSecret" | tr '[:lower:]' '[:upper:]' |sed "s/.* //g")
Then send the request:
curl -sSLkX $METHOD "https://openapi.tuyaeu.com$URL" -H "sign_method: HMAC-SHA256" -H "client_id: $ClientID" -H "t: $TimeStamp" -H "mode: cors" -H "Content-Type: application/json" -H "sign: $SIGN" -H "access_token: $AccessToken" -d "$BODY"