I'm working on integrating the Tuya API into my Python application to control smart devices. I'm able to successfully make GET requests, but I'm encountering issues when trying to make POST requests.
Whenever I attempt to send a POST request to the Tuya API, I consistently receive either a code 1004 error or a "sign invalid" message. I've verified that my client ID and client secret are correct, and my GET requests are working fine.
here is my Request class file
Code: Select all
import time
import hashlib
import hmac
import requests
import subprocess
class Request:
def __init__(self):
self.ClientID = "**"
self.ClientSecret = "**"
self.BaseUrl = "https://openapi.tuyaus.com"
self.EmptyBodyEncoded = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
def headers(self, sign):
return {
"sign_method": "HMAC-SHA256",
"client_id": self.ClientID,
"t": self.tuyatime(),
"mode": "cors",
"Content-Type": "application/json",
"sign": sign
}
def tuyatime(self):
return str(int(time.time() * 1000))
def access_token(self):
URL = "/v1.0/token?grant_type=1"
StringToSign = f"{self.ClientID}{self.tuyatime()}GET\n{self.EmptyBodyEncoded}\n\n{URL}"
AccessTokenSign = hmac.new(self.ClientSecret.encode(), StringToSign.encode(), hashlib.sha256).hexdigest().upper()
AccessTokenResponse = requests.get(f"{self.BaseUrl}{URL}", headers=self.headers(AccessTokenSign))
return AccessTokenResponse.json()['result']["access_token"]
pass
def sign(self, url, method):
access_token = self.access_token()
str_sign = f"{self.ClientID}{access_token}{self.tuyatime()}{method}\n{self.EmptyBodyEncoded}\n\n{url}"
return [
hmac.new(self.ClientSecret.encode(), str_sign.encode(), hashlib.sha256).hexdigest().upper(),
access_token
]
def _sign(self, url, method, data):
# Define the body
print("data >> ", data)
access_token = self.access_token()
encoded_body = self.EmptyBodyEncoded
if data != None:
body_str = str(data).encode('utf-8')
encoded_body = hashlib.sha256(body_str).hexdigest()
print("encoded_body >> ", encoded_body)
stringToSign = "\n".join([
method, #HTTPMethod
encoded_body, #Content-SHA256
"", #Optional_Signature_key
url #URL
])
str_sign = f"{self.ClientID}{access_token}{self.tuyatime()}{stringToSign}"
return [
hmac.new(self.ClientSecret.encode(), str_sign.encode(), hashlib.sha256).hexdigest().upper(),
access_token
]
def request_extra_params(self, url, method, data):
sign, access_token = self._sign(url, method, data)
headers = self.headers(sign)
headers["access_token"] = access_token
return {
"headers" : headers
}
pass
def get(self, url, **kwargs):
extra_params = self.request_extra_params(url, "GET", None)
return requests.get(f"{self.BaseUrl}{url}", **extra_params, **kwargs)
def post(self, url, data, **kwargs):
extra_params = self.request_extra_params(url, "POST", data)
return requests.post(f"{self.BaseUrl}{url}", json=data, **extra_params, **kwargs)
here is the common file
Code: Select all
from classes.Request import Request
import json
_request = Request()
DEVICES = {
"mark_table" : "***"
}
def set_state_mark_table(value = True):
URL = f"/v1.0/devices/{DEVICES['mark_table']}/commands"
return _request.post(URL, data=json.dumps({
"commands" : [{"code":"switch_1","value":value}]
}))
her is the file to trigger the common file and Request class
Code: Select all
import common
value = common.set_state_mark_table(False)
print(value.text)