loupedeck-commander 1.0.1 → 1.2.0

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.
@@ -1,16 +1,37 @@
1
1
  import { loadImage } from 'canvas'
2
- import { sh } from './cmd-executer.mjs'
2
+
3
+ import * as shellif from '../interfaces/shellif.mjs'
4
+ import * as httpif from '../interfaces/httpif.mjs'
5
+ import * as opcuaif from '../interfaces/opcuaif.mjs'
3
6
  import format from 'string-template'
4
7
  import { calcDelta } from './utils.mjs'
5
8
 
6
- const ButtonStyle = {
7
- NONE: 0,
8
- IMAGE: 1,
9
- COLOR: 2,
10
- TEXT: 3,
11
- PHYSICAL: 3
9
+ export var opcuainterface = undefined
10
+ var httpinterface = undefined
11
+ var shellinterface = undefined
12
+
13
+ export async function InitializeInterfaces(appConfig,callbackFunction){
14
+ if (opcuainterface === undefined ){
15
+ opcuainterface = new opcuaif.OPCUAIf()
16
+ opcuainterface.init(appConfig.parameters,appConfig,callbackFunction)
17
+ }
18
+ if (httpinterface === undefined)
19
+ httpinterface = new httpif.HTTPif()
20
+ if (shellinterface === undefined)
21
+ shellinterface = new shellif.SHELLif()
22
+
12
23
  }
13
24
 
25
+ export async function StopInterfaces(){
26
+ if (opcuainterface !== undefined )
27
+ await opcuainterface.stop()
28
+ if (httpinterface !== undefined)
29
+ await httpinterface.stop()
30
+ if (shellinterface !== undefined)
31
+ await shellinterface.stop()
32
+
33
+ }
34
+
14
35
  export const ButtonIndex = {
15
36
  BUTN_0: 0,
16
37
  BUTN_1: 1,
@@ -29,35 +50,69 @@ const ButtonType = {
29
50
  PUSH: 'PUSH'
30
51
  }
31
52
 
32
- export class TouchButtonField {
33
- #buttons = []
53
+ export class ButtonField {
54
+ #buttons = {}
55
+ #screen
34
56
  width = 0
35
57
  height = 0
36
58
  #rows = 0
37
59
  #columns = 0
60
+ #keys = []
61
+ #type
38
62
  #name
39
- constructor (name, rows, columns, width, height, data) {
40
- console.info(`TouchButtonField ${name.padEnd(10, ' ')} Buttons: ${rows} x ${columns} , Pixels ${width} x ${height}`)
63
+ #config
64
+
65
+ constructor (name, rows, columns, width, height, data, config) {
66
+ console.info(`ButtonField ${name.padEnd(10, ' ')} Buttons: ${rows} x ${columns} , Pixels ${width} x ${height}`)
41
67
  this.#name = name
42
68
  this.width = width
43
69
  this.height = height
44
70
  this.#rows = rows
45
71
  this.#columns = columns
46
- for (let i = 0; i < rows * columns; i++) {
47
- const tb = new TouchButton(`touch-${i}`, width / columns, height / rows, data[i])
48
- this.#buttons.push(tb)
72
+ this.#screen = this.width > 0 && this.height > 0
73
+ this.#type = 'button'
74
+ if (this.#screen) { this.#type = 'touch' }
75
+
76
+ const keys = Object.keys(data)
77
+ for (let i = 0; i < keys.length; i++) {
78
+ const key = keys[i]
79
+ const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key],key,config.parameters)
80
+ this.#buttons[key] = tb
49
81
  }
82
+
83
+ this.#keys = keys
84
+ this.#config = config
50
85
  }
51
86
 
52
- async draw (device) {
53
- device.drawScreen(this.#name, ctx => {
54
- for (let i = 0; i < this.#rows * this.#columns; i++) {
55
- const row = Math.floor(i / device.columns)
56
- const column = i % device.columns
87
+ //setProfileConfig (config) {
88
+ // this.#config = config
89
+ // }
57
90
 
58
- this.#buttons[i].draw(row, column, ctx)
91
+ async draw (device) {
92
+ if (!this.#screen) {
93
+ // physical buttons:
94
+ for (let i = 0; i < this.#keys.length; i++) {
95
+ const key = this.#keys[i]
96
+ this.#buttons[key].drawPhysical(device, key)
59
97
  }
60
- })
98
+ } else {
99
+ // screen:
100
+ device.drawScreen(this.#name, ctx => {
101
+ ctx.globalCompositeOperation = 'source-atop'
102
+ for (let i = 0; i < this.#keys.length; i++) {
103
+ const key = this.#keys[i]
104
+ const iValue = parseInt(key, 10)
105
+ const row = Math.floor(iValue / device.columns)
106
+ const column = iValue % device.columns
107
+
108
+ this.#buttons[key].draw(row, column, ctx)
109
+ }
110
+ })
111
+ }
112
+ }
113
+
114
+ setState (id, val) {
115
+ this.#buttons[id].setState(val)
61
116
  }
62
117
 
63
118
  setIntState (id, val) {
@@ -65,127 +120,103 @@ export class TouchButtonField {
65
120
  }
66
121
 
67
122
  async load () {
68
- for (let i = 0; i < this.#rows * this.#columns; i++) {
69
- await this.#buttons[i].load()
123
+ for (let i = 0; i < this.#keys.length; i++) {
124
+ const key = this.#keys[i]
125
+ if (isNaN(key)) {
126
+ await this.#buttons[key].load(this.#config)
127
+ } else {
128
+ const iVal = parseInt(key, 10)
129
+ await this.#buttons[iVal].load(this.#config)
130
+ }
70
131
  }
71
132
  }
72
133
 
73
134
  async pressed (id) {
74
- // console.info(`pressed ${id}`)
75
- await this.#buttons[id].pressed()
135
+ this.checkAndCreateButton(id)
136
+ const result = await this.#buttons[id].pressed()
137
+ if (!result) {
138
+ console.info(`pressed ${this.#type} ${id}`)
139
+ }
140
+ return result
76
141
  }
77
142
 
78
143
  async released (id) {
79
- // console.info(`released ${id}`)
80
144
  const result = await this.#buttons[id].released()
81
145
  if (result) {
82
146
  // disable all other buttons of the group, if this one had been activated:
83
- for (let i = 0; i < this.#rows * this.#columns; i++) {
84
- if (id === i) { continue }
85
- if (this.#buttons[i].group === this.#buttons[id].group) {
86
- this.#buttons[i].setState(0)
147
+ for (let i = 0; i < this.#keys.length; i++) {
148
+ let key = this.#keys[i]
149
+ if (!isNaN(key)) { key = parseInt(key, 10) }
150
+ if (id === key) { continue }
151
+ if (this.#buttons[key].group === this.#buttons[id].group) {
152
+ this.#buttons[key].setState(0)
87
153
  }
88
154
  }
89
155
  }
156
+ if (!result) {
157
+ console.info(`released ${this.#type} ${id}`)
158
+ }
90
159
  return result
91
160
  }
92
- }
93
161
 
94
- export class PhysicalButtonField {
95
- #buttons = {}
96
- #name
97
- constructor (name, data) {
98
- console.info(`PhysicalButtonField ${name.padEnd(10, ' ')} `)
99
- this.#name = name
100
- const keys = Object.keys(data)
101
- for (let i = 0; i < keys.length; i++) {
102
- const key = keys[i]
103
- const tb = new TouchButton(key, 1, 1, data[key])
104
- this.#buttons[key] = tb
105
- }
162
+ async changed(buttonID,nodeid,val){
163
+ for (let i = 0; i < this.#keys.length; i++) {
164
+ let bID = this.#keys[i]
165
+ const result = await this.#buttons[bID].changed(i,nodeid,val)
166
+ }
106
167
  }
107
168
 
108
- async draw (device) {
109
- const keys = Object.keys(this.#buttons)
110
- for (let i = 0; i < keys.length; i++) {
111
- const key = keys[i]
112
- this.#buttons[key].drawPhysical(device, key)
113
- }
169
+ async rotated (id, delta) {
170
+ this.checkAndCreateButton(id)
171
+ const result = await this.#buttons[id].rotated(delta)
172
+ if (!result) { console.info(`rotated ${this.#type} ${id} ${delta}`) }
173
+ return result
114
174
  }
115
175
 
116
- async load () {
117
- const keys = Object.keys(this.#buttons)
118
- for (let i = 0; i < keys.length; i++) {
119
- const key = keys[i]
120
- await this.#buttons[key].load()
121
- }
176
+ async touchmove (id, x, y) {
177
+ this.checkAndCreateButton(id)
178
+ const result = await this.#buttons[id].touchmove(x, y)
179
+ if (!result) { console.info(`touchmove ${id} ${x} ${y}`) }
180
+ return result
122
181
  }
123
182
 
124
183
  checkAndCreateButton (id) {
125
184
  if (!(id in this.#buttons)) {
126
- const tb = new TouchButton(id, 1, 1, id)
185
+ const tb = new Button(id, 1, 1, id)
127
186
  this.#buttons[id] = tb
128
187
  }
129
188
  }
130
-
131
- setIntState (id, val) {
132
- this.checkAndCreateButton(id)
133
- this.#buttons[id].setIntState(val)
134
- }
135
-
136
- async pressed (id) {
137
- // console.info(`pressed ${id}`)
138
- this.checkAndCreateButton(id)
139
- return await this.#buttons[id].pressed()
140
- }
141
-
142
- async released (id) {
143
- // console.info(`released ${id}`)
144
- this.checkAndCreateButton(id)
145
- return await this.#buttons[id].released()
146
- }
147
-
148
- async rotated (id, delta) {
149
- // console.info(`rotated ${id} ${delta}`)
150
- this.checkAndCreateButton(id)
151
- return await this.#buttons[id].rotated(delta)
152
- }
153
189
  }
154
190
 
155
- export class TouchButton {
191
+ export class Button {
192
+ #config
156
193
  width = 0
157
194
  height = 0
158
- #style
159
- #type
160
- #index = 0
161
- #states = []
195
+
196
+ #type = ButtonType.TOGGLE
197
+
162
198
  #min = 0
163
199
  #max = 100
164
200
  #value = 50
165
- #data
166
201
  #name = undefined
202
+ #nodeid = ""
167
203
 
168
- #images = {}
169
- #colors = {
170
- off: '#000000'
171
- // on: '#110011'
172
- }
173
-
174
- #rgbs = {
175
- off: [0, 0, 0]
176
- // on: [0, 255, 0]
177
- }
178
-
179
- #commands = {
180
- off: '',
181
- on: ''
182
- }
204
+ #index = 0
205
+ #keys
206
+ #states
183
207
 
184
208
  group = ''
185
209
 
186
210
  text = ''
187
211
  font = '16px Arial'
188
212
 
213
+ #x
214
+ #y
215
+ #moveLeft
216
+ #moveRight
217
+ #moveUp
218
+ #moveDown
219
+
189
220
  // Timestamp when button was pressed
190
221
  timeStampPressed
191
222
  // Timestamp when button was released
@@ -194,35 +225,24 @@ export class TouchButton {
194
225
  timeHold
195
226
  // Minimum ammount of time in ms to press a button:
196
227
  minPressed = 25
228
+ key = -1
197
229
 
198
- constructor (id, width, height, data) {
230
+ constructor (id, width, height, data,key,params) {
199
231
  this.id = id
232
+ this.key = key
200
233
  this.width = width
201
234
  this.height = height
202
235
  this.#index = 0
203
- this.#style = ButtonStyle.NONE
204
- this.#type = ButtonType.TOGGLE
205
- this.#states = Object.keys(this.#rgbs)
206
236
 
207
- if (data) {
237
+ if (data && data.states) {
208
238
  this.group = data.group
209
- this.#style = ButtonStyle.PHYSICAL
210
- if (data.images && Object.keys(data.images).length > 0) {
211
- this.#style = ButtonStyle.IMAGE
212
- this.#states = Object.keys(data.images)
213
- } else if (data.colors && Object.keys(data.colors).length > 0) {
214
- this.#style = ButtonStyle.COLOR
215
- this.#states = Object.keys(data.colors)
216
- } else if (data.rgb && Object.keys(data.rgb).length > 0) {
217
- this.#states = Object.keys(data.rgb)
218
- }
219
- if (data.commands) {
220
- this.#commands = data.commands
221
- }
222
239
 
240
+ this.#states = data.states
241
+ this.#keys = Object.keys(this.#states)
223
242
  if (data.type) {
224
243
  this.#type = data.type.toUpperCase()
225
244
  }
245
+
226
246
  if (data.minPressed) {
227
247
  this.minPressed = data.minPressed
228
248
  }
@@ -230,12 +250,15 @@ export class TouchButton {
230
250
  if (data.text) {
231
251
  this.text = data.text
232
252
  }
233
- this.#data = data
234
253
  }
235
- }
236
-
237
- setButtonStyle (type) {
238
- this.#style = type
254
+ if (this.#states === undefined) {
255
+ this.#states = {}
256
+ this.#keys = []
257
+ }
258
+ if (data.nodeid){
259
+ this.#nodeid = format(data.nodeid, params)
260
+ }
261
+
239
262
  }
240
263
 
241
264
  setState (index = 0) {
@@ -243,174 +266,78 @@ export class TouchButton {
243
266
  }
244
267
 
245
268
  async drawPhysical (device, id) {
269
+ const elem = this.getCurrentElement()
270
+ if (!elem || !elem.color) { return }
271
+
272
+ const r = parseInt(elem.color.slice(1, 3), 16)
273
+ const g = parseInt(elem.color.slice(3, 5), 16)
274
+ const b = parseInt(elem.color.slice(5, 7), 16)
275
+
246
276
  try {
277
+ var idx = parseInt(id, 10);
278
+
247
279
  const val = {
248
- id,
249
- color: this.getCurrentRGB()
280
+ id:idx,
281
+ color: `rgba(${r}, ${g}, ${b})`
250
282
  }
283
+ //console.log(' Set Button Color',val.id, val.color)
251
284
  device.setButtonColor(val)
252
285
  } catch (error) {
253
- // console.log(' Error', error)
286
+ console.error(' Error', error)
254
287
  }
255
288
  }
256
289
 
257
290
  async draw (row, column, ctx) {
258
291
  const x = column * this.width
259
292
  const y = row * this.height
260
- switch (this.#style) {
261
- case ButtonStyle.IMAGE:
262
- ctx.drawImage(this.getCurrentStateImage(), x, y, this.width, this.height)
263
- break
264
- case ButtonStyle.COLOR:
265
- // Draw a Colored Rectangle
266
- ctx.fillStyle = this.getCurrentStateFill()
267
- ctx.fillRect(x, y, this.width, this.height)
268
- break
269
- case ButtonStyle.NONE:
270
- // Draw a Colored Rectangle
271
- ctx.fillStyle = this.getCurrentStateFill(0)
272
- ctx.fillRect(x, y, this.width, this.height)
273
- break
274
- }
275
293
 
276
- ctx.fillStyle = '#000000'
277
- ctx.font = this.font
278
- ctx.fillText(this.text, x + 10, y - 10)
279
- }
294
+ const elem = this.getCurrentElement()
280
295
 
281
- async load () {
282
- let bLoaded = false
283
- while (!bLoaded) {
284
- switch (this.#style) {
285
- case ButtonStyle.IMAGE:
286
- bLoaded = await this.loadAsImage()
287
- break
288
- case ButtonStyle.COLOR:
289
- bLoaded = await this.loadAsColor()
290
- break
291
- case ButtonStyle.PHYSICAL:
292
- bLoaded = await this.loadAsRGB()
293
- break
294
- default:
295
- bLoaded = true
296
+ if (elem) {
297
+ if (elem.color) {
298
+ ctx.fillStyle = elem.color
299
+ ctx.fillRect(x, y, this.width, this.height)
300
+ }
301
+ if (elem.imgBuffer) {
302
+ ctx.drawImage(elem.imgBuffer, x, y, this.width, this.height)
296
303
  }
297
304
  }
298
- }
299
305
 
300
- async loadAsImage () {
301
- this.#states = Object.keys(this.#data.images)
302
- if (this.#states.length <= 0) {
303
- this.#style = ButtonStyle.COLOR
304
- return false
305
- }
306
+ // ctx.fillStyle = '#000000'
307
+ // ctx.font = this.font
308
+ // ctx.fillText(this.text, x + 10, y - 10)
309
+ }
306
310
 
307
- for (let i = 0; i < this.#states.length; i++) {
308
- const key = this.#states[i]
309
- const file = this.#data.images[key]
311
+ async load (globalConfig) {
312
+ this.#config = globalConfig
313
+ for (let i = 0; i < this.#keys.length; i++) {
314
+ const key = this.#keys[i]
315
+ const elem = this.#states[key]
316
+ const file = elem.image
310
317
  if (file !== undefined && file !== '') {
311
318
  try {
312
- this.#images[key] = await loadImage(file)
319
+ this.#states[key].imgBuffer = await loadImage(file)
313
320
  } catch (e) {
314
321
  console.error('No such image', file)
315
- this.#style = ButtonStyle.COLOR
316
- delete this.#images[key]
317
322
  return false
318
323
  }
319
- } else {
320
- // this is not an image type
321
324
  }
325
+ //const uastate = elem.state
326
+ //if (uastate){
327
+ // await opcuainterface.Subscribe(uastate)
328
+ //}
322
329
  }
323
- return true
324
330
  }
325
331
 
326
- async loadAsColor () {
327
- if (this.#states.length <= 0) {
328
- // use default colors
329
- this.#states = Object.keys(this.#colors)
330
- return true
331
- }
332
-
333
- for (let i = 0; i < this.#states.length; i++) {
334
- const key = this.#states[i]
335
- if (this.#data.colors && key in this.#data.colors) {
336
- const color = this.#data.colors[key]
337
- if (color !== undefined && color !== '') {
338
- this.#colors[key] = color
339
- }
340
- }
341
- }
342
- return true
343
- }
344
-
345
- async loadAsRGB () {
346
- if (this.#states.length <= 0) {
347
- // use default colors
348
- this.#states = Object.keys(this.#colors)
349
- return true
350
- }
351
-
352
- if (this.#data.rgb) {
353
- const keys = Object.keys(this.#data.rgb)
354
- for (let i = 0; i < keys.length; i++) {
355
- const key = this.#states[i]
356
- const rgb = this.#data.rgb[key]
357
- if (rgb !== undefined && rgb !== '') {
358
- this.#rgbs[key] = rgb
359
- }
360
- }
361
- }
362
-
363
- return true
364
- }
365
-
366
- getCurrentStateImage () {
367
- const key = this.#states[this.#index]
368
- return this.#images[key]
369
- }
370
-
371
- getCurrentStateFill (forceIndex = -1) {
372
- let key
373
- if (forceIndex >= 0) {
374
- key = this.#states[forceIndex]
375
- } else {
376
- key = this.#states[this.#index]
377
- }
378
- return this.#colors[key]
379
- }
380
-
381
- getCurrentRGB () {
382
- const key = this.#states[this.#index]
383
- const rgb = this.#rgbs[key]
384
-
385
- return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`
332
+ getCurrentElement () {
333
+ const key = this.#keys[this.#index]
334
+ return this.#states[key]
386
335
  }
387
336
 
388
337
  getCurrentText () {
389
338
  return this.text
390
339
  }
391
340
 
392
- getCurrentCommand () {
393
- const key = this.#states[this.#index]
394
- const cmd = this.#commands[key]
395
-
396
- if (!cmd) { return '' }
397
- // Call an action
398
- const params = {
399
- id: this.id,
400
- state: key,
401
- min: this.#min,
402
- max: this.#max,
403
- value: this.#value,
404
- text: this.getCurrentText()
405
- }
406
- /* const keys = Object.keys(this.#data.config)
407
- keys.forEach(key => {
408
- params[key] = this.#data.config[key]
409
- }) */
410
-
411
- return format(cmd, params)
412
- }
413
-
414
341
  setIntState (val) {
415
342
  this.#index = val
416
343
  }
@@ -418,27 +345,21 @@ export class TouchButton {
418
345
  pressed () {
419
346
  this.timeStampPressed = Date.now()
420
347
 
421
- switch (this.#style) {
422
- case ButtonStyle.NONE:
423
- break
424
- default:
425
- this.#index++
426
- this.#index %= this.#states.length
427
- }
348
+ this.#index++
349
+ this.updateState(this.#index)
428
350
  return true
429
351
  }
430
352
 
431
353
  released () {
354
+ if (!this.getCurrentElement()) { return false }
432
355
  this.timeStampReleased = Date.now()
433
356
  this.timeHold = this.timeStampReleased - this.timeStampPressed
434
357
 
435
- if (this.#style === ButtonStyle.NONE) { return }
436
-
437
358
  if (this.timeHold < this.minPressed) {
438
359
  // Update the State according to the not correct pressed state
439
360
  console.log('Did not hold minimum time of ', this.minPressed, 'only', this.timeHold)
440
361
  this.#index--
441
- if (this.#index < 0) { this.#index = this.#states.length - 1 }
362
+ if (this.#index < 0) { this.#index = this.#keys.length - 1 }
442
363
  return false
443
364
  }
444
365
 
@@ -449,25 +370,134 @@ export class TouchButton {
449
370
  break
450
371
  default:
451
372
  this.#index--
452
- if (this.#index < 0) { this.#index = this.#states.length - 1 }
373
+ if (this.#index < 0) { this.#index = this.#keys.length - 1 }
453
374
 
454
375
  break
455
376
  }
377
+
378
+ this.updateState(this.#index)
379
+
380
+ return true // this.runCommand()
381
+ }
382
+
383
+ updateState(index){
384
+ this.#index = index
385
+ // Update the State according to the correctly pressed state
386
+ if (this.#index < 0) { this.#index = this.#keys.length - 1 }
387
+ this.#index %= this.#keys.length
456
388
  this.runCommand()
389
+ //console.log("TODO: expect newState", newState)
457
390
  return true // this.runCommand()
458
391
  }
459
392
 
460
393
  async rotated (delta) {
394
+ if (!this.getCurrentElement()) { return false }
395
+
461
396
  this.#value = calcDelta(this.#value, delta, this.#max)
462
397
  return this.runCommand()
463
398
  }
464
399
 
465
- runCommand () {
466
- const cmd = this.getCurrentCommand()
467
- if (cmd && cmd !== '') {
468
- sh(cmd)
469
- return true
400
+ async changed(buttonID,nodeid,val){
401
+ // Only handle updates within the same group identified by nodeid
402
+ if (nodeid !== this.#nodeid){
403
+ return
404
+ }
405
+
406
+ this.#index = 0;
407
+ for (let i = 0; i < this.#keys.length; i++) {
408
+ let key = this.#keys[i]
409
+ // check if the state-name is same as the value we get from outside:
410
+ if (val == key){
411
+ this.#index = i;
412
+ break;
413
+ }
414
+
415
+ // check if the nodeid is the same and the value is one of the states
416
+ let state = this.#states[key]
417
+ if (!state.value)
418
+ continue
419
+
420
+ const params = {
421
+ id: buttonID,
422
+ key: buttonID,
423
+ ...state
424
+ }
425
+ let val1 = format(state.value,params)
426
+ if (val1 === val){
427
+ this.#index = i;
428
+ break;
429
+ }
430
+ break;
431
+ }
432
+ }
433
+
434
+ async touchmove (x, y) {
435
+ // if (!this.getCurrentElement()) { return false }
436
+
437
+ if (x > this.#x) {
438
+ this.#moveRight = true
439
+ this.#moveLeft = false
440
+ } else if (x < this.#x) {
441
+ this.#moveRight = false
442
+ this.#moveLeft = true
443
+ }
444
+
445
+ if (y > this.#y) {
446
+ this.#moveDown = true
447
+ this.#moveUp = false
448
+ } else if (y < this.#y) {
449
+ this.#moveDown = false
450
+ this.#moveUp = true
470
451
  }
452
+
453
+ this.#x = x
454
+ this.#y = y
455
+ // console.log(`d: ${this.#moveDown} r: ${this.#moveRight} `)
471
456
  return false
472
457
  }
458
+
459
+ async runCommand () {
460
+ const elem = this.getCurrentElement()
461
+ if (!elem || (!elem.cmd && !elem.http && !elem.opcua)) {
462
+ return
463
+ }
464
+ // Call an action - include dynamic parameters
465
+ // and also all attributes of elem + global config
466
+ const params = {
467
+ id: this.id,
468
+ key: this.key,
469
+ state: this.#keys[this.#index],
470
+ min: this.#min,
471
+ max: this.#max,
472
+ value: this.#value,
473
+ text: this.getCurrentText(),
474
+ ...this.#config.parameters,
475
+ ...elem
476
+ }
477
+
478
+ let res = ''
479
+ if ('cmd' in elem) {
480
+ if (shellinterface){
481
+ res = await shellinterface.call(elem.cmd, params)
482
+ }else{
483
+ console.warn("shellinterface not started")
484
+ }
485
+ }
486
+ if ('http' in elem) {
487
+ if (httpinterface){
488
+ res = await httpinterface.call(elem.http, params)
489
+ }else{
490
+ console.warn("httpinterface not started")
491
+ }
492
+ }
493
+ if ('opcua' in elem) {
494
+ if (opcuainterface){
495
+ res = await opcuainterface.call(elem.opcua, params)
496
+ }else{
497
+ console.warn("opcuainterface not started")
498
+ }
499
+ }
500
+
501
+ return res
502
+ }
473
503
  }