// ====== НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ ======
const CLIENT_ID = "ВАШ_ACCESS_ID_ИЗ_ШАГА_1";
const SECRET = "ВАШ_ACCESS_SECRET_ИЗ_ШАГА_1";
const DEVICE_ID = "ВАШ_DEVICE_ID_УСТРОЙСТВА";
const TUYA_BASE_URL = "https://openapi.tuyaeu.com"; // [cite: 28, 29]
// ===================================
function doGet(e) {
try {
let action = e.parameter.action; // [cite: 30]
let turnOn = (action === 'off') ? false : true; // [cite: 31]
// 1. Получаем свежий токен доступа
let t_token = new Date().getTime().toString(); // [cite: 32]
let signUrl_token = "/v1.0/token?grant_type=1";
let bodyHash_token = calcSha256(""); // [cite: 33]
let stringToSign_token = CLIENT_ID + t_token + "GET\n" + bodyHash_token + "\n\n" + signUrl_token; // [cite: 34]
let sign_token = calcHmacSha256(stringToSign_token, SECRET);
let tokenOpts = {
"method": "get",
"headers": { "client_id": CLIENT_ID, "sign": sign_token, "t": t_token, "sign_method": "HMAC-SHA256" },
"muteHttpExceptions": true
}; // [cite: 35]
let tokenRes = JSON.parse(UrlFetchApp.fetch(`${TUYA_BASE_URL}${signUrl_token}`, tokenOpts).getContentText()); // [cite: 36]
if (!tokenRes.success) return ContentService.createTextOutput(JSON.stringify({ error: "Token failed", detail: tokenRes})).setMimeType(ContentService.MimeType.JSON); // [cite: 37]
let accessToken = tokenRes.result.access_token;
// 2. Формируем и подписываем команду для реле
let t_cmd = new Date().getTime().toString(); // [cite: 38]
let signUrl_cmd = `/v1.0/devices/${DEVICE_ID}/commands`;
let payloadStr = JSON.stringify({ "commands": [{ "code": "switch_1", "value": turnOn }] }); // [cite: 39]
let bodyHash_cmd = calcSha256(payloadStr);
let stringToSign_cmd = CLIENT_ID + accessToken + t_cmd + "POST\n" + bodyHash_cmd + "\n\n" + signUrl_cmd; // [cite: 40]
let sign_cmd = calcHmacSha256(stringToSign_cmd, SECRET);
let cmdOpts = {
"method": "post",
"contentType": "application/json",
"headers": {
"client_id": CLIENT_ID,
"access_token": accessToken,
"sign": sign_cmd,
"t": t_cmd,
"sign_method": "HMAC-SHA256"
},
"payload": payloadStr,
"muteHttpExceptions": true
}; // [cite: 41, 42]
let response = UrlFetchApp.fetch(`${TUYA_BASE_URL}${signUrl_cmd}`, cmdOpts);
return ContentService.createTextOutput(response.getContentText()).setMimeType(ContentService.MimeType.JSON); // [cite: 43]
} catch (err) {
return ContentService.createTextOutput(JSON.stringify({ error: err.toString()})).setMimeType(ContentService.MimeType.JSON); // [cite: 44]
}
}
function calcSha256(input) {
let rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, input, Utilities.Charset.UTF_8); // [cite: 45]
return rawHash.map(function(b) { return ('0' + (b & 0xFF).toString(16)).slice(-2); }).join(''); // [cite: 46]
}
function calcHmacSha256(input, key) {
let rawHmac = Utilities.computeHmacSha256Signature(input, key, Utilities.Charset.UTF_8); // [cite: 46]
return rawHmac.map(function(b) { return ('0' + (b & 0xFF).toString(16)).slice(-2); }).join('').toUpperCase(); // [cite: 47]
}