Comments (4)
For anyone coming around the issue, the following assumes you've already created an account on Tuya IoT Platform as also a Cloud Project in order to get the required credentials, aka Client ID
& Client Secret
, and the project API endpoint (Data center url address).
I was facing the same issue regarding CORS policy, but I've solved that by abstracting tuya-connector-nodejs in order to create an ordinary nodejs / express server. Also I've used cors
package to configure the Access-Control-Allow-Origin
CORS header... I'm sharing the simplified Custom API set up with its own routes which then call tuya-connector-nodejs functions.
On Tuya Iot Platform -> Cloud -> Development: I've left the Cloud Authorization IP Allowlist
option disabled, as my intention was to run the server on localhost only.
Nodejs / Express:
.env
TUYA_DATA_CENTER_URL=https://openapi.tuyaus.com
TUYA_CLIENT_ID=
TUYA_CLIENT_SECRET=
TUYA_IMAGE_URL=https://images.tuyacn.com/
src/config.js
import dotenv from 'dotenv';
dotenv.config()
// Tuya Cloud - IoT Platform
const config = {
baseUrl: `${process.env.TUYA_DATA_CENTER_URL}`, // Western America Data Center
clientId: `${process.env.TUYA_CLIENT_ID}`, // Access ID / Client ID
clientSecret: `${process.env.TUYA_CLIENT_SECRET}`, // Access Secret / Client Secret:
apiImageUrl: `${process.env.TUYA_IMAGE_URL}` // https://images.tuyacn.com/
};
if (!Object.values(config).every(Boolean)) {
throw new Error(
'Please create .env from .env.example and specify all values',
);
}
export default config;
src/index.js
import dotenv from 'dotenv'
import express from 'express'
import axios from 'axios'
import cors from 'cors'
// Custom Tuya Api Routes
import { routes } from './routes/index.js'
const router = express.Router()
dotenv.config()
const port = 3399
const app = express()
app.use(express.urlencoded({ extended: true }))
app.use(express.json({ limit: '32mb' }))
app.use(cors({ origin: '*' })) // This alone didn't work!
app.use(
cors({
origin: [
'https://openapi.tuyeu.com',
'https://openapi.tuyaus.com',
'http://localhost:3000',
'http://localhost:3399',
],
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE', 'OPTIONS'],
allowedHeaders: [
'Origin',
'X-Requested-With',
'Content-Type',
'Accept',
'Signature-Headers',
'client_id',
'access_token',
'sign',
'sign_method',
'stringToSign',
't',
'nonce',
],
})
)
app.use(routes)
app.listen(port, () => {
console.log(
`TuyaApi Started ✓ - Express listening on port : ${port} - press Ctrl-C to terminate.`
)
})
src/routes/index.js
import express from 'express'
const router = express.Router()
// Main Api Routes
import { apiRoutes } from './api/index.js' // src/routes/api/index.js
const api = '/api/v1'
router.use(api, apiRoutes)
router.use(api, (req, res) => res.status(404).json('No API route found'))
export { router as routes }
src/routes/api/index.js
import express from 'express'
const router = express.Router()
import { deviceRoutes } from './devices.js' // src/routes/api/device.js
import { userRoutes } from './user.js' // src/routes/api/user.js
// Device Routes
router.use('/device', deviceRoutes)
// User Routes
router.use('/users', userRoutes)
// Other Routes...
export { router as apiRoutes }
src/utils/redisConnect.js
// Redis (ioRedis) connection
import dotenv from 'dotenv'
dotenv.config()
export const redisConnect = {
port: `${process.env.REDIS_PORT}`,
host: `${process.env.REDIS_HOST}`,
username: 'default',
password: `${process.env.REDIS_PASS}`,
db: 0
}
src/utils/tokenStore.js
//
// redis store
// @see: https://github.com/tuya/tuya-connector-nodejs
//
import Redis from 'ioredis'
import { redisConnect } from '../utils/redisConnect.js'
export class RedisTokenStore {
client = new Redis(redisConnect)
constructor (client, key = 'tuya::token') {
this.client = client
this.key = key
}
async setTokens (tokens) {
const res = await this.client.set(this.key, JSON.stringify(tokens))
return !!res
}
async getAccessToken () {
const jsonStr = (await this.client.get(this.key)) || '{}'
const tokens = JSON.parse(jsonStr)
return tokens && tokens.access_token
}
async getRefreshToken () {
const jsonStr = (await this.client.get(this.key)) || '{}'
const tokens = JSON.parse(jsonStr)
return tokens.refresh_token
}
}
src/routes/api/device.js
Here tuya-connector-nodejs functions are wrapped within ordinary express router logic...
import express from 'express'
import axios from 'axios'
import Redis from 'ioredis'
import { TuyaContext } from '@tuya/tuya-connector-nodejs'
import { RedisTokenStore } from '../../utils/tokenStore.js'
import { redisConnect } from '../../utils/redisConnect.js'
import config from '../../config.js'
const { baseUrl, clientId, clientSecret, deviceId, uid } = config
const router = express.Router()
const redis = new Redis(redisConnect)
const tuya = new TuyaContext({
baseUrl: baseUrl, // https://openapi.tuyaus.com',
accessKey: clientId,
secretKey: clientSecret,
store: new RedisTokenStore(redis),
rpc: axios
})
//
// Devices API Routes
// Tuya Cloud API Reference: https://developer.tuya.com/en/docs/iot/api-reference?id=Ka7qb7vhber64
// @see: https://github.com/tuya/tuya-connector-nodejs
//
//
// Post commands to device
//
router.post('/:id/commands', async (req, res) => {
try {
const deviceId = req.params.id
const { commands } = req.body
const result = await tuya.request({
method: 'POST',
path: `/v1.0/devices/${deviceId}/commands`,
body: { commands }
})
res.status(200).json({
...result,
message: 'Device updated successfully!'
})
} catch (error) {
console.log('ERROR', error)
}
})
//
//
// Update (modify) device details, such as name etc..
//
router.put('/:id/update', async (req, res) => {
try {
const deviceId = req.params.id
const update = req.body
if (Object.keys(update).length === 0) {
return res.status(400).json({ error: 'Missing body params' })
}
const result = await tuya.request({
method: 'PUT',
path: `/v1.0/iot-03/devices/${deviceId}`,
body: update
})
res.status(200).json({
...result,
message: 'Device updated successfully!'
})
} catch (error) {
console.log('ERROR', error)
}
})
//
// Get all devices under a user's account by user ID
//
router.get('/', async (req, res) => {
try {
const response = await tuya.request({
method: 'GET',
path: `/v1.0/users/${uid}/devices`
// body: {},
})
res.status(200).json({
...response.result
})
} catch (error) {
console.log('ERROR', error)
}
})
//
// Get device details by id
//
router.get('/:id', async (req, res) => {
try {
const deviceId = req.params.id
const response = tuya.request({
method: 'GET',
path: `/v1.0/devices/${deviceId}`
// body: {},
})
await response.then(result => {
res.status(200).send(result)
})
} catch (error) {
console.log('ERROR', error)
}
})
//
// Get device available data points
//
router.get('/:id/status', async (req, res) => {
try {
const deviceId = req.params.id
const response = tuya.request({
method: 'GET',
path: `/v1.0/devices/${deviceId}/status`
// body: {},
})
await response.then(result => {
res.status(200).json(result)
})
} catch (error) {
console.log('ERROR', error)
}
})
//
// Get device available functions
//
router.get('/:id/functions', async (req, res) => {
try {
const deviceId = req.params.id
const response = tuya.request({
method: 'GET',
path: `/v1.0/iot-03/devices/${deviceId}/functions`
// body: {},
})
await response.then(result => {
res.status(200).send(result)
})
} catch (error) {
console.log('ERROR', error)
}
})
export { router as deviceRoutes }
After starting the server, if no errors, the API is ready to be consumed. So in the Frontend as usual, by making a GET request to http://localhost:3399/api/v1/devices/:id
, where :id
is the deviceId connected to your Tuya Cloud project, you should get the device details.
I had no issues with CORS with this set up!
Please leave your enhancement ideas, such as a tuya middleware function or any other type of set up that works for you!
from tuya-connector-nodejs.
For anyone coming around the issue, the following assumes you've already created an account on Tuya IoT Platform as also a Cloud Project in order to get the required credentials, aka
Client ID
&Client Secret
, and the project API endpoint (Data center url address).I was facing the same issue regarding CORS policy, but I've solved that by abstrating tuya-connector-nodejs in order to create an ordinary nodejs / express server. Also I've used
cors
package to configure theAccess-Control-Allow-Origin
CORS header... I'm sharing the simplified Custom API set up with its own routes which then call tuya-connector-nodejs functions.On Tuya Iot Platform -> Cloud -> Development: I've left the
Cloud Authorization IP Allowlist
option disabled, as my intention was to run the server on localhost only.Nodejs / Express:
.env
TUYA_DATA_CENTER_URL=https://openapi.tuyaus.com TUYA_CLIENT_ID= TUYA_CLIENT_SECRET= TUYA_IMAGE_URL=https://images.tuyacn.com/
src/config.js
import dotenv from 'dotenv'; dotenv.config() // Tuya Cloud - IoT Platform const config = { baseUrl: `${process.env.TUYA_DATA_CENTER_URL}`, // Western America Data Center clientId: `${process.env.TUYA_CLIENT_ID}`, // Access ID / Client ID clientSecret: `${process.env.TUYA_CLIENT_SECRET}`, // Access Secret / Client Secret: apiImageUrl: `${process.env.TUYA_IMAGE_URL}` // https://images.tuyacn.com/ }; if (!Object.values(config).every(Boolean)) { throw new Error( 'Please create .env from .env.example and specify all values', ); } export default config;
src/index.js
import dotenv from 'dotenv' import express from 'express' import axios from 'axios' import cors from 'cors' // Custom Tuya Api Routes import { routes } from './routes/index.js' const router = express.Router() dotenv.config() const port = 3399 const app = express() app.use(express.urlencoded({ extended: true })) app.use(express.json({ limit: '32mb' })) app.use(cors({ origin: '*' })) // This alone didn't work! app.use( cors({ origin: [ 'https://openapi.tuyeu.com', 'https://openapi.tuyaus.com', 'http://localhost:3000', 'http://localhost:3399', ], methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE', 'OPTIONS'], allowedHeaders: [ 'Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Signature-Headers', 'client_id', 'access_token', 'sign', 'sign_method', 'stringToSign', 't', 'nonce', ], }) ) app.use(routes) app.listen(port, () => { console.log( `TuyaApi Started ✓ - Express listening on port : ${port} - press Ctrl-C to terminate.` ) })
src/routes/index.js
import express from 'express' const router = express.Router() // Main Api Routes import { apiRoutes } from './api/index.js' // src/routes/api/index.js const api = '/api/v1' router.use(api, apiRoutes) router.use(api, (req, res) => res.status(404).json('No API route found')) export { router as routes }
src/routes/api/index.js
import express from 'express' const router = express.Router() import { deviceRoutes } from './devices.js' // src/routes/api/device.js import { userRoutes } from './user.js' // src/routes/api/user.js // Device Routes router.use('/device', deviceRoutes) // User Routes router.use('/users', userRoutes) // Other Routes... export { router as apiRoutes }
src/routes/api/device.js
Here tuya-connector-nodejs functions are wrapped within ordinary express router logic...
import express from 'express' const router = express.Router() import axios from 'axios' import { TuyaContext } from '@tuya/tuya-connector-nodejs'; import { RedisTokenStore } from '../../utils/tokenStore.ts'; import Redis from 'ioredis'; const redis = new Redis(); import config from '../../config.js'; const { baseUrl, clientId, clientSecret } = config; const tuya = new TuyaContext({ baseUrl: baseUrl, //'https://openapi.tuyaus.com', accessKey: clientId, secretKey: clientSecret, store: new RedisTokenStore(redis), rpc: axios }); // // Get device by id // router.get('/:id', async (req, res) => { try { const deviceId = req.params.id const response = tuya.request({ method: 'GET', path: `/v1.0/devices/${deviceId}`, body: {}, }) await response.then(result => { res.status(200).send(result) }) } catch (error) { console.log('ERROR', error); } }) // ... rest of routes // router.get() // router.post() ... export { router as deviceRoutes }After starting the server, if no errors, the API is ready to be consumed. So in the Frontend as usual, by making a GET request to
http://localhost:3399/api/v1/devices/:id
, where:id
is the deviceId connected to your Tuya Cloud project, you should get the device details.I had no issues with CORS with this set up!
Please leave your enhancement ideas, such as a tuya middleware function or any other type of set up that works for you!
Hi did you run the tuya connector node sdk and this node server together,or you just took the functions from their code and that redis token they have in their github,I was facing sign invalid issue.
from tuya-connector-nodejs.
@monecchi Can you share your tokenStore.ts file code
from tuya-connector-nodejs.
Hey @JimRh! You're right, I use their suggested tokenStore solution based on redis. The project I've set up does not use typescript ... I've updated the answer code blocks to include an abstraction of the way I'm connectng to the redis server (remote or local).
from tuya-connector-nodejs.
Related Issues (12)
- How to use this SDK? HOT 2
- Always got sign invalid HOT 2
- /iot-03/ Causing login errors
- Permission Deny error HOT 5
- Incorrect return type for device status endpoint
- Wrong request for tuya.deviceFunction.command() HOT 2
- Issue in passing comma separated values in query TuyaContext.request HOT 1
- "Get the device list" api not working HOT 1
- "No permissions. This API is not subscribed"
- TypeError: crypto.createHash is not a function HOT 1
- No License associated with this project
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tuya-connector-nodejs.