Skip to content

Instantly share code, notes, and snippets.

@SleepWalker
Last active December 4, 2023 12:02
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save SleepWalker/18f19679adbfacee6c415d4f6dc218bb to your computer and use it in GitHub Desktop.
Save SleepWalker/18f19679adbfacee6c415d4f6dc218bb to your computer and use it in GitHub Desktop.
tuya-localKey-demo
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
API_CLIENT_ID=
API_CLIENT_SECRET=
SOCKET_DEVICE_ID=
node_modules
.env
{
"trailingComma": "all",
"singleQuote": true,
"proseWrap": "always",
"endOfLine": "lf"
}

This is a demo code for alternative way to get localKey, that is needed for using codetheweb/tuyapi. tuyapi is a npm package that allows you to control your tuya / Smart Life devices using node.js to implement custom behavior not available in official app (or IFTTT app).

Configuration

In order to try this demo, you should clone it:

git clone git@gist.github.com:18f19679adbfacee6c415d4f6dc218bb.git

Then install dependencies: yarn install or npx yarn install

Create .env file with your api credentials and device id. For additional info about how to get api credentials see issue.

About getLocalKey.js

This script prints you info about your device received from API and shows localKey of your device. Just type node ./localKey in terminal.

About demo.js

This script executes demo code from codetheweb/tuyapi, but gets a localKey from tuya OpenAPI instead of @tuyapi/cli. Just type node ./demo in terminal.

About listDevices.js

This scripts prints all devices available for current user. The user (uid) is determined by deviceId that is set in .env. To run the script type node ./listDevices in terminal.

