node-red-contrib-voice-assistant
Version:
一个小度-小爱-猫精音箱控制NODE-RED自定义设备的节点
197 lines (181 loc) • 6.99 kB
JavaScript
const { default: MqttClient } = require('./lib/comm/mqtt');
const { default: Halink } = require('./lib/service/haService');
const { default: CustomService } = require('./lib/service/customService');
const { default: HandleAttribute } = require('./lib/handleAttr');
module.exports = function (RED) {
'use strict';
var getmac = require('getmac');
var reg = new RegExp(':', 'g');
var models = [];
function XiaoDuSerConfig(n) {
RED.nodes.createNode(this, n);
if (this.credentials) {
this.username = this.credentials.username;
this.password = this.credentials.password;
}
models = this.models = [];
this.localmac = getmac.default().replace(reg, '');
if (!this.username || !this.password) {
return;
}
//生成处理类
this.handleAttribute = new HandleAttribute(this.models);
this.mqttClient = new MqttClient(this.username, this.password);
this.mqttClient.subTopic('sys/user/get/' + this.username + '/#');
this.mqttClient.subTopic('sys/user/get/ha/' + this.username);
this.mqttClient.pubTopic = 'sys/user/update/' + this.username;
this.mqttClient.connect();
this.mqttClient.onData = (err, msg) => {
//console.log(err)
//公用接收
if (err) return;
if (msg.message) {
const { payload } = msg.message;
if (payload.type === 'getProps') {
payload.data = this.handleAttribute.getProps(payload.data);
this.mqttClient.publish(payload);
} else if (payload.type === 'getDevices') {
payload.data = [];
this.models.forEach((it) => {
if (it.enable) payload.data.push(it);
});
this.mqttClient.publish(payload);
}
}
};
this.on('close', (done) => {
this.models = models = [];
this.mqttClient.close(done);
done && done();
});
//网页获取设备
RED.httpAdmin.get('/GetVoiceDeviceList', (req, res) => {
res.json({ data: models });
});
}
RED.nodes.registerType('ServiceConfig', XiaoDuSerConfig, {
credentials: {
username: { type: 'text' },
password: { type: 'password' },
},
});
function XiaoAiIn(n) {
RED.nodes.createNode(this, n);
const configNode = RED.nodes.getNode(n.broker);
var node = this;
if (!configNode) {
node.status({ fill: 'red', shape: 'dot', text: '服务未配置' });
return;
}
node.customService = new CustomService(n.devtype, configNode);
const model = node.customService.createDevModel(n.name);
model && configNode.models.push(model); //生成设备
node.customService.onSetProps = function (msgs) {
console.log('msgs', msgs);
node.send({ devid: msgs.id, payload: { name: msgs.name, value: msgs.value } });
return;
//设置消息
/* msgs.forEach((element) => {
node.send(element);
}); */
};
node.customService.onStatus = function (err, msg) {
if (err) {
node.status({ fill: 'red', shape: 'dot', text: err });
return;
}
if (msg.reconnect) {
node.status({ fill: 'yellow', shape: 'dot', text: '云服务重连中' });
return;
}
if (msg.connect) {
node.status({ fill: 'green', shape: 'dot', text: '云服务连接成功' });
}
};
}
RED.nodes.registerType('cmd in', XiaoAiIn);
function XiaoAiOut(n) {
RED.nodes.createNode(this, n);
const configNode = RED.nodes.getNode(n.broker);
var node = this;
if (configNode) {
//const customService = new CustomService('', configNode);
node.on('input', function (msg) {
try {
configNode.handleAttribute.saveCustomState(msg);
} catch {}
});
}
}
RED.nodes.registerType('state out', XiaoAiOut);
function HassLink(n) {
RED.nodes.createNode(this, n);
this.brokerConn = RED.nodes.getNode(n.broker);
this.devData = n.devdata;
let hasslink;
if (this.brokerConn) {
hasslink = new Halink(this, n.address, n.token);
}
this.on('close', () => {
if (hasslink) hasslink.haClient.close();
});
}
RED.nodes.registerType('hass link', HassLink);
/* frpc */
function run(node) {
node.frpClient.setup(node).then((err) => {
if (err) {
setTimeout(() => {
run(node);
}, 10000);
return node.status({ fill: 'red', shape: 'dot', text: err.msg });
}
node.frpClient.start(function (info) {
if (!info.code) {
console.log(info.msg);
} else {
const status = { fill: 'green', shape: 'dot', text: 'frp连接成功' };
if (info.code === 244) {
node.status(status);
} else {
delete info.code;
node.send({ payload: info });
}
}
});
});
}
function Frpc(n) {
RED.nodes.createNode(this, n);
this.brokerConn = RED.nodes.getNode(n.broker);
this.options = n.options;
const node = this;
for(let i=0;i<this.options.length;i++){
if(this.options[i].url === '' || this.options[i].port === ''){
this.status({ fill: 'red', shape: 'dot', text: '映射参数未配置' });
return;
}
this.options[i].port = parseInt(this.options[i].port);
}
if (this.brokerConn ) {
const { default: FrpClient } = require('./lib/frpc');
node.frpClient = new FrpClient();
node.brokerConn.mqttClient.onData = function (err, data) {
if (err) return;
const msg = data.message;
if (!msg) return;
if (!msg.topic) return;
const type = msg.topic.split('/').length === 5 ? msg.topic.split('/')[4] : null;
if (!type) return;
if (type !== 'frpConfig') return;
node.frpClient.authObj = msg.payload;
};
run(node);
}
this.on('close', (done) => {
this.status({ fill: 'red', shape: 'dot', text: 'frp未连接' });
this.frpClient.close(done);
});
}
RED.nodes.registerType('frpc', Frpc);
};