@demirdeniz/node-red-contrib-tuya-kepler-device
Version:
A node-red module to interact with the tuya smart devices (updated with Tuya protocol 3.5)
194 lines (187 loc) • 6.59 kB
JavaScript
const TuyaDevice = require("@demirdeniz/tuyapi-newgen");
const packageInfo = require("../package.json");
const utils = require('./utils');
module.exports = function (RED) {
function TuyaKeplerDeviceSelfNode(config) {
RED.nodes.createNode(this, config);
let node = this;
let shouldSubscribeData = true;
let shouldSubscribeRefreshData = true;
this.name = config.name;
this.eventMode = config.eventMode || "event-both";
this.logLevel = config.logLevel || "log-level-disable";
this.operations = [];
if (this.eventMode == "event-data") {
shouldSubscribeData = true;
shouldSubscribeRefreshData = false;
} else if (this.eventMode == "event-dp-refresh") {
shouldSubscribeData = false;
shouldSubscribeRefreshData = true;
} else {
// both case or default case
shouldSubscribeData = true;
shouldSubscribeRefreshData = true;
}
if (this.logLevel == "log-level-debug")
this.enableDebug = true;
node.on("input", function (msg) {
let operation = msg.payload.operation || "SET";
delete msg.payload.operation;
let requestID = new Date().getTime();
node.log(
`[${requestID}] recieved data on input : ${JSON.stringify({
...msg,
moduleVersion: packageInfo.version,
})}`
);
// Initiate the device connection and then send the payload
node.operations.push(1);
const tuyaProtocolVersion =
msg.payload.version == null ||
typeof msg.payload.version == "undefined" ||
msg.payload.version.trim() == "" ||
isNaN(msg.payload.version)
? "3.1"
: msg.payload.version.trim();
const connectionParams = {
id: msg.payload.deviceVirtualId,
key: msg.payload.deviceKey,
ip: msg.payload.deviceIp,
issueGetOnConnect: false,
nullPayloadOnJSONError: false,
version: tuyaProtocolVersion,
};
node.log(
`Connecting to tuya with params : ${JSON.stringify(connectionParams)}`
);
let tuyaDevice = new TuyaDevice(connectionParams);
tuyaDevice.on("disconnected", () => {
node.log(`[${requestID}] Disconnected from tuyaDevice.`);
node.operations.pop();
if (node.operations.length === 0) {
// Show the disconnected status if there is no more active connections.
setStatusDisconnected();
}
});
tuyaDevice.on("error", (error) => {
node.operations.pop();
setStatusOnError(error, requestID, "Error", {
context: {
message: error,
deviceVirtualId: msg.payload.deviceVirtualId,
deviceKey: msg.payload.deviceKey,
deviceIp: msg.payload.deviceIp,
requestID: requestID,
},
});
});
tuyaDevice.on("connected", () => {
node.log(
`[${requestID}] Connected to device! ${msg.payload.deviceVirtualId}`
);
setStatusConnected();
switch (operation) {
case "SET":
node.log(
`[${requestID}] sending command SET : ${JSON.stringify(
msg.payload.payload
)}`
);
tuyaDevice.set(msg.payload.payload);
break;
default:
node.log(`[${requestID}] Invalid operation ${operation}`);
}
});
if (shouldSubscribeRefreshData) {
tuyaDevice.on("dp-refresh", (data) => {
node.log(
`[${requestID}] Data from device [event:dp-refresh]: ${JSON.stringify(
data
)}`
);
tuyaDevice.disconnect();
node.send({
payload: {
data: data,
deviceVirtualId: msg.payload.deviceVirtualId,
deviceKey: msg.payload.deviceKey,
deviceName: msg.payload.deviceName,
deviceIp: msg.payload.deviceIp,
requestID: requestID,
},
});
});
}
if (shouldSubscribeData) {
tuyaDevice.on("data", (data) => {
node.log(
`[${requestID}] Data from device [event:data]: ${JSON.stringify(
data
)}`
);
tuyaDevice.disconnect();
node.send({
payload: {
data: data,
deviceVirtualId: msg.payload.deviceVirtualId,
deviceKey: msg.payload.deviceKey,
deviceName: msg.payload.deviceName,
deviceIp: msg.payload.deviceIp,
requestID: requestID,
},
});
});
}
let findDevice = () => {
setStatusConnecting();
node.log(`[${requestID}] initiating the find command`);
tuyaDevice
.find({})
.then(() => {
// Connect to device
tuyaDevice.connect();
})
.catch((e) => {
// We need to retry
setStatusOnError(e.message, requestID, "Can't find device", {
context: {
message: e,
deviceVirtualId: msg.payload.deviceVirtualId,
deviceKey: msg.payload.deviceKey,
deviceIp: msg.payload.deviceIp,
},
});
node.log(`[${requestID}] Cannot find the device`);
//setTimeout(findDevice, 1000);
});
};
findDevice();
});
let setStatusConnecting = function () {
return node.status({ fill: "yellow", shape: "ring", text: "connecting" });
};
let setStatusConnected = function () {
return node.status({ fill: "green", shape: "ring", text: "connected" });
};
let setStatusDisconnected = function () {
return node.status({ fill: "red", shape: "ring", text: "disconnected" });
};
var setStatusOnError = function (
errorText,
requestID,
errorShortText = "error",
data
) {
node.error(`[${requestID}] An error had occured : ${errorText}`, data);
return node.status({ fill: "red", shape: "ring", text: errorShortText });
};
node.on("close", function () {
// tidy up any state
// clearInterval(int);
//shouldTryReconnect = false;
//tuyaDevice.disconnect();
});
}
RED.nodes.registerType("tuya-kepler-device-generic", TuyaKeplerDeviceSelfNode);
};