require('dotenv').config();
const { API_CLIENT_ID, API_CLIENT_SECRET, SOCKET_DEVICE_ID } = process.env;
const config = {
deviceId: SOCKET_DEVICE_ID,
clientId: API_CLIENT_ID,
clientSecret: API_CLIENT_SECRET,
};
if (!Object.values(config).every(Boolean)) {
throw new Error(
'Please create .env from .env.example and specify all values',
);
}
module.exports = config;
const TuyAPI = require('tuyapi');
const tuyaApi = require('./tuyaApi');
const { clientId, clientSecret, deviceId } = require('./config');
(async () => {
try {
await tuyaApi.authorize({
clientId,
clientSecret,
});
const localKey = await tuyaApi.getLocalKey({ deviceId });
const device = new TuyAPI({
id: deviceId,
key: localKey,
});
let stateHasChanged = false;
// Add event listeners
device.on('connected', () => {
console.log('Connected to device!');
});
device.on('disconnected', () => {
console.log('Disconnected from device.');
});
device.on('error', (error) => {
console.log('Error!', error);
});
device.on('data', (data) => {
console.log('Data from device:', data);
console.log(`Boolean status of default property: ${data.dps['1']}.`);
// Set default property to opposite
if (!stateHasChanged) {
device.set({ set: !data.dps['1'] });
// Otherwise we'll be stuck in an endless
// loop of toggling the state.
stateHasChanged = true;
}
});
// Find device on network
await device.find();
// Connect to device
await device.connect();
// Disconnect after 10 seconds
await new Promise((resolve) =>
setTimeout(async () => {
await device.disconnect();
resolve();
}, 10000),
);
} catch (error) {
console.log('ERROR', error);
process.exit(1);
}
process.exit(0);
})();
const { clientId, clientSecret, deviceId } = require('./config');
const tuyaApi = require('./tuyaApi');
/**
* Use this script to get `localKey` value.
*
* Example:
* node ./getLocalKey
*/
(async () => {
try {
await tuyaApi.authorize({
clientId,
clientSecret,
});
const device = await tuyaApi.getDeviceWithFunctions({
deviceId,
});
console.warn('Your device info:\n', device);
console.warn("\nThis is your device's localKey:\n", device.local_key);
} catch (error) {
console.log('ERROR', error);
process.exit(1);
}
process.exit(0);
})();
const { clientId, clientSecret, deviceId } = require('./config');
const tuyaApi = require('./tuyaApi');
/**
* Use this script to get list of all devices attached to your account
*
* Example:
* node ./listDevices
*/
(async () => {
try {
await tuyaApi.authorize({
clientId,
clientSecret,
});
const { uid } = await tuyaApi.getDevice({
deviceId,
});
const devicesList = await tuyaApi.getDeviceList({ uid });
console.warn('Available devices:\n', devicesList);
} catch (error) {
console.log('ERROR', error);
process.exit(1);
}
process.exit(0);
})();
{
"name": "tuya-localkey-demo",
"version": "1.0.0",
"description": "This is a demo code for getting `localKey`, that is needed for using [codetheweb/tuyapi](https://github.com/codetheweb/tuyapi).",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "UNLICENSED",
"private": true,
"dependencies": {
"dotenv": "^8.2.0",
"got": "^11.1.4",
"tuyapi": "codetheweb/tuyapi"
}
}
const got = require('got');
const crypto = require('crypto');
/**
* Some very primitive api implementation for demo purposes
*/
class TuyaApi {
async authorize({ clientId, clientSecret }) {
this.context = {};
this.httpClient = got.extend({
prefixUrl: 'https://openapi.tuyaeu.com/v1.0/',
responseType: 'json',
hooks: {
beforeRequest: [
(options) => {
let { accessToken } = this.context;
const now = Date.now();
if (options.url.pathname.includes('/token')) {
// do not add accessToken if it is token request
accessToken = null;
}
const payload = [clientId, accessToken, now]
.filter(Boolean)
.join('');
options.headers.client_id = clientId;
options.headers.sign = crypto
.createHmac('sha256', clientSecret)
.update(payload)
.digest('hex')
.toUpperCase();
options.headers.t = String(now);
options.headers.sign_method = 'HMAC-SHA256';
options.headers.access_token = accessToken || '';
},
],
},
});
await this.ensureToken();
}
async ensureToken() {
if (!this.tokenExpiresAt || Date.now() - this.tokenExpiresAt > 0) {
const { expiresAt, ...token } = await this.getToken({
grantType: 1,
});
this.tokenExpiresAt = expiresAt;
Object.assign(this.context, token);
}
}
async getToken({ grantType = 1, refreshToken = null } = {}) {
let uri = 'token';
if (refreshToken) {
uri += `/${refreshToken}`;
}
const { body } = await this.httpClient.get(uri, {
searchParams: {
grant_type: grantType,
},
});
assertSuccess(body, 'token');
const { result } = body;
return {
accessToken: result.access_token,
refreshToken: result.refresh_token,
expiresAt: Date.now() + (result.expire_time - 30) * 1000,
};
}
async getLocalKey({ deviceId }) {
const device = await this.getDevice({ deviceId });
return device.local_key;
}
async getDevice({ deviceId }) {
const { body } = await this.httpClient.get(`devices/${deviceId}`);
assertSuccess(body, 'device');
return body.result;
}
async getDeviceList({ uid }) {
const { body } = await this.httpClient.get(`users/${uid}/devices`);
assertSuccess(body, 'user/devices');
return body.result;
}
async getDeviceWithFunctions({ deviceId }) {
await this.ensureToken();
const [device, { body: functions }] = await Promise.all([
this.getDevice({ deviceId }),
this.httpClient.get(`devices/${deviceId}/functions`),
]);
assertSuccess(functions, 'functions');
return {
...device.result,
functions: functions.result,
};
}
/**
* NOTE: this may be used to issue commands directly through Tuya OpenAPI
* over internet instead of local network
*/
async sendCommand({ deviceId, commands }) {
await this.ensureToken();
const { body } = await this.httpClient.post(
`devices/${deviceId}/commands`,
{
json: {
commands,
},
},
);
assertSuccess(body, 'commands');
}
}
function assertSuccess(body, type) {
if (!body.success) {
const error = new Error(
`Error requesting ${type}: ${body['msg']} (${body['code']})`,
);
error['resp'] = body;
throw error;
}
}
module.exports = new TuyaApi();
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@sindresorhus/is@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1"
integrity sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==
"@szmarczak/http-timer@^4.0.5":
version "4.0.5"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152"
integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==
dependencies:
defer-to-connect "^2.0.0"
"@types/cacheable-request@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
dependencies:
"@types/http-cache-semantics" "*"
"@types/keyv" "*"
"@types/node" "*"
"@types/responselike" "*"
"@types/http-cache-semantics@*":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
"@types/keyv@*":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
dependencies:
"@types/node" "*"
"@types/node@*":
version "14.0.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.5.tgz#3d03acd3b3414cf67faf999aed11682ed121f22b"
integrity sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==
"@types/responselike@*", "@types/responselike@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
dependencies:
"@types/node" "*"
"@types/retry@^0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
cacheable-lookup@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3"
integrity sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==
cacheable-request@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58"
integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^4.0.0"
lowercase-keys "^2.0.0"
normalize-url "^4.1.0"
responselike "^2.0.0"
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
debug@4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
decompress-response@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
dependencies:
mimic-response "^3.1.0"
defer-to-connect@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1"
integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==
dotenv@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
get-stream@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
dependencies:
pump "^3.0.0"
got@^11.1.4:
version "11.1.4"
resolved "https://registry.yarnpkg.com/got/-/got-11.1.4.tgz#ecf0064aab26ae4b2989ab52aadd31a17e7bad63"
integrity sha512-z94KIXHhFSpJONuY6C6w1wC+igE7P1d0b5h3H2CvrOXn0/tum/OgFblIGUAxI5PBXukGLvKb9MJXVHW8vsYaBA==
dependencies:
"@sindresorhus/is" "^2.1.1"
"@szmarczak/http-timer" "^4.0.5"
"@types/cacheable-request" "^6.0.1"
"@types/responselike" "^1.0.0"
cacheable-lookup "^5.0.3"
cacheable-request "^7.0.1"
decompress-response "^6.0.0"
get-stream "^5.1.0"
http2-wrapper "^1.0.0-beta.4.5"
lowercase-keys "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
http-cache-semantics@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
http2-wrapper@^1.0.0-beta.4.5:
version "1.0.0-beta.4.6"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.4.6.tgz#9438f0fceb946c8cbd365076c228a4d3bd4d0143"
integrity sha512-9oB4BiGDTI1FmIBlOF9OJ5hwJvcBEmPCqk/hy314Uhy2uq5TjekUZM8w8SPLLlUEM+mxNhXdPAXfrJN2Zbb/GQ==
dependencies:
quick-lru "^5.0.0"
resolve-alpn "^1.0.0"
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
keyv@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.1.tgz#9fe703cb4a94d6d11729d320af033307efd02ee6"
integrity sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw==
dependencies:
json-buffer "3.0.1"
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
mimic-response@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
normalize-url@^4.1.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-cancelable@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-retry@4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.2.0.tgz#ea9066c6b44f23cab4cd42f6147cdbbc6604da5d"
integrity sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==
dependencies:
"@types/retry" "^0.12.0"
retry "^0.12.0"
p-timeout@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
dependencies:
p-finally "^1.0.0"
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
quick-lru@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.0.tgz#1602f339bde554c4dace47880227ec9c2869f2e8"
integrity sha512-WjAKQ9ORzvqjLijJXiXWqc3Gcs1ivoxCj6KJmEjoWBE6OtHwuaDLSAUqGHALUiid7A1KqGqsSHZs8prxF5xxAQ==
resolve-alpn@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c"
integrity sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==
responselike@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
dependencies:
lowercase-keys "^2.0.0"
retry@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
tuyapi@codetheweb/tuyapi:
version "5.3.1"
resolved "https://codeload.github.com/codetheweb/tuyapi/tar.gz/cea119ecdd476fe77364394df18448783cfd454a"
dependencies:
debug "4.1.1"
p-retry "4.2.0"
p-timeout "3.2.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
@HaydenRichardson
Copy link

