loupedeck-commander 1.2.8 → 1.2.10

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.
File without changes
File without changes
@@ -456,10 +456,13 @@ export class Button {
456
456
  state : key,
457
457
  ...state
458
458
  }
459
- let val1 = format(state.value,params)
460
- if (val1 === val.toString()){
461
- this.#index = i;
462
- break;
459
+ if (state && state.value !== undefined){
460
+ let strVal = state.value.toString()
461
+ let val1 = format(strVal,params)
462
+ if (val1 === val?.toString()){
463
+ this.#index = i;
464
+ break;
465
+ }
463
466
  }
464
467
  //break;
465
468
  }
package/common/utils.mjs CHANGED
File without changes
package/config.json CHANGED
@@ -4,10 +4,6 @@
4
4
  {
5
5
  "name": "profile-1",
6
6
  "file": "profile-1.json"
7
- },
8
- {
9
- "name": "profile-2",
10
- "file": "profile-2.json"
11
7
  }
12
8
  ]
13
9
  }
@@ -33,6 +33,7 @@ export class OPCUAIf extends BaseIf {
33
33
  #sub
34
34
  #connected
35
35
  #endpointurl
36
+ #publishingInterval
36
37
  monitoreditems
37
38
  types
38
39
  buttons
@@ -40,14 +41,14 @@ export class OPCUAIf extends BaseIf {
40
41
  super()
41
42
 
42
43
  this.LogInfo(`OPCUAIf Constructed`);
43
- }
44
+ }
44
45
 
