loupedeck-commander 1.2.1 → 1.2.3

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,313 +1,326 @@
1
- import {discover, HAPTIC,LoupedeckDevice } from 'loupedeck'
2
- import { ApplicationConfig } from './ApplicationConfig.mjs'
3
- import { ButtonField, StopInterfaces, InitializeInterfaces,opcuainterface} 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
- var oldProfile = this.currentProfile
122
- if (this.appConfig.profiles.length >= id) {
123
- this.currentProfile = id
124
- }else{
125
- return
126
- }
127
-
128
- const dLeft = this.device.displays.left
129
- const dRight = this.device.displays.right
130
- const dCenter = this.device.displays.center
131
- const dKnob = this.device.displays.knob
132
-
133
- const profile = this.getCurrentProfile()
134
- this.screens.center = new ButtonField('center', this.device.rows, this.device.columns, dCenter.width, dCenter.height, profile.touch.center,profile)
135
- this.screens.left = new ButtonField('left', 1, 1, dLeft.width, dLeft.height, profile.touch.left,profile)
136
- this.screens.right = new ButtonField('right', 1, 1, dRight.width, dRight.height, profile.touch.right,profile)
137
- // knob Display is only available in the CT-version - not with live:
138
- if (dKnob) {
139
- this.screens.knob = new ButtonField('knob', 1, 1, dKnob.width, dKnob.height, profile.touch.knob,profile)
140
- }
141
-
142
- this.buttons = new ButtonField('buttons', 1, 1, 0, 0, profile.buttons,profile)
143
-
144
- await this.screens.center.load()
145
- await this.screens.right.load()
146
- await this.screens.left.load()
147
- if (dKnob) {
148
- await this.screens.knob.load()
149
- }
150
- await this.buttons.load()
151
-
152
- await this.screens.center.draw(this.device)
153
- if (dKnob) {
154
- await this.screens.knob.draw(this.device)
155
- }
156
-
157
- this.buttons.setState(this.currentProfile+1,1)
158
- this.buttons.setState(oldProfile+1,1)
159
-
160
- await this.buttons.draw(this.device)
161
- }
162
-
163
- /**
164
- * get the dictionary iwth the current profile settings
165
- */
166
- getCurrentProfile () {
167
- return this.appConfig.profiles[this.currentProfile]
168
- }
169
-
170
- /**
171
- * Triggered, when LoupeDeck Device is connected
172
- * - Initialize the profile from config-file and
173
- * - start the interface handlers accordingly
174
- */
175
- async onConnected (address) {
176
- console.info(`✅ Connected to ${this.device.type}, ${address}`)
177
-
178
- await this.activateProfile(0)
179
-
180
- var profile = this.getCurrentProfile()
181
- await InitializeInterfaces(profile,this.buttons.setState)
182
-
183
- const self = this
184
-
185
- // Register callback on monitored item change:
186
- opcuainterface.myEmitter.on("monitored item changed",(buttonID,nodeid,val) => { self.buttonStateChanged(buttonID,nodeid,val) })
187
-
188
- this.device.setBrightness(1)
189
- this.device.vibrate(HAPTIC.ASCEND_MED)
190
-
191
- console.info('✅ Done initializing')
192
- }
193
-
194
- /**
195
- * Fore an update of all screens
196
- */
197
- async updateScreens () {
198
- const keys = Object.keys(this.screenUpdate)
199
- for (let i = 0; i < keys.length; i++) {
200
- const screen = keys[i]
201
- await this.screens[screen].draw(this.device)
202
- }
203
- this.screenUpdate = {}
204
- }
205
-
206
- /**
207
- * Button Down Handler - triggered through Event Button Down - connected to LoupeDeck Event
208
- */
209
- async onButtonDown (event) {
210
- let ok = false
211
- const id = event.id
212
- ok = await this.buttons.pressed(id)
213
- await this.buttons.draw(this.device)
214
- return ok
215
- }
216
-
217
- /**
218
- * Button Up Handler - triggered through Event Button Up - connected to LoupeDeck Event
219
- */
220
- async onButtonUp (event) {
221
- let ok = false
222
- const id = event.id
223
- ok = await this.buttons.released(id)
224
- await this.buttons.draw(this.device)
225
-
226
- /*if (this.currentProfile != id){
227
- this.activateProfile(id-1)
228
- }*/
229
- return ok
230
- }
231
-
232
- /**
233
- * Button Rotate Handler - triggered through Event Rotate available with knob-Buttons - connected to LoupeDeck Event
234
- */
235
- async onRotate (event) {
236
- const id = event.id
237
- const delta = event.delta
238
- return await this.buttons.rotated(id, delta)
239
- }
240
-
241
- /**
242
- * TouchStart Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
243
- */
244
- async onTouchStart (event) {
245
- let ok = false
246
- const changedTouches = event.changedTouches
247
- for (let i = 0; i < changedTouches.length; i++) {
248
- const screen = changedTouches[i].target.screen
249
- let id = changedTouches[i].target.key
250
- this.screenUpdate[screen] = true
251
- if (id === undefined) {
252
- id = 0
253
- }
254
- ok = await this.screens[screen].pressed(id)
255
- }
256
- await this.updateScreens()
257
- return ok
258
- }
259
-
260
- /**
261
- * TouchMove Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
262
- */
263
- async onTouchMove (event) {
264
- let ok = false
265
- const changedTouches = event.changedTouches
266
- for (let i = 0; i < changedTouches.length; i++) {
267
- const x = changedTouches[i].x
268
- const y = changedTouches[i].y
269
- const screen = changedTouches[i].target.screen
270
- let id = changedTouches[i].target.key
271
- if (id === undefined) {
272
- id = 0 // for left/right
273
- }
274
- ok = await this.screens[screen].touchmove(id, x, y)
275
- }
276
- return ok
277
- }
278
-
279
- /**
280
- * TouchEnd Handler - triggered through Event touch available on all touchbuttons on the loupedeck display - connected to LoupeDeck Event
281
- */
282
- async onTouchEnd (event) {
283
- let ok = false
284
- const changedTouches = event.changedTouches
285
- for (let i = 0; i < changedTouches.length; i++) {
286
- const elem = changedTouches[i].target
287
- let id = changedTouches[i].target.key
288
- if (id === undefined) {
289
- id = 0
290
- }
291
- this.screenUpdate[elem.screen] = true
292
-
293
- ok = await this.screens[elem.screen].released(id)
294
- }
295
- await this.updateScreens()
296
- return ok
297
- }
298
-
299
- /**
300
- * Handler for StateChanged through OPC/UA Interface - only connected with touch-buttons on center field (yet)
301
- */
302
- async buttonStateChanged(buttonID,nodeid,val) {
303
- let ok = false
304
- this.screenUpdate["center"] = true
305
-
306
- ok = await this.screens.center.changed(buttonID,nodeid,val)
307
-
308
- await this.updateScreens()
309
- return ok
310
- }
311
-
312
-
313
- }
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
+ }