loupedeck-commander 1.2.12 → 1.3.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.
- package/common/ApplicationConfig.mjs +20 -20
- package/common/BaseLoupeDeckHandler.mjs +30 -11
- package/common/ButtonField.mjs +159 -0
- package/common/button.mjs +457 -0
- package/interfaces/interfaces.mjs +34 -0
- package/interfaces/opcuaif.mjs +10 -13
- package/package.json +1 -1
- package/profile-1.json +41 -45
- package/common/touchbuttons.mjs +0 -597
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
|
|
2
|
+
import { loadImage } from 'canvas'
|
|
3
|
+
//import { loadImage } from "https://deno.land/x/canvas/mod.ts";
|
|
4
|
+
import { calcDelta, invertColor } from './utils.mjs'
|
|
5
|
+
import format from 'string-template'
|
|
6
|
+
|
|
7
|
+
import { shellinterface, httpinterface, opcuainterface, profileEmitter } from '../interfaces/interfaces.mjs'
|
|
8
|
+
|
|
9
|
+
export const ButtonType = {
|
|
10
|
+
NONE: '',
|
|
11
|
+
TOGGLE: 'TOGGLE',
|
|
12
|
+
PUSH: 'PUSH'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export class Button {
|
|
18
|
+
#profile
|
|
19
|
+
#params
|
|
20
|
+
//#data
|
|
21
|
+
#index = 0
|
|
22
|
+
#enforcedIndex = -1
|
|
23
|
+
#event
|
|
24
|
+
#keys
|
|
25
|
+
#states
|
|
26
|
+
// Timestamp when button was pressed
|
|
27
|
+
timeStampPressed
|
|
28
|
+
// Timestamp when button was released
|
|
29
|
+
timeStampReleased
|
|
30
|
+
// Time actually hold the button in ms
|
|
31
|
+
timeHold
|
|
32
|
+
#counter = 0
|
|
33
|
+
|
|
34
|
+
constructor (id, width, height, data={},key,profile = {}) {
|
|
35
|
+
this.#states = {}
|
|
36
|
+
this.#keys = []
|
|
37
|
+
|
|
38
|
+
this.id = id
|
|
39
|
+
this.#index = 0
|
|
40
|
+
this.#enforcedIndex = -1
|
|
41
|
+
|
|
42
|
+
this.#profile = profile
|
|
43
|
+
this.#params = {
|
|
44
|
+
"key" : key,
|
|
45
|
+
"state" : '',
|
|
46
|
+
"width" : width,
|
|
47
|
+
"height" : height,
|
|
48
|
+
"min" : 0,
|
|
49
|
+
"max" : 100,
|
|
50
|
+
"x" : 0,
|
|
51
|
+
"y" : 0,
|
|
52
|
+
"color" : '#000000',
|
|
53
|
+
"text" : '',
|
|
54
|
+
"textColor" : '#ffffff',
|
|
55
|
+
"textAlign" : 'center',
|
|
56
|
+
"textBaseline": 'top',
|
|
57
|
+
"font" :'16px Arial',
|
|
58
|
+
"value" : 50,
|
|
59
|
+
"minPressed": 25,
|
|
60
|
+
"moveLeft" : false,
|
|
61
|
+
"moveRight" : false,
|
|
62
|
+
"moveUp" : false,
|
|
63
|
+
"moveDown" : false,
|
|
64
|
+
"nodeid" : '',
|
|
65
|
+
"type" : ButtonType.TOGGLE,
|
|
66
|
+
"group" : key,
|
|
67
|
+
"filter" : "",
|
|
68
|
+
"blink" : false,
|
|
69
|
+
"vibrate" : false,
|
|
70
|
+
"profile" : "",
|
|
71
|
+
"brightness" : undefined,
|
|
72
|
+
"default" : "0"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (profile.parameters){
|
|
76
|
+
let params = Object.keys(profile.parameters)
|
|
77
|
+
for (let i = 0; i < params.length; i++) {
|
|
78
|
+
const k = params[i]
|
|
79
|
+
this.#params[k] = profile.parameters[k]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// enforce key, so it's not oveerwritten somewhere else
|
|
83
|
+
this.#params.key = key
|
|
84
|
+
|
|
85
|
+
// New approach: Use all data from data.params:
|
|
86
|
+
if (data.params){
|
|
87
|
+
this.#params = {
|
|
88
|
+
...this.#params,
|
|
89
|
+
...data.params
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Format the params:
|
|
93
|
+
this.#params.group = format(this.#params.group, this.getParams({}))
|
|
94
|
+
this.#params.nodeid = format(this.#params.nodeid, this.getParams({}))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (data.states) {
|
|
98
|
+
this.#states = data.states
|
|
99
|
+
this.#keys = Object.keys(this.#states)
|
|
100
|
+
|
|
101
|
+
var defaultIndex = this.#keys.indexOf(this.#params.default)
|
|
102
|
+
if (defaultIndex >= 0) {
|
|
103
|
+
this.#index = defaultIndex
|
|
104
|
+
} else {
|
|
105
|
+
this.#params.default = this.#keys[0]
|
|
106
|
+
console.info(` button ${id} default set to ${this.#params.default}, available states`, this.#keys)
|
|
107
|
+
}
|
|
108
|
+
this.#params.state = this.#keys[this.#index]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Set the default value for the button:
|
|
112
|
+
|
|
113
|
+
// Legacy approach: Use data directly:
|
|
114
|
+
if (data.minPressed) {
|
|
115
|
+
console.warn("Legacy approach: minPressed is deprecated, use params.minPressed instead")
|
|
116
|
+
this.#params.minPressed = data.minPressed
|
|
117
|
+
}
|
|
118
|
+
if (data.text) {
|
|
119
|
+
console.warn("Legacy approach: text is deprecated, use params.text instead")
|
|
120
|
+
this.#params.text = data.text
|
|
121
|
+
}
|
|
122
|
+
if (data.nodeid){
|
|
123
|
+
this.#params.nodeid = format(data.nodeid, this.getParams({}))
|
|
124
|
+
console.warn("Legacy approach: nodeid is deprecated, use params.nodeid instead",this.#params.nodeid)
|
|
125
|
+
}
|
|
126
|
+
if (data.type){
|
|
127
|
+
console.warn("Legacy approach: type is deprecated, use params.type instead")
|
|
128
|
+
this.#params.type = data.type
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (data.default) {
|
|
132
|
+
console.warn("Legacy approach: default is deprecated, use params.default instead")
|
|
133
|
+
this.#index = this.#keys.indexOf(data.default)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (data.group){
|
|
137
|
+
console.warn("Legacy approach: group is deprecated, use params.group instead")
|
|
138
|
+
this.#params.group = format(data.group, this.getParams({}))
|
|
139
|
+
}
|
|
140
|
+
// End Legacy approach
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setState (index = 0) {
|
|
144
|
+
this.#index = index
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async drawPhysical (device, id) {
|
|
148
|
+
const elem = this.getCurrentElement()
|
|
149
|
+
if (!elem || !elem.color) { return }
|
|
150
|
+
|
|
151
|
+
const r = parseInt(elem.color.slice(1, 3), 16)
|
|
152
|
+
const g = parseInt(elem.color.slice(3, 5), 16)
|
|
153
|
+
const b = parseInt(elem.color.slice(5, 7), 16)
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
var idx = parseInt(id, 10);
|
|
157
|
+
|
|
158
|
+
const val = {
|
|
159
|
+
id:idx,
|
|
160
|
+
color: `rgba(${r}, ${g}, ${b})`
|
|
161
|
+
}
|
|
162
|
+
// console.log(' Set Button Color',id, val.id,elem.color, val.color)
|
|
163
|
+
device.setButtonColor(val)
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error(' Error', error)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async draw (row, column, ctx) {
|
|
170
|
+
const x = column * this.#params.width
|
|
171
|
+
const y = row * this.#params.height
|
|
172
|
+
|
|
173
|
+
const elem = this.getCurrentElement()
|
|
174
|
+
let params = this.getParams(elem)
|
|
175
|
+
|
|
176
|
+
if (elem) {
|
|
177
|
+
if(elem.blink && this.#counter % 2 == 0) {
|
|
178
|
+
// If blink is set, we switch the color to inverted color
|
|
179
|
+
let oldColor = elem.color
|
|
180
|
+
elem.color = params.textColor
|
|
181
|
+
elem.textColor = oldColor
|
|
182
|
+
//console.log("Blinking Button",this.#index,elem.color)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
ctx.fillStyle = params.color
|
|
186
|
+
ctx.fillRect(x, y, params.width, params.height)
|
|
187
|
+
|
|
188
|
+
if (elem.imgBuffer) {
|
|
189
|
+
ctx.drawImage(elem.imgBuffer, x, y, params.width, params.height)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (params.text != undefined && params.text != '') {
|
|
193
|
+
ctx.fillStyle = params.textColor
|
|
194
|
+
ctx.font = params.font
|
|
195
|
+
ctx.textBaseline = params.textBaseline;
|
|
196
|
+
ctx.textAlign = params.textAlign;
|
|
197
|
+
let dynamicText = format(params.text, this.getParams(elem))
|
|
198
|
+
ctx.fillText(dynamicText,x+6,y+6)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.#counter = this.#counter + 1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async load (globalConfig) {
|
|
205
|
+
this.#profile = globalConfig
|
|
206
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
207
|
+
const key = this.#keys[i]
|
|
208
|
+
const elem = this.#states[key]
|
|
209
|
+
const file = elem.image
|
|
210
|
+
if (file !== undefined && file !== '') {
|
|
211
|
+
try {
|
|
212
|
+
this.#states[key].imgBuffer = await loadImage(file)
|
|
213
|
+
} catch (e) {
|
|
214
|
+
console.error('No such image', file)
|
|
215
|
+
return false
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
getCurrentElement () {
|
|
222
|
+
const state = this.#keys[this.#index]
|
|
223
|
+
return this.#states[state]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
getLastElement () {
|
|
227
|
+
let i=this.#index-1
|
|
228
|
+
if (i < 0) { i = this.#keys.length - 1 }
|
|
229
|
+
|
|
230
|
+
const lastState = this.#keys[i]
|
|
231
|
+
return this.#states[lastState]
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
pressed () {
|
|
235
|
+
this.timeStampPressed = Date.now()
|
|
236
|
+
|
|
237
|
+
this.#index++
|
|
238
|
+
|
|
239
|
+
if (this.#enforcedIndex>=0){
|
|
240
|
+
console.log("Enforced Index",this.#enforcedIndex )
|
|
241
|
+
this.#index = this.#enforcedIndex
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this.updateState(this.#index,"pressed",true)
|
|
245
|
+
return true
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
released () {
|
|
249
|
+
let elem = this.getCurrentElement()
|
|
250
|
+
if (!elem) { return false }
|
|
251
|
+
this.timeStampReleased = Date.now()
|
|
252
|
+
this.timeHold = this.timeStampReleased - this.timeStampPressed
|
|
253
|
+
|
|
254
|
+
let bExecute = true
|
|
255
|
+
if (this.timeHold < this.#params.minPressed) {
|
|
256
|
+
// Update the State according to the not correct pressed state
|
|
257
|
+
console.log('Did not hold minimum time of ', this.#params.minPressed, 'only', this.timeHold)
|
|
258
|
+
//if (this.#index < 0) { this.#index = this.#keys.length - 1 }
|
|
259
|
+
bExecute = false
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Update the State according to the correctly pressed state
|
|
263
|
+
switch (this.#params.type) {
|
|
264
|
+
case ButtonType.TOGGLE:
|
|
265
|
+
// do nothing
|
|
266
|
+
break
|
|
267
|
+
default:
|
|
268
|
+
this.#index--
|
|
269
|
+
//if (this.#index < 0) { this.#index = this.#keys.length - 1 }
|
|
270
|
+
break
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (this.#enforcedIndex>=0){
|
|
274
|
+
console.log("Enforced Index",this.#enforcedIndex )
|
|
275
|
+
this.#index = this.#enforcedIndex
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
this.updateState(this.#index,"released",bExecute)
|
|
280
|
+
|
|
281
|
+
return true // this.runCommand()
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
updateState(index,eventType,bExecute){
|
|
285
|
+
this.#index = index
|
|
286
|
+
this.#event = eventType
|
|
287
|
+
// Update the State according to the correctly pressed state
|
|
288
|
+
if (this.#index < 0) { this.#index = this.#keys.length - 1 }
|
|
289
|
+
this.#index %= this.#keys.length
|
|
290
|
+
if (bExecute)
|
|
291
|
+
this.runCommand()
|
|
292
|
+
//console.log("TODO: expect newState", newState)
|
|
293
|
+
return true // this.runCommand()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async rotated (delta) {
|
|
297
|
+
if (!this.getCurrentElement()) { return false }
|
|
298
|
+
|
|
299
|
+
this.#event = "rotated"
|
|
300
|
+
this.#params.value = calcDelta(this.#params.value, delta, this.#params.min, this.#params.max)
|
|
301
|
+
return this.runCommand()
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async changed(buttonID,nodeid,val){
|
|
305
|
+
// Only handle updates within the same group identified by nodeid
|
|
306
|
+
if (nodeid !== this.#params.nodeid){
|
|
307
|
+
return
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.#index = 0;
|
|
311
|
+
this.#enforcedIndex = -1;
|
|
312
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
313
|
+
let key = this.#keys[i]
|
|
314
|
+
// check if the state-name is same as the value we get from outside:
|
|
315
|
+
if (val == key){
|
|
316
|
+
this.#index = i;
|
|
317
|
+
console.info("enforce index", buttonID,nodeid,val,i)
|
|
318
|
+
this.#enforcedIndex = this.#index;
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// check if the nodeid is the same and the value is one of the states
|
|
323
|
+
// todo überarbeiten
|
|
324
|
+
let state = this.#states[key]
|
|
325
|
+
if (state.value === undefined)
|
|
326
|
+
continue
|
|
327
|
+
|
|
328
|
+
const params = {
|
|
329
|
+
id: buttonID,
|
|
330
|
+
key: buttonID,
|
|
331
|
+
state : key,
|
|
332
|
+
...state
|
|
333
|
+
}
|
|
334
|
+
if (state && state.value !== undefined){
|
|
335
|
+
let strVal = state.value.toString()
|
|
336
|
+
let val1 = format(strVal,params)
|
|
337
|
+
if (val1 === val?.toString()){
|
|
338
|
+
this.#index = i;
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
//break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async touchmove (x, y) {
|
|
347
|
+
// if (!this.getCurrentElement()) { return false }
|
|
348
|
+
|
|
349
|
+
let delta = 0
|
|
350
|
+
if (x > this.#params.x) {
|
|
351
|
+
this.#params.moveRight = true
|
|
352
|
+
this.#params.moveLeft = false
|
|
353
|
+
} else if (x < this.#params.x) {
|
|
354
|
+
this.#params.moveRight = false
|
|
355
|
+
this.#params.moveLeft = true
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (y > this.#params.y) {
|
|
359
|
+
this.#params.moveDown = true
|
|
360
|
+
this.#params.moveUp = false
|
|
361
|
+
delta = -1
|
|
362
|
+
} else if (y < this.#params.y) {
|
|
363
|
+
this.#params.moveDown = false
|
|
364
|
+
this.#params.moveUp = true
|
|
365
|
+
delta = 1
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
this.#params.x = (x%100)
|
|
369
|
+
this.#params.y = (y%100)
|
|
370
|
+
|
|
371
|
+
// Calculate delta for value no touchmove up/down
|
|
372
|
+
this.#params.value = calcDelta(this.#params.value, delta, this.#params.min, this.#params.max)
|
|
373
|
+
|
|
374
|
+
// console.log(`d: ${this.#params.moveDown} r: ${this.#params.moveRight} `)
|
|
375
|
+
return false
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
getParams(elem){
|
|
379
|
+
// Call an action - include dynamic parameters
|
|
380
|
+
// and also all attributes of elem + global config
|
|
381
|
+
const params = {
|
|
382
|
+
...this.#profile.parameters,
|
|
383
|
+
...this.#params,
|
|
384
|
+
...elem,
|
|
385
|
+
id: this.id,
|
|
386
|
+
//key: this.key,
|
|
387
|
+
event: this.#event,
|
|
388
|
+
pressed : this.#event == "pressed",
|
|
389
|
+
released : this.#event == "released",
|
|
390
|
+
rotated : this.#event == "rotated",
|
|
391
|
+
// state: this.#keys[this.#index]
|
|
392
|
+
}
|
|
393
|
+
return params
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async runCommand () {
|
|
397
|
+
const elem = this.getCurrentElement()
|
|
398
|
+
// Only continue, if we have an element:
|
|
399
|
+
if (!elem) {
|
|
400
|
+
return
|
|
401
|
+
}
|
|
402
|
+
// Filter for Event Type:
|
|
403
|
+
if (elem.filter && elem.filter != this.#event){
|
|
404
|
+
return
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (elem.profile !== undefined) {
|
|
408
|
+
profileEmitter.emit("profileChanged", elem.profile)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (elem.brightness !== undefined) {
|
|
412
|
+
profileEmitter.emit("brightnessChanged", elem.brightness)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (elem.vibrate !== undefined) {
|
|
416
|
+
profileEmitter.emit("vibrate", elem.vibrate)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Only continue, if we have an element, that contains some kind of command:
|
|
420
|
+
if (!elem.cmd && !elem.http && !elem.opcua) {
|
|
421
|
+
return
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
let params = this.getParams(elem)
|
|
425
|
+
let res = ''
|
|
426
|
+
if ('cmd' in elem) {
|
|
427
|
+
if (shellinterface){
|
|
428
|
+
res = await shellinterface.call(elem.cmd, params)
|
|
429
|
+
}else{
|
|
430
|
+
console.warn("shellinterface not started")
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if ('http' in elem) {
|
|
434
|
+
if (httpinterface){
|
|
435
|
+
res = await httpinterface.call(elem.http, params)
|
|
436
|
+
}else{
|
|
437
|
+
console.warn("httpinterface not started")
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if ('opcua' in elem) {
|
|
441
|
+
if (opcuainterface){
|
|
442
|
+
res = await opcuainterface.call(elem.opcua, params)
|
|
443
|
+
|
|
444
|
+
/** TODO: CHECK THIS - don't think it's ever used any more */
|
|
445
|
+
/*if (this.#data.statenodeid){
|
|
446
|
+
let stateParams = params
|
|
447
|
+
params.value = params.state
|
|
448
|
+
res = await opcuainterface.call(this.#data.statenodeid, params)
|
|
449
|
+
}*/
|
|
450
|
+
}else{
|
|
451
|
+
console.warn("opcuainterface not started")
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return res
|
|
456
|
+
}
|
|
457
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as shellif from '../interfaces/shellif.mjs'
|
|
2
|
+
import * as httpif from '../interfaces/httpif.mjs'
|
|
3
|
+
import * as opcuaif from '../interfaces/opcuaif.mjs'
|
|
4
|
+
import { EventEmitter } from 'node:events'
|
|
5
|
+
|
|
6
|
+
export var opcuainterface = undefined
|
|
7
|
+
export var httpinterface = undefined
|
|
8
|
+
export var shellinterface = undefined
|
|
9
|
+
export var profileEmitter = undefined
|
|
10
|
+
|
|
11
|
+
export async function InitializeInterfaces(appConfig){
|
|
12
|
+
if (opcuainterface === undefined ){
|
|
13
|
+
opcuainterface = new opcuaif.OPCUAIf()
|
|
14
|
+
}
|
|
15
|
+
// the opcua interface needs the profile to register nodes with subscriptions:
|
|
16
|
+
opcuainterface.init(appConfig.parameters,appConfig)
|
|
17
|
+
if (httpinterface === undefined)
|
|
18
|
+
httpinterface = new httpif.HTTPif()
|
|
19
|
+
if (shellinterface === undefined)
|
|
20
|
+
shellinterface = new shellif.SHELLif()
|
|
21
|
+
if (profileEmitter === undefined)
|
|
22
|
+
profileEmitter = new EventEmitter()
|
|
23
|
+
}
|
|
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
|
+
|
package/interfaces/opcuaif.mjs
CHANGED
|
@@ -79,28 +79,24 @@ export class OPCUAIf extends BaseIf {
|
|
|
79
79
|
for (let f = 0; f < fieldKeys.length; f++) {
|
|
80
80
|
let field = fields[f]
|
|
81
81
|
const keys = Object.keys(field)
|
|
82
|
+
|
|
83
|
+
// Iterate over buttons:
|
|
82
84
|
for (let i = 0; i < keys.length; i++) {
|
|
83
85
|
const key = keys[i]
|
|
84
86
|
const elem = field[key]
|
|
87
|
+
options["key"] = key // we have to know the key of the button
|
|
85
88
|
// groupnode
|
|
86
|
-
if (elem.nodeid) {
|
|
87
|
-
|
|
88
|
-
let formattedNodeId = this.formatString(elem.nodeid, options)
|
|
89
|
+
if (elem.params && elem.params.nodeid) {
|
|
90
|
+
let formattedNodeId = this.formatString(elem.params.nodeid, options)
|
|
89
91
|
let monitoredItemId = await this.Subscribe(formattedNodeId)
|
|
90
|
-
console.log("Subscribe to",formattedNodeId)
|
|
91
|
-
this.buttons[monitoredItemId] = i
|
|
92
|
-
}
|
|
93
|
-
// statenode
|
|
94
|
-
if (elem.statenodeid) {
|
|
95
|
-
let format = this.formatString(elem.statenodeid, options)
|
|
96
|
-
let monitoredItemId = await this.Subscribe(format)
|
|
92
|
+
console.log("Subscribe to",monitoredItemId,formattedNodeId)
|
|
97
93
|
this.buttons[monitoredItemId] = i
|
|
98
94
|
}
|
|
99
95
|
await this.monitorStates(elem, options)
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
} catch (error) {
|
|
103
|
-
this.LogError(`OPCUAIf: Error
|
|
99
|
+
this.LogError(`OPCUAIf: Error\n`,error)
|
|
104
100
|
}
|
|
105
101
|
}
|
|
106
102
|
|
|
@@ -115,8 +111,9 @@ export class OPCUAIf extends BaseIf {
|
|
|
115
111
|
const key2 = stateKeys[i]
|
|
116
112
|
const state = elem.states[key2]
|
|
117
113
|
if (state.opcua) {
|
|
118
|
-
let
|
|
119
|
-
let monitoredItemId = await this.Subscribe(
|
|
114
|
+
let formattedNodeId = this.formatString(state.opcua, options)
|
|
115
|
+
let monitoredItemId = await this.Subscribe(formattedNodeId)
|
|
116
|
+
console.log("Subscribe to",monitoredItemId,formattedNodeId)
|
|
120
117
|
this.buttons[monitoredItemId] = i
|
|
121
118
|
}
|
|
122
119
|
}
|