loupedeck-commander 1.3.1 → 1.3.2
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/BaseLoupeDeckHandler.mjs +4 -4
- package/common/ButtonField.mjs +11 -4
- package/common/button.mjs +43 -25
- package/interfaces/opcuaif.mjs +95 -60
- package/package.json +1 -1
- package/profile-1.yaml +2 -1
- package/profile-2.yaml +4 -1
|
@@ -219,7 +219,7 @@ export class BaseLoupeDeckHandler {
|
|
|
219
219
|
const self = this
|
|
220
220
|
|
|
221
221
|
// Register callback on monitored item change:
|
|
222
|
-
opcuainterface.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
|
|
222
|
+
opcuainterface.on("monitored item changed",(buttonID,attribute,nodeid,val) => { self.buttonStateChanged(buttonID,attribute,nodeid,val) })
|
|
223
223
|
profileEmitter.on("profileChanged",(profileID) => { self.activateProfile(profileID) })
|
|
224
224
|
profileEmitter.on("brightnessChanged",(brightness) => { self.changeBrightness(brightness) })
|
|
225
225
|
profileEmitter.on("vibrate",(pattern) => { self.vibrate(pattern) })
|
|
@@ -364,14 +364,14 @@ export class BaseLoupeDeckHandler {
|
|
|
364
364
|
/**
|
|
365
365
|
* Handler for StateChanged through OPC/UA Interface - only connected with touch-buttons on center field (yet)
|
|
366
366
|
*/
|
|
367
|
-
async buttonStateChanged(buttonID,nodeid,val) {
|
|
367
|
+
async buttonStateChanged(buttonID,attribute,nodeid,val) {
|
|
368
368
|
let ok = false
|
|
369
369
|
this.screenUpdate["center"] = true
|
|
370
370
|
this.screenUpdate["left"] = true
|
|
371
371
|
this.screenUpdate["right"] = true
|
|
372
372
|
|
|
373
|
-
ok = await this.screens.center.
|
|
374
|
-
ok = await this.knobs.
|
|
373
|
+
ok = await this.screens.center.buttonStateChanged(buttonID,attribute,nodeid,val)
|
|
374
|
+
ok = await this.knobs.buttonStateChanged(buttonID,attribute,nodeid,val)
|
|
375
375
|
|
|
376
376
|
//await this.updateScreens()
|
|
377
377
|
return ok
|
package/common/ButtonField.mjs
CHANGED
|
@@ -97,8 +97,13 @@ export class ButtonField {
|
|
|
97
97
|
for (let i = 0; i < this.#keys.length; i++) {
|
|
98
98
|
let key = this.#keys[i]
|
|
99
99
|
if (!isNaN(key)) { key = parseInt(key, 10) }
|
|
100
|
+
// Ignore for myself (active element of the group)
|
|
100
101
|
if (id === key) { continue }
|
|
101
|
-
|
|
102
|
+
let toggleGroup = this.#buttons[id].getGroup()
|
|
103
|
+
// Ignore empty groups
|
|
104
|
+
if (toggleGroup === undefined || toggleGroup == "" ) { continue }
|
|
105
|
+
// Switch all other elements of the same group off:
|
|
106
|
+
if (this.#buttons[key].getGroup() === toggleGroup) {
|
|
102
107
|
this.#buttons[key].setState(0)
|
|
103
108
|
}
|
|
104
109
|
}
|
|
@@ -115,10 +120,12 @@ export class ButtonField {
|
|
|
115
120
|
* @param {*} nodeid
|
|
116
121
|
* @param {*} val
|
|
117
122
|
*/
|
|
118
|
-
async
|
|
123
|
+
async buttonStateChanged(changedButtonID,attribute,nodeid,val){
|
|
124
|
+
// todo: filter for buttonID
|
|
119
125
|
for (let i = 0; i < this.#keys.length; i++) {
|
|
120
|
-
let
|
|
121
|
-
|
|
126
|
+
let buttonID = this.#keys[i]
|
|
127
|
+
if (changedButtonID == buttonID)
|
|
128
|
+
await this.#buttons[buttonID].buttonStateChanged(i,attribute,nodeid,val)
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
131
|
|
package/common/button.mjs
CHANGED
|
@@ -20,6 +20,7 @@ export class Button {
|
|
|
20
20
|
//#data
|
|
21
21
|
#index = 0
|
|
22
22
|
#enforcedIndex = -1
|
|
23
|
+
#enforcedBlink = false
|
|
23
24
|
#event
|
|
24
25
|
#keys
|
|
25
26
|
#states
|
|
@@ -38,6 +39,7 @@ export class Button {
|
|
|
38
39
|
this.id = id
|
|
39
40
|
this.#index = 0
|
|
40
41
|
this.#enforcedIndex = -1
|
|
42
|
+
this.#enforcedBlink = false
|
|
41
43
|
|
|
42
44
|
this.#profile = profile
|
|
43
45
|
this.#params = {
|
|
@@ -144,6 +146,14 @@ export class Button {
|
|
|
144
146
|
this.#index = index
|
|
145
147
|
}
|
|
146
148
|
|
|
149
|
+
/**
|
|
150
|
+
*
|
|
151
|
+
* @returns Group attribute of the current button
|
|
152
|
+
*/
|
|
153
|
+
getGroup() {
|
|
154
|
+
return this.#params.group
|
|
155
|
+
}
|
|
156
|
+
|
|
147
157
|
/**
|
|
148
158
|
* Draw a physical button (color in RGBA format) on a device
|
|
149
159
|
* @param {*} device
|
|
@@ -194,7 +204,7 @@ export class Button {
|
|
|
194
204
|
let color = params.color
|
|
195
205
|
let textColor = params.textColor
|
|
196
206
|
|
|
197
|
-
if (params.blink && this.#counter % 2 == 0) {
|
|
207
|
+
if ((params.blink || this.#enforcedBlink) && this.#counter % 2 == 0) {
|
|
198
208
|
// If blink is set, we switch textcolor and background color:
|
|
199
209
|
color = params.textColor
|
|
200
210
|
textColor = params.color
|
|
@@ -370,28 +380,32 @@ export class Button {
|
|
|
370
380
|
* @param {*} val : the current value of the given nodeid
|
|
371
381
|
* @returns
|
|
372
382
|
*/
|
|
373
|
-
async
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
383
|
+
async buttonStateChanged(buttonID, attribute, nodeid, val) {
|
|
384
|
+
|
|
385
|
+
//
|
|
386
|
+
if (attribute == "nodeid" && nodeid == this.#params.nodeid) {
|
|
387
|
+
this.#index = 0;
|
|
388
|
+
this.#enforcedIndex = -1;
|
|
389
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
390
|
+
let stateStr = this.#keys[i].toString()
|
|
391
|
+
let valStr = val.toString()
|
|
392
|
+
// check if the state-name is same as the value we get from outside:
|
|
393
|
+
if (valStr == stateStr) {
|
|
394
|
+
if (i !== this.#index) {
|
|
395
|
+
console.info("Changed index", this.id, nodeid, val, i)
|
|
396
|
+
this.#index = i;
|
|
397
|
+
console.info("enforce State index", this.id, nodeid, val, i)
|
|
398
|
+
this.#enforcedIndex = this.#index;
|
|
399
|
+
}
|
|
400
|
+
break;
|
|
391
401
|
}
|
|
392
|
-
break;
|
|
393
402
|
}
|
|
394
403
|
}
|
|
404
|
+
|
|
405
|
+
if (attribute == "blink") {
|
|
406
|
+
console.info("Changed blink", buttonID, nodeid, val)
|
|
407
|
+
this.#enforcedBlink = val;
|
|
408
|
+
}
|
|
395
409
|
}
|
|
396
410
|
|
|
397
411
|
/**
|
|
@@ -475,23 +489,27 @@ export class Button {
|
|
|
475
489
|
profileEmitter.emit("profileChanged", params.profile)
|
|
476
490
|
}
|
|
477
491
|
|
|
478
|
-
if (params.brightness !== undefined) {
|
|
492
|
+
if (params.brightness !== undefined && params.brightness !== '') {
|
|
493
|
+
// If brightness is set, we emit a brightnessChanged event with the given params
|
|
494
|
+
// This is used to change the brightness of the device
|
|
479
495
|
profileEmitter.emit("brightnessChanged", params.brightness)
|
|
480
496
|
}
|
|
481
497
|
|
|
482
|
-
if (params.vibrate !== undefined) {
|
|
498
|
+
if (params.vibrate !== undefined && params.vibrate !== '' && params.vibrate !== false) {
|
|
499
|
+
// If vibrate is set, we emit a vibrate event with the given params
|
|
500
|
+
// This is used to trigger a vibration on the device
|
|
483
501
|
profileEmitter.emit("vibrate", params.vibrate)
|
|
484
502
|
}
|
|
485
503
|
|
|
486
504
|
let res = ''
|
|
487
505
|
if ('cmd' in params && shellinterface) {
|
|
488
|
-
|
|
506
|
+
res = await shellinterface.call(params.cmd, params)
|
|
489
507
|
}
|
|
490
508
|
if ('http' in params && httpinterface) {
|
|
491
|
-
|
|
509
|
+
res = await httpinterface.call(params.http, params)
|
|
492
510
|
}
|
|
493
511
|
if ('opcua' in params && opcuainterface) {
|
|
494
|
-
|
|
512
|
+
res = await opcuainterface.call(params.opcua, params)
|
|
495
513
|
}
|
|
496
514
|
|
|
497
515
|
return res
|
package/interfaces/opcuaif.mjs
CHANGED
|
@@ -22,12 +22,14 @@ export class OPCUAIf extends BaseIf {
|
|
|
22
22
|
#endpointurl
|
|
23
23
|
#publishingInterval
|
|
24
24
|
#samplingInterval
|
|
25
|
+
// Dictionary to store monitored items : key = monitoredItemId, value = nodeID
|
|
25
26
|
monitoreditems
|
|
26
27
|
types
|
|
28
|
+
// Dictionary to store buttons : key = monitoredItemId, value = buttonID
|
|
27
29
|
buttons
|
|
28
30
|
constructor() {
|
|
29
31
|
super()
|
|
30
|
-
}
|
|
32
|
+
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
35
|
* Initialize the OPCUA client and subscribe to monitored items.
|
|
@@ -44,13 +46,13 @@ export class OPCUAIf extends BaseIf {
|
|
|
44
46
|
this.#endpointurl = this.formatString(options.endpointurl, options)
|
|
45
47
|
if (options.publishingInterval)
|
|
46
48
|
this.#publishingInterval = options.publishingInterval
|
|
47
|
-
else{
|
|
49
|
+
else {
|
|
48
50
|
this.#publishingInterval = 250;
|
|
49
51
|
this.LogInfo(`OPCUAIf init using default publishingInterval: ${this.#publishingInterval}ms\n`);
|
|
50
52
|
}
|
|
51
53
|
if (options.samplingInterval)
|
|
52
54
|
this.#samplingInterval = options.samplingInterval
|
|
53
|
-
else{
|
|
55
|
+
else {
|
|
54
56
|
this.#samplingInterval = 100;
|
|
55
57
|
this.LogInfo(`OPCUAIf init using default samplingInterval: ${this.#samplingInterval}ms\n`);
|
|
56
58
|
}
|
|
@@ -62,55 +64,65 @@ export class OPCUAIf extends BaseIf {
|
|
|
62
64
|
await this.Connect(this.#endpointurl);
|
|
63
65
|
|
|
64
66
|
let fields = [config.touch.center, config.knobs, config.buttons]
|
|
65
|
-
|
|
66
|
-
for (let f = 0; f < fieldKeys.length; f++) {
|
|
67
|
+
for (let f = 0; f < fields.length; f++) {
|
|
67
68
|
let field = fields[f]
|
|
68
|
-
const
|
|
69
|
+
const buttonNames = Object.keys(field)
|
|
69
70
|
|
|
70
71
|
// Iterate over buttons:
|
|
71
|
-
for (let i = 0; i <
|
|
72
|
-
const
|
|
73
|
-
const elem = field[
|
|
74
|
-
options["key"] =
|
|
72
|
+
for (let i = 0; i < buttonNames.length; i++) {
|
|
73
|
+
const buttonID = buttonNames[i]
|
|
74
|
+
const elem = field[buttonID]
|
|
75
|
+
options["key"] = buttonID // we have to know the key of the button
|
|
75
76
|
// groupnode
|
|
76
|
-
if (elem.params
|
|
77
|
-
let
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
if (elem.params) {
|
|
78
|
+
let attributes = ["nodeid", "blink"]
|
|
79
|
+
for (let j = 0; j < attributes.length; j++) {
|
|
80
|
+
const attribute = attributes[j]
|
|
81
|
+
if (attribute in elem.params) {
|
|
82
|
+
if (!this.IsNodeID(elem.params[attribute])) {
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let monitoredItemId = await this.Subscribe(elem.params[attribute], options,attribute)
|
|
87
|
+
if (monitoredItemId) {
|
|
88
|
+
this.buttons[monitoredItemId] = {
|
|
89
|
+
buttonID: i,
|
|
90
|
+
buttonName: buttonID,
|
|
91
|
+
attribute: attribute
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (elem.states) {
|
|
98
|
+
let attributes = ["opcua", "blink"]
|
|
99
|
+
let states = Object.values(elem.states)
|
|
100
|
+
// Iterate over states:
|
|
101
|
+
for (let j = 0; j < states.length; j++) {
|
|
102
|
+
const state = states[j]
|
|
103
|
+
|
|
104
|
+
for (let k = 0; k < attributes.length; k++) {
|
|
105
|
+
const attribute = attributes[k]
|
|
106
|
+
if (attribute in state) {
|
|
107
|
+
if (!this.IsNodeID(state[attribute])) {
|
|
108
|
+
continue
|
|
109
|
+
}
|
|
110
|
+
let monitoredItemId = await this.Subscribe(state[attribute], options,attribute)
|
|
111
|
+
if (monitoredItemId) {
|
|
112
|
+
this.buttons[monitoredItemId] = {
|
|
113
|
+
buttonID: i,
|
|
114
|
+
buttonName: buttonID,
|
|
115
|
+
attribute: attribute
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
82
120
|
}
|
|
83
|
-
console.log("OPCUAIf: Subscribe to",monitoredItemId,formattedNodeId)
|
|
84
|
-
this.buttons[monitoredItemId] = i
|
|
85
121
|
}
|
|
86
|
-
await this.monitorStates(elem, options)
|
|
87
122
|
}
|
|
88
123
|
}
|
|
89
124
|
} catch (error) {
|
|
90
|
-
this.LogError(`OPCUAIf: Error\n`,error)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Monitor the state OPC/UA node of the given element
|
|
96
|
-
* @param {*} elem : Elem Object
|
|
97
|
-
* @param {*} options
|
|
98
|
-
*/
|
|
99
|
-
async monitorStates(elem, options) {
|
|
100
|
-
const stateKeys = Object.keys(elem.states)
|
|
101
|
-
for (let i = 0; i < stateKeys.length; i++) {
|
|
102
|
-
const key2 = stateKeys[i]
|
|
103
|
-
const state = elem.states[key2]
|
|
104
|
-
if (state.opcua) {
|
|
105
|
-
let formattedNodeId = this.formatString(state.opcua, options)
|
|
106
|
-
let monitoredItemId = await this.Subscribe(formattedNodeId)
|
|
107
|
-
if (monitoredItemId === undefined) {
|
|
108
|
-
this.LogError(`OPCUAIf: Error subscribing State to node ${formattedNodeId}\n`)
|
|
109
|
-
continue
|
|
110
|
-
}
|
|
111
|
-
console.log("OPCUAIf: Subscribe to",monitoredItemId,formattedNodeId)
|
|
112
|
-
this.buttons[monitoredItemId] = i
|
|
113
|
-
}
|
|
125
|
+
this.LogError(`OPCUAIf: Error\n`, error)
|
|
114
126
|
}
|
|
115
127
|
}
|
|
116
128
|
|
|
@@ -231,7 +243,7 @@ export class OPCUAIf extends BaseIf {
|
|
|
231
243
|
async Disconnect() {
|
|
232
244
|
if (this.#client) {
|
|
233
245
|
if (this.#session)
|
|
234
|
-
await this.#client.closeSession(this.#session,true)
|
|
246
|
+
await this.#client.closeSession(this.#session, true)
|
|
235
247
|
this.#session = undefined
|
|
236
248
|
this.#client = undefined
|
|
237
249
|
this.LogInfo(`OPCUAIf: Disconnected\n`);
|
|
@@ -243,10 +255,10 @@ export class OPCUAIf extends BaseIf {
|
|
|
243
255
|
*/
|
|
244
256
|
async Connect(url) {
|
|
245
257
|
let self = this
|
|
246
|
-
if (this.#client){
|
|
258
|
+
if (this.#client) {
|
|
247
259
|
await this.Disconnect()
|
|
248
260
|
}
|
|
249
|
-
|
|
261
|
+
|
|
250
262
|
this.#client = OPCUAClient.create({
|
|
251
263
|
applicationName: "NodeOPCUA-Client",
|
|
252
264
|
endpointMustExist: true,
|
|
@@ -263,7 +275,7 @@ export class OPCUAIf extends BaseIf {
|
|
|
263
275
|
defaultSecureTokenLifetime: 20000,
|
|
264
276
|
tokenRenewalInterval: 1000
|
|
265
277
|
});
|
|
266
|
-
|
|
278
|
+
|
|
267
279
|
|
|
268
280
|
this.#client.on("backoff", (retry, delay) => {
|
|
269
281
|
//if ((retry % 10) == 0)
|
|
@@ -321,12 +333,28 @@ export class OPCUAIf extends BaseIf {
|
|
|
321
333
|
});
|
|
322
334
|
|
|
323
335
|
this.LogInfo(`OPCUAIf: session created\n`);
|
|
324
|
-
// this.LogInfo(`OPCUAIf: client\n`);
|
|
325
|
-
// this.LogInfo(`OPCUAIf: subscription\n`);
|
|
336
|
+
// this.LogInfo(`OPCUAIf: client\n`);
|
|
337
|
+
// this.LogInfo(`OPCUAIf: subscription\n`);
|
|
326
338
|
this.#connected = true
|
|
327
339
|
this.#endpointurl = url
|
|
328
340
|
}
|
|
329
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Check if the given nodeID is a valid OPCUA nodeID.
|
|
344
|
+
* A valid nodeID has the format: ns=<namespace index>;s=<identifier>
|
|
345
|
+
* where <namespace index> is a number and <identifier> is a string.
|
|
346
|
+
* @param {*} nodeID
|
|
347
|
+
* @returns
|
|
348
|
+
*/
|
|
349
|
+
IsNodeID(nodeID) {
|
|
350
|
+
let strNodeID = nodeID.toString()
|
|
351
|
+
// regex: ns=\d;s=.*
|
|
352
|
+
if (strNodeID.match(/^ns=\d+;s=.*$/)) {
|
|
353
|
+
return true
|
|
354
|
+
}
|
|
355
|
+
return false
|
|
356
|
+
}
|
|
357
|
+
|
|
330
358
|
/**
|
|
331
359
|
* Register a subscription for a nodeID.
|
|
332
360
|
* This method will create a monitored item for the given nodeID and return the monitored item ID.
|
|
@@ -334,15 +362,16 @@ export class OPCUAIf extends BaseIf {
|
|
|
334
362
|
* @param {*} nodeID
|
|
335
363
|
* @returns
|
|
336
364
|
*/
|
|
337
|
-
async Subscribe(
|
|
365
|
+
async Subscribe(unformattedNodeID, options = {},attribute) {
|
|
366
|
+
// Format the nodeID using the provided options
|
|
367
|
+
let nodeID = this.formatString(unformattedNodeID, options)
|
|
368
|
+
|
|
338
369
|
// install monitored item
|
|
339
|
-
const
|
|
340
|
-
for (let i = 0; i <
|
|
341
|
-
|
|
342
|
-
const elem = this.monitoreditems[key]
|
|
343
|
-
if (elem == nodeID) {
|
|
370
|
+
const monitoredNodeIdList = Object.values(this.monitoreditems)
|
|
371
|
+
for (let i = 0; i < monitoredNodeIdList.length; i++) {
|
|
372
|
+
if (monitoredNodeIdList[i] == nodeID) {
|
|
344
373
|
// already registered => return itemid
|
|
345
|
-
return
|
|
374
|
+
return this.monitoreditems[i]
|
|
346
375
|
}
|
|
347
376
|
}
|
|
348
377
|
|
|
@@ -357,7 +386,7 @@ export class OPCUAIf extends BaseIf {
|
|
|
357
386
|
};
|
|
358
387
|
|
|
359
388
|
if (!this.#sub) {
|
|
360
|
-
this.LogError(`OPCUAIf:
|
|
389
|
+
this.LogError(`OPCUAIf: no subscription - don't register monitored items $itemToMonitor\n`);
|
|
361
390
|
return
|
|
362
391
|
}
|
|
363
392
|
const monitoredItem = await this.#sub.monitor(itemToMonitor, monitoringParameters, TimestampsToReturn.Both);
|
|
@@ -365,14 +394,20 @@ export class OPCUAIf extends BaseIf {
|
|
|
365
394
|
var self = this
|
|
366
395
|
monitoredItem.on("changed", function (dataValue) {
|
|
367
396
|
var nodeId = self.monitoreditems[this.monitoredItemId]
|
|
368
|
-
var
|
|
397
|
+
var buttonInfo = self.buttons[this.monitoredItemId]
|
|
369
398
|
// store the type of a nodeid in local dictionary
|
|
370
399
|
self.types[nodeId] = dataValue.value.dataType
|
|
371
400
|
// publish the value to subscribers:
|
|
372
|
-
self.LogInfo(`OPCUAIf: monitored item changed: ${nodeId} => ${dataValue.value.value}\n`);
|
|
373
|
-
self.emit('monitored item changed', buttonID, nodeId, dataValue.value.value)
|
|
401
|
+
self.LogInfo(`OPCUAIf: monitored item changed: ${buttonInfo.buttonID} ${buttonInfo.attribute} ${nodeId} => ${dataValue.value.value}\n`);
|
|
402
|
+
self.emit('monitored item changed', buttonInfo.buttonID, buttonInfo.attribute, nodeId, dataValue.value.value)
|
|
374
403
|
});
|
|
375
404
|
|
|
405
|
+
if (monitoredItem.monitoredItemId === undefined) {
|
|
406
|
+
this.LogError(`OPCUAIf: Error subscribing to node ${nodeID} (attribute ${attribute})\n`)
|
|
407
|
+
} else {
|
|
408
|
+
this.LogDebug(`OPCUAIf: Subscribe to ${monitoredItem.monitoredItemId},${nodeID},(attribute ${attribute})\n`);
|
|
409
|
+
}
|
|
410
|
+
|
|
376
411
|
return monitoredItem.monitoredItemId;
|
|
377
412
|
}
|
|
378
413
|
|
package/package.json
CHANGED
package/profile-1.yaml
CHANGED
package/profile-2.yaml
CHANGED
|
@@ -31,6 +31,8 @@ touch:
|
|
|
31
31
|
cmd: echo "{id} {state}"
|
|
32
32
|
"1":
|
|
33
33
|
default: two
|
|
34
|
+
params:
|
|
35
|
+
nodeid: ns=2;s=DRV.AAFHR.compOut.FeldTempGetriebeoel
|
|
34
36
|
states:
|
|
35
37
|
off:
|
|
36
38
|
color: "#000099"
|
|
@@ -185,7 +187,8 @@ knobs:
|
|
|
185
187
|
states:
|
|
186
188
|
on:
|
|
187
189
|
cmd: echo "{id} {state}"
|
|
188
|
-
opcua: ns=2;s=
|
|
190
|
+
opcua: ns=2;s=DRV.AAFHR.compOut.FeldTempGetriebeoel
|
|
191
|
+
blink: ns=2;s=DRV.AAFHR.compOut.Feststellbremse
|
|
189
192
|
group: ""
|
|
190
193
|
knobTR:
|
|
191
194
|
states:
|