hello there i was wondering if u could help me with an issue

@hooverds54
Copy link

I am having trouble getting the example code to work and it seems to be failing in the authorization routine. Is it possible that being in the US I should use a different server in this line

prefixUrl: 'https://openapi.tuyaeu.com/v1.0/',

@hooverds54
Copy link

However even changing that to

prefixUrl: 'https://openapi.tuyaus.com/v1.0/', still generates this error

node ./getLocalKey
ERROR Error: Error requesting token: sign invalid (1004)
at assertSuccess (/home/hooverds/Downloads/Tuya-API-Sleepwalker/tuyaApi.js:143:19)
at TuyaApi.getToken (/home/hooverds/Downloads/Tuya-API-Sleepwalker/tuyaApi.js:72:5)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async TuyaApi.ensureToken (/home/hooverds/Downloads/Tuya-API-Sleepwalker/tuyaApi.js:49:39)
at async TuyaApi.authorize (/home/hooverds/Downloads/Tuya-API-Sleepwalker/tuyaApi.js:44:5)
at async /home/hooverds/Downloads/Tuya-API-Sleepwalker/getLocalKey.js:13:5 {
resp: {
code: 1004,
msg: 'sign invalid',
success: false,
t: 1672869803286,
tid: '9b4e20558c7b11ed9be9a6a27ab27b2a'
}
}

@hooverds54
Copy link

I suspect this code no longer works because Tuya has change the authorization procedure. I am fairly certain everything is set right based on the code that was supplied but it fails in the "authorize" function I know I have the correct clientId and "Secret access" string because I used same values in Postman and it worked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment