loupedeck-commander 1.2.0 → 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 +16 -5
- package/common/BaseLoupeDeckHandler.mjs +57 -16
- package/common/touchbuttons.mjs +17 -7
- package/interfaces/baseif.mjs +16 -5
- package/interfaces/httpif.mjs +5 -10
- package/interfaces/opcuaif.mjs +37 -41
- package/interfaces/shellif.mjs +7 -6
- package/package.json +2 -2
- package/profile-1.json +208 -22
- package/test.mjs +1 -1
- package/config-test.json +0 -9
- package/interfaces/opcuaif_test.mjs +0 -31
- package/interfaces/pubel.js +0 -95
- package/profile-2.json +0 -164
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
62
|
-
|
|
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:
|
|
@@ -12,13 +12,14 @@ export class BaseLoupeDeckHandler {
|
|
|
12
12
|
screenUpdate = {}
|
|
13
13
|
stopping = false
|
|
14
14
|
|
|
15
|
-
//touchButtons = undefined
|
|
16
|
-
|
|
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
25
|
while (!this.device && !this.stopping) {
|
|
@@ -61,11 +62,17 @@ export class BaseLoupeDeckHandler {
|
|
|
61
62
|
console.info(`✅ Registered callbacks`)
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
/**
|
|
66
|
+
* event handler - loupedeck device disconnected
|
|
67
|
+
*/
|
|
64
68
|
async disconnectDevice (event) {
|
|
65
|
-
console.info("Device Disconnected"
|
|
69
|
+
console.info("Device Disconnected")
|
|
66
70
|
this.device=undefined
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
/**
|
|
74
|
+
* stop handler - close the dipslay-connection and also stop all interface handlers
|
|
75
|
+
*/
|
|
69
76
|
async stop () {
|
|
70
77
|
console.info('Stopping Handler')
|
|
71
78
|
|
|
@@ -74,39 +81,41 @@ export class BaseLoupeDeckHandler {
|
|
|
74
81
|
this.stopping = true
|
|
75
82
|
if (this.device){
|
|
76
83
|
this.device.vibrate(HAPTIC.DESCEND_MED)
|
|
77
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
84
|
+
await new Promise(resolve => setTimeout(resolve, 250))
|
|
78
85
|
}
|
|
79
86
|
if (this.device){
|
|
80
87
|
this.device.setBrightness(0)
|
|
81
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
88
|
+
await new Promise(resolve => setTimeout(resolve, 250))
|
|
82
89
|
}
|
|
83
90
|
if (this.device){
|
|
84
91
|
this.device.reconnectInterval = 0
|
|
85
92
|
await this.device.close()
|
|
86
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
87
|
-
console.
|
|
93
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
94
|
+
console.info(`Device Closed`)
|
|
88
95
|
}
|
|
89
96
|
|
|
90
97
|
console.info(`Stopping interfaces`)
|
|
91
|
-
|
|
92
98
|
await StopInterfaces()
|
|
93
|
-
await new Promise(resolve => setTimeout(resolve,
|
|
94
|
-
|
|
95
|
-
this.device = null
|
|
96
|
-
} catch (e) {
|
|
97
|
-
console.error(`${e}. Catched error in 3 seconds...`)
|
|
98
|
-
}
|
|
99
|
+
await new Promise(resolve => setTimeout(resolve, 500))
|
|
100
|
+
} catch (e) {}
|
|
99
101
|
|
|
100
102
|
process.exit()
|
|
101
103
|
|
|
102
104
|
}
|
|
103
105
|
|
|
106
|
+
/**
|
|
107
|
+
* load Application config file from JSON
|
|
108
|
+
* @param filename
|
|
109
|
+
*/
|
|
104
110
|
loadConfig (fileName) {
|
|
105
111
|
console.info(`Loading Config File ${fileName}`)
|
|
106
112
|
this.appConfig = new ApplicationConfig()
|
|
107
113
|
this.appConfig.loadFromFile(fileName)
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
/**
|
|
117
|
+
* activate the profile with the givven ID
|
|
118
|
+
*/
|
|
110
119
|
async activateProfile (id) {
|
|
111
120
|
// todo Profile-change implementation
|
|
112
121
|
var oldProfile = this.currentProfile
|
|
@@ -151,11 +160,18 @@ export class BaseLoupeDeckHandler {
|
|
|
151
160
|
await this.buttons.draw(this.device)
|
|
152
161
|
}
|
|
153
162
|
|
|
163
|
+
/**
|
|
164
|
+
* get the dictionary iwth the current profile settings
|
|
165
|
+
*/
|
|
154
166
|
getCurrentProfile () {
|
|
155
167
|
return this.appConfig.profiles[this.currentProfile]
|
|
156
168
|
}
|
|
157
169
|
|
|
158
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Triggered, when LoupeDeck Device is connected
|
|
172
|
+
* - Initialize the profile from config-file and
|
|
173
|
+
* - start the interface handlers accordingly
|
|
174
|
+
*/
|
|
159
175
|
async onConnected (address) {
|
|
160
176
|
console.info(`✅ Connected to ${this.device.type}, ${address}`)
|
|
161
177
|
|
|
@@ -166,14 +182,18 @@ export class BaseLoupeDeckHandler {
|
|
|
166
182
|
|
|
167
183
|
const self = this
|
|
168
184
|
|
|
185
|
+
// Register callback on monitored item change:
|
|
169
186
|
opcuainterface.myEmitter.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
|
|
170
187
|
|
|
171
188
|
this.device.setBrightness(1)
|
|
172
189
|
this.device.vibrate(HAPTIC.ASCEND_MED)
|
|
173
190
|
|
|
174
|
-
console.info('Done initializing')
|
|
191
|
+
console.info('✅ Done initializing')
|
|
175
192
|
}
|
|
176
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Fore an update of all screens
|
|
196
|
+
*/
|
|
177
197
|
async updateScreens () {
|
|
178
198
|
const keys = Object.keys(this.screenUpdate)
|
|
179
199
|
for (let i = 0; i < keys.length; i++) {
|
|
@@ -183,6 +203,9 @@ export class BaseLoupeDeckHandler {
|
|
|
183
203
|
this.screenUpdate = {}
|
|
184
204
|
}
|
|
185
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Button Down Handler - triggered through Event Button Down - connected to LoupeDeck Event
|
|
208
|
+
*/
|
|
186
209
|
async onButtonDown (event) {
|
|
187
210
|
let ok = false
|
|
188
211
|
const id = event.id
|
|
@@ -191,6 +214,9 @@ export class BaseLoupeDeckHandler {
|
|
|
191
214
|
return ok
|
|
192
215
|
}
|
|
193
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Button Up Handler - triggered through Event Button Up - connected to LoupeDeck Event
|
|
219
|
+
*/
|
|
194
220
|
async onButtonUp (event) {
|
|
195
221
|
let ok = false
|
|
196
222
|
const id = event.id
|
|
@@ -203,12 +229,18 @@ export class BaseLoupeDeckHandler {
|
|
|
203
229
|
return ok
|
|
204
230
|
}
|
|
205
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Button Rotate Handler - triggered through Event Rotate available with knob-Buttons - connected to LoupeDeck Event
|
|
234
|
+
*/
|
|
206
235
|
async onRotate (event) {
|
|
207
236
|
const id = event.id
|
|
208
237
|
const delta = event.delta
|
|
209
238
|
return await this.buttons.rotated(id, delta)
|
|
210
239
|
}
|
|
211
240
|
|
|
241
|
+
/**
|
|
242
|
+
* TouchStart Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
|
|
243
|
+
*/
|
|
212
244
|
async onTouchStart (event) {
|
|
213
245
|
let ok = false
|
|
214
246
|
const changedTouches = event.changedTouches
|
|
@@ -225,6 +257,9 @@ export class BaseLoupeDeckHandler {
|
|
|
225
257
|
return ok
|
|
226
258
|
}
|
|
227
259
|
|
|
260
|
+
/**
|
|
261
|
+
* TouchMove Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
|
|
262
|
+
*/
|
|
228
263
|
async onTouchMove (event) {
|
|
229
264
|
let ok = false
|
|
230
265
|
const changedTouches = event.changedTouches
|
|
@@ -241,6 +276,9 @@ export class BaseLoupeDeckHandler {
|
|
|
241
276
|
return ok
|
|
242
277
|
}
|
|
243
278
|
|
|
279
|
+
/**
|
|
280
|
+
* TouchEnd Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
|
|
281
|
+
*/
|
|
244
282
|
async onTouchEnd (event) {
|
|
245
283
|
let ok = false
|
|
246
284
|
const changedTouches = event.changedTouches
|
|
@@ -258,6 +296,9 @@ export class BaseLoupeDeckHandler {
|
|
|
258
296
|
return ok
|
|
259
297
|
}
|
|
260
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Handler for StateChanged through OPC/UA Interface - only connected with touch-buttons on center field (yet)
|
|
301
|
+
*/
|
|
261
302
|
async buttonStateChanged(buttonID,nodeid,val) {
|
|
262
303
|
let ok = false
|
|
263
304
|
this.screenUpdate["center"] = true
|
package/common/touchbuttons.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadImage } from 'canvas'
|
|
2
|
+
//import { loadImage } from "https://deno.land/x/canvas/mod.ts";
|
|
2
3
|
|
|
3
4
|
import * as shellif from '../interfaces/shellif.mjs'
|
|
4
5
|
import * as httpif from '../interfaces/httpif.mjs'
|
|
@@ -202,6 +203,7 @@ export class Button {
|
|
|
202
203
|
#nodeid = ""
|
|
203
204
|
|
|
204
205
|
#index = 0
|
|
206
|
+
#event
|
|
205
207
|
#keys
|
|
206
208
|
#states
|
|
207
209
|
|
|
@@ -346,7 +348,7 @@ export class Button {
|
|
|
346
348
|
this.timeStampPressed = Date.now()
|
|
347
349
|
|
|
348
350
|
this.#index++
|
|
349
|
-
this.updateState(this.#index)
|
|
351
|
+
this.updateState(this.#index,"pressed")
|
|
350
352
|
return true
|
|
351
353
|
}
|
|
352
354
|
|
|
@@ -375,13 +377,14 @@ export class Button {
|
|
|
375
377
|
break
|
|
376
378
|
}
|
|
377
379
|
|
|
378
|
-
this.updateState(this.#index)
|
|
380
|
+
this.updateState(this.#index,"released")
|
|
379
381
|
|
|
380
382
|
return true // this.runCommand()
|
|
381
383
|
}
|
|
382
384
|
|
|
383
|
-
updateState(index){
|
|
385
|
+
updateState(index,eventType){
|
|
384
386
|
this.#index = index
|
|
387
|
+
this.#event = eventType
|
|
385
388
|
// Update the State according to the correctly pressed state
|
|
386
389
|
if (this.#index < 0) { this.#index = this.#keys.length - 1 }
|
|
387
390
|
this.#index %= this.#keys.length
|
|
@@ -393,6 +396,7 @@ export class Button {
|
|
|
393
396
|
async rotated (delta) {
|
|
394
397
|
if (!this.getCurrentElement()) { return false }
|
|
395
398
|
|
|
399
|
+
this.#event = "rotated"
|
|
396
400
|
this.#value = calcDelta(this.#value, delta, this.#max)
|
|
397
401
|
return this.runCommand()
|
|
398
402
|
}
|
|
@@ -458,21 +462,27 @@ export class Button {
|
|
|
458
462
|
|
|
459
463
|
async runCommand () {
|
|
460
464
|
const elem = this.getCurrentElement()
|
|
465
|
+
// Only continue, if we have an element, that contains some kind of command:
|
|
461
466
|
if (!elem || (!elem.cmd && !elem.http && !elem.opcua)) {
|
|
462
467
|
return
|
|
463
468
|
}
|
|
469
|
+
// Filter for Event Type:
|
|
470
|
+
if (elem.filter && elem.filter != this.#event){
|
|
471
|
+
return
|
|
472
|
+
}
|
|
464
473
|
// Call an action - include dynamic parameters
|
|
465
474
|
// and also all attributes of elem + global config
|
|
466
475
|
const params = {
|
|
476
|
+
text: this.getCurrentText(),
|
|
477
|
+
...this.#config.parameters,
|
|
478
|
+
...elem,
|
|
467
479
|
id: this.id,
|
|
468
480
|
key: this.key,
|
|
481
|
+
event: this.#event,
|
|
469
482
|
state: this.#keys[this.#index],
|
|
470
483
|
min: this.#min,
|
|
471
484
|
max: this.#max,
|
|
472
|
-
value: this.#value
|
|
473
|
-
text: this.getCurrentText(),
|
|
474
|
-
...this.#config.parameters,
|
|
475
|
-
...elem
|
|
485
|
+
value: this.#value
|
|
476
486
|
}
|
|
477
487
|
|
|
478
488
|
let res = ''
|
package/interfaces/baseif.mjs
CHANGED
|
@@ -22,7 +22,11 @@ export class BaseIf {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
formatString (cmd, options = {}) {
|
|
25
|
-
|
|
25
|
+
let f =""
|
|
26
|
+
try{
|
|
27
|
+
f = format(cmd, options)
|
|
28
|
+
}catch(e){}
|
|
29
|
+
return f
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
Check(options) {
|
|
@@ -44,14 +48,21 @@ export class BaseIf {
|
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
LogError(...args){
|
|
47
|
-
|
|
51
|
+
let str = new String(args)
|
|
52
|
+
process.stderr.write(str.toString())
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
LogDebug(...args){
|
|
56
|
+
if (this.options && this.options.verbose){
|
|
57
|
+
let str = new String(args)
|
|
58
|
+
process.stdout.write(str.toString())
|
|
59
|
+
}
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
LogInfo(...args){
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
let str = new String(args)
|
|
64
|
+
process.stdout.write(str.toString())
|
|
53
65
|
}
|
|
54
|
-
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
|
package/interfaces/httpif.mjs
CHANGED
|
@@ -12,15 +12,15 @@ export class HTTPif extends BaseIf {
|
|
|
12
12
|
try {
|
|
13
13
|
myURL = new url.URL(url1)
|
|
14
14
|
await this.get(myURL, options)
|
|
15
|
-
} catch (
|
|
16
|
-
|
|
15
|
+
} catch (e) {
|
|
16
|
+
this.LogError(`HTTPif: error with URL: ${e.message}\n`)
|
|
17
17
|
return false
|
|
18
18
|
}
|
|
19
19
|
return true
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async stop(){
|
|
23
|
-
|
|
23
|
+
this.LogInfo("HTTPif: Stopping\n")
|
|
24
24
|
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -30,10 +30,6 @@ export class HTTPif extends BaseIf {
|
|
|
30
30
|
return res
|
|
31
31
|
if (!options.hostname)
|
|
32
32
|
return -21
|
|
33
|
-
/*if (!options.port)
|
|
34
|
-
return -22
|
|
35
|
-
if (!options.pathname)
|
|
36
|
-
return -23*/
|
|
37
33
|
return 0
|
|
38
34
|
}
|
|
39
35
|
|
|
@@ -53,8 +49,7 @@ export class HTTPif extends BaseIf {
|
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
console.log('HTTPIf call URL:', myURL, getOptions)
|
|
52
|
+
this.LogInfo(`HTTPIf: call URL ${myURL} ${getOptions}\n`)
|
|
58
53
|
|
|
59
54
|
|
|
60
55
|
const prom = new Promise((resolve, reject) => {
|
|
@@ -76,7 +71,7 @@ export class HTTPif extends BaseIf {
|
|
|
76
71
|
})
|
|
77
72
|
|
|
78
73
|
req.on('error', (e) => {
|
|
79
|
-
|
|
74
|
+
this.LogError(`HTTPif: ignore other errors like ERRNOTCONNECTED: ${e.message}\n`)
|
|
80
75
|
return false
|
|
81
76
|
});
|
|
82
77
|
}).catch(function (error) { // (*)
|
package/interfaces/opcuaif.mjs
CHANGED
|
@@ -42,32 +42,32 @@ export class OPCUAIf extends BaseIf {
|
|
|
42
42
|
super()
|
|
43
43
|
this.myEmitter = new EventEmitter();
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
this.LogInfo(`OPCUAIf Constructed`);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
async stop(){
|
|
49
49
|
if (!this.#client)
|
|
50
50
|
return
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
this.LogInfo(`OPCUAIf Stopping`)
|
|
53
53
|
await this.#client.closeSession(this.#session,true)
|
|
54
54
|
await this.#client.disconnect()
|
|
55
55
|
this.#connected = false
|
|
56
56
|
this.#client = null
|
|
57
|
-
|
|
57
|
+
this.LogInfo(`OPCUAIf Stopped\n`)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
async init( options = {},config = {},callbackFunction){
|
|
61
61
|
var res = this.Check(options)
|
|
62
62
|
if (res<0){
|
|
63
|
-
|
|
63
|
+
this.LogError(`OPCUAIf: Missing essential options in dictionary => Quitting $res $options\n`)
|
|
64
64
|
}
|
|
65
65
|
try{
|
|
66
66
|
this.#endpointurl = options.endpointurl
|
|
67
67
|
this.#callback = callbackFunction
|
|
68
68
|
this.monitoreditems = {}
|
|
69
69
|
this.buttons = {}
|
|
70
|
-
|
|
70
|
+
this.LogInfo(`OPCUAIf init ${this.#endpointurl}\n`);
|
|
71
71
|
|
|
72
72
|
await this.Connect(this.#endpointurl);
|
|
73
73
|
|
|
@@ -84,21 +84,21 @@ export class OPCUAIf extends BaseIf {
|
|
|
84
84
|
|
|
85
85
|
}
|
|
86
86
|
} catch (error) {
|
|
87
|
-
|
|
87
|
+
this.LogError(`OPCUAIf: Error $error\n`)
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
async call (opcuaNode, options = {}) {
|
|
92
92
|
var res = this.Check(options)
|
|
93
93
|
if (res<0){
|
|
94
|
-
|
|
94
|
+
this.LogError(`OPCUAIf call: Missing essential options in dictionary => Quitting $res\n`)
|
|
95
95
|
return false
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
var nodeId = super.formatString(opcuaNode, options)
|
|
99
99
|
var value = super.formatString(options.value, options)
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
this.LogInfo(`OPCUAIf: write ${nodeId} => ${value}\n`)
|
|
102
102
|
await this.Write(nodeId,value)
|
|
103
103
|
|
|
104
104
|
var NewState = "waiting"
|
|
@@ -120,9 +120,9 @@ export class OPCUAIf extends BaseIf {
|
|
|
120
120
|
|
|
121
121
|
async Disconnect() {
|
|
122
122
|
if (this.#client){
|
|
123
|
-
|
|
123
|
+
this.LogInfo(`OPCUAIf: Disconnect\n`);
|
|
124
124
|
await this.#client.Disconnect()
|
|
125
|
-
|
|
125
|
+
this.LogInfo(`OPCUAIf: Disconnected\n`);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
async Connect(url) {
|
|
@@ -137,8 +137,8 @@ export class OPCUAIf extends BaseIf {
|
|
|
137
137
|
securityPolicy: SecurityPolicy.None,
|
|
138
138
|
connectionStrategy: {
|
|
139
139
|
maxRetry: -1,
|
|
140
|
-
maxDelay:
|
|
141
|
-
initialDelay:
|
|
140
|
+
maxDelay: 5000,
|
|
141
|
+
initialDelay: 2500
|
|
142
142
|
},
|
|
143
143
|
|
|
144
144
|
defaultSecureTokenLifetime: 20000,
|
|
@@ -146,52 +146,49 @@ export class OPCUAIf extends BaseIf {
|
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
this.#client.on("backoff", (retry, delay) => {
|
|
149
|
-
|
|
149
|
+
if((retry%10) == 0)
|
|
150
|
+
this.LogInfo(`OPCUAIf Try Reconnection ${retry} next attempt in ${delay}ms ${self.#endpointurl}\n`);
|
|
150
151
|
});
|
|
151
152
|
|
|
152
153
|
this.#client.on("connection_lost", () => {
|
|
153
|
-
|
|
154
|
+
this.LogInfo(`OPCUAIf: Connection lost\n`);
|
|
154
155
|
});
|
|
155
156
|
|
|
156
157
|
this.#client.on("connection_reestablished", () => {
|
|
157
|
-
|
|
158
|
+
this.LogInfo(`OPCUAIf: Connection re-established\n`);
|
|
158
159
|
});
|
|
159
160
|
|
|
160
161
|
this.#client.on("connection_failed", () => {
|
|
161
|
-
|
|
162
|
+
this.LogInfo(`OPCUAIf: Connection failed\n`);
|
|
162
163
|
});
|
|
163
164
|
this.#client.on("start_reconnection", () => {
|
|
164
|
-
|
|
165
|
+
this.LogInfo(`OPCUAIf: Starting reconnection\n`);
|
|
165
166
|
});
|
|
166
167
|
|
|
167
168
|
this.#client.on("after_reconnection", (err) => {
|
|
168
|
-
|
|
169
|
+
this.LogInfo(`OPCUAIf: After Reconnection event => ${err}\n`);
|
|
169
170
|
});
|
|
170
171
|
this.#client.on("security_token_renewed", () => {
|
|
171
|
-
|
|
172
|
-
//console.log(this.#client.toString());
|
|
173
|
-
})
|
|
174
|
-
this.#client.on("lifetime_75", (token) => {
|
|
175
|
-
//// /*ChannelSecurityToken*/
|
|
176
|
-
//console.log("lifetime_75 =>", token.toString());
|
|
172
|
+
this.LogInfo(`OPCUAIf: security_token_renewed\n`);
|
|
177
173
|
})
|
|
174
|
+
this.#client.on("lifetime_75", (token) => {})
|
|
178
175
|
|
|
179
|
-
|
|
176
|
+
this.LogInfo(`OPCUAIf: connecting client to ${url}\n`);//, this.#session.toString());
|
|
180
177
|
await this.#client.connect(url);
|
|
181
178
|
|
|
182
179
|
this.#session = await this.#client.createSession();
|
|
183
180
|
|
|
184
181
|
this.#session.on("session_closed", (statusCode) => {
|
|
185
|
-
|
|
182
|
+
this.LogInfo(`OPCUAIf: Session has been closed\n`);
|
|
186
183
|
})
|
|
187
184
|
this.#session.on("session_restored", () => {
|
|
188
|
-
|
|
185
|
+
this.LogInfo(`OPCUAIf: Session has been restored\n`);
|
|
189
186
|
});
|
|
190
187
|
this.#session.on("keepalive", (lastKnownServerState) => {
|
|
191
|
-
|
|
188
|
+
this.LogInfo(`OPCUAIf: KeepAlive lastKnownServerState ${lastKnownServerState}\n`);
|
|
192
189
|
});
|
|
193
190
|
this.#session.on("keepalive_failure", () => {
|
|
194
|
-
|
|
191
|
+
this.LogInfo(`OPCUAIf: KeepAlive failure\n`);
|
|
195
192
|
});
|
|
196
193
|
|
|
197
194
|
this.#sub = await this.#session.createSubscription2({
|
|
@@ -202,9 +199,9 @@ export class OPCUAIf extends BaseIf {
|
|
|
202
199
|
requestedPublishingInterval: 1000
|
|
203
200
|
});
|
|
204
201
|
|
|
205
|
-
this.LogInfo(
|
|
206
|
-
this.LogInfo(
|
|
207
|
-
this.LogInfo(
|
|
202
|
+
this.LogInfo(`OPCUAIf: session created\n`);//, this.#session.toString());
|
|
203
|
+
this.LogInfo(`OPCUAIf: client\n`);
|
|
204
|
+
this.LogInfo(`OPCUAIf: subscription\n`);
|
|
208
205
|
this.#connected = true
|
|
209
206
|
this.#endpointurl = url
|
|
210
207
|
}
|
|
@@ -222,17 +219,16 @@ export class OPCUAIf extends BaseIf {
|
|
|
222
219
|
};
|
|
223
220
|
|
|
224
221
|
if (!this.#sub){
|
|
225
|
-
this.LogError(
|
|
222
|
+
this.LogError(`OPCUAIf: not register monitored items $itemToMonitor\n`);
|
|
226
223
|
return
|
|
227
224
|
}
|
|
228
225
|
const monitoredItem = await this.#sub.monitor(itemToMonitor, monitoringParameters, TimestampsToReturn.Both);
|
|
229
226
|
this.monitoreditems[monitoredItem.monitoredItemId] = nodeID
|
|
230
227
|
var self=this
|
|
231
|
-
//monitoredItem.on("changed", this.MonitoredItemUpdate)
|
|
232
228
|
monitoredItem.on("changed", function (dataValue) {
|
|
233
229
|
var nodeId = self.monitoreditems[this.monitoredItemId]
|
|
234
230
|
var buttonID = self.buttons[this.monitoredItemId]
|
|
235
|
-
|
|
231
|
+
this.LogDebug("OPCUAIf: monitored item changed: ", this.monitoredItemId,nodeId, dataValue.value.value,"\n");
|
|
236
232
|
self.myEmitter.emit('monitored item changed',buttonID,nodeId, dataValue.value.value)
|
|
237
233
|
});
|
|
238
234
|
|
|
@@ -245,18 +241,18 @@ export class OPCUAIf extends BaseIf {
|
|
|
245
241
|
attributeId: AttributeIds.Value
|
|
246
242
|
};
|
|
247
243
|
if (!this.#connected){
|
|
248
|
-
this.LogError(
|
|
244
|
+
this.LogError(`OPCUAIf: not connected, cannot read ${nodeID}\n`);
|
|
249
245
|
return
|
|
250
246
|
}
|
|
251
247
|
const dataValue2 = await this.#session.read(nodeToRead, 0);
|
|
252
|
-
this.LogError("
|
|
248
|
+
this.LogError("OPCUAIf: read nodeID ",nodeID, dataValue2.toString(),"\n");
|
|
253
249
|
return dataValue2
|
|
254
250
|
}
|
|
255
251
|
|
|
256
252
|
async Write(nodeID,value,datatype=DataType.String) {
|
|
257
253
|
let self = this
|
|
258
254
|
if (!this.#connected){
|
|
259
|
-
self.LogError(" not connected, cannot write",nodeID, value);
|
|
255
|
+
self.LogError("OPCUAIf: not connected, cannot write",nodeID, value,"\n");
|
|
260
256
|
return
|
|
261
257
|
}
|
|
262
258
|
var nodesToWrite = [{
|
|
@@ -273,12 +269,12 @@ export class OPCUAIf extends BaseIf {
|
|
|
273
269
|
await this.#session.write(nodesToWrite, function(err,statusCodes) {
|
|
274
270
|
if (!err) {
|
|
275
271
|
if (statusCodes && statusCodes[0].value != 0){
|
|
276
|
-
self.LogInfo(
|
|
272
|
+
self.LogInfo(`OPCUAIf: status $statusCodes\n`);
|
|
277
273
|
}else{
|
|
278
|
-
self.LogInfo(
|
|
274
|
+
self.LogInfo(`OPCUAIf: wrote $nodeID => $value\n`);
|
|
279
275
|
}
|
|
280
276
|
}else{
|
|
281
|
-
self.LogError(" write NOT ok",nodeID, value);
|
|
277
|
+
self.LogError("OPCUAIf: write NOT ok",nodeID, value,"\n");
|
|
282
278
|
self.LogError(err)
|
|
283
279
|
}
|
|
284
280
|
});
|
package/interfaces/shellif.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { exec } from 'child_process'
|
|
2
|
+
//import { exec } from 'node:child_process'
|
|
2
3
|
import { BaseIf } from './baseif.mjs'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -11,7 +12,7 @@ export class SHELLif extends BaseIf {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
async stop(){
|
|
14
|
-
|
|
15
|
+
this.LogInfo("SHELLif: Stopping")
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
Check(options) {
|
|
@@ -26,15 +27,15 @@ export class SHELLif extends BaseIf {
|
|
|
26
27
|
* @returns
|
|
27
28
|
*/
|
|
28
29
|
async sh (cmd) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
let self = this;
|
|
31
|
+
this.LogDebug(`ShellIf: runCmd: ${cmd}\n`)
|
|
32
|
+
|
|
32
33
|
return new Promise(function (resolve, reject) {
|
|
33
34
|
exec(cmd, (err, stdout, stderr) => {
|
|
34
35
|
if (stdout.length>0)
|
|
35
|
-
|
|
36
|
+
self.LogInfo(`SHELLif Out: ${stdout}`)
|
|
36
37
|
if (stderr.length>0)
|
|
37
|
-
|
|
38
|
+
self.LogError(`SHELLif Err: ${stderr}`)
|
|
38
39
|
if (err) {
|
|
39
40
|
reject(err)
|
|
40
41
|
} else {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loupedeck-commander",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "A system to ease working with LoupeDeck devices using CMD-line interfaces",
|
|
3
|
+
"version": "1.2.1",
|
|
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
7
|
"test": "node test.mjs",
|
package/profile-1.json
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
"password": "httppasswd",
|
|
7
7
|
"verbose" : false,
|
|
8
8
|
"endpointurl": "opc.tcp://localhost:4840",
|
|
9
|
-
"nodeid" : "ns=
|
|
10
|
-
"value" : "
|
|
11
|
-
"
|
|
9
|
+
"nodeid" : "ns=0;s=OpcUaNode-{customarg}",
|
|
10
|
+
"value" : "value",
|
|
11
|
+
"customarg": "1"
|
|
12
12
|
},
|
|
13
13
|
"description": "",
|
|
14
14
|
"config": {},
|
|
@@ -29,25 +29,22 @@
|
|
|
29
29
|
"cmd": "echo \"{id} {state}\""
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
-
"group": "
|
|
32
|
+
"group": "group1"
|
|
33
33
|
},
|
|
34
34
|
"1": {
|
|
35
35
|
"states": {
|
|
36
36
|
"off": {
|
|
37
37
|
"color": "#aaaaaa",
|
|
38
|
-
"image": "icons/bulb.png"
|
|
39
|
-
"http": "http://{user}:{password}@{hostname}:7778/control/connections"
|
|
38
|
+
"image": "icons/bulb.png"
|
|
40
39
|
},
|
|
41
40
|
"on": {
|
|
42
41
|
"color": "#11ff11",
|
|
43
42
|
"image": "icons/bulb.png",
|
|
44
|
-
"http": "http://{hostname}:7778/control/connections",
|
|
45
|
-
"opcua": "write",
|
|
46
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
43
|
+
"http": "http://{user}:{password}@{hostname}:7778/control/connections",
|
|
47
44
|
"value": "{key}"
|
|
48
45
|
}
|
|
49
46
|
},
|
|
50
|
-
"group": "
|
|
47
|
+
"group": "group1"
|
|
51
48
|
},
|
|
52
49
|
"2": {
|
|
53
50
|
"states": {
|
|
@@ -58,33 +55,222 @@
|
|
|
58
55
|
"on": {
|
|
59
56
|
"color": "#11ff11",
|
|
60
57
|
"image": "icons/mountain.png",
|
|
61
|
-
"opcua": "
|
|
62
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
58
|
+
"opcua": "ns=0;s=Node{simnbr}",
|
|
63
59
|
"value": "{key}"
|
|
64
60
|
}
|
|
65
61
|
},
|
|
66
|
-
"group": "
|
|
62
|
+
"group": "group1"
|
|
63
|
+
},
|
|
64
|
+
"8": {
|
|
65
|
+
"states": {
|
|
66
|
+
"off": {
|
|
67
|
+
"color": "#aaaaaa",
|
|
68
|
+
"cmd": "echo \"{id} {state} {event} {value}\"",
|
|
69
|
+
"value": "custom-value-{key}" },
|
|
70
|
+
"on": {
|
|
71
|
+
"color": "#11ff11",
|
|
72
|
+
"cmd": "echo \"{id} {state} {event} {value}\"",
|
|
73
|
+
"value": "custom-value-{key}"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"group": "group2"
|
|
77
|
+
},
|
|
78
|
+
"9": {
|
|
79
|
+
"states": {
|
|
80
|
+
"off": {
|
|
81
|
+
"color": "#bbbbbb",
|
|
82
|
+
"cmd": "echo \"{id} {state} {event} {value}\"",
|
|
83
|
+
"value": "custom-value-{key}" },
|
|
84
|
+
"on": {
|
|
85
|
+
"color": "#33ff33",
|
|
86
|
+
"cmd": "echo \"{id} {state} {event} {value}\"",
|
|
87
|
+
"value": "custom-value-{key}"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"group": "group2"
|
|
67
91
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"knobs": {
|
|
72
|
-
"left": {},
|
|
73
|
-
"right": {}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
}
|
|
74
95
|
},
|
|
75
96
|
"buttons": {
|
|
97
|
+
"knobTL": {
|
|
98
|
+
"states": {
|
|
99
|
+
"off": {
|
|
100
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
101
|
+
},
|
|
102
|
+
"on": {
|
|
103
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"knobCL": {
|
|
108
|
+
"states": {
|
|
109
|
+
"off": {
|
|
110
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
111
|
+
},
|
|
112
|
+
"on": {
|
|
113
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"knobBL": {
|
|
118
|
+
"states": {
|
|
119
|
+
"off": {
|
|
120
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
121
|
+
},
|
|
122
|
+
"on": {
|
|
123
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"knobTR": {
|
|
128
|
+
"states": {
|
|
129
|
+
"off": {
|
|
130
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
131
|
+
},
|
|
132
|
+
"on": {
|
|
133
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"knobCR": {
|
|
138
|
+
"states": {
|
|
139
|
+
"off": {
|
|
140
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
141
|
+
},
|
|
142
|
+
"on": {
|
|
143
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"knobBR": {
|
|
148
|
+
"states": {
|
|
149
|
+
"off": {
|
|
150
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
151
|
+
},
|
|
152
|
+
"on": {
|
|
153
|
+
"cmd": "echo \"{id} {state} Val: {value} Event: {event}\""
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"0": {
|
|
158
|
+
"states": {
|
|
159
|
+
"off": {
|
|
160
|
+
"color": "#aaaaaa",
|
|
161
|
+
"cmd": "echo \"{id} {state} {event}\""
|
|
162
|
+
},
|
|
163
|
+
"med": {
|
|
164
|
+
"color": "ff11ff",
|
|
165
|
+
"cmd": "echo \"{id} {state} {event}\""
|
|
166
|
+
},
|
|
167
|
+
"on": {
|
|
168
|
+
"color": "#11ff11",
|
|
169
|
+
"cmd": "echo \"{id} {state} {event}\""
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"group": "group1"
|
|
173
|
+
},
|
|
76
174
|
"1": {
|
|
77
175
|
"states": {
|
|
78
176
|
"off": {
|
|
79
177
|
"color": "#aaaaaa",
|
|
80
|
-
"cmd": "echo \"{id} {state}\""
|
|
178
|
+
"cmd": "echo \"{id} {state} {event}\""
|
|
81
179
|
},
|
|
180
|
+
"med": {
|
|
181
|
+
"color": "ff11ff",
|
|
182
|
+
"cmd": "echo \"{id} {state} {event}\""
|
|
183
|
+
},
|
|
184
|
+
"on": {
|
|
185
|
+
"color": "#11ff11",
|
|
186
|
+
"cmd": "echo \"{id} {state} {event}\""
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"group": "group1"
|
|
190
|
+
},
|
|
191
|
+
"2": {
|
|
192
|
+
"states": {
|
|
193
|
+
"off": {
|
|
194
|
+
"color": "#aaaaaa",
|
|
195
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
196
|
+
"filter": "released" },
|
|
197
|
+
"on": {
|
|
198
|
+
"color": "#11ff11",
|
|
199
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
200
|
+
"filter": "released"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"group": "group1"
|
|
204
|
+
},
|
|
205
|
+
"3": {
|
|
206
|
+
"states": {
|
|
207
|
+
"off": {
|
|
208
|
+
"color": "#aaaaaa",
|
|
209
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
210
|
+
"filter": "released" },
|
|
211
|
+
"on": {
|
|
212
|
+
"color": "#11ff11",
|
|
213
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
214
|
+
"filter": "released"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
"group": "group1"
|
|
218
|
+
},
|
|
219
|
+
"4": {
|
|
220
|
+
"states": {
|
|
221
|
+
"off": {
|
|
222
|
+
"color": "#aaaaaa",
|
|
223
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
224
|
+
"filter": "released" },
|
|
225
|
+
"on": {
|
|
226
|
+
"color": "#11ff11",
|
|
227
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
228
|
+
"filter": "released"
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"group": "group1"
|
|
232
|
+
},
|
|
233
|
+
"5": {
|
|
234
|
+
"states": {
|
|
235
|
+
"off": {
|
|
236
|
+
"color": "#aaaaaa",
|
|
237
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
238
|
+
"filter": "released" },
|
|
239
|
+
"on": {
|
|
240
|
+
"color": "#11ff11",
|
|
241
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
242
|
+
"filter": "released"
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
"group": "group1"
|
|
246
|
+
},
|
|
247
|
+
"6": {
|
|
248
|
+
"states": {
|
|
249
|
+
"off": {
|
|
250
|
+
"color": "#aaaaaa",
|
|
251
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
252
|
+
"filter": "released" },
|
|
253
|
+
"on": {
|
|
254
|
+
"color": "#11ff11",
|
|
255
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
256
|
+
"filter": "released"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"group": "group1"
|
|
260
|
+
},
|
|
261
|
+
"7": {
|
|
262
|
+
"states": {
|
|
263
|
+
"off": {
|
|
264
|
+
"color": "#aaaaaa",
|
|
265
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
266
|
+
"filter": "released" },
|
|
82
267
|
"on": {
|
|
83
268
|
"color": "#11ff11",
|
|
84
|
-
"cmd": "echo \"{id} {state}\""
|
|
269
|
+
"cmd": "echo \"{id} {key} {state} {event}\"",
|
|
270
|
+
"filter": "released"
|
|
85
271
|
}
|
|
86
272
|
},
|
|
87
|
-
"group": "
|
|
273
|
+
"group": "group1"
|
|
88
274
|
}
|
|
89
275
|
}
|
|
90
276
|
}
|
package/test.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseLoupeDeckHandler } from './common/BaseLoupeDeckHandler.mjs'
|
|
2
2
|
//import { BaseLoupeDeckHandler } from 'loupedeck-commander'
|
|
3
3
|
|
|
4
|
-
const handler = new BaseLoupeDeckHandler('config
|
|
4
|
+
const handler = new BaseLoupeDeckHandler('config.json')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Stop the handlers when a signal like SIGINT or SIGTERM arrive
|
package/config-test.json
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import * as opcuaif from '../interfaces/opcuaif.mjs'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var opcuainterface = new opcuaif.OPCUAIf()
|
|
5
|
-
import {
|
|
6
|
-
DataType
|
|
7
|
-
} from "node-opcua";
|
|
8
|
-
|
|
9
|
-
var call = {
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
var option = {
|
|
14
|
-
"id" : "touch-0",
|
|
15
|
-
"key" : "1",
|
|
16
|
-
"state" : "off",
|
|
17
|
-
"min": "0",
|
|
18
|
-
"max": "0",
|
|
19
|
-
"color": "0",
|
|
20
|
-
"image": "0",
|
|
21
|
-
"endpointurl": "opc.tcp://localhost:4840",
|
|
22
|
-
"nodeid": "ns=4;s=Is{key}.Kvm.in.Source",
|
|
23
|
-
"value": "{key}"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
await opcuainterface.call(call,option)
|
|
27
|
-
await opcuainterface.Subscribe("ns=4;s=Is1.Kvm.out.Source")
|
|
28
|
-
await opcuainterface.Subscribe("ns=4;s=Is1.Kvm.out.Turret")
|
|
29
|
-
await opcuainterface.Write("ns=4;s=Is1.Kvm.out.Turret",1,DataType.Int16)
|
|
30
|
-
await opcuainterface.Write("ns=4;s=Is1.Kvm.out.Source","hello",DataType.String)
|
|
31
|
-
//await opcuainterface.Write("ns=4;s=Is1.Kvm.state",2,DataType.Int32)
|
package/interfaces/pubel.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OPCUAClient,
|
|
3
|
-
BrowseDirection,
|
|
4
|
-
AttributeIds,
|
|
5
|
-
NodeClassMask,
|
|
6
|
-
makeBrowsePath,
|
|
7
|
-
resolveNodeId,
|
|
8
|
-
TimestampsToReturn,
|
|
9
|
-
coerceInt32,
|
|
10
|
-
coerceByteString
|
|
11
|
-
} from "node-opcua";
|
|
12
|
-
import { BaseIf } from './baseif.mjs'
|
|
13
|
-
|
|
14
|
-
var endpointUrl = "opc.tcp://localhost:4840";
|
|
15
|
-
const subscriptionParameters = {
|
|
16
|
-
maxNotificationsPerPublish: 1000,
|
|
17
|
-
publishingEnabled: true,
|
|
18
|
-
requestedLifetimeCount: 100,
|
|
19
|
-
requestedMaxKeepAliveCount: 10,
|
|
20
|
-
requestedPublishingInterval: 1000
|
|
21
|
-
};
|
|
22
|
-
var client
|
|
23
|
-
var GlobalSession
|
|
24
|
-
var GlobalSub
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
async function Connect() {
|
|
28
|
-
client = OPCUAClient.create({
|
|
29
|
-
endpointMustExist: false
|
|
30
|
-
});
|
|
31
|
-
client.on("backoff", (retry, delay) =>
|
|
32
|
-
console.log("still trying to connect to ", endpointUrl, ": retry =", retry, "next attempt in ", delay / 1000, "seconds")
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//await client.connect(endpointUrl)
|
|
37
|
-
var self=this
|
|
38
|
-
await client.withSubscriptionAsync(endpointUrl, subscriptionParameters, async (session, subscription) => {
|
|
39
|
-
GlobalSession = session
|
|
40
|
-
GlobalSub = subscription
|
|
41
|
-
console.log("Session initialized")
|
|
42
|
-
|
|
43
|
-
// wait until CTRL+C is pressed
|
|
44
|
-
console.log("CTRL+C to stop");
|
|
45
|
-
await new Promise((resolve) => process.once("SIGINT", resolve));
|
|
46
|
-
} )
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function Subscribe(nodeID) {
|
|
50
|
-
// install monitored item
|
|
51
|
-
|
|
52
|
-
nodeID = "ns=4;s=Is1.Kvm.in.Source"
|
|
53
|
-
const itemToMonitor = {
|
|
54
|
-
nodeId: resolveNodeId(nodeID),
|
|
55
|
-
attributeId: AttributeIds.Value
|
|
56
|
-
};
|
|
57
|
-
const monitoringParameters = {
|
|
58
|
-
samplingInterval: 100,
|
|
59
|
-
discardOldest: true,
|
|
60
|
-
queueSize: 10
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const monitoredItem = await GlobalSub.monitor(itemToMonitor, monitoringParameters, TimestampsToReturn.Both);
|
|
64
|
-
monitoredItem.on("changed", function (dataValue) {
|
|
65
|
-
//console.log("monitored item changed: ", coerceInt32(dataValue.value.value), "bytes");
|
|
66
|
-
console.log("monitored item changed: ", nodeID, dataValue.value.value);
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function Read(nodeID) {
|
|
71
|
-
if client
|
|
72
|
-
const maxAge = 0;
|
|
73
|
-
const nodeToRead = {
|
|
74
|
-
nodeId: "ns=4;s=Is1.Kvm.in.Receiver",
|
|
75
|
-
attributeId: AttributeIds.Value
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const dataValue2 = await GlobalSession.read(nodeToRead, maxAge);
|
|
79
|
-
console.log(" nodeID ",nodeID, dataValue2.toString());
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
Connect();
|
|
83
|
-
//await Read("ns=4;s=Is1.Kvm.in.Receiver")
|
|
84
|
-
await Subscribe("ns=4;s=Is1.Kvm.in.Receiver")
|
|
85
|
-
await new Promise((resolve) => process.once("SIGINT", resolve));
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Our Special-Handler just used the Default - and adds Vibration after triggers through Button-Releases
|
|
90
|
-
*/
|
|
91
|
-
export class OPCUAIf extends BaseIf {
|
|
92
|
-
async call (callString, options = {}) {
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
package/profile-2.json
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"profile": "sample",
|
|
3
|
-
"parameters": {
|
|
4
|
-
"hostname": "localhost",
|
|
5
|
-
"user": "httpuser",
|
|
6
|
-
"password": "httppasswd",
|
|
7
|
-
"verbose" : false,
|
|
8
|
-
"endpointurl": "opc.tcp://localhost:4840",
|
|
9
|
-
"nodeid" : "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
10
|
-
"value" : "kvm-transmitter-1",
|
|
11
|
-
"simnbr": "1"
|
|
12
|
-
},
|
|
13
|
-
"description": "",
|
|
14
|
-
"config": {},
|
|
15
|
-
"touch": {
|
|
16
|
-
"left": {},
|
|
17
|
-
"right": {},
|
|
18
|
-
"center": {
|
|
19
|
-
"0": {
|
|
20
|
-
"states": {
|
|
21
|
-
"off": {
|
|
22
|
-
"color": "#aaaaaa",
|
|
23
|
-
"image": "icons/home.png"
|
|
24
|
-
},
|
|
25
|
-
"on": {
|
|
26
|
-
"color": "#11ff11",
|
|
27
|
-
"image": "icons/home.png",
|
|
28
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
29
|
-
"value": "kvm-transmitter{key}-1"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
33
|
-
"group": "kvm1"
|
|
34
|
-
},
|
|
35
|
-
"1": {
|
|
36
|
-
"states": {
|
|
37
|
-
"off": {
|
|
38
|
-
"color": "#aaaaaa",
|
|
39
|
-
"image": "icons/bulb.png"
|
|
40
|
-
},
|
|
41
|
-
"on": {
|
|
42
|
-
"color": "#11ff11",
|
|
43
|
-
"image": "icons/bulb.png",
|
|
44
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
45
|
-
"value": "kvm-transmitter{key}-1"
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
49
|
-
"group": "kvm1"
|
|
50
|
-
},
|
|
51
|
-
"2": {
|
|
52
|
-
"states": {
|
|
53
|
-
"off": {
|
|
54
|
-
"color": "#aaaaaa",
|
|
55
|
-
"image": "icons/mountain.png"
|
|
56
|
-
},
|
|
57
|
-
"on": {
|
|
58
|
-
"color": "#11ff11",
|
|
59
|
-
"image": "icons/mountain.png",
|
|
60
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
61
|
-
"value": "kvm-transmitter{key}-1"
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
65
|
-
"group": "kvm1"
|
|
66
|
-
},
|
|
67
|
-
"3": {
|
|
68
|
-
"states": {
|
|
69
|
-
"off": {
|
|
70
|
-
"color": "#aaaaaa",
|
|
71
|
-
"image": "icons/mountain.png"
|
|
72
|
-
},
|
|
73
|
-
"on": {
|
|
74
|
-
"color": "#11ff11",
|
|
75
|
-
"image": "icons/mountain.png",
|
|
76
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
77
|
-
"value": "kvm-transmitter{key}-1"
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
81
|
-
"group": "kvm1"
|
|
82
|
-
},
|
|
83
|
-
"4": {
|
|
84
|
-
"states": {
|
|
85
|
-
"off": {
|
|
86
|
-
"color": "#aaaaaa",
|
|
87
|
-
"image": "icons/mountain.png"
|
|
88
|
-
},
|
|
89
|
-
"on": {
|
|
90
|
-
"color": "#11ff11",
|
|
91
|
-
"image": "icons/mountain.png",
|
|
92
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.in.Source",
|
|
93
|
-
"value": "kvm-transmitter{key}-1"
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
"nodeid": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
97
|
-
"group": "kvm1"
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
"knob": {}
|
|
101
|
-
},
|
|
102
|
-
"knobs": {
|
|
103
|
-
"left": {},
|
|
104
|
-
"right": {}
|
|
105
|
-
},
|
|
106
|
-
"buttons": {
|
|
107
|
-
"1": {
|
|
108
|
-
"states": {
|
|
109
|
-
"off": {
|
|
110
|
-
"color": "#aaaaaa"
|
|
111
|
-
},
|
|
112
|
-
"on": {
|
|
113
|
-
"color": "#11ff11",
|
|
114
|
-
"http": "http://{hostname}:7778/control/connections",
|
|
115
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
116
|
-
"value": "kvm-transmitter{key}-1"
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
"group": "kvm1"
|
|
120
|
-
},
|
|
121
|
-
"2": {
|
|
122
|
-
"states": {
|
|
123
|
-
"off": {
|
|
124
|
-
"color": "#aaaaaa"
|
|
125
|
-
},
|
|
126
|
-
"on": {
|
|
127
|
-
"color": "#11ff11",
|
|
128
|
-
"http": "http://{hostname}:7778/control/connections",
|
|
129
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
130
|
-
"value": "kvm-transmitter{key}-1"
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
"group": "kvm1"
|
|
134
|
-
},
|
|
135
|
-
"3": {
|
|
136
|
-
"states": {
|
|
137
|
-
"off": {
|
|
138
|
-
"color": "#aaaaaa"
|
|
139
|
-
},
|
|
140
|
-
"on": {
|
|
141
|
-
"color": "#11ff11",
|
|
142
|
-
"http": "http://{hostname}:7778/control/connections",
|
|
143
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
144
|
-
"value": "kvm-transmitter{key}-1"
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
"group": "kvm1"
|
|
148
|
-
},
|
|
149
|
-
"4": {
|
|
150
|
-
"states": {
|
|
151
|
-
"off": {
|
|
152
|
-
"color": "#aaaaaa"
|
|
153
|
-
},
|
|
154
|
-
"on": {
|
|
155
|
-
"color": "#11ff11",
|
|
156
|
-
"http": "http://{hostname}:7778/control/connections",
|
|
157
|
-
"opcua": "ns=4;s=Is{simnbr}.Kvm.out.Source",
|
|
158
|
-
"value": "kvm-transmitter{key}-1"
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
"group": "kvm1"
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|