node-red-contrib-voice-assistant
Version:
一个小度-小爱-猫精音箱控制NODE-RED自定义设备的节点
192 lines (191 loc) • 6.68 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ws_1 = __importDefault(require("ws"));
class HaClient {
constructor(url, token) {
this.sendCallback = {};
this.pong_bit = false;
this.connected = false;
this.connecting = false;
this.closeFlag = false;
this.url = url;
this.token = token;
this.init();
}
/**
* 初始化
*/
init() {
this.client = new ws_1.default(this.url + '/api/websocket');
this.client.on('open', () => {
console.log('open');
this.connecting = true;
this.client.on('message', this.on_message.bind(this));
});
this.client.on('connect', function () {
console.log('connect');
//this.connected = false;
});
this.client.on('error', (err) => {
//if (err as string === '重连') this.client.close();
//console.log(err)
if (err.message === '重连')
this.client.close();
//this._on_message && this._on_message({ err: '准备重连' });
});
this.client.on('close', () => {
console.log('close');
this.connected = false;
this.connecting = false;
this.pong_bit = false;
this.client.removeAllListeners();
if (!this.closeFlag)
this.reconnectFn();
else
this._on_message && this._on_message({ err: 'HA断开连接' });
});
}
reconnectFn() {
this._on_message && this._on_message({ err: 'HA准备重连' });
setTimeout(() => {
this._on_message && this._on_message({ err: 'HA正在重连' });
this.init();
}, 10000);
}
set onMessage(fn) {
this._on_message = fn;
}
/**
* 发送数据
*/
sendData(type, access_token, event_type) {
const sendData = {
type,
access_token,
event_type,
id: Date.now(),
};
if (access_token)
delete sendData.id;
this.client.send(JSON.stringify(sendData));
}
sendPong() {
this.pong_bit = true;
console.log('心跳');
this.sendData('ping');
setTimeout(() => {
if (this.pong_bit)
//无回应
this.client.emit('error', new Error('重连'));
}, 3000);
}
/**
* 消息接收
* @param data
*/
on_message(data) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let recvData;
try {
recvData = JSON.parse(data);
}
catch (_b) {
return;
}
this.pongTimer && clearTimeout(this.pongTimer);
this.pongTimer = setTimeout(() => {
this.sendPong(); //发心跳
}, 60000);
switch (recvData.type) {
case 'auth_required':
this.sendData('auth', this.token);
break;
case 'auth_ok':
console.log('auth_ok');
this.connected = true;
this.connecting = false;
this.sendData('subscribe_events', undefined, 'state_changed');
this._on_message && this._on_message({ connect: true });
break;
case 'auth_invalid':
this._on_message && this._on_message({ err: 'HA认证失败' });
this.close();
break;
case 'event':
if (((_a = recvData === null || recvData === void 0 ? void 0 : recvData.event) === null || _a === void 0 ? void 0 : _a.event_type) !== 'state_changed')
return;
this._on_message && this._on_message({ data: recvData });
break;
case 'result':
this.sendCallback[recvData.id] && this.sendCallback[recvData.id](recvData);
break;
case 'pong':
this.pong_bit = false;
break;
default:
break;
}
});
}
close(done) {
if (this.connected || this.connecting)
this.client.close();
this.pongTimer && clearTimeout(this.pongTimer);
this.closeFlag = true;
//this.init();
done && done();
}
/**
* 调用HA服务
* 返回调用成功状态
* @returns
*/
callservice(sendData) {
return new Promise((resolve) => {
const id = sendData.id;
this.client.send(JSON.stringify(sendData), () => {
this.sendCallback[id] = (data) => {
if (data.success)
resolve({ status: 0 });
else
resolve({ status: -1 });
delete this.sendCallback[id];
};
});
});
}
/**
* 获取HA全部状态
* @returns
*/
getStates() {
return new Promise((resolve) => {
const id = Date.now();
this.client.send(JSON.stringify({ id: id, type: 'get_states' }), () => {
const timeout = setTimeout(() => {
delete this.sendCallback[id];
resolve({ type: 'states', success: false });
}, 3000);
this.sendCallback[id] = (data) => {
clearTimeout(timeout);
resolve(data);
delete this.sendCallback[id];
};
});
});
}
}
exports.default = HaClient;