sign invalid | POST: /v1.0/iot-03/devices/{device_id}/commands
I'm trying to control a lamp I have in my room through an HTTP request using curl. Analyzing the documentation at the links:
https://developer.tuya.com/en/docs/iot/ ... 0q34cs2e5g
https://developer.tuya.com/en/docs/clou ... 0parameter
I understood that before accessing the POST endpoint: /v1.0/iot-03/devices/{device_id}/commands I should generate an access_token via the /v1.0/token?grant_type=1 endpoint, I managed to do this and get the sign and timestamp with python code, I used the following:
Code: Select all
import time
import hmac
import hashlib
# Definição da função generate_tuya_sign
def generate_tuya_sign(client_id, secret, http_method, url, query_params=None, body=None, access_token=None):
# Timestamp atual em milissegundos
timestamp = str(int(time.time() * 1000))
# 1. Criar o stringToSign
# Método HTTP
method = http_method.upper()
# Ordenar query_params por chave, se existirem
sorted_query = "&".join(f"{k}={v}" for k, v in sorted(query_params.items())) if query_params else ""
# Hash do corpo da requisição
if body:
body_string = str(body) # Certifique-se de serializar o corpo de forma consistente
body_hash = hashlib.sha256(body_string.encode('utf-8')).hexdigest().lower()
else:
body_hash = hashlib.sha256("".encode('utf-8')).hexdigest().lower()
# Concatenar no formato exigido
string_to_sign = f"{method}\n{body_hash}\n\n{url}?{sorted_query}"
# 2. Concatenar os parâmetros do sign
if access_token:
string_to_sign = f"{client_id}{access_token}{timestamp}{string_to_sign}"
else:
string_to_sign = f"{client_id}{timestamp}{string_to_sign}"
# 3. Gerar a assinatura usando HMAC-SHA256
sign = hmac.new(secret.encode('utf-8'), string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest().upper()
return sign, timestamp
# Configuração para o endpoint de autenticação
client_id = "client"
secret = "secret"
http_method = "GET" # Método HTTP da requisição
url = "/v1.0/token" # Caminho relativo para o endpoint
query_params = {"grant_type": "1"} # Parâmetros da query string
body = None # Nenhum corpo necessário para este endpoint
access_token = None # Não é necessário para autenticação inicial
# Gerar sign e timestamp
sign, timestamp = generate_tuya_sign(client_id, secret, http_method, url, query_params, body, access_token)
# Imprimir resultados
print("Sign:", sign)
print("Timestamp:", timestamp)
After obtaining the access token I used a new code in Python to generate the sign and timestamp for the request at the POST end point: /v1.0/iot-03/devices/{device_id}/commands
Code: Select all
import hashlib
import hmac
import json
import time
import uuid
def generate_tuya_signature(client_id, secret, access_token, method, url, body):
# Gerar timestamp atual em milissegundos
t = str(int(time.time() * 1000))
# Gerar nonce (UUID)
nonce = str(uuid.uuid4())
# Certificar que o corpo é uma string JSON ordenada
body_str = json.dumps(body, separators=(',', ':'), ensure_ascii=False)
# Calcular Content-SHA256
content_sha256 = hashlib.sha256(body_str.encode('utf-8')).hexdigest()
# Construir stringToSign
string_to_sign = f"{method}\n{content_sha256}\n\n{url}"
# Concatenar elementos para formar a string a ser assinada
str_to_sign = client_id + access_token + t + nonce + string_to_sign
# Calcular HMAC-SHA256 e converter para maiúsculas
sign = hmac.new(secret.encode('utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).hexdigest().upper()
return {
't': t,
'nonce': nonce,
'sign': sign
}
# Exemplo de uso
client_id = 'client'
secret = 'secret'
access_token = 'token'
method = 'POST'
url = '/v1.0/iot-03/devices/id-device/commands'
body = {
"commands": [
{
"code": "switch_2",
"value": True
}
]
}
auth_params = generate_tuya_signature(client_id, secret, access_token, method, url, body)
print(auth_params)
Right after generating the sign and timestamp I went to postman and tried to make the request through curl
Code: Select all
curl --location 'https://openapi.tuyaus.com/v1.0/iot-03/devices/device-id/commands' \
--header 'sign_method: HMAC-SHA256' \
--header 'client_id: client-id' \
--header 't: 1733445725839' \
--header 'sign: sing' \
--header 'Content-Type: application/json' \
--data '{
"commands": [
{
"code": "switch_2",
"value": true
}
]
}'
My return is always:
Code: Select all
{
"code": 1004,
"msg": "sign invalid",
"success": false,
"t": 1733446405671,
"tid": "7ff94900b36c11efbb1feeec0f1e308d"
}
I've also tried downloading the postaman file from the documentation to perform the test, and even with the official files and creating the environment variables as requested in the documentation, I also get this sign invalid error. Can anyone help me solve this problem?