loupedeck-commander 1.2.5 → 1.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,7 @@ export class ApplicationConfig {
19
19
  else{
20
20
  this.application = config.application
21
21
  for (let i = 0; i < config.profiles.length; i++) {
22
- const profile = new Profile(config.profiles[i])
22
+ const profile = new Profile(config.profiles[i],config.profiles.length,i)
23
23
  if (profile.loaded){
24
24
  this.profiles.push(profile)
25
25
  }else{
@@ -45,10 +45,14 @@ class Profile {
45
45
  #file = ''
46
46
  loaded = false
47
47
  #error = true
48
+ #profileCount = 0
49
+ #index = 0
48
50
 
49
- constructor (data) {
51
+ constructor (data,profileCount,index) {
50
52
  this.name = data.name
51
53
  this.#file = data.file
54
+ this.#profileCount = profileCount
55
+ this.#index = index
52
56
  this.touch = new TouchConfig({})
53
57
  this.buttons = new ButtonConfig().buttons
54
58
  this.knobs = new KnobsConfig().knobs
@@ -59,7 +63,7 @@ class Profile {
59
63
  }
60
64
 
61
65
  loadFromFile (fileName) {
62
- console.info(`ProfileConfig: Loading Profile File ${fileName}`)
66
+ console.info(`ProfileConfig: Loading Profile File ${fileName}, Index ${this.#index}`)
63
67
  const config = readJSONFile(fileName)
64
68
  if (config === undefined) {
65
69
  console.warn(`ProfileConfig: Cannot parse/load Profile File ${fileName}`)
@@ -70,12 +74,12 @@ class Profile {
70
74
  }else if (!config.touch){
71
75
  console.warn(`ProfileConfig: File ${fileName} is missing a touch attribute`)
72
76
  return false
73
- }else if (!config.buttons){
74
- console.warn(`ProfileConfig: File ${fileName} is missing a buttons attribute`)
75
- return false
76
77
  }else if (!config.parameters){
77
78
  console.warn(`ProfileConfig: File ${fileName} is missing a parameters attribute`)
78
79
  return false
80
+ }else if (!config.buttons){
81
+ console.info(`ProfileConfig: File ${fileName} is missing a buttons attribute - will be used to switch profiles by default`)
82
+ // return false
79
83
  }
80
84
  this.profile = config.profile
81
85
  this.description = config.description
@@ -84,7 +88,7 @@ class Profile {
84
88
  this.touch = new TouchConfig(config.touch)
85
89
  // Load the Configurations for Button-Areas
86
90
 
87
- this.buttons = new ButtonConfig(config.buttons).buttons
91
+ this.buttons = new ButtonConfig(config.buttons,this.#profileCount,this.#index).buttons
88
92
  this.knobs = new KnobsConfig(config.knobs).knobs
89
93
  // Load Parameters.parameters = config.parameters
90
94
  this.parameters = new ParametersConfig(config.parameters).parameters
@@ -154,19 +158,32 @@ class TouchConfig {
154
158
  * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
155
159
  */
156
160
  class ButtonConfig {
157
- buttons = {
158
- "0" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#550000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
159
- "1" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#ff0000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
160
- "2" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#005500", "cmd": "echo \"{id} {state}\"" } }, group : "" },
161
- "3" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "" },
162
- "4" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#000055", "cmd": "echo \"{id} {state}\"" } }, group : "" },
163
- "5" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#0000ff", "cmd": "echo \"{id} {state}\"" } }, group : "" },
164
- "6" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#555500", "cmd": "echo \"{id} {state}\"" } }, group : "" },
165
- "7" : { "states" : { "off" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#ffff00", "cmd": "echo \"{id} {state}\"" } }, group : "" },
161
+ buttons = {}
162
+ defaultButtons = {
163
+ "0" : {"states" : { "off" : { "filter": "pressed", "color": "#000000", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed","color": "#ff0000", "cmd": "echo \"{id} {state}\"" } }, group : "onoff" },
164
+ "1" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 0, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
165
+ "2" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 1, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
166
+ "3" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 2, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
167
+ "4" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 3, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
168
+ "5" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 4, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
169
+ "6" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 5, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
170
+ "7" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "cmd": "echo \"{id} {state}\"" }, "on" : { "filter": "pressed", "profile": 6, "color": "#00ff00", "cmd": "echo \"{id} {state}\"" } }, group : "profiles" },
166
171
  }
167
172
 
168
- constructor (data) {
169
- this.loadFromJSON(data)
173
+ constructor (data,profileCount,index) {
174
+ if (data)
175
+ return this.loadFromJSON(data)
176
+ // Default to profile switching buttons
177
+ var keys = Object.keys(this.defaultButtons)
178
+ for (let i = 0; i <= profileCount; i++) {
179
+ var key = keys[i]
180
+ this.buttons[key] = this.defaultButtons[key]
181
+ if (i==(index+1)){
182
+ this.buttons[key].default = "on"
183
+ }
184
+
185
+ }
186
+
170
187
  }
171
188
 
172
189
  loadFromJSON (data) {
@@ -134,6 +134,13 @@ export class BaseLoupeDeckHandler {
134
134
  const dLeft = this.device.displays.left
135
135
  const dRight = this.device.displays.right
136
136
  const dCenter = this.device.displays.center
137
+
138
+ this.screens.center = undefined
139
+ this.screens.left = undefined
140
+ this.screens.right = undefined
141
+ this.buttons = undefined
142
+ this.knobs = undefined
143
+
137
144
 
138
145
  this.screens.center = new ButtonField('center', this.device.rows, this.device.columns, dCenter.width, dCenter.height, profile.touch.center,profile)
139
146
  this.screens.left = new ButtonField('left', 1, 1, dLeft.width, dLeft.height, profile.touch.left,profile)
@@ -222,7 +229,7 @@ export class BaseLoupeDeckHandler {
222
229
  const id = event.id
223
230
  if (Number.isInteger(id)){
224
231
  ok = await this.buttons.pressed(id)
225
- await this.buttons.draw(this.device)
232
+ //await this.buttons.draw(this.device)
226
233
  }else{
227
234
  ok = await this.knobs.pressed(id)
228
235
  }
@@ -237,7 +244,7 @@ export class BaseLoupeDeckHandler {
237
244
  const id = event.id
238
245
  if (Number.isInteger(id) && this.buttons){
239
246
  ok = await this.buttons.released(id)
240
- await this.buttons.draw(this.device)
247
+ //await this.buttons.draw(this.device)
241
248
  }else{
242
249
  if(this.knobs)
243
250
  ok = await this.knobs.released(id)
@@ -64,9 +64,9 @@ export class ButtonField {
64
64
  #keys = []
65
65
  #type
66
66
  #name
67
- #config
67
+ #profile
68
68
 
69
- constructor (name, rows, columns, width, height, data, config) {
69
+ constructor (name, rows, columns, width, height, data, profile) {
70
70
  console.info(`ButtonField ${name.padEnd(10, ' ')} Buttons: ${rows} x ${columns} , Pixels ${width} x ${height}`)
71
71
  this.#name = name
72
72
  this.width = width
@@ -75,17 +75,17 @@ export class ButtonField {
75
75
  this.#columns = columns
76
76
  this.#screen = this.width > 0 && this.height > 0
77
77
  this.#type = 'button'
78
+ this.#profile = profile
78
79
  if (this.#screen) { this.#type = 'touch' }
79
80
 
80
81
  const keys = Object.keys(data)
81
82
  for (let i = 0; i < keys.length; i++) {
82
83
  const key = keys[i]
83
- const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key],key,config.parameters)
84
+ const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key],key,this.#profile.parameters)
84
85
  this.#buttons[key] = tb
85
86
  }
86
87
 
87
88
  this.#keys = keys
88
- this.#config = config
89
89
  }
90
90
 
91
91
 
@@ -124,10 +124,10 @@ export class ButtonField {
124
124
  for (let i = 0; i < this.#keys.length; i++) {
125
125
  const key = this.#keys[i]
126
126
  if (isNaN(key)) {
127
- await this.#buttons[key].load(this.#config)
127
+ await this.#buttons[key].load(this.#profile)
128
128
  } else {
129
129
  const iVal = parseInt(key, 10)
130
- await this.#buttons[iVal].load(this.#config)
130
+ await this.#buttons[iVal].load(this.#profile)
131
131
  }
132
132
  }
133
133
  }
@@ -190,7 +190,7 @@ export class ButtonField {
190
190
  }
191
191
 
192
192
  export class Button {
193
- #config
193
+ #profile
194
194
  width = 0
195
195
  height = 0
196
196
 
@@ -212,8 +212,8 @@ export class Button {
212
212
  text = ''
213
213
  font = '16px Arial'
214
214
 
215
- #x
216
- #y
215
+ #x = 0
216
+ #y = 0
217
217
  #moveLeft
218
218
  #moveRight
219
219
  #moveUp
@@ -260,7 +260,10 @@ export class Button {
260
260
  if (data.nodeid){
261
261
  this.#nodeid = format(data.nodeid, params)
262
262
  }
263
-
263
+ if (data.default) {
264
+ this.#index = this.#keys.indexOf(data.default)
265
+ }
266
+
264
267
  }
265
268
 
266
269
  setState (index = 0) {
@@ -282,7 +285,7 @@ export class Button {
282
285
  id:idx,
283
286
  color: `rgba(${r}, ${g}, ${b})`
284
287
  }
285
- // console.log(' Set Button Color',val.id,elem.color, val.color)
288
+ // console.log(' Set Button Color',id, val.id,elem.color, val.color)
286
289
  device.setButtonColor(val)
287
290
  } catch (error) {
288
291
  console.error(' Error', error)
@@ -315,7 +318,7 @@ export class Button {
315
318
  }
316
319
 
317
320
  async load (globalConfig) {
318
- this.#config = globalConfig
321
+ this.#profile = globalConfig
319
322
  for (let i = 0; i < this.#keys.length; i++) {
320
323
  const key = this.#keys[i]
321
324
  const elem = this.#states[key]
@@ -392,7 +395,7 @@ export class Button {
392
395
 
393
396
  updateState(index,eventType){
394
397
  this.#index = index
395
- this.#event = eventType
398
+ this.#event = eventType
396
399
  // Update the State according to the correctly pressed state
397
400
  if (this.#index < 0) { this.#index = this.#keys.length - 1 }
398
401
  this.#index %= this.#keys.length
@@ -479,7 +482,7 @@ export class Button {
479
482
  return
480
483
  }
481
484
 
482
- if (elem.profile){
485
+ if (elem.profile !== undefined) {
483
486
  profileEmitter.emit("profileChanged", elem.profile)
484
487
  }
485
488
 
@@ -492,7 +495,7 @@ export class Button {
492
495
  // and also all attributes of elem + global config
493
496
  const params = {
494
497
  text: this.getCurrentText(),
495
- ...this.#config.parameters,
498
+ ...this.#profile.parameters,
496
499
  ...elem,
497
500
  id: this.id,
498
501
  key: this.key,
@@ -500,6 +503,8 @@ export class Button {
500
503
  state: this.#keys[this.#index],
501
504
  min: this.#min,
502
505
  max: this.#max,
506
+ x: (this.#x %100),
507
+ y: (this.#y %100)
503
508
  }
504
509
 
505
510
  if (!params.value)
package/config.json CHANGED
@@ -4,6 +4,10 @@
4
4
  {
5
5
  "name": "profile-1",
6
6
  "file": "profile-1.json"
7
+ },
8
+ {
9
+ "name": "profile-2",
10
+ "file": "profile-2.json"
7
11
  }
8
12
  ]
9
13
  }
@@ -14,7 +14,9 @@ export class BaseIf extends EventEmitter {
14
14
 
15
15
  this.cmd = cmd
16
16
  this.options = options
17
- this.formattedCommand = this.formatString(cmd, options)
17
+ this.formattedCommand = this.formatString(cmd, options)
18
+ this.LogDebug("Formatted command: ", this.formattedCommand,"\n")
19
+ this.LogDebug("Options",JSON.stringify(options),"\n" )
18
20
  return this.formattedCommand
19
21
  }
20
22
 
@@ -23,7 +23,6 @@ const subscriptionParameters = {
23
23
  requestedPublishingInterval: 1000
24
24
  };
25
25
 
26
-
27
26
  /**
28
27
  * Our Special-Handler just used the Default - and adds Vibration after triggers through Button-Releases
29
28
  */
@@ -35,6 +34,7 @@ export class OPCUAIf extends BaseIf {
35
34
  #connected
36
35
  #endpointurl
37
36
  monitoreditems
37
+ types
38
38
  buttons
39
39
  #callback
40
40
  constructor() {
@@ -55,6 +55,12 @@ export class OPCUAIf extends BaseIf {
55
55
  this.LogInfo(`OPCUAIf Stopped\n`)
56
56
  }
57
57
 
58
+ /**
59
+ * Initialize the OPCUA client and subscribe to monitored items.
60
+ * @param {*} options
61
+ * @param {*} config
62
+ * @param {*} callbackFunction
63
+ */
58
64
  async init( options = {},config = {},callbackFunction){
59
65
  var res = this.Check(options)
60
66
  if (res<0){
@@ -64,28 +70,87 @@ export class OPCUAIf extends BaseIf {
64
70
  this.#endpointurl = this.formatString(options.endpointurl,options)
65
71
  this.#callback = callbackFunction
66
72
  this.monitoreditems = {}
73
+ this.types = {}
67
74
  this.buttons = {}
68
75
  this.LogInfo(`OPCUAIf init ${this.#endpointurl}\n`);
69
76
 
70
77
  await this.Connect(this.#endpointurl);
71
78
 
72
- let field=config.touch.center
73
- const keys = Object.keys(field)
74
- for (let i = 0; i < keys.length; i++) {
75
- const key = keys[i]
76
- const elem = config.touch.center[key]
77
- if (elem.nodeid){
78
- let format = this.formatString(elem.nodeid,options)
79
- let monitoredItemId = await this.Subscribe(format)
80
- this.buttons[monitoredItemId] = i
79
+ let fields = [config.touch.center, config.knobs, config.buttons]
80
+ const fieldKeys = Object.keys(fields)
81
+ for (let f = 0; f < fieldKeys.length; f++) {
82
+ let field=fields[f]
83
+ const keys = Object.keys(field)
84
+ for (let i = 0; i < keys.length; i++) {
85
+ const key = keys[i]
86
+ const elem = field[key]
87
+ if (elem.nodeid){
88
+ let format = this.formatString(elem.nodeid,options)
89
+ let monitoredItemId = await this.Subscribe(format)
90
+ this.buttons[monitoredItemId] = i
91
+ }
92
+ await this.monitorStates(elem,options)
81
93
  }
82
-
83
94
  }
84
95
  } catch (error) {
85
96
  this.LogError(`OPCUAIf: Error $error\n`)
86
97
  }
87
98
  }
88
99
 
100
+ /**
101
+ *
102
+ * @param {*} elem : Elem Object
103
+ * @param {*} options
104
+ */
105
+ async monitorStates(elem,options){
106
+ const stateKeys = Object.keys(elem.states)
107
+ for (let i = 0; i < stateKeys.length; i++) {
108
+ const key2 = stateKeys[i]
109
+ const state = elem.states[key2]
110
+ if (state.opcua){
111
+ let format = this.formatString(state.opcua,options)
112
+ let monitoredItemId = await this.Subscribe(format)
113
+ this.buttons[monitoredItemId] = i
114
+ }
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Convert the given value to the specified type.
120
+ * @param {*} value : The value to convert.
121
+ * @param {*} type : The type to convert to. Can be one of the following:
122
+ * - DataType.Int16
123
+ * - DataType.Int32
124
+ * - DataType.Float
125
+ * - DataType.String
126
+ * @returns the converted value.
127
+ */
128
+ convert(value,type){
129
+ switch(type){
130
+ case DataType.Int16:
131
+ case DataType.Int32:
132
+ if (typeof value == "number"){
133
+ if (Number.isInteger(value))
134
+ return value
135
+ else
136
+ return Math.trunc(value)
137
+ }
138
+ return parseInt(value,10)
139
+ break
140
+ case DataType.Float:
141
+ if (typeof value == "number")
142
+ return value
143
+ return parseFloat(value)
144
+ break;
145
+ case DataType.String:
146
+ if (typeof value == "number")
147
+ return value.toString();
148
+ return value
149
+ default:
150
+ return value
151
+ }
152
+ }
153
+
89
154
  async call (opcuaNode, options = {}) {
90
155
  var res = this.Check(options)
91
156
  if (res<0){
@@ -94,10 +159,15 @@ export class OPCUAIf extends BaseIf {
94
159
  }
95
160
 
96
161
  var nodeId = super.formatString(opcuaNode, options)
97
- var value = super.formatString(options.value, options)
98
162
 
99
- //this.LogInfo(`OPCUAIf: write ${nodeId} => ${value}\n`)
100
- await this.Write(nodeId,value)
163
+ var type = this.types[nodeId]
164
+ var value = options.value
165
+ if (typeof value == "string")
166
+ value = super.formatString(options.value, options)
167
+
168
+ var convertedValue = this.convert(value,type)
169
+ this.LogInfo(`OPCUAIf: write ${nodeId} => ${value}\n`)
170
+ await this.Write(nodeId,convertedValue,type)
101
171
 
102
172
  var NewState = "waiting"
103
173
  return NewState
@@ -109,13 +179,13 @@ export class OPCUAIf extends BaseIf {
109
179
  this.LogError(`OPCUAIf: mandatory parameter missing\n`)
110
180
  return res
111
181
  }
112
- if (!options.endpointurl){
182
+ if (!"endpointurl" in options){
113
183
  this.LogError(`OPCUAIf: mandatory parameter endpointurl missing\n`)
114
184
  return -11}
115
- if (!options.nodeid){
185
+ if (!"nodeid" in options){
116
186
  this.LogError(`OPCUAIf: mandatory parameter nodeid missing\n`)
117
187
  return -12}
118
- if (!options.value){
188
+ if (!"value" in options){
119
189
  this.LogError(`OPCUAIf: mandatory parameter value missing\n`)
120
190
  return -13}
121
191
  return 0
@@ -242,6 +312,9 @@ export class OPCUAIf extends BaseIf {
242
312
  monitoredItem.on("changed", function (dataValue) {
243
313
  var nodeId = self.monitoreditems[this.monitoredItemId]
244
314
  var buttonID = self.buttons[this.monitoredItemId]
315
+ // store the type of a nodeid in local dictionary
316
+ self.types[nodeId] = dataValue.value.dataType
317
+ // publish the value to subscribers:
245
318
  self.LogInfo(`OPCUAIf: monitored item changed: ${nodeId} => ${dataValue.value.value}\n`);
246
319
  self.emit('monitored item changed',buttonID,nodeId, dataValue.value.value)
247
320
  });
@@ -0,0 +1,5 @@
1
+ # Numbers Icons
2
+
3
+ Downloaded from:
4
+
5
+ - https://www.freepik.com/author/moniruldislam/icons/generic-color-lineal-color_10172?query=Number#from_element=families
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "loupedeck-commander",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "A system to ease working with LoupeDeck devices using CMD-line, OPC/UA or HTTP-client interfaces",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
7
- "test": "echo \"INFO: no test specified\" && exit 0",
7
+ "test": "node test.mjs",
8
8
  "lint": "echo \"INFO: no linter specified\" && exit 0",
9
9
  "format": "echo \"INFO: no format rule specified\" && exit 0",
10
10
  "start": "node index.mjs"
11
11
  },
12
12
  "dependencies": {
13
- "canvas": "^2.11.2",
14
- "loupedeck": "^6.0.1",
13
+ "canvas": "^3.1.0",
14
+ "loupedeck": "^7.0.0",
15
15
  "mkdirp": "^3.0.1",
16
- "node-opcua": "^2.138.1",
16
+ "node-opcua": "^2.153.0",
17
17
  "string-template": "^1.0.0"
18
18
  },
19
19
  "author": "Thomas Schneider",
package/profile-1.json CHANGED
@@ -228,7 +228,8 @@
228
228
  "knobBL": {
229
229
  "states": {
230
230
  "on": {
231
- "cmd": "echo \"{id} {state}\""
231
+ "cmd": "echo \"{id} {state}\"",
232
+ "opcua": "ns=2;s=Is{simnbr}.Audio.in.VolumeAccustic"
232
233
  }
233
234
  },
234
235
  "group": ""
@@ -258,117 +259,11 @@
258
259
  "group": ""
259
260
  }
260
261
  },
261
- "buttons": {
262
- "0": {
263
- "states": {
264
- "off": {
265
- "color": "#000000",
266
- "cmd": "echo \"{id} {state}\""
267
- },
268
- "on": {
269
- "color": "#550000",
270
- "cmd": "echo \"{id} {state}\""
271
- }
272
- },
273
- "group": ""
274
- },
275
- "1": {
276
- "states": {
277
- "off": {
278
- "color": "#000000",
279
- "cmd": "echo \"{id} {state}\""
280
- },
281
- "on": {
282
- "color": "#ff0000",
283
- "cmd": "echo \"{id} {state}\""
284
- }
285
- },
286
- "group": ""
287
- },
288
- "2": {
289
- "states": {
290
- "off": {
291
- "color": "#000000",
292
- "cmd": "echo \"{id} {state}\""
293
- },
294
- "on": {
295
- "color": "#005500",
296
- "cmd": "echo \"{id} {state}\""
297
- }
298
- },
299
- "group": ""
300
- },
301
- "3": {
302
- "states": {
303
- "off": {
304
- "color": "#000000",
305
- "cmd": "echo \"{id} {state}\""
306
- },
307
- "on": {
308
- "color": "#00ff00",
309
- "cmd": "echo \"{id} {state}\""
310
- }
311
- },
312
- "group": ""
313
- },
314
- "4": {
315
- "states": {
316
- "off": {
317
- "color": "#000000",
318
- "cmd": "echo \"{id} {state}\""
319
- },
320
- "on": {
321
- "color": "#000055",
322
- "cmd": "echo \"{id} {state}\""
323
- }
324
- },
325
- "group": ""
326
- },
327
- "5": {
328
- "states": {
329
- "off": {
330
- "color": "#000000",
331
- "cmd": "echo \"{id} {state}\""
332
- },
333
- "on": {
334
- "color": "#0000ff",
335
- "cmd": "echo \"{id} {state}\""
336
- }
337
- },
338
- "group": ""
339
- },
340
- "6": {
341
- "states": {
342
- "off": {
343
- "color": "#000000",
344
- "cmd": "echo \"{id} {state}\""
345
- },
346
- "on": {
347
- "color": "#555500",
348
- "cmd": "echo \"{id} {state}\""
349
- }
350
- },
351
- "group": ""
352
- },
353
- "7": {
354
- "states": {
355
- "off": {
356
- "color": "#000000",
357
- "cmd": "echo \"{id} {state}\""
358
- },
359
- "on": {
360
- "color": "#ffff00",
361
- "cmd": "echo \"{id} {state}\"",
362
- "http": "http://{hostname}:7778/control/connections",
363
- "opcua": "ns=4;s=Is{simnbr}.Kvm.out.Source"
364
- }
365
- },
366
- "group": ""
367
- }
368
- },
369
262
  "parameters": {
370
263
  "hostname": "127.0.0.1",
264
+ "simnbr": "1",
371
265
  "endpointurl": "opc.tcp://{hostname}:4840",
372
- "nodeid" : "ns=0;s=nodeID"
266
+ "nodeid" : "ns=0;s=nodeID",
267
+ "verbose": true
373
268
  }
374
269
  }
package/profile-2.json ADDED
@@ -0,0 +1,290 @@
1
+ {
2
+ "name": "profile-1",
3
+ "profile": "example",
4
+ "description": "",
5
+ "touch": {
6
+ "center": {
7
+ "0": {
8
+ "default": "one",
9
+ "states": {
10
+ "off": {
11
+ "color": "#000099",
12
+ "cmd": "echo \"{id} {state}\""
13
+ },
14
+ "one": {
15
+ "color": "#00ff00",
16
+ "image": "numbers/one_9278045.png",
17
+ "cmd": "echo \"{id} {state}\""
18
+ },
19
+ "two": {
20
+ "color": "#00ff00",
21
+ "image": "numbers/two_9278103.png",
22
+ "cmd": "echo \"{id} {state}\""
23
+ },
24
+ "three": {
25
+ "color": "#00ff00",
26
+ "image": "numbers/three_9278150.png",
27
+ "cmd": "echo \"{id} {state}\""
28
+ },
29
+ "four": {
30
+ "color": "#00ff00",
31
+ "image": "numbers/four_9278183.png",
32
+ "cmd": "echo \"{id} {state}\""
33
+ },
34
+ "five": {
35
+ "color": "#00ff00",
36
+ "image": "numbers/five_9278222.png",
37
+ "cmd": "echo \"{id} {state}\""
38
+ }
39
+ }
40
+ },
41
+ "1": {
42
+ "default": "two",
43
+ "states": {
44
+ "off": {
45
+ "color": "#000099",
46
+ "cmd": "echo \"{id} {state}\""
47
+ },
48
+ "one": {
49
+ "color": "#00ff00",
50
+ "image": "numbers/one_9278045.png",
51
+ "cmd": "echo \"{id} {state}\""
52
+ },
53
+ "two": {
54
+ "color": "#00ff00",
55
+ "image": "numbers/two_9278103.png",
56
+ "cmd": "echo \"{id} {state}\""
57
+ },
58
+ "three": {
59
+ "color": "#00ff00",
60
+ "image": "numbers/three_9278150.png",
61
+ "cmd": "echo \"{id} {state}\""
62
+ },
63
+ "four": {
64
+ "color": "#00ff00",
65
+ "image": "numbers/four_9278183.png",
66
+ "cmd": "echo \"{id} {state}\""
67
+ },
68
+ "five": {
69
+ "color": "#00ff00",
70
+ "image": "numbers/five_9278222.png",
71
+ "cmd": "echo \"{id} {state}\""
72
+ }
73
+ }
74
+ },
75
+ "2": {
76
+ "default": "three",
77
+ "states": {
78
+ "off": {
79
+ "color": "#000099",
80
+ "cmd": "echo \"{id} {state}\""
81
+ },
82
+ "one": {
83
+ "color": "#00ff00",
84
+ "image": "numbers/one_9278045.png",
85
+ "cmd": "echo \"{id} {state}\""
86
+ },
87
+ "two": {
88
+ "color": "#00ff00",
89
+ "image": "numbers/two_9278103.png",
90
+ "cmd": "echo \"{id} {state}\""
91
+ },
92
+ "three": {
93
+ "color": "#00ff00",
94
+ "image": "numbers/three_9278150.png",
95
+ "cmd": "echo \"{id} {state}\""
96
+ },
97
+ "four": {
98
+ "color": "#00ff00",
99
+ "image": "numbers/four_9278183.png",
100
+ "cmd": "echo \"{id} {state}\""
101
+ },
102
+ "five": {
103
+ "color": "#00ff00",
104
+ "image": "numbers/five_9278222.png",
105
+ "cmd": "echo \"{id} {state}\""
106
+ }
107
+ }
108
+ },
109
+ "3": {
110
+ "default": "four",
111
+ "states": {
112
+ "off": {
113
+ "color": "#000099",
114
+ "cmd": "echo \"{id} {state}\""
115
+ },
116
+ "one": {
117
+ "color": "#00ff00",
118
+ "image": "numbers/one_9278045.png",
119
+ "cmd": "echo \"{id} {state}\""
120
+ },
121
+ "two": {
122
+ "color": "#00ff00",
123
+ "image": "numbers/two_9278103.png",
124
+ "cmd": "echo \"{id} {state}\""
125
+ },
126
+ "three": {
127
+ "color": "#00ff00",
128
+ "image": "numbers/three_9278150.png",
129
+ "cmd": "echo \"{id} {state}\""
130
+ },
131
+ "four": {
132
+ "color": "#00ff00",
133
+ "image": "numbers/four_9278183.png",
134
+ "cmd": "echo \"{id} {state}\""
135
+ },
136
+ "five": {
137
+ "color": "#00ff00",
138
+ "image": "numbers/five_9278222.png",
139
+ "cmd": "echo \"{id} {state}\""
140
+ }
141
+ }
142
+ },
143
+ "4": {
144
+ "default": "five",
145
+ "states": {
146
+ "off": {
147
+ "color": "#000099",
148
+ "cmd": "echo \"{id} {state}\""
149
+ },
150
+ "one": {
151
+ "color": "#00ff00",
152
+ "image": "numbers/one_9278045.png",
153
+ "cmd": "echo \"{id} {state}\""
154
+ },
155
+ "two": {
156
+ "color": "#00ff00",
157
+ "image": "numbers/two_9278103.png",
158
+ "cmd": "echo \"{id} {state}\""
159
+ },
160
+ "three": {
161
+ "color": "#00ff00",
162
+ "image": "numbers/three_9278150.png",
163
+ "cmd": "echo \"{id} {state}\""
164
+ },
165
+ "four": {
166
+ "color": "#00ff00",
167
+ "image": "numbers/four_9278183.png",
168
+ "cmd": "echo \"{id} {state}\""
169
+ },
170
+ "five": {
171
+ "color": "#00ff00",
172
+ "image": "numbers/five_9278222.png",
173
+ "cmd": "echo \"{id} {state}\""
174
+ }
175
+ }
176
+ },
177
+ "5": {
178
+ "states": {
179
+ "off": {
180
+ "color": "#000099",
181
+ "cmd": "echo \"{id} {state}\""
182
+ },
183
+ "one": {
184
+ "color": "#00ff00",
185
+ "image": "numbers/one_9278045.png",
186
+ "cmd": "echo \"{id} {state}\""
187
+ },
188
+ "two": {
189
+ "color": "#00ff00",
190
+ "image": "numbers/two_9278103.png",
191
+ "cmd": "echo \"{id} {state}\""
192
+ },
193
+ "three": {
194
+ "color": "#00ff00",
195
+ "image": "numbers/three_9278150.png",
196
+ "cmd": "echo \"{id} {state}\""
197
+ },
198
+ "four": {
199
+ "color": "#00ff00",
200
+ "image": "numbers/four_9278183.png",
201
+ "cmd": "echo \"{id} {state}\""
202
+ },
203
+ "five": {
204
+ "color": "#00ff00",
205
+ "image": "numbers/five_9278222.png",
206
+ "cmd": "echo \"{id} {state}\""
207
+ }
208
+ }
209
+ }
210
+ },
211
+ "left": {
212
+ "0": {
213
+ "states": {
214
+ "on": {
215
+ "color": "#000000",
216
+ "cmd": "echo \"{id} {state}\""
217
+ }
218
+ }
219
+ }
220
+ },
221
+ "right": {
222
+ "0": {
223
+ "states": {
224
+ "on": {
225
+ "color": "#000000",
226
+ "cmd": "echo \"{id} {state}\""
227
+ }
228
+ }
229
+ }
230
+ }
231
+ },
232
+ "knobs": {
233
+ "knobTL": {
234
+ "states": {
235
+ "on": {
236
+ "cmd": "echo \"{id} {state}\""
237
+ }
238
+ },
239
+ "group": ""
240
+ },
241
+ "knobCL": {
242
+ "states": {
243
+ "on": {
244
+ "cmd": "echo \"{id} {state}\""
245
+ }
246
+ },
247
+ "group": ""
248
+ },
249
+ "knobBL": {
250
+ "states": {
251
+ "on": {
252
+ "cmd": "echo \"{id} {state}\"",
253
+ "opcua": "ns=2;s=Is{simnbr}.Audio.in.VolumeAccustic"
254
+ }
255
+ },
256
+ "group": ""
257
+ },
258
+ "knobTR": {
259
+ "states": {
260
+ "on": {
261
+ "cmd": "echo \"{id} {state}\""
262
+ }
263
+ },
264
+ "group": ""
265
+ },
266
+ "knobCR": {
267
+ "states": {
268
+ "on": {
269
+ "cmd": "echo \"{id} {state}\""
270
+ }
271
+ },
272
+ "group": ""
273
+ },
274
+ "knobBR": {
275
+ "states": {
276
+ "on": {
277
+ "cmd": "echo \"{id} {state}\""
278
+ }
279
+ },
280
+ "group": ""
281
+ }
282
+ },
283
+ "parameters": {
284
+ "hostname": "127.0.0.1",
285
+ "simnbr": "1",
286
+ "endpointurl": "opc.tcp://{hostname}:4840",
287
+ "nodeid" : "ns=0;s=nodeID",
288
+ "verbose": true
289
+ }
290
+ }
@@ -0,0 +1,373 @@
1
+ {
2
+ "name": "profile-1",
3
+ "profile": "example",
4
+ "description": "",
5
+ "touch": {
6
+ "center": {
7
+ "0": {
8
+ "states": {
9
+ "off": {
10
+ "color": "#000099",
11
+ "image": "icons/home.png",
12
+ "cmd": "echo \"{id} {state}\""
13
+ },
14
+ "on": {
15
+ "color": "#00ff00",
16
+ "image": "icons/home.png",
17
+ "cmd": "echo \"{id} {state}\""
18
+ }
19
+ },
20
+ "group": ""
21
+ },
22
+ "1": {
23
+ "states": {
24
+ "off": {
25
+ "color": "#000099",
26
+ "image": "icons/home.png",
27
+ "cmd": "echo \"{id} {state}\""
28
+ },
29
+ "on": {
30
+ "color": "#00ff00",
31
+ "image": "icons/home.png",
32
+ "cmd": "echo \"{id} {state}\""
33
+ }
34
+ },
35
+ "group": ""
36
+ },
37
+ "2": {
38
+ "states": {
39
+ "off": {
40
+ "color": "#000099",
41
+ "image": "icons/home.png",
42
+ "cmd": "echo \"{id} {state}\""
43
+ },
44
+ "on": {
45
+ "color": "#00ff00",
46
+ "image": "icons/home.png",
47
+ "cmd": "echo \"{id} {state}\""
48
+ }
49
+ },
50
+ "group": ""
51
+ },
52
+ "3": {
53
+ "states": {
54
+ "off": {
55
+ "color": "#000099",
56
+ "image": "icons/home.png",
57
+ "cmd": "echo \"{id} {state}\""
58
+ },
59
+ "on": {
60
+ "color": "#00ff00",
61
+ "image": "icons/home.png",
62
+ "cmd": "echo \"{id} {state}\""
63
+ }
64
+ },
65
+ "group": ""
66
+ },
67
+ "4": {
68
+ "states": {
69
+ "off": {
70
+ "color": "#000099",
71
+ "image": "icons/home.png",
72
+ "cmd": "echo \"{id} {state}\""
73
+ },
74
+ "on": {
75
+ "color": "#00ff00",
76
+ "image": "icons/home.png",
77
+ "cmd": "echo \"{id} {state}\""
78
+ }
79
+ },
80
+ "group": ""
81
+ },
82
+ "5": {
83
+ "states": {
84
+ "off": {
85
+ "color": "#000099",
86
+ "image": "icons/home.png",
87
+ "cmd": "echo \"{id} {state}\""
88
+ },
89
+ "on": {
90
+ "color": "#00ff00",
91
+ "image": "icons/home.png",
92
+ "cmd": "echo \"{id} {state}\""
93
+ }
94
+ },
95
+ "group": ""
96
+ },
97
+ "6": {
98
+ "states": {
99
+ "off": {
100
+ "color": "#000099",
101
+ "image": "icons/home.png",
102
+ "cmd": "echo \"{id} {state}\""
103
+ },
104
+ "on": {
105
+ "color": "#00ff00",
106
+ "image": "icons/home.png",
107
+ "cmd": "echo \"{id} {state}\""
108
+ }
109
+ },
110
+ "group": ""
111
+ },
112
+ "7": {
113
+ "states": {
114
+ "off": {
115
+ "color": "#000099",
116
+ "image": "icons/home.png",
117
+ "cmd": "echo \"{id} {state}\""
118
+ },
119
+ "on": {
120
+ "color": "#00ff00",
121
+ "image": "icons/home.png",
122
+ "cmd": "echo \"{id} {state}\""
123
+ }
124
+ },
125
+ "group": ""
126
+ },
127
+ "8": {
128
+ "states": {
129
+ "off": {
130
+ "color": "#000099",
131
+ "image": "icons/home.png",
132
+ "cmd": "echo \"{id} {state}\""
133
+ },
134
+ "on": {
135
+ "color": "#00ff00",
136
+ "image": "icons/home.png",
137
+ "cmd": "echo \"{id} {state}\""
138
+ }
139
+ },
140
+ "group": ""
141
+ },
142
+ "9": {
143
+ "states": {
144
+ "off": {
145
+ "color": "#000099",
146
+ "image": "icons/home.png",
147
+ "cmd": "echo \"{id} {state}\""
148
+ },
149
+ "on": {
150
+ "color": "#00ff00",
151
+ "image": "icons/home.png",
152
+ "cmd": "echo \"{id} {state}\""
153
+ }
154
+ },
155
+ "group": ""
156
+ },
157
+ "10": {
158
+ "states": {
159
+ "off": {
160
+ "color": "#000099",
161
+ "image": "icons/home.png",
162
+ "cmd": "echo \"{id} {state}\""
163
+ },
164
+ "on": {
165
+ "color": "#00ff00",
166
+ "image": "icons/home.png",
167
+ "cmd": "echo \"{id} {state}\""
168
+ }
169
+ },
170
+ "group": ""
171
+ },
172
+ "11": {
173
+ "states": {
174
+ "off": {
175
+ "color": "#000099",
176
+ "image": "icons/home.png",
177
+ "cmd": "echo \"{id} {state}\""
178
+ },
179
+ "on": {
180
+ "color": "#00ff00",
181
+ "image": "icons/home.png",
182
+ "cmd": "echo \"{id} {state}\""
183
+ }
184
+ },
185
+ "group": ""
186
+ }
187
+ },
188
+ "left": {
189
+ "0": {
190
+ "states": {
191
+ "on": {
192
+ "color": "#000000",
193
+ "cmd": "echo \"{id} {state}\""
194
+ }
195
+ },
196
+ "group": ""
197
+ }
198
+ },
199
+ "right": {
200
+ "0": {
201
+ "states": {
202
+ "on": {
203
+ "color": "#000000",
204
+ "cmd": "echo \"{id} {state}\""
205
+ }
206
+ },
207
+ "group": ""
208
+ }
209
+ }
210
+ },
211
+ "knobs": {
212
+ "knobTL": {
213
+ "states": {
214
+ "on": {
215
+ "cmd": "echo \"{id} {state}\""
216
+ }
217
+ },
218
+ "group": ""
219
+ },
220
+ "knobCL": {
221
+ "states": {
222
+ "on": {
223
+ "cmd": "echo \"{id} {state}\""
224
+ }
225
+ },
226
+ "group": ""
227
+ },
228
+ "knobBL": {
229
+ "states": {
230
+ "on": {
231
+ "cmd": "echo \"{id} {state}\""
232
+ }
233
+ },
234
+ "group": ""
235
+ },
236
+ "knobTR": {
237
+ "states": {
238
+ "on": {
239
+ "cmd": "echo \"{id} {state}\""
240
+ }
241
+ },
242
+ "group": ""
243
+ },
244
+ "knobCR": {
245
+ "states": {
246
+ "on": {
247
+ "cmd": "echo \"{id} {state}\""
248
+ }
249
+ },
250
+ "group": ""
251
+ },
252
+ "knobBR": {
253
+ "states": {
254
+ "on": {
255
+ "cmd": "echo \"{id} {state}\""
256
+ }
257
+ },
258
+ "group": ""
259
+ }
260
+ },
261
+ "buttons": {
262
+ "0": {
263
+ "states": {
264
+ "off": {
265
+ "color": "#000000",
266
+ "cmd": "echo \"{id} {state}\""
267
+ },
268
+ "on": {
269
+ "color": "#550000",
270
+ "cmd": "echo \"{id} {state}\""
271
+ }
272
+ },
273
+ "group": ""
274
+ },
275
+ "1": {
276
+ "states": {
277
+ "off": {
278
+ "color": "#000000",
279
+ "cmd": "echo \"{id} {state}\""
280
+ },
281
+ "on": {
282
+ "color": "#ff0000",
283
+ "cmd": "echo \"{id} {state}\""
284
+ }
285
+ },
286
+ "group": ""
287
+ },
288
+ "2": {
289
+ "states": {
290
+ "off": {
291
+ "color": "#000000",
292
+ "cmd": "echo \"{id} {state}\""
293
+ },
294
+ "on": {
295
+ "color": "#005500",
296
+ "cmd": "echo \"{id} {state}\""
297
+ }
298
+ },
299
+ "group": ""
300
+ },
301
+ "3": {
302
+ "states": {
303
+ "off": {
304
+ "color": "#000000",
305
+ "cmd": "echo \"{id} {state}\""
306
+ },
307
+ "on": {
308
+ "color": "#00ff00",
309
+ "cmd": "echo \"{id} {state}\""
310
+ }
311
+ },
312
+ "group": ""
313
+ },
314
+ "4": {
315
+ "states": {
316
+ "off": {
317
+ "color": "#000000",
318
+ "cmd": "echo \"{id} {state}\""
319
+ },
320
+ "on": {
321
+ "color": "#000055",
322
+ "cmd": "echo \"{id} {state}\""
323
+ }
324
+ },
325
+ "group": ""
326
+ },
327
+ "5": {
328
+ "states": {
329
+ "off": {
330
+ "color": "#000000",
331
+ "cmd": "echo \"{id} {state}\""
332
+ },
333
+ "on": {
334
+ "color": "#0000ff",
335
+ "cmd": "echo \"{id} {state}\""
336
+ }
337
+ },
338
+ "group": ""
339
+ },
340
+ "6": {
341
+ "states": {
342
+ "off": {
343
+ "color": "#000000",
344
+ "cmd": "echo \"{id} {state}\""
345
+ },
346
+ "on": {
347
+ "color": "#555500",
348
+ "cmd": "echo \"{id} {state}\""
349
+ }
350
+ },
351
+ "group": ""
352
+ },
353
+ "7": {
354
+ "states": {
355
+ "off": {
356
+ "color": "#000000",
357
+ "cmd": "echo \"{id} {state}\""
358
+ },
359
+ "on": {
360
+ "color": "#ffff00",
361
+ "cmd": "echo \"{id} {state}\""
362
+ }
363
+ },
364
+ "group": ""
365
+ }
366
+ },
367
+ "parameters": {
368
+ "hostname": "127.0.0.1",
369
+ "endpointurl": "opc.tcp://{hostname}:4840",
370
+ "nodeid": "ns=0;s=nodeID"
371
+ },
372
+ "loaded": false
373
+ }