loupedeck-commander 1.4.0 → 1.4.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.
@@ -1,281 +1,300 @@
1
- import { readConfigFile as readConfigFile, writeJSONFile,syncParams, writeYAMLFile } from './utils.mjs'
2
-
3
- export class ApplicationConfig {
4
- application = 'undefined'
5
- profiles = []
6
- initialized = false
7
-
8
- loadFromFile (fileName) {
9
- console.info(`ApplicationConfig: Loading Config File ${fileName}`)
10
- const config = readConfigFile(fileName)
11
-
12
-
13
- if (!config){
14
- console.info(`ApplicationConfig: Could not read/parse Config File ${fileName} - breaking here`)
15
- }else if (!config.application){
16
- console.info(`ApplicationConfig: Config File ${fileName} does not contain an application attribute - breaking here`)
17
- }else if (!config.profiles){
18
- console.info(`ApplicationConfig: Config File ${fileName} does not contain a profiles attribute - breaking here`)
19
- }
20
- else{
21
- this.application = config.application
22
- for (let i = 0; i < config.profiles.length; i++) {
23
- const profile = new Profile(config.profiles[i],config.profiles.length,i)
24
- if (profile.loaded){
25
- this.profiles.push(profile)
26
- }else{
27
- return false
28
- }
29
- }
30
-
31
- this.initialized=true
32
- }
33
- return this.initialized
34
- }
35
- }
36
-
37
- class Profile {
38
- name = ''
39
- profile = 'example'
40
- description = ''
41
-
42
- touch = {}
43
- knobs = {}
44
- buttons = {}
45
- parameters = {}
46
- default = {}
47
- #file = ''
48
- loaded = false
49
- #error = true
50
- #profileCount = 0
51
- #index = 0
52
-
53
- constructor (data,profileCount,index) {
54
- this.name = data.name
55
- this.#file = data.file
56
- this.#profileCount = profileCount
57
- this.#index = index
58
- this.touch = new TouchConfig({})
59
- this.buttons = new ButtonConfig().buttons
60
- this.knobs = new KnobsConfig().knobs
61
- this.parameters = new ParametersConfig().parameters
62
- this.default = new DefaultConfig().default
63
-
64
- this.loadFromFile(this.#file)
65
- if (this.#error) {
66
- this.saveToFile(`profile-${this.name}-sav.json`)
67
- }
68
- }
69
-
70
- loadFromFile (fileName) {
71
- console.info(`ProfileConfig: Loading Profile File ${fileName}, Index ${this.#index}`)
72
- const config = readConfigFile(fileName)
73
- if (config === undefined) {
74
- console.warn(`ProfileConfig: Cannot parse/load Profile File ${fileName}`)
75
- return false
76
- }else if (!config.profile){
77
- console.warn(`ProfileConfig: File ${fileName} is missing a profile attribute`)
78
- return false
79
- }else if (!config.touch){
80
- console.warn(`ProfileConfig: File ${fileName} is missing a touch attribute`)
81
- return false
82
- }else if (!config.parameters){
83
- console.warn(`ProfileConfig: File ${fileName} is missing a parameters attribute`)
84
- return false
85
- }else if (!config.buttons){
86
- console.info(`ProfileConfig: File ${fileName} is missing a buttons attribute - will be used to switch profiles by default`)
87
- // return false
88
- }
89
- this.profile = config.profile
90
- this.description = config.description
91
- // Load Parameters.parameters = config.parameters
92
- this.parameters = new ParametersConfig(config.parameters).parameters
93
- this.default = new DefaultConfig(config.default).default
94
-
95
- // Load the Configurations for Touch-Displays
96
- this.touch = new TouchConfig(config.touch,this.default)
97
- // Load the Configurations for Button-Areas
98
-
99
- this.buttons = new ButtonConfig(config.buttons,this.#profileCount,this.#index).buttons
100
- this.knobs = new KnobsConfig(config.knobs).knobs
101
-
102
- this.#error = false
103
- this.loaded = true
104
- return this.loaded
105
- }
106
-
107
- saveToFile (fileName) {
108
- fileName = fileName.toLowerCase()
109
-
110
- console.info(`ProfileConfig: Save To Config File ${fileName}`)
111
- if(fileName.endsWith('.json')) {
112
- writeJSONFile(fileName, this)
113
- writeYAMLFile(fileName.replace('.json','.yaml'), this)
114
- }else if(fileName.endsWith('.yaml')) {
115
- writeYAMLFile(fileName, this)
116
- writeJSONFile(fileName.replace('.yaml','.json'), this)
117
- }
118
- }
119
- }
120
-
121
- /**
122
- * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
123
- */
124
- class TouchConfig {
125
- center = {
126
- "0" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
127
- "1" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
128
- "2" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
129
- "3" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
130
- "4" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
131
- "5" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
132
- "6" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
133
- "7" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
134
- "8" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
135
- "9" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
136
- "10" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
137
- "11" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
138
- } // CENTER Display Config - Available in CT & LIVE
139
- left = {
140
- "0" : { "states" : { "on" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
141
- } // LEFT Display Config - Available in CT & LIVE
142
- right = {
143
- "0" : { "states" : { "on" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
144
- } // RIGHT Display Config - Available in CT & LIVE
145
- //knob = {} // KNOB Display Config - Available only in CT
146
-
147
- constructor (data,defaultState) {
148
- this.loadFromJSON(data,defaultState)
149
- }
150
-
151
- loadFromJSON (data,defaultState) {
152
- if (!data)
153
- return
154
- if (!data.center)
155
- return
156
- if (!data.left)
157
- return
158
- if (!data.right)
159
- return
160
- //if (!data.knob)
161
- // return
162
- this.center = data.center
163
- this.left = data.left
164
- this.right = data.right
165
-
166
- /**
167
- * Sychronize the states of the buttons with the default state - add missing options from default state
168
- */
169
- var buttons = Object.keys(this.center)
170
- for (var buttonID=0;buttonID<buttons.length;buttonID++){
171
- if (!this.center[buttonID])
172
- continue
173
- var states = Object.keys(this.center[buttonID].states)
174
- for (var stateID=0;stateID<states.length;stateID++){
175
- var stateKey = states[stateID]
176
- var stateOld = this.center[buttonID].states[stateKey]
177
- this.center[buttonID].states[stateKey] = syncParams(stateOld,defaultState)
178
- }
179
- }
180
- }
181
- }
182
-
183
- /**
184
- * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
185
- */
186
- class ButtonConfig {
187
- buttons = {}
188
- defaultButtons = {
189
- "0" : {"states" : { "off" : { "filter": "pressed", "color": "#005500", "brightness" : 0 }, "half" : { "filter": "pressed", "brightness" : 0.5, "vibrate": 0x58, "color": "#00aa00" } , "on" : { "filter": "pressed", "brightness" : 1, "color": "#00ff00" } }, params: { group : "brightness"} },
190
- "1" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 0, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
191
- "2" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 1, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
192
- "3" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 2, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
193
- "4" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 3, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
194
- "5" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 4, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
195
- "6" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 5, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
196
- "7" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 6, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} }
197
- }
198
-
199
- constructor (data,profileCount,index) {
200
- if (data)
201
- return this.loadFromJSON(data)
202
- // Default to profile switching buttons
203
- var keys = Object.keys(this.defaultButtons)
204
- for (let i = 0; i <= profileCount; i++) {
205
- var key = keys[i]
206
- this.buttons[key] = this.defaultButtons[key]
207
- if (i==(index+1)){
208
- this.buttons[key].default = "on"
209
- }
210
-
211
- }
212
-
213
- }
214
-
215
- loadFromJSON (data) {
216
- if (!data)
217
- return
218
- this.buttons = data
219
- }
220
- }
221
-
222
- /**
223
- * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
224
- */
225
- class KnobsConfig {
226
- knobs = {
227
- "knobTL" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
228
- "knobCL" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
229
- "knobBL" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
230
- "knobTR" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
231
- "knobCR" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
232
- "knobBR" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
233
- } // KNOB Config - Available only in CT
234
-
235
- constructor (data) {
236
- this.loadFromJSON(data)
237
- }
238
-
239
- loadFromJSON (data) {
240
- if (!data)
241
- return
242
- this.knobs = data
243
- }
244
- }
245
-
246
- class ParametersConfig {
247
- parameters = {
248
- "hostname": "127.0.0.1",
249
- "endpointurl": "opc.tcp://{hostname}:4840",
250
- "nodeid" : "ns=0;s=nodeID",
251
- "min" : 0,
252
- "max" : 100
253
- }
254
-
255
- constructor (data) {
256
- this.loadFromJSON(data)
257
- }
258
-
259
- loadFromJSON (data) {
260
- if (!data)
261
- return
262
- this.parameters = data
263
- }
264
- }
265
-
266
- class DefaultConfig {
267
- default = {
268
- // "filter": "released",
269
- "color": "#111111"
270
- }
271
-
272
- constructor (data) {
273
- this.loadFromJSON(data)
274
- }
275
-
276
- loadFromJSON (data) {
277
- if (!data)
278
- return
279
- this.default = data
280
- }
281
- }
1
+ import { readConfigFile as readConfigFile, writeJSONFile,syncParams, writeYAMLFile } from './utils.mjs'
2
+
3
+ export class ApplicationConfig {
4
+ application = 'undefined'
5
+ profiles = []
6
+ parameters = {}
7
+ initialized = false
8
+
9
+ loadFromFile (fileName) {
10
+ console.info(`ApplicationConfig: Loading Config File ${fileName}`)
11
+ const config = readConfigFile(fileName)
12
+
13
+
14
+ if (!config){
15
+ console.info(`ApplicationConfig: Could not read/parse Config File ${fileName} - breaking here`)
16
+ }else if (!config.application){
17
+ console.info(`ApplicationConfig: Config File ${fileName} does not contain an application attribute - breaking here`)
18
+ }else if (!config.profiles){
19
+ console.info(`ApplicationConfig: Config File ${fileName} does not contain a profiles attribute - breaking here`)
20
+ }
21
+ else{
22
+ this.application = config.application
23
+ this.parameters = new ParametersConfig()
24
+
25
+
26
+ for (let i = 0; i < config.profiles.length; i++) {
27
+ const profile = new Profile(config.profiles[i],config.profiles.length,i)
28
+ profile.setParams(config.parameters)
29
+ if (profile.loaded){
30
+ this.profiles.push(profile)
31
+ }else{
32
+ return false
33
+ }
34
+ }
35
+
36
+ this.initialized=true
37
+ }
38
+ return this.initialized
39
+ }
40
+ }
41
+
42
+ class Profile {
43
+ name = ''
44
+ profile = 'example'
45
+ description = ''
46
+
47
+ touch = {}
48
+ knobs = {}
49
+ buttons = {}
50
+ parameters = {}
51
+ default = {}
52
+ #file = ''
53
+ loaded = false
54
+ #error = true
55
+ #profileCount = 0
56
+ #index = 0
57
+
58
+ constructor (data,profileCount,index) {
59
+ this.name = data.name
60
+ this.#file = data.file
61
+ this.#profileCount = profileCount
62
+ this.#index = index
63
+ this.touch = new TouchConfig({})
64
+ this.buttons = new ButtonConfig().buttons
65
+ this.knobs = new KnobsConfig().knobs
66
+ this.parameters = new ParametersConfig().parameters
67
+ this.default = new DefaultConfig().default
68
+
69
+ this.loadFromFile(this.#file)
70
+ if (this.#error) {
71
+ this.saveToFile(`profile-${this.name}-sav.json`)
72
+ }
73
+ }
74
+
75
+ loadFromFile (fileName) {
76
+ console.info(`ProfileConfig: Loading Profile File ${fileName}, Index ${this.#index}`)
77
+ const config = readConfigFile(fileName)
78
+ if (config === undefined) {
79
+ console.warn(`ProfileConfig: Cannot parse/load Profile File ${fileName}`)
80
+ return false
81
+ }else if (!config.profile){
82
+ console.warn(`ProfileConfig: File ${fileName} is missing a profile attribute`)
83
+ return false
84
+ }else if (!config.touch){
85
+ console.warn(`ProfileConfig: File ${fileName} is missing a touch attribute`)
86
+ return false
87
+ }else if (!config.parameters){
88
+ console.warn(`ProfileConfig: File ${fileName} is missing a parameters attribute`)
89
+ return false
90
+ }else if (!config.buttons){
91
+ console.info(`ProfileConfig: File ${fileName} is missing a buttons attribute - will be used to switch profiles by default`)
92
+ // return false
93
+ }
94
+ this.profile = config.profile
95
+ this.description = config.description
96
+ // Load Parameters.parameters = config.parameters
97
+ this.parameters = new ParametersConfig(config.parameters).parameters
98
+ this.default = new DefaultConfig(config.default).default
99
+
100
+ // Load the Configurations for Touch-Displays
101
+ this.touch = new TouchConfig(config.touch,this.default)
102
+ // Load the Configurations for Button-Areas
103
+
104
+ this.buttons = new ButtonConfig(config.buttons,this.#profileCount,this.#index).buttons
105
+ this.knobs = new KnobsConfig(config.knobs).knobs
106
+
107
+ this.#error = false
108
+ this.loaded = true
109
+ return this.loaded
110
+ }
111
+
112
+ setParams(parameters){
113
+ if (parameters === undefined)
114
+ return
115
+
116
+ let keys = Object.keys(parameters)
117
+ for (var i=0;i<keys.length;i++){
118
+ let key = keys[i]
119
+ if (!(key in this.parameters)){
120
+ this.parameters[key] = parameters[key]
121
+ }
122
+ }
123
+
124
+ }
125
+
126
+ saveToFile (fileName) {
127
+ fileName = fileName.toLowerCase()
128
+
129
+ console.info(`ProfileConfig: Save To Config File ${fileName}`)
130
+ if(fileName.endsWith('.json')) {
131
+ writeJSONFile(fileName, this)
132
+ writeYAMLFile(fileName.replace('.json','.yaml'), this)
133
+ }else if(fileName.endsWith('.yaml')) {
134
+ writeYAMLFile(fileName, this)
135
+ writeJSONFile(fileName.replace('.yaml','.json'), this)
136
+ }
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
142
+ */
143
+ class TouchConfig {
144
+ center = {
145
+ "0" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
146
+ "1" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
147
+ "2" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
148
+ "3" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
149
+ "4" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
150
+ "5" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
151
+ "6" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
152
+ "7" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
153
+ "8" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
154
+ "9" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
155
+ "10" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
156
+ "11" : { "states" : { "off" : { "color": "#000099", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" }, "on" : { "color": "#00ff00", "image": "icons/home.png","cmd": "echo \"{id} {state}\"" } } },
157
+ } // CENTER Display Config - Available in CT & LIVE
158
+ left = {
159
+ "0" : { "states" : { "on" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
160
+ } // LEFT Display Config - Available in CT & LIVE
161
+ right = {
162
+ "0" : { "states" : { "on" : { "color": "#000000", "cmd": "echo \"{id} {state}\"" } }, group : "" },
163
+ } // RIGHT Display Config - Available in CT & LIVE
164
+ //knob = {} // KNOB Display Config - Available only in CT
165
+
166
+ constructor (data,defaultState) {
167
+ this.loadFromJSON(data,defaultState)
168
+ }
169
+
170
+ loadFromJSON (data,defaultState) {
171
+ if (!data)
172
+ return
173
+ if (!data.center)
174
+ return
175
+ if (!data.left)
176
+ return
177
+ if (!data.right)
178
+ return
179
+ //if (!data.knob)
180
+ // return
181
+ this.center = data.center
182
+ this.left = data.left
183
+ this.right = data.right
184
+
185
+ /**
186
+ * Sychronize the states of the buttons with the default state - add missing options from default state
187
+ */
188
+ var buttons = Object.keys(this.center)
189
+ for (var buttonID=0;buttonID<buttons.length;buttonID++){
190
+ if (!this.center[buttonID])
191
+ continue
192
+ var states = Object.keys(this.center[buttonID].states)
193
+ for (var stateID=0;stateID<states.length;stateID++){
194
+ var stateKey = states[stateID]
195
+ var stateOld = this.center[buttonID].states[stateKey]
196
+ this.center[buttonID].states[stateKey] = syncParams(stateOld,defaultState)
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
204
+ */
205
+ class ButtonConfig {
206
+ buttons = {}
207
+ defaultButtons = {
208
+ "0" : {"states" : { "off" : { "filter": "pressed", "color": "#005500", "brightness" : 0 }, "half" : { "filter": "pressed", "brightness" : 0.5, "vibrate": 0x58, "color": "#00aa00" } , "on" : { "filter": "pressed", "brightness" : 1, "color": "#00ff00" } }, params: { group : "brightness"} },
209
+ "1" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 0, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
210
+ "2" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 1, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
211
+ "3" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 2, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
212
+ "4" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 3, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
213
+ "5" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 4, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
214
+ "6" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 5, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} },
215
+ "7" : {"states" : { "off" : { "filter": "pressed", "color": "#000055", "profile": 6, }, "on" : { "filter": "pressed", "color": "#00ff00" } }, params: { group : "profiles"} }
216
+ }
217
+
218
+ constructor (data,profileCount,index) {
219
+ if (data)
220
+ return this.loadFromJSON(data)
221
+ // Default to profile switching buttons
222
+ var keys = Object.keys(this.defaultButtons)
223
+ for (let i = 0; i <= profileCount; i++) {
224
+ var key = keys[i]
225
+ this.buttons[key] = this.defaultButtons[key]
226
+ if (i==(index+1)){
227
+ this.buttons[key].params.default = "on"
228
+ }
229
+
230
+ }
231
+
232
+ }
233
+
234
+ loadFromJSON (data) {
235
+ if (!data)
236
+ return
237
+ this.buttons = data
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Class that handles the different configs for the touch displays of the device covering Loupedeck Live (without knob) and also CT (with knob)
243
+ */
244
+ class KnobsConfig {
245
+ knobs = {
246
+ "knobTL" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
247
+ "knobCL" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
248
+ "knobBL" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
249
+ "knobTR" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
250
+ "knobCR" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
251
+ "knobBR" : { "states" : { "on" : { "cmd": "echo \"{id} {state}\"" } }, group : "" },
252
+ } // KNOB Config - Available only in CT
253
+
254
+ constructor (data) {
255
+ this.loadFromJSON(data)
256
+ }
257
+
258
+ loadFromJSON (data) {
259
+ if (!data)
260
+ return
261
+ this.knobs = data
262
+ }
263
+ }
264
+
265
+ class ParametersConfig {
266
+ parameters = {
267
+ "hostname": "127.0.0.1",
268
+ "endpointurl": "opc.tcp://{hostname}:4840",
269
+ "nodeid" : "ns=0;s=nodeID",
270
+ "min" : 0,
271
+ "max" : 100
272
+ }
273
+
274
+ constructor (data) {
275
+ this.loadFromJSON(data)
276
+ }
277
+
278
+ loadFromJSON (data) {
279
+ if (!data)
280
+ return
281
+ this.parameters = data
282
+ }
283
+ }
284
+
285
+ class DefaultConfig {
286
+ default = {
287
+ // "filter": "released",
288
+ "color": "#111111"
289
+ }
290
+
291
+ constructor (data) {
292
+ this.loadFromJSON(data)
293
+ }
294
+
295
+ loadFromJSON (data) {
296
+ if (!data)
297
+ return
298
+ this.default = data
299
+ }
300
+ }