I've set up a cloud project in Tuya, and I'm trying to write Java code in Android Studio to turn on a Wi-Fi socket. However, I'm encountering an issue.
Here's my code:
Code: Select all
public class TuyaApiHelper {
private static final String TAG = "TuyaHelper";
private static final String ACCESS_ID = "Access id from cloud project overview section";
private static final String ACCESS_SECRET = "Access secret from cloud project overview section";
private static final String DEVICE_ID = "Device id"; // ← Replace this
private static final String BASE_URL = "https://openapi.tuyacn.com";
private static final OkHttpClient client = new OkHttpClient();
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
public interface Callback {
void onSuccess(String result);
void onFailure(String error);
}
public static void switchDevice(final boolean turnOn, final Callback callback) {
getAccessToken(new Callback() {
@Override
public void onSuccess(String token) {
sendCommand(token, turnOn, callback);
}
@Override
public void onFailure(String error) {
callback.onFailure("Token error: " + error);
}
});
}
private static void getAccessToken(final Callback callback) {
long timestamp = System.currentTimeMillis();
String stringToSign = ACCESS_ID + timestamp;
String sign = hmacSHA256(stringToSign, ACCESS_SECRET).toUpperCase();
String url = BASE_URL + "/v1.0/token";
Request request = new Request.Builder()
.url(url)
.get()
.addHeader("client_id", ACCESS_ID)
.addHeader("sign", sign)
.addHeader("t", String.valueOf(timestamp))
.addHeader("sign_method", "HMAC-SHA256")
.build();
client.newCall(request).enqueue(new okhttp3.Callback() {
@Override
public void onFailure(Call call, IOException e) {
callback.onFailure(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string();
try {
JSONObject obj = new JSONObject(json);
String token = obj.getJSONObject("result").getString("access_token");
callback.onSuccess(token);
} catch (Exception e) {
callback.onFailure("Parsing error: " + e.getMessage() + " \n Response: " + json);
}
}
});
}
private static void sendCommand(String token, boolean turnOn, Callback callback) {
String endpoint = "/v1.0/iot-03/devices/" + DEVICE_ID + "/commands";
String url = BASE_URL + endpoint;
String value = turnOn ? "true" : "false";
String json = "{\n" +
" \"commands\": [\n" +
" {\n" +
" \"code\": \"switch_1\",\n" +
" \"value\": " + value + "\n" +
" }\n" +
" ]\n" +
"}";
RequestBody body = RequestBody.create(json, MediaType.get("application/json"));
long timestamp = System.currentTimeMillis();
String signStr = ACCESS_ID + token + timestamp;
String sign = hmacSHA256(signStr, ACCESS_SECRET).toUpperCase();
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("client_id", ACCESS_ID)
.addHeader("access_token", token)
.addHeader("t", String.valueOf(timestamp))
.addHeader("sign_method", "HMAC-SHA256")
.addHeader("sign", sign)
.addHeader("Content-Type", "application/json")
.build();
client.newCall(request).enqueue(new okhttp3.Callback() {
@Override
public void onFailure(Call call, IOException e) {
callback.onFailure(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
callback.onSuccess(response.body().string());
}
});
}
private static String hmacSHA256(String data, String key) {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
return "";
}
}
}
Code: Select all
public static String sha256_HMAC(String clientId, String clientSecret, String timestamp) throws NoSuchAlgorithmException, InvalidKeyException {
String message = clientId + timestamp;
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hash = sha256_HMAC.doFinal(message.getBytes(StandardCharsets.UTF_8));
// Convert bytes to hex
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString().toUpperCase(); // Tuya requires UPPERCASE hex
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes)
sb.append(String.format("%02x", b));
return sb.toString();
}
I am getting "code": 1004, "msg": "sign invalid" response. Am I missing any thing in the creating the sign string. Any help is appreciated.