mirror of
https://github.com/lehanspb/tuya-mqtt.git
synced 2025-12-16 17:54:36 +00:00
248 lines
7.1 KiB
JavaScript
248 lines
7.1 KiB
JavaScript
const mqtt = require('mqtt');
|
|
const TuyaDevice = require('./tuya-device');
|
|
const debug = require('debug')('tuya-mqtt');
|
|
const debugColor = require('debug')('color');
|
|
const debugMqtt = require('debug')('mqtt');
|
|
const debugTuya = require('debug')('tuyAPI-Events');
|
|
const debugError = require('debug')('error');
|
|
var cleanup = require('./cleanup').Cleanup(onExit);
|
|
|
|
function bmap(istate) {
|
|
return istate ? 'ON' : "OFF";
|
|
}
|
|
|
|
function boolToString(istate) {
|
|
return istate ? 'true' : "false";
|
|
}
|
|
|
|
var connected = undefined;
|
|
var CONFIG = undefined;
|
|
|
|
try {
|
|
CONFIG = require("./config");
|
|
} catch (e) {
|
|
console.error("Configuration file not found")
|
|
debugError(e)
|
|
process.exit(1)
|
|
}
|
|
|
|
if (typeof CONFIG.qos == "undefined") {
|
|
CONFIG.qos = 2;
|
|
}
|
|
if (typeof CONFIG.retain == "undefined") {
|
|
CONFIG.retain = false;
|
|
}
|
|
|
|
const mqtt_client = mqtt.connect({
|
|
host: CONFIG.host,
|
|
port: CONFIG.port,
|
|
username: CONFIG.mqtt_user,
|
|
password: CONFIG.mqtt_pass,
|
|
});
|
|
|
|
mqtt_client.on('connect', function (err) {
|
|
debugMqtt("Verbindung mit MQTT-Server hergestellt");
|
|
connected = true;
|
|
var topic = CONFIG.topic + '#';
|
|
mqtt_client.subscribe(topic, {
|
|
retain: CONFIG.retain,
|
|
qos: CONFIG.qos
|
|
});
|
|
});
|
|
|
|
mqtt_client.on("reconnect", function (error) {
|
|
if (connected) {
|
|
debugMqtt("Verbindung mit MQTT-Server wurde unterbrochen. Erneuter Verbindungsversuch!");
|
|
} else {
|
|
debugMqtt("Verbindung mit MQTT-Server konnte nicht herrgestellt werden.");
|
|
}
|
|
connected = false;
|
|
});
|
|
|
|
mqtt_client.on("error", function (error) {
|
|
debugMqtt("Verbindung mit MQTT-Server konnte nicht herrgestellt werden.", error);
|
|
connected = false;
|
|
});
|
|
|
|
/**
|
|
* execute function on topic message
|
|
*/
|
|
function boolToString(istate) {
|
|
return istate == 1 ? 'on' : "off";
|
|
}
|
|
|
|
function convertMessage(message) {
|
|
var status = message.toString();
|
|
status = boolToString(status);
|
|
status = status.toLowerCase();
|
|
return status;
|
|
}
|
|
|
|
mqtt_client.on('message', function (topic, message) {
|
|
try {
|
|
var cMessage = convertMessage(message);
|
|
var topic = topic.split("/");
|
|
var options = {
|
|
type: topic[1],
|
|
id: topic[2],
|
|
key: topic[3],
|
|
ip: topic[4],
|
|
};
|
|
var exec = topic[5];
|
|
|
|
if (options.type == "socket" || options.type == "lightbulb") {
|
|
debug("device", options);
|
|
debug("message", cMessage);
|
|
var device = new TuyaDevice(options);
|
|
|
|
if (exec == "command") {
|
|
var status = topic[6];
|
|
if (status == null) {
|
|
device.switch(cMessage);
|
|
} else {
|
|
device.switch(status);
|
|
}
|
|
}
|
|
if (exec == "color") {
|
|
var color = message.toString();
|
|
color = color.toLowerCase();
|
|
debugColor("topic: ", topic);
|
|
debugColor("onColor: ", color);
|
|
device.setColor(color);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
debugError(e);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Publish current TuyaDevice state to MQTT-Topic
|
|
* @param {TuyaDevice} device
|
|
* @param {boolean} status
|
|
*/
|
|
function publishStatus(device, status) {
|
|
if (mqtt_client.connected == true) {
|
|
try {
|
|
var type = device.type;
|
|
var tuyaID = device.options.id;
|
|
var tuyaKey = device.options.key;
|
|
var tuyaIP = device.options.ip;
|
|
|
|
if (typeof tuyaID != "undefined" && typeof tuyaKey != "undefined" && typeof tuyaIP != "undefined") {
|
|
var topic = CONFIG.topic + type + "/" + tuyaID + "/" + tuyaKey + "/" + tuyaIP + "/state";
|
|
mqtt_client.publish(topic, status, {
|
|
retain: CONFIG.retain,
|
|
qos: CONFIG.qos
|
|
});
|
|
debugTuya("mqtt status updated to:" + topic + " -> " + status);
|
|
} else {
|
|
debugTuya("mqtt status not updated");
|
|
}
|
|
} catch (e) {
|
|
debugError(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
function publishColorState(device, state) {
|
|
|
|
}
|
|
|
|
/**
|
|
* publish all dps-values to topic
|
|
* @param {TuyaDevice} device
|
|
* @param {Object} dps
|
|
*/
|
|
function publishDPS(device, dps) {
|
|
if (mqtt_client.connected == true) {
|
|
try {
|
|
var type = device.type;
|
|
var tuyaID = device.options.id;
|
|
var tuyaKey = device.options.key;
|
|
var tuyaIP = device.options.ip;
|
|
|
|
if (typeof tuyaID != "undefined" && typeof tuyaKey != "undefined" && typeof tuyaIP != "undefined") {
|
|
var topic = CONFIG.topic + type + "/" + tuyaID + "/" + tuyaKey + "/" + tuyaIP + "/dps";
|
|
var data = JSON.stringify(dps);
|
|
debugTuya("mqtt dps updated to:" + topic + " -> ", data);
|
|
mqtt_client.publish(topic, data, {
|
|
retain: CONFIG.retain,
|
|
qos: CONFIG.qos
|
|
});
|
|
|
|
Object.keys(dps).forEach(function (key) {
|
|
var topic = CONFIG.topic + type + "/" + tuyaID + "/" + tuyaKey + "/" + tuyaIP + "/dps/" + key;
|
|
var data = JSON.stringify(dps[key]);
|
|
debugTuya("mqtt dps updated to:" + topic + " -> dps[" + key + "]", data);
|
|
mqtt_client.publish(topic, data, {
|
|
retain: CONFIG.retain,
|
|
qos: CONFIG.qos
|
|
});
|
|
});
|
|
} else {
|
|
debugTuya("mqtt dps not updated");
|
|
}
|
|
} catch (e) {
|
|
debugError(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* event fires if TuyaDevice sends data
|
|
* @see TuyAPI (https://github.com/codetheweb/tuyapi)
|
|
*/
|
|
TuyaDevice.onAll('data', function (data) {
|
|
try {
|
|
debugTuya('Data from device ' + this.type + ' :', data);
|
|
var status = data.dps['1'];
|
|
if (typeof status != "undefined") {
|
|
publishStatus(this, bmap(status));
|
|
}
|
|
publishDPS(this, data.dps);
|
|
} catch (e) {
|
|
debugError(e);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* MQTT connection tester
|
|
*/
|
|
function MQTT_Tester() {
|
|
this.interval = null;
|
|
|
|
function mqttConnectionTest() {
|
|
if (mqtt_client.connected != connected) {
|
|
connected = mqtt_client.connected;
|
|
if (connected) {
|
|
debugMqtt('MQTT-Server verbunden.');
|
|
} else {
|
|
debugMqtt('MQTT-Server nicht verbunden.');
|
|
}
|
|
}
|
|
}
|
|
|
|
this.destroy = function () {
|
|
clearInterval(this.interval);
|
|
this.interval = undefined;
|
|
}
|
|
|
|
this.connect = function () {
|
|
this.interval = setInterval(mqttConnectionTest, 1500);
|
|
mqttConnectionTest();
|
|
}
|
|
|
|
var constructor = (function (that) {
|
|
that.connect.call(that);
|
|
})(this);
|
|
}
|
|
var tester = new MQTT_Tester();
|
|
|
|
/**
|
|
* Function call on script exit
|
|
*/
|
|
function onExit() {
|
|
TuyaDevice.disconnectAll();
|
|
if (tester) tester.destroy();
|
|
}; |