first commit
This commit is contained in:
commit
050032f726
|
|
@ -0,0 +1,7 @@
|
||||||
|
node_modules/
|
||||||
|
.pnp.*
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.DS_Store
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Bitfocus AS - Open Source
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
## companion-module-purelink-pt-ma-hd44m
|
||||||
|
|
||||||
|
See [HELP.md](./companion/HELP.md) and [LICENSE](./LICENSE)
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
const { Regex } = require('@companion-module/base');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getActions() {
|
||||||
|
const actions = {};
|
||||||
|
|
||||||
|
actions.setCrosspoint = {
|
||||||
|
name: 'Set crosspoint',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: 'out',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'OUTPUT',
|
||||||
|
choices: this.getOutputsList(true),
|
||||||
|
default: this.getFirstOutID()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ipt',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'INPUT',
|
||||||
|
choices: this.getInputsList(),
|
||||||
|
default: this.getFirstIptID()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: async (event) => {
|
||||||
|
let out = this.getOutByID(event.options.out);
|
||||||
|
let ipt = this.getIptByID(event.options.ipt);
|
||||||
|
this.log('info', `PT-MA-HD44M MATRIX | SET CROSSPOINT >>> ${out.label} > ${ipt.label}`);
|
||||||
|
this.sendPriorityCommand(`#video_d out${event.options.out} matrix=${event.options.ipt}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.recallPreset = {
|
||||||
|
name: 'Preset - Recall',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: 'pst',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'PRESET',
|
||||||
|
choices: this.getPresetsList(),
|
||||||
|
default: this.getFirstPstID()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: async (event) => {
|
||||||
|
let pst = this.getPstByID(event.options.pst);
|
||||||
|
this.log('info', `PT-MA-HD44M MATRIX | RECALL PRESET >>> ${pst.label}`);
|
||||||
|
this.sendPriorityCommand(`#preset:${event.options.pst} exe=0`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.savePreset = {
|
||||||
|
name: 'Preset - Save',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: 'pst',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'PRESET',
|
||||||
|
choices: this.getPresetsList(),
|
||||||
|
default: this.getFirstPstID()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: async (event) => {
|
||||||
|
let pst = this.getPstByID(event.options.pst);
|
||||||
|
this.log('info', `PT-MA-HD44M MATRIX | SAVE PRESET >>> ${pst.label}`);
|
||||||
|
this.sendPriorityCommand(`#preset:${event.options.pst} exe=1`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.clearPreset = {
|
||||||
|
name: 'Preset - Clear',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: 'pst',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'PRESET',
|
||||||
|
choices: this.getPresetsList(),
|
||||||
|
default: this.getFirstPstID()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: async (event) => {
|
||||||
|
let pst = this.getPstByID(event.options.pst);
|
||||||
|
this.log('info', `PT-MA-HD44M MATRIX | CLEAR PRESET >>> ${pst.label}`);
|
||||||
|
this.sendPriorityCommand(`#preset:${event.options.pst} exe=2`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.refreshInfo = {
|
||||||
|
name: 'Refresh Info',
|
||||||
|
options: [],
|
||||||
|
callback: async () => {
|
||||||
|
this.log('info', `PT-MA-HD44M MATRIX | REFRESH INFO`);
|
||||||
|
this.sendPriorityCommand(`#get info`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.sendCommand = {
|
||||||
|
name: 'Send Command',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
type: 'textinput',
|
||||||
|
id: 'cmd',
|
||||||
|
label: 'Command:',
|
||||||
|
tooltip: 'Use %hh to insert Hex codes\nObsolete, use Send HEX command instead',
|
||||||
|
default: '',
|
||||||
|
useVariables: true,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: async (event) => {
|
||||||
|
this.log('info', `PT-MA-HD44M MATRIX | SEND COMMAND >>> ${event.options.cmd}`);
|
||||||
|
await this.sendPriorityCommand(event.options.cmd, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# PureLink - PT-MA-HD44M
|
||||||
|
|
||||||
|
Companion module to control PureLink PureTools PT-MA-HD44M video matrix
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"id": "purelink-pt-ma-hd44m",
|
||||||
|
"name": "purelink-pt-ma-hd44m",
|
||||||
|
"shortname": "PT-MA-HD44M Matrix",
|
||||||
|
"description": "PureLink PT-MA-HD44M Matrix module for Companion",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "git+https://github.com/bitfocus/companion-module-purelink-pt-ma-hd44m.git",
|
||||||
|
"bugs": "https://github.com/bitfocus/companion-module-purelink-pt-ma-hd44m/issues",
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "Adrien RENARD",
|
||||||
|
"email": "arenard@pixap.fr"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"runtime": {
|
||||||
|
"type": "node18",
|
||||||
|
"api": "nodejs-ipc",
|
||||||
|
"apiVersion": "1.3.0",
|
||||||
|
"entrypoint": "../main.js"
|
||||||
|
},
|
||||||
|
"legacyIds": [],
|
||||||
|
"manufacturer": "purelink",
|
||||||
|
"products": [
|
||||||
|
"PT-MA-HD44M"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"Video Matrix"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
const { Regex } = require('@companion-module/base');
|
||||||
|
module.exports = {
|
||||||
|
getConfigFields() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'info',
|
||||||
|
type: 'static-text',
|
||||||
|
width: 12,
|
||||||
|
label: 'Information',
|
||||||
|
value: "This module allow to controls a PureLink PureTools PT-MA-HD44M video matrix crosspoints.<br/>It's based on this native <a target='_blank' href='https://cloud.purelink.de/index.php/s/cMPB4FsRSCNb5fk/download'>protocol</a><br/>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'textinput',
|
||||||
|
id: 'host',
|
||||||
|
label: 'Matrix IP',
|
||||||
|
width: 8,
|
||||||
|
regex: Regex.IP,
|
||||||
|
default: '192.168.1.168'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'textinput',
|
||||||
|
id: 'port',
|
||||||
|
label: 'Matrix Port',
|
||||||
|
width: 4,
|
||||||
|
regex: Regex.PORT,
|
||||||
|
min: 1,
|
||||||
|
max: 65535,
|
||||||
|
default: '5000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
id: 'timeout',
|
||||||
|
label: 'Send Command Timeout (in ms)',
|
||||||
|
width: 12,
|
||||||
|
regex: Regex.PORT,
|
||||||
|
min: 5,
|
||||||
|
max: 500,
|
||||||
|
default: 100
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
const { InstanceBase, combineRgb } = require('@companion-module/base');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getFeedbacks() {
|
||||||
|
const feedbacks = {};
|
||||||
|
|
||||||
|
feedbacks.crosspoint_status = {
|
||||||
|
name: 'Crosspoint Status',
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Crosspoint Status',
|
||||||
|
defaultStyle: {
|
||||||
|
bgcolor: combineRgb(255, 0, 0)
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: 'outID',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'OUTPUT',
|
||||||
|
choices: this.getOutputsList(false),
|
||||||
|
default: this.getFirstOutID(false)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'xpt',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'INPUT',
|
||||||
|
choices: this.getInputsList(false),
|
||||||
|
default: this.getFirstIptID(false)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: (feedback) => {
|
||||||
|
var out = this.getOutByID( feedback.options.outID );
|
||||||
|
return out.xpt == feedback.options.xpt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
feedbacks.last_pst = {
|
||||||
|
name: 'Last Recalled Preset',
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Last Recalled Preset',
|
||||||
|
defaultStyle: {
|
||||||
|
bgcolor: combineRgb(255, 0, 0)
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: 'pst',
|
||||||
|
type: 'dropdown',
|
||||||
|
label: 'PRESET',
|
||||||
|
choices: this.getPresetsList(),
|
||||||
|
default: this.getFirstPstID()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
callback: (feedback) => { return feedback.options.pst == this.getLastPstID(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
feedbacks.connect_status = {
|
||||||
|
name: 'Connection Status',
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Matrix connection status',
|
||||||
|
defaultStyle: {
|
||||||
|
color: combineRgb(255, 255, 255)
|
||||||
|
},
|
||||||
|
options: [],
|
||||||
|
callback: (feedback) => {
|
||||||
|
return this.getVariableValue('connect_status') == 'ok';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return feedbacks;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,402 @@
|
||||||
|
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 MixerInstance 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) 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 = 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 = 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 = 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 = PRESETS[i];
|
||||||
|
pst.num = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pst;
|
||||||
|
}
|
||||||
|
getFirstPstID() { return PRESETS[0].id; }
|
||||||
|
|
||||||
|
// TCP CONNECTION
|
||||||
|
initTCP() {
|
||||||
|
this.killTCP();
|
||||||
|
|
||||||
|
this.log('info', `PT-MA-HD44M MIXER | INIT TCP CONNECTION >>> ${this.config.host} ${this.config.port}`);
|
||||||
|
|
||||||
|
if(this.config.host && this.config.port) {
|
||||||
|
this.log('info', `PT-MA-HD44M MIXER | 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 MIXER | 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 MIXER | 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 MIXER | 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 MIXER | CANNOT SEND COMMAND - Socket not connected >>> ${cmd}`);
|
||||||
|
}
|
||||||
|
else if(tcpCommandBuffer.length>0) this.sendNextCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendCommandTimeout() {
|
||||||
|
this.log('warn', `PT-MA-HD44M MIXER | 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 MIXER | 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 MIXER | 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 MIXER | 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 MIXER | 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 MIXER | 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]);
|
||||||
|
console.log(p);
|
||||||
|
|
||||||
|
// SAVE
|
||||||
|
if(p[2] == "Save") {
|
||||||
|
this.log('info', `PT-MA-HD44M MIXER | PRESET #${pst.id} SAVED >>> ${p[1]}`);
|
||||||
|
this.saveLastPstID(pst.id);
|
||||||
|
}
|
||||||
|
// CALL
|
||||||
|
else if(p[2] == "Call") {
|
||||||
|
this.log('info', `PT-MA-HD44M MIXER | 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 MIXER | 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(MixerInstance, []);
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "purelink-pt-ma-hd44m",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"format": "prettier -w ."
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/bitfocus/companion-module-purelink-pt-ma-hd44m.git"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@companion-module/base": "~1.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@companion-module/tools": "^1.3.2"
|
||||||
|
},
|
||||||
|
"prettier": "@companion-module/tools/.prettierrc.json",
|
||||||
|
"packageManager": "yarn@4.9.2"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
const { combineRgb } = require('@companion-module/base');
|
||||||
|
module.exports = {
|
||||||
|
getPresets() {
|
||||||
|
const presets = {};
|
||||||
|
|
||||||
|
// CROSSPOINTS
|
||||||
|
var outList = this.getOutputsList(false);
|
||||||
|
var iptList = this.getInputsList(false);
|
||||||
|
outList.forEach((out) => {
|
||||||
|
iptList.forEach((ipt) => {
|
||||||
|
|
||||||
|
presets[`xpt_${out.id}_${ipt.id}`] = {
|
||||||
|
type: 'button',
|
||||||
|
category: out.label+" - XPT",
|
||||||
|
style: {
|
||||||
|
text: `OUT#${out.id} \nIN#${ipt.id}`,
|
||||||
|
size: '16',
|
||||||
|
color: combineRgb(255, 255, 255),
|
||||||
|
bgcolor: combineRgb(0, 0, 0)
|
||||||
|
},
|
||||||
|
steps: [{
|
||||||
|
down: [{
|
||||||
|
actionId: 'setCrosspoint',
|
||||||
|
options: { out: out.id, ipt: ipt.id }
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
feedbacks: [
|
||||||
|
{
|
||||||
|
feedbackId: 'crosspoint_status',
|
||||||
|
options: { outID: out.id, xpt: ipt.id },
|
||||||
|
style: { bgcolor: combineRgb(255, 0, 0) }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feedbackId: 'connect_status',
|
||||||
|
options: {},
|
||||||
|
isInverted: true,
|
||||||
|
style: { color: combineRgb(255, 80, 80), bgcolor: combineRgb(80, 0, 0) }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// RECALL PRESETS
|
||||||
|
var pstList = this.getPresetsList(false);
|
||||||
|
pstList.forEach((pst) => {
|
||||||
|
presets[`recall_pst${pst.id}`] = {
|
||||||
|
type: 'button',
|
||||||
|
category: "Preset - Recall",
|
||||||
|
style: {
|
||||||
|
text: `Recall \nPST#${pst.id}`,
|
||||||
|
size: '16',
|
||||||
|
color: combineRgb(24, 76, 119),
|
||||||
|
bgcolor: combineRgb(128, 198, 255)
|
||||||
|
},
|
||||||
|
steps: [{
|
||||||
|
down: [{
|
||||||
|
actionId: 'recallPreset',
|
||||||
|
options: { pst: pst.id }
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
feedbacks: [
|
||||||
|
{
|
||||||
|
feedbackId: 'last_pst',
|
||||||
|
options: { pst: pst.id },
|
||||||
|
style: { color: combineRgb(255, 255, 255), bgcolor: combineRgb(27, 158, 62) }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feedbackId: 'connect_status',
|
||||||
|
options: {},
|
||||||
|
isInverted: true,
|
||||||
|
style: { color: combineRgb(255, 80, 80), bgcolor: combineRgb(80, 0, 0) }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// SAVE PRESETS
|
||||||
|
pstList.forEach((pst) => {
|
||||||
|
presets[`save_pst${pst.id}`] = {
|
||||||
|
type: 'button',
|
||||||
|
category: "Preset - Save",
|
||||||
|
style: {
|
||||||
|
text: `Save \nPST#${pst.id}`,
|
||||||
|
size: '16',
|
||||||
|
color: combineRgb(0, 0, 0),
|
||||||
|
bgcolor: combineRgb(249, 177, 21)
|
||||||
|
},
|
||||||
|
steps: [{
|
||||||
|
down: [{
|
||||||
|
actionId: 'savePreset',
|
||||||
|
options: { pst: pst.id }
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
feedbacks: [
|
||||||
|
{
|
||||||
|
feedbackId: 'connect_status',
|
||||||
|
options: {},
|
||||||
|
isInverted: true,
|
||||||
|
style: { color: combineRgb(255, 80, 80), bgcolor: combineRgb(80, 0, 0) }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// CLEAR PRESETS
|
||||||
|
pstList.forEach((pst) => {
|
||||||
|
presets[`clear_pst${pst.id}`] = {
|
||||||
|
type: 'button',
|
||||||
|
category: "Preset - Clear",
|
||||||
|
style: {
|
||||||
|
text: `Clear \nPST#${pst.id}`,
|
||||||
|
size: '16',
|
||||||
|
color: combineRgb(255, 255, 255),
|
||||||
|
bgcolor: combineRgb(213, 2, 2)
|
||||||
|
},
|
||||||
|
steps: [{
|
||||||
|
down: [{
|
||||||
|
actionId: 'clearPreset',
|
||||||
|
options: { pst: pst.id }
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
feedbacks: [
|
||||||
|
{
|
||||||
|
feedbackId: 'connect_status',
|
||||||
|
options: {},
|
||||||
|
isInverted: true,
|
||||||
|
style: { color: combineRgb(255, 80, 80), bgcolor: combineRgb(80, 0, 0) }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return presets;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
module.exports = {
|
||||||
|
getVariables() {
|
||||||
|
const variables = [];
|
||||||
|
|
||||||
|
// CONNECTED
|
||||||
|
variables.push({ variableId: 'connect_status', name: 'Connection Status' });
|
||||||
|
|
||||||
|
// INPUTS
|
||||||
|
var list = this.getInputsList(false);
|
||||||
|
list.forEach((i) => {
|
||||||
|
variables.push({ variableId: i.var_name, name: `${i.label} - NAME` });
|
||||||
|
});
|
||||||
|
|
||||||
|
// OUTPUTS
|
||||||
|
list = this.getOutputsList(false);
|
||||||
|
list.forEach((i) => {
|
||||||
|
variables.push({ variableId: i.var_name, name: `${i.label} - NAME` });
|
||||||
|
variables.push({ variableId: i.var_xpt , name: `${i.label} - XPT` });
|
||||||
|
});
|
||||||
|
|
||||||
|
// PRESETS
|
||||||
|
list = this.getPresetsList(false);
|
||||||
|
list.forEach((i) => {
|
||||||
|
variables.push({ variableId: i.var_name, name: `${i.label} - NAME` });
|
||||||
|
});
|
||||||
|
|
||||||
|
// LAST PRESET
|
||||||
|
variables.push({ variableId: "pst_last", name: `Last Recalled Preset` });
|
||||||
|
|
||||||
|
return variables;
|
||||||
|
},
|
||||||
|
initVariablesValues() {
|
||||||
|
const variables = {};
|
||||||
|
|
||||||
|
// INPUTS NAMES
|
||||||
|
var list = this.getInputsList();
|
||||||
|
list.forEach((i) => { variables[i.var_name] = i.label; });
|
||||||
|
|
||||||
|
// OUTPUTS NAMES
|
||||||
|
list = this.getOutputsList();
|
||||||
|
list.forEach((i) => { variables[i.var_name] = i.label; });
|
||||||
|
|
||||||
|
// PRESETS NAMES
|
||||||
|
list = this.getPresetsList();
|
||||||
|
list.forEach((i) => { variables[i.var_name] = i.label; });
|
||||||
|
|
||||||
|
// LAST PRESET
|
||||||
|
variables.pst_last = 0;
|
||||||
|
|
||||||
|
this.setVariableValues(variables);
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue