loupedeck-commander 1.0.2 → 1.2.1

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.
package/README.md CHANGED
@@ -53,15 +53,26 @@ import { BaseLoupeDeckHandler } from 'loupedeck-commander'
53
53
 
54
54
  const handler = new BaseLoupeDeckHandler('config.json')
55
55
 
56
- const stopHandler = () => {
57
- console.log('Receiving SIGINT => Stopping processes.')
58
- handler.stop()
56
+ /**
57
+ * Stop the handlers when a signal like SIGINT or SIGTERM arrive
58
+ * @param {*} signal
59
+ */
60
+ const stopHandler = async(signal) => {
61
+ console.log(`Receiving ${signal} => Stopping processes.`)
62
+ await handler.stop()
59
63
  }
60
64
 
61
- // Initiating a process
62
- process.on('SIGINT', stopHandler)
65
+ // Initiating the signal handlers:
66
+ // see https://www.tutorialspoint.com/unix/unix-signals-traps.htm
67
+ process.on('SIGINT', async (signal) => { stopHandler(signal) })
68
+ process.on('SIGTERM', async (signal) => { stopHandler(signal) })
63
69
 
70
+ // Start it
64
71
  await handler.start()
72
+
73
+ // Take care of running background processes and stop them accordingly:
74
+ await new Promise((resolve) => process.once("SIGINT", resolve));
75
+
65
76
  ```
66
77
 
67
78
  Run the script using the following command:
@@ -72,8 +83,26 @@ node index.mjs
72
83
 
73
84
  If you end up with errors related to canvas module - please install the dependencies as mentioned below, and run `npm install -s` again
74
85
 
86
+ ## Thanks
87
+
88
+ Big thanks go out to [foxxyz](https://github.com/foxxyz/loupedeck) and his team maintaining a great javascript loopdeck module
89
+
75
90
  ## Hints
76
91
 
92
+ ### Cannot connect to Loupedeck device
93
+
94
+ You may need to add your user to the `dialout` group to allow access to the LoupeDeck device, you could do su using the `usermod` as shown below
95
+
96
+ ```bash
97
+ # ls -la /dev/ttyACM0
98
+ crw-rw---- 1 root dialout 166, 0 Nov 30 12:59 /dev/ttyACM0
99
+
100
+ # add the current user to the dialout group:
101
+ # sudo usermod -a -G dialout $USER
102
+ ```
103
+
104
+ After modifying users group you need to logout and login again to activate this change
105
+
77
106
  ### CANVAS Module - additional effort needed
78
107
 
79
108
  The library is using [canvas](https://www.npmjs.com/package/canvas) to load images and render graphical content on the LoupeDeck devices.
@@ -24,6 +24,7 @@ class Profile {
24
24
  touch = {}
25
25
  knobs = {}
26
26
  buttons = {}
27
+ parameters = {}
27
28
  #file = ''
28
29
  #loaded = false
29
30
  #error = false
@@ -48,6 +49,8 @@ class Profile {
48
49
  this.touch = new TouchConfig(config.touch)
49
50
  // Load the Configurations for Button-Areas
50
51
  this.buttons = config.buttons
52
+ // Load Parameters
53
+ this.parameters = config.parameters
51
54
  }
52
55
  }
53
56
 
@@ -1,7 +1,6 @@
1
- import pkg from 'loupedeck'
1
+ import {discover, HAPTIC,LoupedeckDevice } from 'loupedeck'
2
2
  import { ApplicationConfig } from './ApplicationConfig.mjs'
3
- import { ButtonField } from './touchbuttons.mjs'
4
- const { discover, HAPTIC } = pkg
3
+ import { ButtonField, StopInterfaces, InitializeInterfaces,opcuainterface} from './touchbuttons.mjs'
5
4
 
6
5
  export class BaseLoupeDeckHandler {
7
6
  device = undefined
@@ -11,25 +10,43 @@ export class BaseLoupeDeckHandler {
11
10
  screens = {}
12
11
  buttons = {}
13
12
  screenUpdate = {}
14
-
15
- touchButtons = undefined
13
+ stopping = false
16
14
 
17
15
  constructor (config) {
18
16
  console.log(`INIT with config ${config}`)
19
17
  this.loadConfig(config)
20
18
  }
21
19
 
20
+ /**
21
+ * event handler - start
22
+ */
22
23
  async start () {
23
24
  console.info('Start')
24
- while (!this.device) {
25
+ while (!this.device && !this.stopping) {
25
26
  try {
27
+ var list = await LoupedeckDevice.list()
28
+ if (list.length>0){
29
+ var element = list[0]
30
+ console.log("Connecting to device")
31
+ console.log("Path: ", element.path)
32
+ console.log("vendorId: ", element.vendorId, element.productId)
33
+ console.log("serialNumber: ", element.serialNumber)
34
+ }
35
+
26
36
  this.device = await discover()
37
+
38
+
39
+
27
40
  } catch (e) {
28
41
  console.error(`${e}. Reattempting in 3 seconds...`)
29
- await new Promise(res => setTimeout(res, 3000))
42
+ await new Promise(resolve => setTimeout(resolve, 3000))
43
+ }
44
+
45
+ if (this.stopping){
46
+ return
30
47
  }
31
48
  }
32
- console.info(`✅ Connected to ${this.device.type}`)
49
+ console.info(`✅ Discovered Device ${this.device.type}`)
33
50
 
34
51
  const self = this
35
52
 
@@ -40,51 +57,89 @@ export class BaseLoupeDeckHandler {
40
57
  this.device.on('touchstart', (event) => { self.onTouchStart(event) })
41
58
  this.device.on('touchmove', (event) => { self.onTouchMove(event) })
42
59
  this.device.on('touchend', (event) => { self.onTouchEnd(event) })
60
+ this.device.on('disconnect', (event) => { self.disconnectDevice(event) })
61
+
62
+ console.info(`✅ Registered callbacks`)
63
+ }
43
64
 
44
- // return await this.device.connect()
65
+ /**
66
+ * event handler - loupedeck device disconnected
67
+ */
68
+ async disconnectDevice (event) {
69
+ console.info("Device Disconnected")
70
+ this.device=undefined
45
71
  }
46
72
 
47
- stop () {
73
+ /**
74
+ * stop handler - close the dipslay-connection and also stop all interface handlers
75
+ */
76
+ async stop () {
48
77
  console.info('Stopping Handler')
49
- this.device.close()
78
+
79
+ try {
80
+ console.info(`Closing Device`)
81
+ this.stopping = true
82
+ if (this.device){
83
+ this.device.vibrate(HAPTIC.DESCEND_MED)
84
+ await new Promise(resolve => setTimeout(resolve, 250))
85
+ }
86
+ if (this.device){
87
+ this.device.setBrightness(0)
88
+ await new Promise(resolve => setTimeout(resolve, 250))
89
+ }
90
+ if (this.device){
91
+ this.device.reconnectInterval = 0
92
+ await this.device.close()
93
+ await new Promise(resolve => setTimeout(resolve, 2000))
94
+ console.info(`Device Closed`)
95
+ }
96
+
97
+ console.info(`Stopping interfaces`)
98
+ await StopInterfaces()
99
+ await new Promise(resolve => setTimeout(resolve, 500))
100
+ } catch (e) {}
101
+
102
+ process.exit()
103
+
50
104
  }
51
105
 
106
+ /**
107
+ * load Application config file from JSON
108
+ * @param filename
109
+ */
52
110
  loadConfig (fileName) {
53
111
  console.info(`Loading Config File ${fileName}`)
54
112
  this.appConfig = new ApplicationConfig()
55
113
  this.appConfig.loadFromFile(fileName)
56
114
  }
57
115
 
116
+ /**
117
+ * activate the profile with the givven ID
118
+ */
58
119
  async activateProfile (id) {
59
120
  // todo Profile-change implementation
121
+ var oldProfile = this.currentProfile
60
122
  if (this.appConfig.profiles.length >= id) {
61
123
  this.currentProfile = id
124
+ }else{
125
+ return
62
126
  }
63
- await this.buttons.draw(this.device)
64
- }
65
127
 
66
- getCurrentProfile () {
67
- return this.appConfig.profiles[this.currentProfile]
68
- }
69
-
70
- // Events:
71
- async onConnected (address) {
72
- console.info('Connected: ', address)
73
128
  const dLeft = this.device.displays.left
74
129
  const dRight = this.device.displays.right
75
130
  const dCenter = this.device.displays.center
76
131
  const dKnob = this.device.displays.knob
77
-
132
+
78
133
  const profile = this.getCurrentProfile()
79
- this.screens.center = new ButtonField('center', this.device.rows, this.device.columns, dCenter.width, dCenter.height, profile.touch.center)
80
- this.screens.left = new ButtonField('left', 1, 1, dLeft.width, dLeft.height, profile.touch.left)
81
- this.screens.right = new ButtonField('right', 1, 1, dRight.width, dRight.height, profile.touch.right)
134
+ this.screens.center = new ButtonField('center', this.device.rows, this.device.columns, dCenter.width, dCenter.height, profile.touch.center,profile)
135
+ this.screens.left = new ButtonField('left', 1, 1, dLeft.width, dLeft.height, profile.touch.left,profile)
136
+ this.screens.right = new ButtonField('right', 1, 1, dRight.width, dRight.height, profile.touch.right,profile)
82
137
  // knob Display is only available in the CT-version - not with live:
83
138
  if (dKnob) {
84
- this.screens.knob = new ButtonField('knob', 1, 1, dKnob.width, dKnob.height, profile.touch.knob)
139
+ this.screens.knob = new ButtonField('knob', 1, 1, dKnob.width, dKnob.height, profile.touch.knob,profile)
85
140
  }
86
141
 
87
- this.buttons = new ButtonField('buttons', 1, 1, 0, 0, profile.buttons)
142
+ this.buttons = new ButtonField('buttons', 1, 1, 0, 0, profile.buttons,profile)
88
143
 
89
144
  await this.screens.center.load()
90
145
  await this.screens.right.load()
@@ -98,15 +153,47 @@ export class BaseLoupeDeckHandler {
98
153
  if (dKnob) {
99
154
  await this.screens.knob.draw(this.device)
100
155
  }
101
- await this.activateProfile(0)
156
+
157
+ this.buttons.setState(this.currentProfile+1,1)
158
+ this.buttons.setState(oldProfile+1,1)
159
+
102
160
  await this.buttons.draw(this.device)
161
+ }
162
+
163
+ /**
164
+ * get the dictionary iwth the current profile settings
165
+ */
166
+ getCurrentProfile () {
167
+ return this.appConfig.profiles[this.currentProfile]
168
+ }
169
+
170
+ /**
171
+ * Triggered, when LoupeDeck Device is connected
172
+ * - Initialize the profile from config-file and
173
+ * - start the interface handlers accordingly
174
+ */
175
+ async onConnected (address) {
176
+ console.info(`✅ Connected to ${this.device.type}, ${address}`)
177
+
178
+ await this.activateProfile(0)
179
+
180
+ var profile = this.getCurrentProfile()
181
+ await InitializeInterfaces(profile,this.buttons.setState)
182
+
183
+ const self = this
184
+
185
+ // Register callback on monitored item change:
186
+ opcuainterface.myEmitter.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
103
187
 
104
188
  this.device.setBrightness(1)
105
189
  this.device.vibrate(HAPTIC.ASCEND_MED)
106
190
 
107
- console.info('Done initializing')
191
+ console.info('Done initializing')
108
192
  }
109
193
 
194
+ /**
195
+ * Fore an update of all screens
196
+ */
110
197
  async updateScreens () {
111
198
  const keys = Object.keys(this.screenUpdate)
112
199
  for (let i = 0; i < keys.length; i++) {
@@ -116,6 +203,9 @@ export class BaseLoupeDeckHandler {
116
203
  this.screenUpdate = {}
117
204
  }
118
205
 
206
+ /**
207
+ * Button Down Handler - triggered through Event Button Down - connected to LoupeDeck Event
208
+ */
119
209
  async onButtonDown (event) {
120
210
  let ok = false
121
211
  const id = event.id
@@ -124,20 +214,33 @@ export class BaseLoupeDeckHandler {
124
214
  return ok
125
215
  }
126
216
 
217
+ /**
218
+ * Button Up Handler - triggered through Event Button Up - connected to LoupeDeck Event
219
+ */
127
220
  async onButtonUp (event) {
128
221
  let ok = false
129
222
  const id = event.id
130
223
  ok = await this.buttons.released(id)
131
224
  await this.buttons.draw(this.device)
225
+
226
+ /*if (this.currentProfile != id){
227
+ this.activateProfile(id-1)
228
+ }*/
132
229
  return ok
133
230
  }
134
231
 
232
+ /**
233
+ * Button Rotate Handler - triggered through Event Rotate available with knob-Buttons - connected to LoupeDeck Event
234
+ */
135
235
  async onRotate (event) {
136
236
  const id = event.id
137
237
  const delta = event.delta
138
238
  return await this.buttons.rotated(id, delta)
139
239
  }
140
240
 
241
+ /**
242
+ * TouchStart Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
243
+ */
141
244
  async onTouchStart (event) {
142
245
  let ok = false
143
246
  const changedTouches = event.changedTouches
@@ -154,6 +257,9 @@ export class BaseLoupeDeckHandler {
154
257
  return ok
155
258
  }
156
259
 
260
+ /**
261
+ * TouchMove Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
262
+ */
157
263
  async onTouchMove (event) {
158
264
  let ok = false
159
265
  const changedTouches = event.changedTouches
@@ -170,6 +276,9 @@ export class BaseLoupeDeckHandler {
170
276
  return ok
171
277
  }
172
278
 
279
+ /**
280
+ * TouchEnd Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
281
+ */
173
282
  async onTouchEnd (event) {
174
283
  let ok = false
175
284
  const changedTouches = event.changedTouches
@@ -186,4 +295,19 @@ export class BaseLoupeDeckHandler {
186
295
  await this.updateScreens()
187
296
  return ok
188
297
  }
298
+
299
+ /**
300
+ * Handler for StateChanged through OPC/UA Interface - only connected with touch-buttons on center field (yet)
301
+ */
302
+ async buttonStateChanged(buttonID,nodeid,val) {
303
+ let ok = false
304
+ this.screenUpdate["center"] = true
305
+
306
+ ok = await this.screens.center.changed(buttonID,nodeid,val)
307
+
308
+ await this.updateScreens()
309
+ return ok
310
+ }
311
+
312
+
189
313
  }
@@ -1,8 +1,38 @@
1
1
  import { loadImage } from 'canvas'
2
- import { sh } from './cmd-executer.mjs'
2
+ //import { loadImage } from "https://deno.land/x/canvas/mod.ts";
3
+
4
+ import * as shellif from '../interfaces/shellif.mjs'
5
+ import * as httpif from '../interfaces/httpif.mjs'
6
+ import * as opcuaif from '../interfaces/opcuaif.mjs'
3
7
  import format from 'string-template'
4
8
  import { calcDelta } from './utils.mjs'
5
9
 
10
+ export var opcuainterface = undefined
11
+ var httpinterface = undefined
12
+ var shellinterface = undefined
13
+
14
+ export async function InitializeInterfaces(appConfig,callbackFunction){
15
+ if (opcuainterface === undefined ){
16
+ opcuainterface = new opcuaif.OPCUAIf()
17
+ opcuainterface.init(appConfig.parameters,appConfig,callbackFunction)
18
+ }
19
+ if (httpinterface === undefined)
20
+ httpinterface = new httpif.HTTPif()
21
+ if (shellinterface === undefined)
22
+ shellinterface = new shellif.SHELLif()
23
+
24
+ }
25
+
26
+ export async function StopInterfaces(){
27
+ if (opcuainterface !== undefined )
28
+ await opcuainterface.stop()
29
+ if (httpinterface !== undefined)
30
+ await httpinterface.stop()
31
+ if (shellinterface !== undefined)
32
+ await shellinterface.stop()
33
+
34
+ }
35
+
6
36
  export const ButtonIndex = {
7
37
  BUTN_0: 0,
8
38
  BUTN_1: 1,
@@ -31,7 +61,9 @@ export class ButtonField {
31
61
  #keys = []
32
62
  #type
33
63
  #name
34
- constructor (name, rows, columns, width, height, data) {
64
+ #config
65
+
66
+ constructor (name, rows, columns, width, height, data, config) {
35
67
  console.info(`ButtonField ${name.padEnd(10, ' ')} Buttons: ${rows} x ${columns} , Pixels ${width} x ${height}`)
36
68
  this.#name = name
37
69
  this.width = width
@@ -45,13 +77,18 @@ export class ButtonField {
45
77
  const keys = Object.keys(data)
46
78
  for (let i = 0; i < keys.length; i++) {
47
79
  const key = keys[i]
48
- const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key])
80
+ const tb = new Button(`${this.#type}-${key}`, width / columns, height / rows, data[key],key,config.parameters)
49
81
  this.#buttons[key] = tb
50
82
  }
51
83
 
52
84
  this.#keys = keys
85
+ this.#config = config
53
86
  }
54
87
 
88
+ //setProfileConfig (config) {
89
+ // this.#config = config
90
+ // }
91
+
55
92
  async draw (device) {
56
93
  if (!this.#screen) {
57
94
  // physical buttons:
@@ -75,6 +112,10 @@ export class ButtonField {
75
112
  }
76
113
  }
77
114
 
115
+ setState (id, val) {
116
+ this.#buttons[id].setState(val)
117
+ }
118
+
78
119
  setIntState (id, val) {
79
120
  this.#buttons[id].setIntState(val)
80
121
  }
@@ -83,10 +124,10 @@ export class ButtonField {
83
124
  for (let i = 0; i < this.#keys.length; i++) {
84
125
  const key = this.#keys[i]
85
126
  if (isNaN(key)) {
86
- await this.#buttons[key].load()
127
+ await this.#buttons[key].load(this.#config)
87
128
  } else {
88
129
  const iVal = parseInt(key, 10)
89
- await this.#buttons[iVal].load()
130
+ await this.#buttons[iVal].load(this.#config)
90
131
  }
91
132
  }
92
133
  }
@@ -119,6 +160,13 @@ export class ButtonField {
119
160
  return result
120
161
  }
121
162
 
163
+ async changed(buttonID,nodeid,val){
164
+ for (let i = 0; i < this.#keys.length; i++) {
165
+ let bID = this.#keys[i]
166
+ const result = await this.#buttons[bID].changed(i,nodeid,val)
167
+ }
168
+ }
169
+
122
170
  async rotated (id, delta) {
123
171
  this.checkAndCreateButton(id)
124
172
  const result = await this.#buttons[id].rotated(delta)
@@ -142,6 +190,7 @@ export class ButtonField {
142
190
  }
143
191
 
144
192
  export class Button {
193
+ #config
145
194
  width = 0
146
195
  height = 0
147
196
 
@@ -151,8 +200,10 @@ export class Button {
151
200
  #max = 100
152
201
  #value = 50
153
202
  #name = undefined
203
+ #nodeid = ""
154
204
 
155
205
  #index = 0
206
+ #event
156
207
  #keys
157
208
  #states
158
209
 
@@ -176,9 +227,11 @@ export class Button {
176
227
  timeHold
177
228
  // Minimum ammount of time in ms to press a button:
178
229
  minPressed = 25
230
+ key = -1
179
231
 
180
- constructor (id, width, height, data) {
232
+ constructor (id, width, height, data,key,params) {
181
233
  this.id = id
234
+ this.key = key
182
235
  this.width = width
183
236
  this.height = height
184
237
  this.#index = 0
@@ -204,6 +257,10 @@ export class Button {
204
257
  this.#states = {}
205
258
  this.#keys = []
206
259
  }
260
+ if (data.nodeid){
261
+ this.#nodeid = format(data.nodeid, params)
262
+ }
263
+
207
264
  }
208
265
 
209
266
  setState (index = 0) {
@@ -219,13 +276,16 @@ export class Button {
219
276
  const b = parseInt(elem.color.slice(5, 7), 16)
220
277
 
221
278
  try {
279
+ var idx = parseInt(id, 10);
280
+
222
281
  const val = {
223
- id,
282
+ id:idx,
224
283
  color: `rgba(${r}, ${g}, ${b})`
225
284
  }
285
+ //console.log(' Set Button Color',val.id, val.color)
226
286
  device.setButtonColor(val)
227
287
  } catch (error) {
228
- // console.log(' Error', error)
288
+ console.error(' Error', error)
229
289
  }
230
290
  }
231
291
 
@@ -250,7 +310,8 @@ export class Button {
250
310
  // ctx.fillText(this.text, x + 10, y - 10)
251
311
  }
252
312
 
253
- async load () {
313
+ async load (globalConfig) {
314
+ this.#config = globalConfig
254
315
  for (let i = 0; i < this.#keys.length; i++) {
255
316
  const key = this.#keys[i]
256
317
  const elem = this.#states[key]
@@ -263,6 +324,10 @@ export class Button {
263
324
  return false
264
325
  }
265
326
  }
327
+ //const uastate = elem.state
328
+ //if (uastate){
329
+ // await opcuainterface.Subscribe(uastate)
330
+ //}
266
331
  }
267
332
  }
268
333
 
@@ -283,7 +348,7 @@ export class Button {
283
348
  this.timeStampPressed = Date.now()
284
349
 
285
350
  this.#index++
286
- this.#index %= this.#keys.length
351
+ this.updateState(this.#index,"pressed")
287
352
  return true
288
353
  }
289
354
 
@@ -311,17 +376,65 @@ export class Button {
311
376
 
312
377
  break
313
378
  }
379
+
380
+ this.updateState(this.#index,"released")
381
+
382
+ return true // this.runCommand()
383
+ }
384
+
385
+ updateState(index,eventType){
386
+ this.#index = index
387
+ this.#event = eventType
388
+ // Update the State according to the correctly pressed state
389
+ if (this.#index < 0) { this.#index = this.#keys.length - 1 }
390
+ this.#index %= this.#keys.length
314
391
  this.runCommand()
392
+ //console.log("TODO: expect newState", newState)
315
393
  return true // this.runCommand()
316
394
  }
317
395
 
318
396
  async rotated (delta) {
319
397
  if (!this.getCurrentElement()) { return false }
320
398
 
399
+ this.#event = "rotated"
321
400
  this.#value = calcDelta(this.#value, delta, this.#max)
322
401
  return this.runCommand()
323
402
  }
324
403
 
404
+ async changed(buttonID,nodeid,val){
405
+ // Only handle updates within the same group identified by nodeid
406
+ if (nodeid !== this.#nodeid){
407
+ return
408
+ }
409
+
410
+ this.#index = 0;
411
+ for (let i = 0; i < this.#keys.length; i++) {
412
+ let key = this.#keys[i]
413
+ // check if the state-name is same as the value we get from outside:
414
+ if (val == key){
415
+ this.#index = i;
416
+ break;
417
+ }
418
+
419
+ // check if the nodeid is the same and the value is one of the states
420
+ let state = this.#states[key]
421
+ if (!state.value)
422
+ continue
423
+
424
+ const params = {
425
+ id: buttonID,
426
+ key: buttonID,
427
+ ...state
428
+ }
429
+ let val1 = format(state.value,params)
430
+ if (val1 === val){
431
+ this.#index = i;
432
+ break;
433
+ }
434
+ break;
435
+ }
436
+ }
437
+
325
438
  async touchmove (x, y) {
326
439
  // if (!this.getCurrentElement()) { return false }
327
440
 
@@ -347,27 +460,54 @@ export class Button {
347
460
  return false
348
461
  }
349
462
 
350
- runCommand () {
463
+ async runCommand () {
351
464
  const elem = this.getCurrentElement()
352
- if (!elem || !elem.cmd) {
465
+ // Only continue, if we have an element, that contains some kind of command:
466
+ if (!elem || (!elem.cmd && !elem.http && !elem.opcua)) {
353
467
  return
354
468
  }
355
- // Call an action
469
+ // Filter for Event Type:
470
+ if (elem.filter && elem.filter != this.#event){
471
+ return
472
+ }
473
+ // Call an action - include dynamic parameters
474
+ // and also all attributes of elem + global config
356
475
  const params = {
476
+ text: this.getCurrentText(),
477
+ ...this.#config.parameters,
478
+ ...elem,
357
479
  id: this.id,
480
+ key: this.key,
481
+ event: this.#event,
358
482
  state: this.#keys[this.#index],
359
483
  min: this.#min,
360
484
  max: this.#max,
361
- value: this.#value,
362
- text: this.getCurrentText()
485
+ value: this.#value
363
486
  }
364
- /* const keys = Object.keys(this.#data.config)
365
- keys.forEach(key => {
366
- params[key] = this.#data.config[key]
367
- }) */
368
487
 
369
- const cmdFormatted = format(elem.cmd, params)
488
+ let res = ''
489
+ if ('cmd' in elem) {
490
+ if (shellinterface){
491
+ res = await shellinterface.call(elem.cmd, params)
492
+ }else{
493
+ console.warn("shellinterface not started")
494
+ }
495
+ }
496
+ if ('http' in elem) {
497
+ if (httpinterface){
498
+ res = await httpinterface.call(elem.http, params)
499
+ }else{
500
+ console.warn("httpinterface not started")
501
+ }
502
+ }
503
+ if ('opcua' in elem) {
504
+ if (opcuainterface){
505
+ res = await opcuainterface.call(elem.opcua, params)
506
+ }else{
507
+ console.warn("opcuainterface not started")
508
+ }
509
+ }
370
510
 
371
- return sh(cmdFormatted)
511
+ return res
372
512
  }
373
513
  }
@@ -0,0 +1,9 @@
1
+ import globals from "globals";
2
+ import pluginJs from "@eslint/js";
3
+
4
+
5
+ /** @type {import('eslint').Linter.Config[]} */
6
+ export default [
7
+ {languageOptions: { globals: globals.browser }},
8
+ pluginJs.configs.recommended,
9
+ ];