first commit
This commit is contained in:
commit
7f375dd75b
|
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
.DS_Store
|
||||
|
|
@ -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-panasonic-av-hs6000
|
||||
|
||||
See [HELP.md](./companion/HELP.md) and [LICENSE](./LICENSE)
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
const { Regex } = require('@companion-module/base');
|
||||
|
||||
module.exports = {
|
||||
getActions() {
|
||||
const actions = {};
|
||||
|
||||
actions.setCrosspoint = {
|
||||
name: 'Set crosspoint',
|
||||
options: [
|
||||
{
|
||||
id: 'bus',
|
||||
type: 'dropdown',
|
||||
label: 'BUS',
|
||||
choices: this.getBusList(),
|
||||
default: this.getFirstBusID()
|
||||
},
|
||||
{
|
||||
id: 'src',
|
||||
type: 'dropdown',
|
||||
label: 'SOURCE',
|
||||
choices: this.getSourcesList(),
|
||||
default: '01'
|
||||
}
|
||||
],
|
||||
callback: async (event) => {
|
||||
this.log('info', `AV-HS6000 | SET CROSSPOINT >>> ${this.getBusNameByID(event.options.bus)} > ${this.getSourceNameByID(event.options.src, false)}`);
|
||||
this.sendPriorityCommand('%02SBUS:' + event.options.bus + ":" + event.options.src + "%03");
|
||||
}
|
||||
};
|
||||
|
||||
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', `AV-HS6000 | SEND COMMAND >>> ${event.options.cmd}`);
|
||||
await this.sendPriorityCommand(event.options.cmd, false);
|
||||
}
|
||||
};
|
||||
|
||||
return actions;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Panasonic - AV-HS6000
|
||||
|
||||
Companion module to control Panasonic AV-HS6000 video mixer BUS
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"id": "panasonic-av-hs6000",
|
||||
"name": "panasonic-av-hs6000",
|
||||
"shortname": "AV-HS6000",
|
||||
"description": "Panasonic AV-HS6000 mixer module for Companion",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"repository": "git+https://github.com/bitfocus/companion-module-panasonic-av-hs6000.git",
|
||||
"bugs": "https://github.com/bitfocus/companion-module-panasonic-av-hs6000/issues",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Adrien RENARD",
|
||||
"email": "arenard@pixap.fr"
|
||||
}
|
||||
],
|
||||
"runtime": {
|
||||
"type": "node18",
|
||||
"api": "nodejs-ipc",
|
||||
"apiVersion": "1.3.0",
|
||||
"entrypoint": "../main.js"
|
||||
},
|
||||
"legacyIds": [],
|
||||
"manufacturer": "panasonic",
|
||||
"products": [
|
||||
"AV-HS6000"
|
||||
],
|
||||
"keywords": [
|
||||
"Video Mixer"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
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 Panasonic AV-HS6000 video mixer buses crosspoints.<br/>It's based on this native <a target='_blank' href='https://eww.pass.panasonic.co.jp/pro-av/support/dload/hs6000_3ext/AV-HS6000%20external%20IF_protocol-E.pdf'>protocol</a><br/>",
|
||||
},
|
||||
{
|
||||
type: 'textinput',
|
||||
id: 'host',
|
||||
label: 'Mixer IP',
|
||||
width: 8,
|
||||
regex: Regex.IP,
|
||||
default: '192.168.0.10'
|
||||
},
|
||||
{
|
||||
type: 'textinput',
|
||||
id: 'port',
|
||||
label: 'Mixer Port',
|
||||
width: 4,
|
||||
regex: Regex.PORT,
|
||||
min: 1,
|
||||
max: 65535,
|
||||
default: '62000'
|
||||
},
|
||||
{
|
||||
id: 'info',
|
||||
type: 'static-text',
|
||||
width: 12,
|
||||
label: 'Refresh crosspoints',
|
||||
value: "As this protocol does not allow you to be notified when a crosspoint is modified, to keep the crosspoint status up to date, you need to query the mixer regularly.<br/>Moreover, this protocol requires you to send at least one command every 20s, otherwise you'll be automatically disconnected. This crosspoint refresh keeps the connection open at all times."
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
id: 'refreshTiming',
|
||||
label: 'Refresh timing (in seconds)',
|
||||
width: 4,
|
||||
regex: Regex.PORT,
|
||||
min: 0,
|
||||
max: 30,
|
||||
default: 1
|
||||
},
|
||||
{
|
||||
id: 'info',
|
||||
type: 'static-text',
|
||||
width: 12,
|
||||
label: 'Enables BUSES',
|
||||
value: "Select below buses you want to control."
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableME1',
|
||||
label: 'ME1',
|
||||
width: 2,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableME2',
|
||||
label: 'ME2',
|
||||
width: 2,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableAUX',
|
||||
label: 'AUX',
|
||||
width: 2,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableDSK',
|
||||
label: 'DSK',
|
||||
width: 2,
|
||||
default: false
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableUSK',
|
||||
label: 'USK',
|
||||
width: 4,
|
||||
default: false
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableMV1',
|
||||
label: 'MV1',
|
||||
width: 2,
|
||||
default: false
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableMV2',
|
||||
label: 'MV2',
|
||||
width: 2,
|
||||
default: false
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableMV3',
|
||||
label: 'MV3',
|
||||
width: 2,
|
||||
default: false
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
id: 'enableMV4',
|
||||
label: 'MV4',
|
||||
width: 6,
|
||||
default: false
|
||||
},
|
||||
{
|
||||
id: 'src_name',
|
||||
type: 'dropdown',
|
||||
label: 'Sources Name',
|
||||
width: 6,
|
||||
default: 'default',
|
||||
choices: [
|
||||
{ id: 'default' , label: 'Default' },
|
||||
{ id: 'panel' , label: 'Mixer Panel' },
|
||||
{ id: 'mv' , label: 'Mixer MV' }
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
id: 'srcNameRefreshTiming',
|
||||
label: 'Sources Name Refresh timing (in seconds)',
|
||||
width: 6,
|
||||
regex: Regex.PORT,
|
||||
min: 10,
|
||||
max: 120,
|
||||
default: 30,
|
||||
isVisible: (configValues) => (configValues.src_name === 'panel' || configValues.src_name === 'mv')
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
id: 'timeout',
|
||||
label: 'Send Command Timeout (in ms)',
|
||||
width: 12,
|
||||
regex: Regex.PORT,
|
||||
min: 5,
|
||||
max: 500,
|
||||
default: 100
|
||||
}
|
||||
];
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
const { InstanceBase, combineRgb } = require('@companion-module/base');
|
||||
|
||||
module.exports = {
|
||||
getFeedbacks() {
|
||||
const feedbacks = {};
|
||||
|
||||
feedbacks.crosspoint_status = {
|
||||
name: 'BUS/SOURCE Crosspoint Status',
|
||||
type: 'boolean',
|
||||
label: 'BUS/SOURCE Crosspoint Status',
|
||||
defaultStyle: {
|
||||
bgcolor: combineRgb(255, 0, 0)
|
||||
},
|
||||
options: [
|
||||
{
|
||||
id: 'bus',
|
||||
type: 'dropdown',
|
||||
label: 'BUS',
|
||||
choices: this.getBusList(),
|
||||
default: this.getFirstBusID()
|
||||
},
|
||||
{
|
||||
id: 'src',
|
||||
type: 'dropdown',
|
||||
label: 'SOURCE',
|
||||
choices: this.getSourcesList(),
|
||||
default: '01'
|
||||
}
|
||||
],
|
||||
callback: (feedback) => {
|
||||
var busVar = this.getBusVariableFromID( feedback.options.bus );
|
||||
const busStatus = this.getVariableValue(busVar);
|
||||
return busStatus == feedback.options.src;
|
||||
}
|
||||
};
|
||||
|
||||
feedbacks.connect_status = {
|
||||
name: 'Connection Status',
|
||||
type: 'boolean',
|
||||
label: 'Mixer connection status',
|
||||
defaultStyle: {
|
||||
color: combineRgb(255, 255, 255)
|
||||
},
|
||||
options: [],
|
||||
callback: (feedback) => {
|
||||
return this.getVariableValue('connect_status') == 'ok';
|
||||
}
|
||||
};
|
||||
|
||||
return feedbacks;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,609 @@
|
|||
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 refreshBusTimer;
|
||||
var refreshSrcTimer;
|
||||
|
||||
var tcpCommandBuffer = [];
|
||||
var tcpSendTimeout;
|
||||
var tcpSendTimeoutTime = 100;
|
||||
var currentCmd = false;
|
||||
|
||||
var autoReply = false;
|
||||
|
||||
const BUS = [
|
||||
{ id: '01' , label: 'ME1 PGM' }, // 0
|
||||
{ id: '02' , label: 'ME1 PRW' },
|
||||
{ id: '03' , label: 'ME1 KEY1-F' },
|
||||
{ id: '04' , label: 'ME1 KEY1-S' },
|
||||
{ id: '05' , label: 'ME1 KEY2-F' },
|
||||
{ id: '06' , label: 'ME1 KEY2-S' },
|
||||
{ id: '07' , label: 'ME1 KEY3-F' },
|
||||
{ id: '08' , label: 'ME1 KEY3-S' },
|
||||
{ id: '09' , label: 'ME1 KEY4-F' },
|
||||
{ id: '10' , label: 'ME1 KEY4-S' },
|
||||
{ id: '11' , label: 'ME1 UTIL1' },
|
||||
{ id: '12' , label: 'ME1 UTIL2' }, // 11
|
||||
|
||||
{ id: '13' , label: 'ME2 PGM' }, // 12
|
||||
{ id: '14' , label: 'ME2 PRW' },
|
||||
{ id: '15' , label: 'ME2 KEY1-F' },
|
||||
{ id: '16' , label: 'ME2 KEY1-S' },
|
||||
{ id: '17' , label: 'ME2 KEY2-F' },
|
||||
{ id: '18' , label: 'ME2 KEY2-S' },
|
||||
{ id: '19' , label: 'ME2 KEY3-F' },
|
||||
{ id: '20' , label: 'ME2 KEY3-S' },
|
||||
{ id: '21' , label: 'ME2 KEY4-F' },
|
||||
{ id: '22' , label: 'ME2 KEY4-S' },
|
||||
{ id: '23' , label: 'ME2 UTIL1' },
|
||||
{ id: '24' , label: 'ME2 UTIL2' }, // 23
|
||||
|
||||
{ id: '97' , label: 'DSK 1-F' }, // 24
|
||||
{ id: '98' , label: 'DSK 1-S' },
|
||||
{ id: '99' , label: 'DSK 2-F' },
|
||||
{ id: '100' , label: 'DSK 2-S' },
|
||||
{ id: '101' , label: 'DSK 3-F' },
|
||||
{ id: '102' , label: 'DSK 3-S' },
|
||||
{ id: '103' , label: 'DSK 4-F' },
|
||||
{ id: '104' , label: 'DSK 4-S' }, // 31
|
||||
|
||||
{ id: '113' , label: 'AUX 01' }, // 32
|
||||
{ id: '114' , label: 'AUX 02' },
|
||||
{ id: '115' , label: 'AUX 03' },
|
||||
{ id: '116' , label: 'AUX 04' },
|
||||
{ id: '117' , label: 'AUX 05' },
|
||||
{ id: '118' , label: 'AUX 06' },
|
||||
{ id: '119' , label: 'AUX 07' },
|
||||
{ id: '120' , label: 'AUX 08' },
|
||||
{ id: '121' , label: 'AUX 09' },
|
||||
{ id: '122' , label: 'AUX 10' },
|
||||
{ id: '123' , label: 'AUX 11' },
|
||||
{ id: '124' , label: 'AUX 12' },
|
||||
{ id: '125' , label: 'AUX 13' },
|
||||
{ id: '126' , label: 'AUX 14' },
|
||||
{ id: '127' , label: 'AUX 15' },
|
||||
{ id: '128' , label: 'AUX 16' }, // 47
|
||||
|
||||
{ id: '141' , label: 'DISP' }, // 48
|
||||
{ id: '142' , label: 'USK 1-F' },
|
||||
{ id: '143' , label: 'USK 1-S' },
|
||||
{ id: '144' , label: 'USK 2-F' },
|
||||
{ id: '145' , label: 'USK 2-S' },
|
||||
{ id: '146' , label: 'USK 3-F' },
|
||||
{ id: '147' , label: 'USK 3-S' },
|
||||
{ id: '148' , label: 'USK 4-F' },
|
||||
{ id: '149' , label: 'USK 4-S' },
|
||||
{ id: '150' , label: 'VMEM-V' },
|
||||
{ id: '151' , label: 'VMEM-K' }, // 58
|
||||
|
||||
{ id: '153' , label: 'MV1-1' }, // 59
|
||||
{ id: '154' , label: 'MV1-2' },
|
||||
{ id: '155' , label: 'MV1-3' },
|
||||
{ id: '156' , label: 'MV1-4' },
|
||||
{ id: '157' , label: 'MV1-5' },
|
||||
{ id: '158' , label: 'MV1-6' },
|
||||
{ id: '159' , label: 'MV1-7' },
|
||||
{ id: '160' , label: 'MV1-8' },
|
||||
{ id: '161' , label: 'MV1-9' },
|
||||
{ id: '162' , label: 'MV1-10' },
|
||||
{ id: '163' , label: 'MV1-11' },
|
||||
{ id: '164' , label: 'MV1-12' },
|
||||
{ id: '165' , label: 'MV1-13' },
|
||||
{ id: '166' , label: 'MV1-14' },
|
||||
{ id: '167' , label: 'MV1-15' },
|
||||
{ id: '168' , label: 'MV1-16' }, // 74
|
||||
|
||||
{ id: '169' , label: 'MV2-1' }, // 75
|
||||
{ id: '170' , label: 'MV2-2' },
|
||||
{ id: '171' , label: 'MV2-3' },
|
||||
{ id: '172' , label: 'MV2-4' },
|
||||
{ id: '173' , label: 'MV2-5' },
|
||||
{ id: '174' , label: 'MV2-6' },
|
||||
{ id: '175' , label: 'MV2-7' },
|
||||
{ id: '176' , label: 'MV2-8' },
|
||||
{ id: '177' , label: 'MV2-9' },
|
||||
{ id: '178' , label: 'MV2-10' },
|
||||
{ id: '179' , label: 'MV2-11' },
|
||||
{ id: '180' , label: 'MV2-12' },
|
||||
{ id: '181' , label: 'MV2-13' },
|
||||
{ id: '182' , label: 'MV2-14' },
|
||||
{ id: '183' , label: 'MV2-15' },
|
||||
{ id: '184' , label: 'MV2-16' }, // 90
|
||||
|
||||
{ id: '185' , label: 'MV3-1' }, // 91
|
||||
{ id: '186' , label: 'MV3-2' },
|
||||
{ id: '187' , label: 'MV3-3' },
|
||||
{ id: '188' , label: 'MV3-4' },
|
||||
{ id: '189' , label: 'MV3-5' },
|
||||
{ id: '190' , label: 'MV3-6' },
|
||||
{ id: '191' , label: 'MV3-7' },
|
||||
{ id: '192' , label: 'MV3-8' },
|
||||
{ id: '193' , label: 'MV3-9' },
|
||||
{ id: '194' , label: 'MV3-10' },
|
||||
{ id: '195' , label: 'MV3-11' },
|
||||
{ id: '196' , label: 'MV3-12' },
|
||||
{ id: '197' , label: 'MV3-13' },
|
||||
{ id: '198' , label: 'MV3-14' },
|
||||
{ id: '199' , label: 'MV3-15' },
|
||||
{ id: '200' , label: 'MV3-16' }, // 106
|
||||
|
||||
{ id: '201' , label: 'MV4-1' }, // 107
|
||||
{ id: '202' , label: 'MV4-2' },
|
||||
{ id: '203' , label: 'MV4-3' },
|
||||
{ id: '204' , label: 'MV4-4' },
|
||||
{ id: '205' , label: 'MV4-5' },
|
||||
{ id: '206' , label: 'MV4-6' },
|
||||
{ id: '207' , label: 'MV4-7' },
|
||||
{ id: '208' , label: 'MV4-8' },
|
||||
{ id: '209' , label: 'MV4-9' },
|
||||
{ id: '210' , label: 'MV4-10' },
|
||||
{ id: '211' , label: 'MV4-11' },
|
||||
{ id: '212' , label: 'MV4-12' },
|
||||
{ id: '213' , label: 'MV4-13' },
|
||||
{ id: '214' , label: 'MV4-14' },
|
||||
{ id: '215' , label: 'MV4-15' },
|
||||
{ id: '216' , label: 'MV4-16' } // 122
|
||||
];
|
||||
|
||||
const SOURCES = [
|
||||
{ id: '01' , label: 'SDI 01' },
|
||||
{ id: '02' , label: 'SDI 02' },
|
||||
{ id: '03' , label: 'SDI 03' },
|
||||
{ id: '04' , label: 'SDI 04' },
|
||||
{ id: '05' , label: 'SDI 05' },
|
||||
{ id: '06' , label: 'SDI 06' },
|
||||
{ id: '07' , label: 'SDI 07' },
|
||||
{ id: '08' , label: 'SDI 08' },
|
||||
{ id: '09' , label: 'SDI 09' },
|
||||
{ id: '10' , label: 'SDI 10' },
|
||||
{ id: '11' , label: 'SDI 11' },
|
||||
{ id: '12' , label: 'SDI 12' },
|
||||
{ id: '13' , label: 'SDI 13' },
|
||||
{ id: '14' , label: 'SDI 14' },
|
||||
{ id: '15' , label: 'SDI 15' },
|
||||
{ id: '16' , label: 'SDI 16' },
|
||||
{ id: '17' , label: 'SDI 17' },
|
||||
{ id: '18' , label: 'SDI 18' },
|
||||
{ id: '19' , label: 'SDI 19' },
|
||||
{ id: '20' , label: 'SDI 20' },
|
||||
{ id: '21' , label: 'SDI 21' },
|
||||
{ id: '22' , label: 'SDI 22' },
|
||||
{ id: '23' , label: 'SDI 23' },
|
||||
{ id: '24' , label: 'SDI 24' },
|
||||
{ id: '25' , label: 'SDI 25' },
|
||||
{ id: '26' , label: 'SDI 26' },
|
||||
{ id: '27' , label: 'SDI 27' },
|
||||
{ id: '28' , label: 'SDI 28' },
|
||||
{ id: '29' , label: 'SDI 29' },
|
||||
{ id: '30' , label: 'SDI 30' },
|
||||
{ id: '31' , label: 'SDI 31' },
|
||||
{ id: '32' , label: 'SDI 32' },
|
||||
|
||||
{ id: '73' , label: 'DVI 1' },
|
||||
{ id: '74' , label: 'DVI 2' },
|
||||
|
||||
{ id: '145' , label: 'CBGD 1' },
|
||||
{ id: '146' , label: 'CBGD 2' },
|
||||
{ id: '147' , label: 'CBAR' },
|
||||
|
||||
{ id: '148' , label: 'BLACK' },
|
||||
|
||||
{ id: '149' , label: 'STILL 1-V' },
|
||||
{ id: '150' , label: 'STILL 1-K' },
|
||||
{ id: '151' , label: 'STILL 2-V' },
|
||||
{ id: '152' , label: 'STILL 2-K' },
|
||||
{ id: '153' , label: 'STILL 3-V' },
|
||||
{ id: '154' , label: 'STILL 3-K' },
|
||||
{ id: '155' , label: 'STILL 4-V' },
|
||||
{ id: '156' , label: 'STILL 4-K' },
|
||||
|
||||
{ id: '157' , label: 'CLIP 1-V' },
|
||||
{ id: '158' , label: 'CLIP 1-K' },
|
||||
{ id: '159' , label: 'CLIP 2-V' },
|
||||
{ id: '160' , label: 'CLIP 2-K' },
|
||||
{ id: '161' , label: 'CLIP 3-V' },
|
||||
{ id: '162' , label: 'CLIP 3-K' },
|
||||
{ id: '163' , label: 'CLIP 4-V' },
|
||||
{ id: '164' , label: 'CLIP 4-K' },
|
||||
|
||||
{ id: '165' , label: 'MV1' },
|
||||
{ id: '166' , label: 'MV2' },
|
||||
{ id: '167' , label: 'MV3' },
|
||||
{ id: '168' , label: 'MV4' },
|
||||
|
||||
{ id: '169' , label: 'ME1 PGM' },
|
||||
{ id: '170' , label: 'ME1 PVW' },
|
||||
{ id: '171' , label: 'ME1 CLN' },
|
||||
{ id: '172' , label: 'ME1 KEY PVW' },
|
||||
|
||||
{ id: '173' , label: 'ME2 PGM' },
|
||||
{ id: '174' , label: 'ME2 PVW' },
|
||||
{ id: '175' , label: 'ME2 CLN' },
|
||||
{ id: '176' , label: 'ME2 KEY PVW' },
|
||||
|
||||
{ id: '201' , label: 'DSK PGM 1' },
|
||||
{ id: '202' , label: 'DSK PGM 2' },
|
||||
{ id: '203' , label: 'DSK PVW 1' },
|
||||
{ id: '204' , label: 'DSK PVW 2' },
|
||||
|
||||
{ id: '209' , label: 'DSK1 CLN' },
|
||||
{ id: '210' , label: 'DSK2 CLN' },
|
||||
{ id: '211' , label: 'DSK3 CLN' },
|
||||
{ id: '212' , label: 'DSK4 CLN' },
|
||||
|
||||
{ id: '225' , label: 'SEL-KEYPVW' },
|
||||
|
||||
{ id: '227' , label: 'AUX 01' },
|
||||
{ id: '228' , label: 'AUX 02' },
|
||||
{ id: '229' , label: 'AUX 03' },
|
||||
{ id: '230' , label: 'AUX 04' },
|
||||
{ id: '231' , label: 'AUX 05' },
|
||||
{ id: '232' , label: 'AUX 06' },
|
||||
{ id: '233' , label: 'AUX 07' },
|
||||
{ id: '234' , label: 'AUX 08' },
|
||||
{ id: '235' , label: 'AUX 09' },
|
||||
{ id: '236' , label: 'AUX 10' },
|
||||
{ id: '237' , label: 'AUX 11' },
|
||||
{ id: '238' , label: 'AUX 12' },
|
||||
{ id: '239' , label: 'AUX 13' },
|
||||
{ id: '240' , label: 'AUX 14' },
|
||||
{ id: '241' , label: 'AUX 15' },
|
||||
{ id: '242' , label: 'AUX 16' },
|
||||
|
||||
{ id: '251' , label: 'CLOCK' },
|
||||
{ id: '252' , label: 'LTC' }
|
||||
];
|
||||
|
||||
class AVHSInstance 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.refreshTiming>0===false) this.config.refreshTiming = 0;
|
||||
else if(this.config.refreshTiming>30) this.config.refreshTiming = 30;
|
||||
|
||||
if(this.config.srcNameRefreshTiming>10===false) this.config.srcNameRefreshTiming = 10;
|
||||
else if(this.config.srcNameRefreshTiming>120) this.config.srcNameRefreshTiming = 120;
|
||||
|
||||
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() ); }
|
||||
|
||||
// BUS LIST
|
||||
getBusList() {
|
||||
var busList = [];
|
||||
if(this.config.enableME1) busList = busList.concat( BUS.slice(0,12) );
|
||||
if(this.config.enableME2) busList = busList.concat( BUS.slice(12,24) );
|
||||
if(this.config.enableDSK) busList = busList.concat( BUS.slice(24,32) );
|
||||
if(this.config.enableAUX) busList = busList.concat( BUS.slice(32,48) );
|
||||
if(this.config.enableUSK) busList = busList.concat( BUS.slice(48,59) );
|
||||
if(this.config.enableMV1) busList = busList.concat( BUS.slice(59,75) );
|
||||
if(this.config.enableMV2) busList = busList.concat( BUS.slice(75,91) );
|
||||
if(this.config.enableMV3) busList = busList.concat( BUS.slice(91,107) );
|
||||
if(this.config.enableMV4) busList = busList.concat( BUS.slice(107) );
|
||||
return busList;
|
||||
}
|
||||
getBusNameByID(id) {
|
||||
var name = "";
|
||||
var l = BUS.length;
|
||||
for(var i=0; i<l; i++) {
|
||||
if(BUS[i].id == id) {
|
||||
name = BUS[i].label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
getBusNumByID(id) {
|
||||
var busList = this.getBusList();
|
||||
var num = -1;
|
||||
var l = busList.length;
|
||||
for(var i=0; i<l; i++) {
|
||||
if(busList[i].id == id) {
|
||||
num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
getBusVariableFromName(name) { return "bus_"+name.replaceAll(" ", "-"); }
|
||||
getBusVariableFromID(id) { let name = this.getBusNameByID(id); return (name!="") ? this.getBusVariableFromName(name) : ""; }
|
||||
getFirstBusID() {
|
||||
var busList = this.getBusList();
|
||||
if(busList.length>0) return busList[0].id;
|
||||
return "00";
|
||||
}
|
||||
|
||||
// SOURCES
|
||||
getSourcesList() { return SOURCES; }
|
||||
getSourceNameByID(id, forceDefault) {
|
||||
var name = "";
|
||||
var l = SOURCES.length;
|
||||
for(var i=0; i<l; i++) {
|
||||
if(SOURCES[i].id == id) {
|
||||
let label = SOURCES[i].label;
|
||||
name = (this.config.src_name=="panel" || this.config.src_name=="mv") && !forceDefault ? this.getVariableValue(this.getSourceVariableFromName(label)) : label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
getSourceNumByID(id) {
|
||||
var num = -1;
|
||||
var l = SOURCES.length;
|
||||
for(var i=0; i<l; i++) {
|
||||
if(SOURCES[i].id == id) {
|
||||
num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
getSourceVariableFromName(name) { return "src_"+name.replaceAll(" ", "-"); }
|
||||
getSourceVariableFromID(id) { let name = this.getSourceNameByID(id, true); return (name!="") ? this.getSourceVariableFromName(name) : ""; }
|
||||
|
||||
// TCP CONNECTION
|
||||
initTCP() {
|
||||
this.killTCP();
|
||||
|
||||
this.log('info', `AV-HS6000 | INIT TCP CONNECTION >>> ${this.config.host} ${this.config.port}`);
|
||||
|
||||
if(this.config.host && this.config.port) {
|
||||
this.log('info', `AV-HS6000 | 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', `AV-HS6000 | TCP connection status changed >>> ${status}`);
|
||||
if(status=="ok") {
|
||||
this.refreshBusesXPT();
|
||||
this.refreshSourcesNames();
|
||||
}
|
||||
else {
|
||||
this.stopRefreshBusesXPTtimer();
|
||||
this.stopRefreshSourcesNamesTimer();
|
||||
this.clearTcpCommandBuffer();
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on('error', (err) => {
|
||||
this.updateStatus(InstanceStatus.ConnectionFailure, err.message);
|
||||
this.log('error', 'TCP CONTROL | Network error: ' + err.message);
|
||||
});
|
||||
|
||||
this.socket.on('data', (data) => {
|
||||
this.parseReceivedMessage(data.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
killTCP() {
|
||||
this.stopRefreshBusesXPTtimer();
|
||||
this.stopRefreshSourcesNamesTimer();
|
||||
this.clearTcpCommandBuffer();
|
||||
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', `AV-HS6000 | SENDIND COMMAND >>> ${escCmd} | callback: ${cue.clbk}`);
|
||||
const sendBuf = Buffer.from(escCmd, 'latin1');
|
||||
if(this.socket !== undefined && this.socket.isConnected) {
|
||||
currentCmd = cue;
|
||||
this.socket.send(sendBuf);
|
||||
tcpSendTimeout = setTimeout(function(self) { self.onSendCommandTimeout(); }, this.config.timeout, this);
|
||||
|
||||
/*** AUTO REPLY ***/
|
||||
if(autoReply) {
|
||||
cmd = cmd.replaceAll("%02", "").replaceAll("%03", "");
|
||||
var parts = cmd.split(":");
|
||||
// GET BUS XPT
|
||||
if(parts[0] == "QBSC" && parts.length==2) {
|
||||
setTimeout(function(self) {
|
||||
const busStatus = self.getVariableValue(self.getBusVariableFromID(parts[1]));
|
||||
var source = (busStatus && busStatus!='00') ? busStatus : '01';
|
||||
self.parseReceivedMessage(` ABSC:${parts[1]}:${source} `);
|
||||
}, 2, this);
|
||||
}
|
||||
// SET BUS XPT
|
||||
else if(parts[0] == "SBUS" && parts.length==3) {
|
||||
setTimeout(function(self) {
|
||||
self.parseReceivedMessage(` ABUS:${parts[1]}:${parts[2]} `);
|
||||
}, 2, this);
|
||||
}
|
||||
// SRC NAME
|
||||
else if(parts[0] == "QSNM" && parts.length==3) {
|
||||
setTimeout(function(self) {
|
||||
const srcName = self.getVariableValue(self.getSourceVariableFromID(parts[2]));
|
||||
self.parseReceivedMessage(` ASNM:${parts[1]}:${parts[2]}:TOTO `);
|
||||
}, 2, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else this.log('warn', `AV-HS6000 | CANNOT SEND COMMAND - Socket not connected >>> ${cmd}`);
|
||||
}
|
||||
else if(tcpCommandBuffer.length>0) this.sendNextCommand();
|
||||
}
|
||||
|
||||
onSendCommandTimeout() {
|
||||
this.log('warn', `AV-HS6000 | SEND COMMAND TIMEOUT >>> ${currentCmd.cmd}`);
|
||||
tcpSendTimeout=undefined;
|
||||
|
||||
// CALLBACK
|
||||
if(currentCmd.clbk=="startRefreshBusesXPTtimer") this.startRefreshBusesXPTtimer();
|
||||
else if(currentCmd.clbk=="startRefreshSourcesNamesTimer") this.startRefreshSourcesNamesTimer();
|
||||
|
||||
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', `AV-HS6000 | receive message > "${msg}"`);
|
||||
msg = msg.slice(1, -1);
|
||||
var method = msg.slice(0,4);
|
||||
// BUS XPT
|
||||
if(method=="ABUS" || method=="ABSC") {
|
||||
let parts = msg.split(":");
|
||||
if(parts.length==3) {
|
||||
let busVar = this.getBusVariableFromID( parts[1] );
|
||||
if(busVar!="") {
|
||||
const variables = {};
|
||||
variables[busVar] = parts[2];
|
||||
this.setVariableValues(variables);
|
||||
this.checkFeedbacks('crosspoint_status');
|
||||
}
|
||||
}
|
||||
}
|
||||
// SRC NAME
|
||||
else if(method=="ASNM") {
|
||||
let parts = msg.split(":");
|
||||
if(parts.length==4) {
|
||||
let srcVar = this.getSourceVariableFromID( parts[2] );
|
||||
let srcName = parts[3].replaceAll(' ', '\n');
|
||||
if(srcVar!="") {
|
||||
const variables = {};
|
||||
variables[srcVar] = srcName;
|
||||
this.setVariableValues(variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CALLBACK
|
||||
if(currentCmd.clbk=="startRefreshBusesXPTtimer") this.startRefreshBusesXPTtimer();
|
||||
else if(currentCmd.clbk=="startRefreshSourcesNamesTimer") this.startRefreshSourcesNamesTimer();
|
||||
currentCmd = false;
|
||||
|
||||
this.sendNextCommand();
|
||||
}
|
||||
|
||||
// REFRESH BUS XPT
|
||||
refreshBusesXPT() {
|
||||
var busList = this.getBusList();
|
||||
var l = busList.length;
|
||||
for(var i=0; i<l; i++) {
|
||||
let busID = busList[i].id;
|
||||
let cmd = `%02QBSC:${busID}%03`;
|
||||
this.sendCommand(cmd, (i==l-1) ? "startRefreshBusesXPTtimer" : false);
|
||||
}
|
||||
}
|
||||
startRefreshBusesXPTtimer() {
|
||||
if(this.config.refreshTiming>0) refreshBusTimer = setTimeout(
|
||||
function(self) { self.refreshBusesXPT(); },
|
||||
this.config.refreshTiming*1000,
|
||||
this
|
||||
);
|
||||
}
|
||||
stopRefreshBusesXPTtimer() {
|
||||
if(refreshBusTimer) {
|
||||
clearTimeout( refreshBusTimer );
|
||||
refreshBusTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// REFRESH SRC NAME
|
||||
refreshSourcesNames() {
|
||||
var srcList = this.getSourcesList();
|
||||
var l = srcList.length;
|
||||
if(l>0 && (this.config.src_name=="panel" || this.config.src_name=="mv")) {
|
||||
var from = this.config.src_name=="panel" ? '00' : '01';
|
||||
for(var i=0; i<l; i++) {
|
||||
let srcID = srcList[i].id;
|
||||
let cmd = `%02QSNM:${from}:${srcID}%03`;
|
||||
this.sendCommand(cmd, (i==l-1) ? "startRefreshSourcesNamesTimer" : false);
|
||||
}
|
||||
}
|
||||
}
|
||||
startRefreshSourcesNamesTimer() {
|
||||
if(this.config.srcNameRefreshTiming>0) refreshSrcTimer = setTimeout(
|
||||
function(self) { self.refreshSourcesNames(); },
|
||||
this.config.srcNameRefreshTiming*1000,
|
||||
this
|
||||
);
|
||||
}
|
||||
stopRefreshSourcesNamesTimer() {
|
||||
if(refreshSrcTimer) {
|
||||
clearTimeout( refreshSrcTimer );
|
||||
refreshSrcTimer = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runEntrypoint(AVHSInstance, []);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "panasonic-av-hs6000",
|
||||
"version": "1.0.0",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"format": "prettier -w ."
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/bitfocus/companion-module-panasonic-av-hs6000.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.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538"
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
const { combineRgb } = require('@companion-module/base');
|
||||
module.exports = {
|
||||
getPresets() {
|
||||
const presets = {};
|
||||
|
||||
var busList = this.getBusList();
|
||||
var srcList = this.getSourcesList();
|
||||
busList.forEach((bus) => {
|
||||
srcList.forEach((src) => {
|
||||
let srcVar = this.getSourceVariableFromName(src.label);
|
||||
presets[`xpt_${bus.id}_${src.id}`] = {
|
||||
type: 'button',
|
||||
category: bus.label+" - XPT",
|
||||
style: {
|
||||
text: `$(AV-HS6000:${srcVar})`,
|
||||
//size: '16',
|
||||
color: combineRgb(255, 255, 255),
|
||||
bgcolor: combineRgb(0, 0, 0)
|
||||
},
|
||||
steps: [{
|
||||
down: [{
|
||||
actionId: 'setCrosspoint',
|
||||
options: { bus: bus.id, src: src.id }
|
||||
}]
|
||||
}],
|
||||
feedbacks: [
|
||||
{
|
||||
feedbackId: 'crosspoint_status',
|
||||
options: { bus: bus.id, src: src.id },
|
||||
style: { bgcolor: combineRgb(255, 0, 0) }
|
||||
},
|
||||
{
|
||||
feedbackId: 'connect_status',
|
||||
options: {},
|
||||
isInverted: true,
|
||||
style: { color: combineRgb(255, 80, 80), bgcolor: combineRgb(80, 0, 0) }
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return presets;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
module.exports = {
|
||||
getVariables() {
|
||||
const variables = [];
|
||||
|
||||
// CONNECTED
|
||||
variables.push({ variableId: 'connect_status', name: 'Connection Status' });
|
||||
|
||||
// BUS
|
||||
const busList = this.getBusList();
|
||||
busList.forEach((b) => {
|
||||
let id = this.getBusVariableFromName( b.label );
|
||||
variables.push({ variableId: id, name: b.label });
|
||||
});
|
||||
// SOURCES
|
||||
const sourcesList = this.getSourcesList();
|
||||
sourcesList.forEach((s) => {
|
||||
let id = this.getSourceVariableFromName( s.label );
|
||||
variables.push({ variableId: id, name: s.label });
|
||||
});
|
||||
return variables;
|
||||
},
|
||||
initVariablesValues() {
|
||||
const variables = {};
|
||||
|
||||
// BUS
|
||||
var busList = this.getBusList();
|
||||
busList.forEach((b) => {
|
||||
let id = this.getBusVariableFromName( b.label );
|
||||
variables[id] = '00';
|
||||
});
|
||||
// SOURCES
|
||||
const sourcesList = this.getSourcesList();
|
||||
sourcesList.forEach((s) => {
|
||||
let id = this.getSourceVariableFromName( s.label );
|
||||
variables[id] = s.label.replaceAll(' ', '\n');
|
||||
});
|
||||
this.setVariableValues(variables);
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue