companion-module-puretech-p.../main.js

402 lines
12 KiB
JavaScript

const { InstanceBase, Regex, runEntrypoint, InstanceStatus, TCPHelper, combineRgb, CompanionVariableValues } = require('@companion-module/base');
const configFields = require('./configFields');
const actions = require('./actions');
const feedbacks = require('./feedbacks');
const presets = require('./presets');
const variables = require('./variables');
var tcpCommandBuffer = [];
var tcpSendTimeout;
var tcpSendTimeoutTime = 100;
var currentCmd = false;
let tcpReceivebuffer = '';
var INPUTS = [
{ id: '1' , label: 'Input #1' , name: 'Input1' , var_name: 'ipt_name_1' },
{ id: '2' , label: 'Input #2' , name: 'Input2' , var_name: 'ipt_name_2' },
{ id: '3' , label: 'Input #3' , name: 'Input3' , var_name: 'ipt_name_3' },
{ id: '4' , label: 'Input #4' , name: 'Input4' , var_name: 'ipt_name_4' }
];
var OUTPUTS = [
{ id: '1' , label: 'Output #1' , name: 'Output1' , var_name: 'out_name_1', xpt: undefined, var_xpt: 'xpt_out_1' },
{ id: '2' , label: 'Output #2' , name: 'Output2' , var_name: 'out_name_2', xpt: undefined, var_xpt: 'xpt_out_2' },
{ id: '3' , label: 'Output #3' , name: 'Output3' , var_name: 'out_name_3', xpt: undefined, var_xpt: 'xpt_out_3' },
{ id: '4' , label: 'Output #4' , name: 'Output4' , var_name: 'out_name_4', xpt: undefined, var_xpt: 'xpt_out_4' }
];
const PRESETS = [
{ id: '1' , label: 'Preset #1' , name: 'Preset1' , var_name: 'pst_name_1' },
{ id: '2' , label: 'Preset #2' , name: 'Preset2' , var_name: 'pst_name_2' },
{ id: '3' , label: 'Preset #3' , name: 'Preset3' , var_name: 'pst_name_3' },
{ id: '4' , label: 'Preset #4' , name: 'Preset4' , var_name: 'pst_name_4' },
{ id: '5' , label: 'Preset #5' , name: 'Preset5' , var_name: 'pst_name_5' },
{ id: '6' , label: 'Preset #6' , name: 'Preset6' , var_name: 'pst_name_6' },
{ id: '7' , label: 'Preset #7' , name: 'Preset7' , var_name: 'pst_name_7' },
{ id: '8' , label: 'Preset #8' , name: 'Preset8' , var_name: 'pst_name_8' }
];
class MatrixInstance extends InstanceBase {
constructor(internal) {
super(internal);
Object.assign(this, {
...configFields,
...actions,
...feedbacks,
...presets,
...variables
});
}
async init(config) {
this.config = config;
this.updateActionsDefinitions();
this.updateFeedbacksDefinitions();
this.updateVariableDefinitions();
this.updatePresetsDefinitions();
// INIT CONNECTION
this.initTCP();
}
// When module gets deleted
async destroy() { this.killTCP(); }
async configUpdated(config) {
this.killTCP();
this.config = config;
if(this.config.timeout>5===false) this.config.timeout = 5;
else if(this.config.timeout>500) this.config.timeout = 500;
this.updateActionsDefinitions();
this.updateFeedbacksDefinitions();
this.updateVariableDefinitions();
this.updatePresetsDefinitions();
this.initTCP();
}
updateActionsDefinitions() { this.setActionDefinitions( this.getActions() ); }
updateFeedbacksDefinitions() { this.setFeedbackDefinitions( this.getFeedbacks() ); }
updateVariableDefinitions() { this.setVariableDefinitions( this.getVariables() ); this.initVariablesValues(); }
updatePresetsDefinitions() { this.setPresetDefinitions( this.getPresets() ); }
// OUTPUTS
getOutputsList(all) {
var list = [...OUTPUTS];
if(all===true) list.push( { id: '0', label: 'All Outputs' } );
return list;
}
getOutByID(id) {
var out = false;
var l = OUTPUTS.length;
for(var i=0; i<l; i++) {
if(OUTPUTS[i].id == id) {
out = Object.assign({}, OUTPUTS[i]);
out.num = i;
break;
}
}
return out;
}
getFirstOutID() { return OUTPUTS[0].id; }
// INPUTS
getInputsList() { return [...INPUTS]; }
getIptByID(id) {
var ipt = false;
var l = INPUTS.length;
for(var i=0; i<l; i++) {
if(INPUTS[i].id == id) {
ipt = Object.assign({}, INPUTS[i]);
ipt.num = i;
break;
}
}
return ipt;
}
getFirstIptID() { return INPUTS[0].id; }
// PRESETS
getPresetsList() { return [...PRESETS]; }
getPstByID(id) {
var pst = false;
var l = PRESETS.length;
for(var i=0; i<l; i++) {
if(PRESETS[i].id == id) {
pst = Object.assign({}, PRESETS[i]);
pst.num = i;
break;
}
}
return pst;
}
getPstByName(name) {
var pst = false;
var l = PRESETS.length;
for(var i=0; i<l; i++) {
if(PRESETS[i].name == name) {
pst = Object.assign({}, PRESETS[i]);
pst.num = i;
break;
}
}
return pst;
}
getFirstPstID() { return PRESETS[0].id; }
// TCP CONNECTION
initTCP() {
this.killTCP();
this.log('info', `PT-MA-HD44M MATRIX | INIT TCP CONNECTION >>> ${this.config.host} ${this.config.port}`);
if(this.config.host && this.config.port) {
this.log('info', `PT-MA-HD44M MATRIX | Opening TCP connection to ${this.config.host}:${this.config.port}`);
this.socket = new TCPHelper(this.config.host, this.config.port, { reconnect: true });
this.socket.on('status_change', (status, message) => {
this.updateStatus(status, message);
this.setVariableValues({connect_status: status});
this.checkFeedbacks('connect_status');
this.log('info', `PT-MA-HD44M MATRIX | TCP connection status changed >>> ${status}`);
if(status=="ok") {
this.sendCommand('#get info');
}
else {
this.clearTcpCommandBuffer();
}
});
this.socket.on('error', (err) => {
this.updateStatus(InstanceStatus.ConnectionFailure, err.message);
this.log('error', 'PT-MA-HD44M MATRIX | Network error: ' + err.message);
});
this.socket.on('data', (chunk) => {
let i = 0;
let line = '';
let offset = 0;
tcpReceivebuffer += chunk.toString();
while ((i = tcpReceivebuffer.indexOf('\n', offset)) !== -1) {
line = tcpReceivebuffer.slice(offset, i);
offset = i + 1;
line = line.replaceAll('\r\r', '');
if(line!="") this.socket.emit('receiveline', line);
}
tcpReceivebuffer = tcpReceivebuffer.slice(offset);
});
this.socket.on('receiveline', (data) => {
this.parseReceivedMessage(data.toString());
});
}
}
killTCP() {
this.clearTcpCommandBuffer();
tcpReceivebuffer = '';
if(this.socket !== undefined) {
this.socket.destroy();
delete this.socket;
}
this.setVariableValues({connect_status: 'disconnected'});
this.checkFeedbacks('connect_status');
}
// SEND COMMAND
sendCommand(cmd, clbk) {
if(cmd!='') {
tcpCommandBuffer.push({cmd: cmd, clbk: clbk});
this.sendNextCommand();
}
}
sendPriorityCommand(cmd, clbk) {
if(cmd!='') {
tcpCommandBuffer.unshift({cmd: cmd, clbk: clbk});
this.sendNextCommand();
}
}
async sendNextCommand() {
if(tcpSendTimeout || tcpCommandBuffer.length==0) return;
tcpSendTimeout = true;
var cue = tcpCommandBuffer.shift();
var cmd = cue.cmd;
var escCmd = unescape(await this.parseVariablesInString(cmd));
if(escCmd!="") {
this.log('debug', `PT-MA-HD44M MATRIX | SENDIND COMMAND >>> ${escCmd} | callback: ${cue.clbk}`);
const sendBuf = Buffer.from(escCmd+"\n", 'latin1');
if(this.socket !== undefined && this.socket.isConnected) {
currentCmd = cue;
this.socket.send(sendBuf);
tcpSendTimeout = setTimeout(function(self) { self.onSendCommandTimeout(); }, this.config.timeout, this);
}
else this.log('warn', `PT-MA-HD44M MATRIX | CANNOT SEND COMMAND - Socket not connected >>> ${cmd}`);
}
else if(tcpCommandBuffer.length>0) this.sendNextCommand();
}
onSendCommandTimeout() {
this.log('warn', `PT-MA-HD44M MATRIX | SEND COMMAND TIMEOUT >>> ${currentCmd.cmd}`);
tcpSendTimeout = undefined;
currentCmd = false;
this.sendNextCommand();
}
clearTcpCommandBuffer() {
if(tcpSendTimeout) { clearTimeout(tcpSendTimeout); tcpSendTimeout=undefined; }
tcpCommandBuffer = [];
currentCmd = false;
}
// PARSE RECEIVED MESSAGE
parseReceivedMessage(msg) {
if(tcpSendTimeout) { clearTimeout(tcpSendTimeout); tcpSendTimeout=undefined; }
this.log('debug', `PT-MA-HD44M MATRIX | receive message > "${msg}"`);
let namePos = msg.indexOf("[name=");
let endNamePos = msg.indexOf("]");
let dataPos = msg.indexOf("[Data=");
let endDataPos = msg.indexOf(" : ", dataPos);
let xptPos = msg.indexOf("Video matrix");
// GET INFOS - INPUT NAME
if(msg.slice(0,6) == "<Input" && namePos>0 && endNamePos>0) {
let ipt = this.getIptByID( msg.substr(6,1) );
let name = msg.slice(namePos+6, endNamePos);
if(ipt && ipt.name != name) {
this.log('info', `PT-MA-HD44M MATRIX | INPUT #${ipt.id} - NAME CHANGED >>> ${name}`);
ipt.name = name;
INPUTS[ipt.num] = ipt;
this.setVariableValue(ipt.var_name, name);
}
}
// GET INFOS - OUTPUT NAME
else if(msg.slice(0,7) == "<Output" && namePos>0 && endNamePos>0) {
let out = this.getOutByID( msg.substr(7,1) );
let name = msg.slice(namePos+6, endNamePos);
if(out && out.name != name) {
this.log('info', `PT-MA-HD44M MATRIX | OUTPUT #${out.id} - NAME CHANGED >>> ${name}`);
out.name = name;
OUTPUTS[out.num] = out;
this.setVariableValue(out.var_name, name);
}
}
// GET INFOS - PRESET NAME
else if(msg.slice(0,7) == "<Preset" && namePos>0 && endNamePos>0) {
let pst = this.getPstByID( msg.substr(7,1) );
let name = msg.slice(namePos+6, endNamePos);
if(pst && pst.name != name) {
this.log('info', `PT-MA-HD44M MATRIX | PRESET #${pst.id} - NAME CHANGED >>> ${name}`);
pst.name = name;
PRESETS[pst.num] = pst;
this.setVariableValue(pst.var_name, name);
}
}
// OUTPUT XPT
else if(msg.slice(0,7) == "<Output" && xptPos>0 && dataPos>0 && endDataPos>0) {
let out = this.getOutByID( msg.substr(7,1) );
let xpt = (parseInt( msg.slice(dataPos+6, endDataPos) ) + 1).toString();
if(out && out.xpt != xpt) {
this.log('info', `PT-MA-HD44M MATRIX | OUTPUT #${out.id} - XPT CHANGED >>> ${xpt}`);
out.xpt = xpt;
OUTPUTS[out.num] = out;
this.setVariableValue(out.var_xpt, xpt);
this.checkFeedbacks('crosspoint_status');
}
}
// SET NAME
else if(msg.slice(0,8) == "Set name") {
let nameID = parseInt(msg.slice(8));
let name = msg.slice( msg.indexOf(" > ")+3 );
// INPUTS
if(nameID<4) {
let ipt = INPUTS[nameID];
if(ipt.name != name) {
this.log('info', `INPUT #${ipt.id} - NAME = ${name}`);
ipt.name = name;
INPUTS[nameID] = ipt;
this.setVariableValue(ipt.var_name, name);
}
}
// OUTPUTS
else if(nameID<8) {
let out = OUTPUTS[nameID-4];
if(out.name != name) {
this.log('info', `OUTPUT #${out.id} - NAME = ${name}`);
out.name = name;
OUTPUTS[nameID-4] = out;
this.setVariableValue(out.var_name, name);
}
}
// PRESETS
else {
let pst = PRESETS[nameID-8];
if(pst.name != name) {
this.log('info', `PRESET #${pst.id} - NAME = ${name}`);
pst.name = name;
PRESETS[nameID-8] = pst;
this.setVariableValue(pst.var_name, name);
}
}
}
// PRESET
else if(msg.slice(0,7) == "Preset:") {
let p = msg.split(' ');
let pst = this.getPstByName(p[1]);
// SAVE
if(p[2] == "Save") {
this.log('info', `PT-MA-HD44M MATRIX | PRESET #${pst.id} SAVED >>> ${p[1]}`);
this.saveLastPstID(pst.id);
}
// CALL
else if(p[2] == "Call") {
this.log('info', `PT-MA-HD44M MATRIX | PRESET #${pst.id} RECALLED >>> ${p[1]}`);
this.saveLastPstID(pst.id);
// REFRESH INFO
this.sendPriorityCommand('#get info');
}
// CLEAR
else if(p[2] == "Clear") {
this.log('info', `PT-MA-HD44M MATRIX | PRESET #${pst.id} CLEARED >>> ${p[1]}`);
if(this.getLastPstID() == pst.id) this.saveLastPstID(0);
}
}
currentCmd = false;
this.sendNextCommand();
}
// CURRENT PRESET
getLastPstID() { return this.getVariableValue('pst_last'); }
saveLastPstID(id) {
id = parseInt(id);
if(id<0 || id>8) return;
let last = this.getLastPstID();
if(last != id) {
this.setVariableValue('pst_last', id.toString());
this.checkFeedbacks('last_pst');
}
}
// SET VARIABLE VALUE
setVariableValue(name, value) {
const variables = {};
variables[name] = value;
this.setVariableValues(variables);
}
}
runEntrypoint(MatrixInstance, []);