loupedeck-commander 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,326 +1,335 @@
1
- import {discover, HAPTIC,LoupedeckDevice } from 'loupedeck'
2
- import { ApplicationConfig } from './ApplicationConfig.mjs'
3
- import { ButtonField, StopInterfaces, InitializeInterfaces,opcuainterface,profileEmitter} from './touchbuttons.mjs'
4
-
5
- export class BaseLoupeDeckHandler {
6
- device = undefined
7
- appConfig = undefined
8
- profileConfigs = []
9
- currentProfile = 0
10
- screens = {}
11
- buttons = {}
12
- screenUpdate = {}
13
- stopping = false
14
-
15
- constructor (config) {
16
- console.log(`INIT with config ${config}`)
17
- this.loadConfig(config)
18
- }
19
-
20
- /**
21
- * event handler - start
22
- */
23
- async start () {
24
- console.info('Start')
25
- while (!this.device && !this.stopping) {
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
-
36
- this.device = await discover()
37
-
38
-
39
-
40
- } catch (e) {
41
- console.error(`${e}. Reattempting in 3 seconds...`)
42
- await new Promise(resolve => setTimeout(resolve, 3000))
43
- }
44
-
45
- if (this.stopping){
46
- return
47
- }
48
- }
49
- console.info(`✅ Discovered Device ${this.device.type}`)
50
-
51
- const self = this
52
-
53
- this.device.on('connect', (address) => { self.onConnected(address) })
54
- this.device.on('down', (event) => { self.onButtonDown(event) })
55
- this.device.on('up', (event) => { self.onButtonUp(event) })
56
- this.device.on('rotate', (event) => { self.onRotate(event) })
57
- this.device.on('touchstart', (event) => { self.onTouchStart(event) })
58
- this.device.on('touchmove', (event) => { self.onTouchMove(event) })
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
- }
64
-
65
- /**
66
- * event handler - loupedeck device disconnected
67
- */
68
- async disconnectDevice (event) {
69
- console.info("Device Disconnected")
70
- this.device=undefined
71
- }
72
-
73
- /**
74
- * stop handler - close the dipslay-connection and also stop all interface handlers
75
- */
76
- async stop () {
77
- console.info('Stopping Handler')
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
-
104
- }
105
-
106
- /**
107
- * load Application config file from JSON
108
- * @param filename
109
- */
110
- loadConfig (fileName) {
111
- console.info(`Loading Config File ${fileName}`)
112
- this.appConfig = new ApplicationConfig()
113
- this.appConfig.loadFromFile(fileName)
114
- }
115
-
116
- /**
117
- * activate the profile with the givven ID
118
- */
119
- async activateProfile (id) {
120
- // todo Profile-change implementation
121
- id = Number(id)
122
- var oldProfile = this.currentProfile
123
- if (this.appConfig.profiles.length > id) {
124
- this.currentProfile = id
125
- }else{
126
- return
127
- }
128
- const profile = this.getCurrentProfile()
129
- console.info("ACTIVATE PROFILE",id,profile.name)
130
- const dLeft = this.device.displays.left
131
- const dRight = this.device.displays.right
132
- const dCenter = this.device.displays.center
133
- const dKnob = this.device.displays.knob
134
-
135
- this.screens.center = new ButtonField('center', this.device.rows, this.device.columns, dCenter.width, dCenter.height, profile.touch.center,profile)
136
- this.screens.left = new ButtonField('left', 1, 1, dLeft.width, dLeft.height, profile.touch.left,profile)
137
- this.screens.right = new ButtonField('right', 1, 1, dRight.width, dRight.height, profile.touch.right,profile)
138
- // knob Display is only available in the CT-version - not with live:
139
- if (dKnob) {
140
- this.screens.knob = new ButtonField('knob', 1, 1, dKnob.width, dKnob.height, profile.touch.knob,profile)
141
- }
142
-
143
- this.buttons = new ButtonField('buttons', 1, 1, 0, 0, profile.buttons,profile)
144
-
145
- await this.screens.center.load()
146
- await this.screens.right.load()
147
- await this.screens.left.load()
148
- if (dKnob) {
149
- await this.screens.knob.load()
150
- }
151
- await this.buttons.load()
152
-
153
- await this.screens.center.draw(this.device)
154
- if (dKnob) {
155
- await this.screens.knob.draw(this.device)
156
- }
157
-
158
- this.buttons.setState(this.currentProfile+1,1)
159
- this.buttons.setState(oldProfile+1,1)
160
-
161
- await this.buttons.draw(this.device)
162
-
163
- }
164
-
165
- /**
166
- * get the dictionary iwth the current profile settings
167
- */
168
- getCurrentProfile () {
169
- return this.appConfig.profiles[this.currentProfile]
170
- }
171
-
172
- /**
173
- * Triggered, when LoupeDeck Device is connected
174
- * - Initialize the profile from config-file and
175
- * - start the interface handlers accordingly
176
- */
177
- async onConnected (address) {
178
- console.info(`✅ Connected to ${this.device.type}, ${address}`)
179
-
180
- await this.activateProfile(0)
181
-
182
- var profile = this.getCurrentProfile()
183
- await InitializeInterfaces(profile,this.buttons.setState)
184
-
185
- const self = this
186
-
187
- // Register callback on monitored item change:
188
- opcuainterface.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
189
- profileEmitter.on("profileChanged",(profileID) => { self.activateProfile(profileID) })
190
-
191
-
192
- this.device.setBrightness(1)
193
- this.device.vibrate(HAPTIC.ASCEND_MED)
194
-
195
- // Fore update of all screens
196
- console.info('✅ Force Screen update')
197
- this.screenUpdate["center"] = true
198
- this.screenUpdate["left"] = true
199
- this.screenUpdate["right"] = true
200
- await this.updateScreens()
201
-
202
- console.info('✅ Done initializing')
203
- }
204
-
205
- /**
206
- * Fore an update of all screens
207
- */
208
- async updateScreens () {
209
- const keys = Object.keys(this.screenUpdate)
210
- for (let i = 0; i < keys.length; i++) {
211
- const screen = keys[i]
212
- await this.screens[screen].draw(this.device)
213
- }
214
- this.screenUpdate = {}
215
- }
216
-
217
- /**
218
- * Button Down Handler - triggered through Event Button Down - connected to LoupeDeck Event
219
- */
220
- async onButtonDown (event) {
221
- let ok = false
222
- const id = event.id
223
- ok = await this.buttons.pressed(id)
224
- await this.buttons.draw(this.device)
225
- return ok
226
- }
227
-
228
- /**
229
- * Button Up Handler - triggered through Event Button Up - connected to LoupeDeck Event
230
- */
231
- async onButtonUp (event) {
232
- let ok = false
233
- const id = event.id
234
- ok = await this.buttons.released(id)
235
- await this.buttons.draw(this.device)
236
-
237
- /*if (this.currentProfile != id){
238
- this.activateProfile(id-1)
239
- }*/
240
- return ok
241
- }
242
-
243
- /**
244
- * Button Rotate Handler - triggered through Event Rotate available with knob-Buttons - connected to LoupeDeck Event
245
- */
246
- async onRotate (event) {
247
- const id = event.id
248
- const delta = event.delta
249
- return await this.buttons.rotated(id, delta)
250
- }
251
-
252
- /**
253
- * TouchStart Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
254
- */
255
- async onTouchStart (event) {
256
- let ok = false
257
- const changedTouches = event.changedTouches
258
- for (let i = 0; i < changedTouches.length; i++) {
259
- const screen = changedTouches[i].target.screen
260
- let id = changedTouches[i].target.key
261
- this.screenUpdate[screen] = true
262
- if (id === undefined) {
263
- id = 0
264
- }
265
- ok = await this.screens[screen].pressed(id)
266
- }
267
- await this.updateScreens()
268
- return ok
269
- }
270
-
271
- /**
272
- * TouchMove Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
273
- */
274
- async onTouchMove (event) {
275
- let ok = false
276
- const changedTouches = event.changedTouches
277
- for (let i = 0; i < changedTouches.length; i++) {
278
- const x = changedTouches[i].x
279
- const y = changedTouches[i].y
280
- const screen = changedTouches[i].target.screen
281
- let id = changedTouches[i].target.key
282
- if (id === undefined) {
283
- id = 0 // for left/right
284
- }
285
- ok = await this.screens[screen].touchmove(id, x, y)
286
- }
287
- return ok
288
- }
289
-
290
- /**
291
- * TouchEnd Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
292
- */
293
- async onTouchEnd (event) {
294
- let ok = false
295
- const changedTouches = event.changedTouches
296
- for (let i = 0; i < changedTouches.length; i++) {
297
- const elem = changedTouches[i].target
298
- let id = changedTouches[i].target.key
299
- if (id === undefined) {
300
- id = 0
301
- }
302
- this.screenUpdate[elem.screen] = true
303
-
304
- ok = await this.screens[elem.screen].released(id)
305
- }
306
- await this.updateScreens()
307
- return ok
308
- }
309
-
310
- /**
311
- * Handler for StateChanged through OPC/UA Interface - only connected with touch-buttons on center field (yet)
312
- */
313
- async buttonStateChanged(buttonID,nodeid,val) {
314
- let ok = false
315
- this.screenUpdate["center"] = true
316
- this.screenUpdate["left"] = true
317
- this.screenUpdate["right"] = true
318
-
319
- ok = await this.screens.center.changed(buttonID,nodeid,val)
320
-
321
- await this.updateScreens()
322
- return ok
323
- }
324
-
325
-
326
- }
1
+ import {discover, HAPTIC,LoupedeckDevice } from 'loupedeck'
2
+ import { ApplicationConfig } from './ApplicationConfig.mjs'
3
+ import { ButtonField, StopInterfaces, InitializeInterfaces,opcuainterface,profileEmitter} from './touchbuttons.mjs'
4
+
5
+ export class BaseLoupeDeckHandler {
6
+ device = undefined
7
+ appConfig = undefined
8
+ profileConfigs = []
9
+ currentProfile = 0
10
+ screens = {}
11
+ buttons = {}
12
+ knobs = {}
13
+ screenUpdate = {}
14
+ stopping = false
15
+
16
+ constructor (config) {
17
+ console.log(`INIT with config ${config}`)
18
+ let result = this.loadConfig(config)
19
+ if (!result){
20
+ process.exit(-1)
21
+ }
22
+ }
23
+
24
+ /**
25
+ * event handler - start
26
+ */
27
+ async start () {
28
+ console.info('Start')
29
+ while (!this.device && !this.stopping) {
30
+ try {
31
+ var list = await LoupedeckDevice.list()
32
+ if (list.length>0){
33
+ var element = list[0]
34
+ console.log("Connecting to device")
35
+ console.log("Path: ", element.path)
36
+ console.log("vendorId: ", element.vendorId, element.productId)
37
+ console.log("serialNumber: ", element.serialNumber)
38
+ }
39
+
40
+ this.device = await discover()
41
+
42
+
43
+
44
+ } catch (e) {
45
+ console.error(`${e}. Reattempting in 3 seconds...`)
46
+ await new Promise(resolve => setTimeout(resolve, 3000))
47
+ }
48
+
49
+ if (this.stopping){
50
+ return
51
+ }
52
+ }
53
+ console.info(`✅ Discovered Device ${this.device.type}`)
54
+
55
+ const self = this
56
+
57
+ this.device.on('connect', (address) => { self.onConnected(address) })
58
+ this.device.on('down', (event) => { self.onButtonDown(event) })
59
+ this.device.on('up', (event) => { self.onButtonUp(event) })
60
+ this.device.on('rotate', (event) => { self.onRotate(event) })
61
+ this.device.on('touchstart', (event) => { self.onTouchStart(event) })
62
+ this.device.on('touchmove', (event) => { self.onTouchMove(event) })
63
+ this.device.on('touchend', (event) => { self.onTouchEnd(event) })
64
+ this.device.on('disconnect', (event) => { self.disconnectDevice(event) })
65
+
66
+ console.info(`✅ Registered callbacks`)
67
+ }
68
+
69
+ /**
70
+ * event handler - loupedeck device disconnected
71
+ */
72
+ async disconnectDevice (event) {
73
+ console.info("Device Disconnected")
74
+ this.device=undefined
75
+ }
76
+
77
+ /**
78
+ * stop handler - close the dipslay-connection and also stop all interface handlers
79
+ */
80
+ async stop () {
81
+ console.info('Stopping Handler')
82
+
83
+ try {
84
+ console.info(`Closing Device`)
85
+ this.stopping = true
86
+ if (this.device){
87
+ this.device.vibrate(HAPTIC.DESCEND_MED)
88
+ await new Promise(resolve => setTimeout(resolve, 250))
89
+ }
90
+ if (this.device){
91
+ this.device.setBrightness(0)
92
+ await new Promise(resolve => setTimeout(resolve, 250))
93
+ }
94
+ if (this.device){
95
+ this.device.reconnectInterval = 0
96
+ await this.device.close()
97
+ await new Promise(resolve => setTimeout(resolve, 2000))
98
+ console.info(`Device Closed`)
99
+ }
100
+
101
+ console.info(`Stopping interfaces`)
102
+ await StopInterfaces()
103
+ await new Promise(resolve => setTimeout(resolve, 500))
104
+ } catch (e) {}
105
+
106
+ process.exit()
107
+
108
+ }
109
+
110
+ /**
111
+ * load Application config file from JSON
112
+ * @param filename
113
+ */
114
+ loadConfig (fileName) {
115
+ console.info(`Loading Config File ${fileName}`)
116
+ this.appConfig = new ApplicationConfig()
117
+ return this.appConfig.loadFromFile(fileName)
118
+ }
119
+
120
+ /**
121
+ * activate the profile with the givven ID
122
+ */
123
+ async activateProfile (id) {
124
+ // todo Profile-change implementation
125
+ id = Number(id)
126
+ var oldProfile = this.currentProfile
127
+ if (this.appConfig.profiles.length > id) {
128
+ this.currentProfile = id
129
+ }else{
130
+ return
131
+ }
132
+ const profile = this.getCurrentProfile()
133
+ console.info("ACTIVATE PROFILE",id,profile.name)
134
+ const dLeft = this.device.displays.left
135
+ const dRight = this.device.displays.right
136
+ const dCenter = this.device.displays.center
137
+
138
+ this.screens.center = new ButtonField('center', this.device.rows, this.device.columns, dCenter.width, dCenter.height, profile.touch.center,profile)
139
+ this.screens.left = new ButtonField('left', 1, 1, dLeft.width, dLeft.height, profile.touch.left,profile)
140
+ this.screens.right = new ButtonField('right', 1, 1, dRight.width, dRight.height, profile.touch.right,profile)
141
+
142
+ // knobs are only available in the CT-version:
143
+ if (this.device.knobs) {
144
+ this.knobs = new ButtonField('knob', 1, 1, 0, 0, profile.knobs,profile)
145
+ }
146
+ if (this.device.buttons) {
147
+ this.buttons = new ButtonField('buttons', 1, 1, 0, 0, profile.buttons,profile)
148
+ }
149
+ await this.screens.center.load()
150
+ await this.screens.right.load()
151
+ await this.screens.left.load()
152
+ await this.buttons.load()
153
+ await this.knobs.load()
154
+
155
+ // Force a screen Update on all screens:
156
+ this.screenUpdate["center"] = true
157
+ this.screenUpdate["left"] = true
158
+ this.screenUpdate["right"] = true
159
+ await this.updateScreens()
160
+
161
+ await this.buttons.draw(this.device)
162
+
163
+ }
164
+
165
+ /**
166
+ * get the dictionary iwth the current profile settings
167
+ */
168
+ getCurrentProfile () {
169
+ return this.appConfig.profiles[this.currentProfile]
170
+ }
171
+
172
+ /**
173
+ * Triggered, when LoupeDeck Device is connected
174
+ * - Initialize the profile from config-file and
175
+ * - start the interface handlers accordingly
176
+ */
177
+ async onConnected (address) {
178
+ console.info(`✅ Connected to ${this.device.type}, ${address}`)
179
+
180
+ await this.activateProfile(0)
181
+
182
+ var profile = this.getCurrentProfile()
183
+ await InitializeInterfaces(profile,this.buttons.setState)
184
+
185
+ const self = this
186
+
187
+ // Register callback on monitored item change:
188
+ opcuainterface.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
189
+ profileEmitter.on("profileChanged",(profileID) => { self.activateProfile(profileID) })
190
+
191
+
192
+ this.device.setBrightness(1)
193
+ this.device.vibrate(HAPTIC.ASCEND_MED)
194
+
195
+ // Fore update of all screens
196
+ console.info('✅ Force Screen update')
197
+ this.screenUpdate["center"] = true
198
+ this.screenUpdate["left"] = true
199
+ this.screenUpdate["right"] = true
200
+ await this.updateScreens()
201
+
202
+ console.info('✅ Done initializing')
203
+ }
204
+
205
+ /**
206
+ * Fore an update of all screens
207
+ */
208
+ async updateScreens () {
209
+ const keys = Object.keys(this.screenUpdate)
210
+ for (let i = 0; i < keys.length; i++) {
211
+ const screen = keys[i]
212
+ await this.screens[screen].draw(this.device)
213
+ }
214
+ this.screenUpdate = {}
215
+ }
216
+
217
+ /**
218
+ * Button Down Handler - triggered through Event Button Down - connected to LoupeDeck Event
219
+ */
220
+ async onButtonDown (event) {
221
+ let ok = false
222
+ const id = event.id
223
+ if (Number.isInteger(id)){
224
+ ok = await this.buttons.pressed(id)
225
+ await this.buttons.draw(this.device)
226
+ }else{
227
+ ok = await this.knobs.pressed(id)
228
+ }
229
+ return ok
230
+ }
231
+
232
+ /**
233
+ * Button Up Handler - triggered through Event Button Up - connected to LoupeDeck Event
234
+ */
235
+ async onButtonUp (event) {
236
+ let ok = false
237
+ const id = event.id
238
+ if (Number.isInteger(id) && this.buttons){
239
+ ok = await this.buttons.released(id)
240
+ await this.buttons.draw(this.device)
241
+ }else{
242
+ if(this.knobs)
243
+ ok = await this.knobs.released(id)
244
+ }
245
+ return ok
246
+ }
247
+
248
+ /**
249
+ * Button Rotate Handler - triggered through Event Rotate available with knob-Buttons - connected to LoupeDeck Event
250
+ */
251
+ async onRotate (event) {
252
+ const id = event.id
253
+ const delta = event.delta
254
+ if (this.knobs)
255
+ return await this.knobs.rotated(id, delta)
256
+ }
257
+
258
+ /**
259
+ * TouchStart Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
260
+ */
261
+ async onTouchStart (event) {
262
+ let ok = false
263
+ const changedTouches = event.changedTouches
264
+ for (let i = 0; i < changedTouches.length; i++) {
265
+ const screen = changedTouches[i].target.screen
266
+ let id = changedTouches[i].target.key
267
+ this.screenUpdate[screen] = true
268
+ if (id === undefined) {
269
+ id = 0
270
+ }
271
+ if (this.screens[screen])
272
+ ok = await this.screens[screen].pressed(id)
273
+ }
274
+ await this.updateScreens()
275
+ return ok
276
+ }
277
+
278
+ /**
279
+ * TouchMove Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
280
+ */
281
+ async onTouchMove (event) {
282
+ let ok = false
283
+ const changedTouches = event.changedTouches
284
+ for (let i = 0; i < changedTouches.length; i++) {
285
+ const x = changedTouches[i].x
286
+ const y = changedTouches[i].y
287
+ const screen = changedTouches[i].target.screen
288
+ let id = changedTouches[i].target.key
289
+ if (id === undefined) {
290
+ id = 0 // for left/right
291
+ }
292
+ if (this.screens[screen])
293
+ ok = await this.screens[screen].touchmove(id, x, y)
294
+ }
295
+ return ok
296
+ }
297
+
298
+ /**
299
+ * TouchEnd Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
300
+ */
301
+ async onTouchEnd (event) {
302
+ let ok = false
303
+ const changedTouches = event.changedTouches
304
+ for (let i = 0; i < changedTouches.length; i++) {
305
+ const elem = changedTouches[i].target
306
+ let id = changedTouches[i].target.key
307
+ if (id === undefined) {
308
+ id = 0
309
+ }
310
+ this.screenUpdate[elem.screen] = true
311
+
312
+ if (this.screens[elem.screen])
313
+ ok = await this.screens[elem.screen].released(id)
314
+ }
315
+ await this.updateScreens()
316
+ return ok
317
+ }
318
+
319
+ /**
320
+ * Handler for StateChanged through OPC/UA Interface - only connected with touch-buttons on center field (yet)
321
+ */
322
+ async buttonStateChanged(buttonID,nodeid,val) {
323
+ let ok = false
324
+ this.screenUpdate["center"] = true
325
+ this.screenUpdate["left"] = true
326
+ this.screenUpdate["right"] = true
327
+
328
+ ok = await this.screens.center.changed(buttonID,nodeid,val)
329
+
330
+ await this.updateScreens()
331
+ return ok
332
+ }
333
+
334
+
335
+ }