45
- async stop(){
46
+ async stop() {
46
47
  if (!this.#client)
47
48
  return
48
-
49
+
49
50
  this.LogInfo(`OPCUAIf Stopping\n`)
50
- await this.#client.closeSession(this.#session,true)
51
+ await this.#client.closeSession(this.#session, true)
51
52
  await this.#client.disconnect()
52
53
  this.#connected = false
53
54
  this.#client = null
@@ -60,41 +61,49 @@ export class OPCUAIf extends BaseIf {
60
61
  * @param {*} config
61
62
  * @param {*} callbackFunction
62
63
  */
63
- async init( options = {},config = {}){
64
+ async init(options = {}, config = {}) {
64
65
  var res = this.Check(options)
65
- if (res<0){
66
+ if (res < 0) {
66
67
  this.LogError(`OPCUAIf: Missing essential options in dictionary => Quitting $res $options\n`)
67
68
  }
68
- try{
69
- this.#endpointurl = this.formatString(options.endpointurl,options)
69
+ try {
70
+ this.#endpointurl = this.formatString(options.endpointurl, options)
71
+ if (options.publishingInterval)
72
+ this.#publishingInterval = options.publishingInterval
73
+ else{
74
+ this.#publishingInterval = 250;
75
+ this.LogInfo(`OPCUAIf init using default publishingInterval: ${this.#publishingInterval}ms\n`);
76
+ }
70
77
  this.monitoreditems = {}
71
78
  this.types = {}
72
79
  this.buttons = {}
73
80
  this.LogInfo(`OPCUAIf init ${this.#endpointurl}\n`);
74
-
81
+
75
82
  await this.Connect(this.#endpointurl);
76
83
 
77
84
  let fields = [config.touch.center, config.knobs, config.buttons]
78
85
  const fieldKeys = Object.keys(fields)
79
86
  for (let f = 0; f < fieldKeys.length; f++) {
80
- let field=fields[f]
87
+ let field = fields[f]
81
88
  const keys = Object.keys(field)
82
89
  for (let i = 0; i < keys.length; i++) {
83
90
  const key = keys[i]
84
91
  const elem = field[key]
85
92
  // groupnode
86
- if (elem.nodeid){
87
- let format = this.formatString(elem.nodeid,options)
88
- let monitoredItemId = await this.Subscribe(format)
93
+ if (elem.nodeid) {
94
+ options["key"] = key
95
+ let formattedNodeId = this.formatString(elem.nodeid, options)
96
+ let monitoredItemId = await this.Subscribe(formattedNodeId)
97
+ console.log("Subscribe to",formattedNodeId)
89
98
  this.buttons[monitoredItemId] = i
90
99
  }
91
100
  // statenode
92
- if (elem.statenodeid){
93
- let format = this.formatString(elem.statenodeid,options)
101
+ if (elem.statenodeid) {
102
+ let format = this.formatString(elem.statenodeid, options)
94
103
  let monitoredItemId = await this.Subscribe(format)
95
104
  this.buttons[monitoredItemId] = i
96
105
  }
97
- await this.monitorStates(elem,options)
106
+ await this.monitorStates(elem, options)
98
107
  }
99
108
  }
100
109
  } catch (error) {
@@ -107,17 +116,17 @@ export class OPCUAIf extends BaseIf {
107
116
  * @param {*} elem : Elem Object
108
117
  * @param {*} options
109
118
  */
110
- async monitorStates(elem,options){
119
+ async monitorStates(elem, options) {
111
120
  const stateKeys = Object.keys(elem.states)
112
121
  for (let i = 0; i < stateKeys.length; i++) {
113
122
  const key2 = stateKeys[i]
114
123
  const state = elem.states[key2]
115
- if (state.opcua){
116
- let format = this.formatString(state.opcua,options)
124
+ if (state.opcua) {
125
+ let format = this.formatString(state.opcua, options)
117
126
  let monitoredItemId = await this.Subscribe(format)
118
127
  this.buttons[monitoredItemId] = i
119
128
  }
120
- }
129
+ }
121
130
  }
122
131
 
123
132
  /**
@@ -130,17 +139,17 @@ export class OPCUAIf extends BaseIf {
130
139
  * - DataType.String
131
140
  * @returns the converted value.
132
141
  */
133
- convert(value,type){
134
- switch(type){
142
+ convert(value, type) {
143
+ switch (type) {
135
144
  case DataType.Int16:
136
145
  case DataType.Int32:
137
- if (typeof value == "number"){
146
+ if (typeof value == "number") {
138
147
  if (Number.isInteger(value))
139
148
  return value
140
- else
149
+ else
141
150
  return Math.trunc(value)
142
151
  }
143
- return parseInt(value,10)
152
+ return parseInt(value, 10)
144
153
  break
145
154
  case DataType.Float:
146
155
  if (typeof value == "number")
@@ -154,8 +163,8 @@ export class OPCUAIf extends BaseIf {
154
163
  case DataType.Boolean:
155
164
  if (typeof value == "number" && value === 1)
156
165
  return true
157
- if (typeof value == "string"){
158
- if (["true","on"].includes(value)){
166
+ if (typeof value == "string") {
167
+ if (["true", "on"].includes(value)) {
159
168
  return true
160
169
  }
161
170
  }
@@ -165,10 +174,10 @@ export class OPCUAIf extends BaseIf {
165
174
  }
166
175
  }
167
176
 
168
- async call (opcuaNode, options = {}) {
177
+ async call(opcuaNode, options = {}) {
169
178
  var res = this.Check(options)
170
- if (res<0){
171
- // this.LogError(`OPCUAIf call: Missing essential options in dictionary => Quitting $res\n`)
179
+ if (res < 0) {
180
+ // this.LogError(`OPCUAIf call: Missing essential options in dictionary => Quitting $res\n`)
172
181
  return false
173
182
  }
174
183
 
@@ -179,45 +188,59 @@ export class OPCUAIf extends BaseIf {
179
188
  if (typeof value == "string")
180
189
  value = super.formatString(options.value, options)
181
190
 
182
- var convertedValue = this.convert(value,type)
191
+ var convertedValue = this.convert(value, type)
183
192
  this.LogInfo(`OPCUAIf: write ${nodeId} => ${value}\n`)
184
- await this.Write(nodeId,convertedValue,type)
193
+ await this.Write(nodeId, convertedValue, type)
185
194
 
186
195
  var NewState = "waiting"
187
196
  return NewState
188
197
  }
189
198
 
190
199
  Check(options) {
191
- var res= super.Check(options)
192
- if (res <0){
193
- this.LogError(`OPCUAIf: mandatory parameter missing\n`)
200
+ var res = super.Check(options)
201
+ if (res < 0) {
202
+ this.LogError(`OPCUAIf: mandatory parameter missing\n`)
194
203
  return res
195
204
  }
196
- if (!"endpointurl" in options){
197
- this.LogError(`OPCUAIf: mandatory parameter endpointurl missing\n`)
198
- return -11}
199
- if (!"nodeid" in options){
200
- this.LogError(`OPCUAIf: mandatory parameter nodeid missing\n`)
201
- return -12}
202
- if (!"value" in options){
203
- this.LogError(`OPCUAIf: mandatory parameter value missing\n`)
204
- return -13}
205
+ if (!"endpointurl" in options) {
206
+ this.LogError(`OPCUAIf: mandatory parameter endpointurl missing\n`)
207
+ return -11
208
+ }
209
+ if (!"publishingInterval" in options) {
210
+ this.LogError(`OPCUAIf: mandatory parameter publishingInterval missing\n`)
211
+ return -11
212
+ }
213
+ if (!"nodeid" in options) {
214
+ this.LogError(`OPCUAIf: mandatory parameter nodeid missing\n`)
215
+ return -12
216
+ }
217
+ if (!"value" in options) {
218
+ this.LogError(`OPCUAIf: mandatory parameter value missing\n`)
219
+ return -13
220
+ }
205
221
  return 0
206
222
  }
207
223
 
208
224
  async Disconnect() {
209
- if (this.#client){
225
+ if (this.#client) {
210
226
  this.LogInfo(`OPCUAIf: Disconnect\n`);
211
- await this.#client.Disconnect()
227
+ if (this.#session)
228
+ await this.#client.closeSession(this.#session,true)
229
+ this.#session = undefined
230
+ this.#client = undefined
212
231
  this.LogInfo(`OPCUAIf: Disconnected\n`);
213
232
  }
214
233
  }
215
234
  async Connect(url) {
216
235
  let self = this
236
+ if (this.#client){
237
+ console.log("Closing session first")
238
+ await this.Disconnect()
239
+ }
240
+
217
241
  this.#client = OPCUAClient.create({
218
242
  applicationName: "NodeOPCUA-Client",
219
-
220
- endpointMustExist: false,
243
+ endpointMustExist: true,
221
244
  // keepSessionAlive: true,
222
245
  requestedSessionTimeout: 60 * 1000,
223
246
  securityMode: MessageSecurityMode.None,
@@ -227,44 +250,45 @@ export class OPCUAIf extends BaseIf {
227
250
  maxDelay: 5000,
228
251
  initialDelay: 2500
229
252
  },
230
-
253
+
231
254
  defaultSecureTokenLifetime: 20000,
232
255
  tokenRenewalInterval: 1000
233
256
  });
234
257
 
258
+
235
259
  this.#client.on("backoff", (retry, delay) => {
236
- if((retry%10) == 0)
237
- self.LogInfo(`OPCUAIf Try Reconnection ${retry} next attempt in ${delay}ms ${self.#endpointurl}\n`);
260
+ //if ((retry % 10) == 0)
261
+ // self.LogInfo(`OPCUAIf Try Reconnection ${retry} next attempt in ${delay}ms ${self.#endpointurl}\n`);
238
262
  });
239
-
263
+
240
264
  this.#client.on("connection_lost", () => {
241
265
  self.LogInfo(`OPCUAIf: Connection lost\n`);
242
266
  });
243
-
267
+
244
268
  this.#client.on("connection_reestablished", () => {
245
269
  self.LogInfo(`OPCUAIf: Connection re-established\n`);
246
270
  });
247
-
271
+
248
272
  this.#client.on("connection_failed", () => {
249
273
  self.LogInfo(`OPCUAIf: Connection failed\n`);
250
274
  });
251
275
  this.#client.on("start_reconnection", () => {
252
276
  self.LogInfo(`OPCUAIf: Starting reconnection\n`);
253
277
  });
254
-
278
+
255
279
  this.#client.on("after_reconnection", (err) => {
256
280
  self.LogInfo(`OPCUAIf: After Reconnection event => ${err}\n`);
257
281
  });
258
282
  this.#client.on("security_token_renewed", () => {
259
283
  self.LogDebug(`OPCUAIf: security_token_renewed\n`);
260
284
  })
261
- this.#client.on("lifetime_75", (token) => {})
262
-
285
+ this.#client.on("lifetime_75", (token) => { })
286
+
263
287
  this.LogInfo(`OPCUAIf: connecting client to ${url}\n`);//, this.#session.toString());
264
288
  await this.#client.connect(url);
265
-
289
+
266
290
  this.#session = await this.#client.createSession();
267
-
291
+
268
292
  this.#session.on("session_closed", (statusCode) => {
269
293
  self.LogInfo(`OPCUAIf: Session has been closed\n`);
270
294
  })
@@ -277,13 +301,14 @@ export class OPCUAIf extends BaseIf {
277
301
  this.#session.on("keepalive_failure", () => {
278
302
  self.LogInfo(`OPCUAIf: KeepAlive failure\n`);
279
303
  });
280
-
304
+
305
+ // create subscription with a custom publishing interval:
281
306
  this.#sub = await this.#session.createSubscription2({
282
307
  maxNotificationsPerPublish: 9000,
283
308
  publishingEnabled: true,
284
309
  requestedLifetimeCount: 10,
285
310
  requestedMaxKeepAliveCount: 10,
286
- requestedPublishingInterval: 1000
311
+ requestedPublishingInterval: this.#publishingInterval
287
312
  });
288
313
 
289
314
  this.LogInfo(`OPCUAIf: session created\n`);//, this.#session.toString());
@@ -292,7 +317,7 @@ export class OPCUAIf extends BaseIf {
292
317
  this.#connected = true
293
318
  this.#endpointurl = url
294
319
  }
295
-
320
+
296
321
  async Subscribe(nodeID) {
297
322
  // install monitored item
298
323
 
@@ -300,7 +325,7 @@ export class OPCUAIf extends BaseIf {
300
325
  for (let i = 0; i < keys.length; i++) {
301
326
  const key = keys[i]
302
327
  const elem = this.monitoreditems[key]
303
- if (elem == nodeID){
328
+ if (elem == nodeID) {
304
329
  // already registered => return itemid
305
330
  return key
306
331
  }
@@ -315,14 +340,14 @@ export class OPCUAIf extends BaseIf {
315
340
  discardOldest: true,
316
341
  queueSize: 10
317
342
  };
318
-
319
- if (!this.#sub){
343
+
344
+ if (!this.#sub) {
320
345
  this.LogError(`OPCUAIf: not register monitored items $itemToMonitor\n`);
321
346
  return
322
347
  }
323
348
  const monitoredItem = await this.#sub.monitor(itemToMonitor, monitoringParameters, TimestampsToReturn.Both);
324
349
  this.monitoreditems[monitoredItem.monitoredItemId] = nodeID
325
- var self=this
350
+ var self = this
326
351
  monitoredItem.on("changed", function (dataValue) {
327
352
  var nodeId = self.monitoreditems[this.monitoredItemId]
328
353
  var buttonID = self.buttons[this.monitoredItemId]
@@ -330,55 +355,59 @@ export class OPCUAIf extends BaseIf {
330
355
  self.types[nodeId] = dataValue.value.dataType
331
356
  // publish the value to subscribers:
332
357
  self.LogInfo(`OPCUAIf: monitored item changed: ${nodeId} => ${dataValue.value.value}\n`);
333
- self.emit('monitored item changed',buttonID,nodeId, dataValue.value.value)
358
+ self.emit('monitored item changed', buttonID, nodeId, dataValue.value.value)
334
359
  });
335
360
 
336
361
  return monitoredItem.monitoredItemId;
337
362
  }
338
-
363
+
339
364
  async Read(nodeID) {
340
365
  const nodeToRead = {
341
366
  nodeId: nodeID,
342
367
  attributeId: AttributeIds.Value
343
368
  };
344
- if (!this.#connected){
369
+ if (!this.#connected) {
345
370
  this.LogError(`OPCUAIf: not connected, cannot read ${nodeID}\n`);
346
371
  return
347
372
  }
348
373
  const dataValue2 = await this.#session.read(nodeToRead, 0);
349
- this.LogError("OPCUAIf: read nodeID ",nodeID, dataValue2.toString(),"\n");
374
+ this.LogError("OPCUAIf: read nodeID ", nodeID, dataValue2.toString(), "\n");
350
375
  return dataValue2
351
376
  }
352
377
 
353
- async Write(nodeID,value,datatype=DataType.String) {
378
+ async Write(nodeID, value, datatype = DataType.String) {
354
379
  let self = this
355
- if (!this.#connected){
356
- self.LogError("OPCUAIf: not connected, cannot write",nodeID, value,"\n");
380
+ if (!this.#connected) {
381
+ self.LogError("OPCUAIf: not connected, cannot write", nodeID, value, "\n");
357
382
  return
358
383
  }
359
384
  var nodesToWrite = [{
360
385
  nodeId: nodeID,
361
386
  attributeId: AttributeIds.Value,
362
387
  indexRange: null,
363
- value: {
364
- value: {
388
+ value: {
389
+ value: {
365
390
  dataType: datatype,
366
391
  value: value
367
392
  }
368
- }
393
+ }
369
394
  }];
370
- await this.#session.write(nodesToWrite, function(err,statusCodes) {
371
- if (!err) {
372
- if (statusCodes && statusCodes[0].value != 0){
373
- self.LogInfo(`OPCUAIf: error with Node: "${nodeID}", status ${statusCodes[0]}\n`);
374
- }else{
375
- self.LogInfo(`OPCUAIf: wrote ${nodeID} => ${value}\n`);
395
+ try {
396
+ await this.#session.write(nodesToWrite, function (err, statusCodes) {
397
+ if (!err) {
398
+ if (statusCodes && statusCodes[0].value != 0) {
399
+ self.LogInfo(`OPCUAIf: error with Node: "${nodeID}", status ${statusCodes[0]}\n`);
400
+ } else {
401
+ self.LogInfo(`OPCUAIf: wrote ${nodeID} => ${value}\n`);
402
+ }
403
+ } else {
404
+ self.LogError("OPCUAIf: write NOT ok", nodeID, value, "\n");
405
+ self.LogError(err)
376
406
  }
377
- }else{
378
- self.LogError("OPCUAIf: write NOT ok",nodeID, value,"\n");
379
- self.LogError(err)
380
- }
381
- });
407
+ });
408
+ } catch (err) {
409
+ self.LogError("OPCUAIf: write NOT ok", nodeID, value, "\n");
410
+ self.LogError(err)
411
+ }
382
412
  }
383
413
  }
384
-
@@ -6,23 +6,23 @@ import { BaseIf } from './baseif.mjs'
6
6
  * Our Special-Handler just used the Default - and adds Vibration after triggers through Button-Releases
7
7
  */
8
8
  export class SHELLif extends BaseIf {
9
- async call (cmd, options = {}) {
9
+ async call(cmd, options = {}) {
10
10
  var res = this.Check(options)
11
- if (res<0){
12
- return false
11
+ if (res < 0) {
12
+ return false
13
13
  }
14
14
  let formattedCmd = super.call(cmd, options)
15
15
  return await this.sh(formattedCmd)
16
16
  }
17
17
 
18
- async stop(){
18
+ async stop() {
19
19
  this.LogInfo("SHELLif: Stopping")
20
20
  }
21
21
 
22
22
  Check(options) {
23
- var res= super.Check(options)
24
- if (res <0){
25
- this.LogError(`SHELLif: mandatory parameter missing\n`)
23
+ var res = super.Check(options)
24
+ if (res < 0) {
25
+ this.LogError(`SHELLif: mandatory parameter missing\n`)
26
26
  return res
27
27
  }
28
28
  }
@@ -32,22 +32,27 @@ export class SHELLif extends BaseIf {
32
32
  * @param {*} cmd
33
33
  * @returns
34
34
  */
35
- async sh (cmd) {
36
- let self = this;
35
+ async sh(cmd) {
36
+ let self = this;
37
37
  this.LogDebug(`ShellIf: runCmd: ${cmd}\n`)
38
-
38
+
39
39
  return new Promise(function (resolve, reject) {
40
- exec(cmd, (err, stdout, stderr) => {
41
- if (stdout.length>0)
42
- self.LogInfo(`SHELLif Out: ${stdout}`)
43
- if (stderr.length>0)
44
- self.LogError(`SHELLif Err: ${stderr}`)
45
- if (err) {
46
- reject(err)
47
- } else {
48
- resolve({ stdout, stderr })
49
- }
50
- })
40
+ try {
41
+ exec(cmd, (err, stdout, stderr) => {
42
+ if (stdout.length > 0)
43
+ self.LogInfo(`SHELLif Out: ${stdout}`)
44
+ if (stderr.length > 0)
45
+ self.LogError(`SHELLif Err: ${stderr}`)
46
+ if (err) {
47
+ resolve(err)
48
+ } else {
49
+ resolve({ stdout, stderr })
50
+ }
51
+ })
52
+ } catch (e) {
53
+ console.error(`Error in script: ${e}`)
54
+ resolve()
55
+ }
51
56
  })
52
57
  }
53
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loupedeck-commander",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
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": {
package/profile-1.json CHANGED
@@ -229,7 +229,7 @@
229
229
  "states": {
230
230
  "on": {
231
231
  "cmd": "echo \"{id} {state}\"",
232
- "opcua": "ns=2;s=Is{simnbr}.Audio.in.VolumeAccustic"
232
+ "opcua": "ns=1;s={simnbr}.Function1"
233
233
  }
234
234
  },
235
235
  "group": ""
@@ -263,6 +263,7 @@
263
263
  "hostname": "127.0.0.1",
264
264
  "simnbr": "1",
265
265
  "endpointurl": "opc.tcp://{hostname}:4840",
266
+ "publishingInterval" : 200,
266
267
  "nodeid" : "ns=0;s=nodeID",
267
268
  "verbose": true
268
269
  }