Page 1 of 1

sign invalid | POST: /v1.0/iot-03/devices/{device_id}/commands

Posted: 2024年 Dec 6日 08:59
by wevertonl

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?