amaran-light-cli 1.0.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.
Files changed (97) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +374 -0
  3. package/dist/__tests__/autoCct.test.d.ts +2 -0
  4. package/dist/__tests__/autoCct.test.d.ts.map +1 -0
  5. package/dist/__tests__/autoCct.test.js +65 -0
  6. package/dist/__tests__/autoCct.test.js.map +1 -0
  7. package/dist/__tests__/cctUtil.test.d.ts +2 -0
  8. package/dist/__tests__/cctUtil.test.d.ts.map +1 -0
  9. package/dist/__tests__/cctUtil.test.js +195 -0
  10. package/dist/__tests__/cctUtil.test.js.map +1 -0
  11. package/dist/__tests__/cli.smoke.test.d.ts +2 -0
  12. package/dist/__tests__/cli.smoke.test.d.ts.map +1 -0
  13. package/dist/__tests__/cli.smoke.test.js +18 -0
  14. package/dist/__tests__/cli.smoke.test.js.map +1 -0
  15. package/dist/__tests__/intensityApi.test.d.ts +2 -0
  16. package/dist/__tests__/intensityApi.test.d.ts.map +1 -0
  17. package/dist/__tests__/intensityApi.test.js +105 -0
  18. package/dist/__tests__/intensityApi.test.js.map +1 -0
  19. package/dist/__tests__/lightControl.test.d.ts +2 -0
  20. package/dist/__tests__/lightControl.test.d.ts.map +1 -0
  21. package/dist/__tests__/lightControl.test.js +185 -0
  22. package/dist/__tests__/lightControl.test.js.map +1 -0
  23. package/dist/cctUtil.d.ts +26 -0
  24. package/dist/cctUtil.d.ts.map +1 -0
  25. package/dist/cctUtil.js +93 -0
  26. package/dist/cctUtil.js.map +1 -0
  27. package/dist/cli.d.ts +10 -0
  28. package/dist/cli.d.ts.map +1 -0
  29. package/dist/cli.js +274 -0
  30. package/dist/cli.js.map +1 -0
  31. package/dist/commands/autoCct.d.ts +5 -0
  32. package/dist/commands/autoCct.d.ts.map +1 -0
  33. package/dist/commands/autoCct.js +270 -0
  34. package/dist/commands/autoCct.js.map +1 -0
  35. package/dist/commands/cct.d.ts +5 -0
  36. package/dist/commands/cct.d.ts.map +1 -0
  37. package/dist/commands/cct.js +68 -0
  38. package/dist/commands/cct.js.map +1 -0
  39. package/dist/commands/color.d.ts +5 -0
  40. package/dist/commands/color.d.ts.map +1 -0
  41. package/dist/commands/color.js +63 -0
  42. package/dist/commands/color.js.map +1 -0
  43. package/dist/commands/discover.d.ts +5 -0
  44. package/dist/commands/discover.d.ts.map +1 -0
  45. package/dist/commands/discover.js +30 -0
  46. package/dist/commands/discover.js.map +1 -0
  47. package/dist/commands/hsi.d.ts +5 -0
  48. package/dist/commands/hsi.d.ts.map +1 -0
  49. package/dist/commands/hsi.js +65 -0
  50. package/dist/commands/hsi.js.map +1 -0
  51. package/dist/commands/intensity.d.ts +5 -0
  52. package/dist/commands/intensity.d.ts.map +1 -0
  53. package/dist/commands/intensity.js +56 -0
  54. package/dist/commands/intensity.js.map +1 -0
  55. package/dist/commands/list.d.ts +5 -0
  56. package/dist/commands/list.d.ts.map +1 -0
  57. package/dist/commands/list.js +36 -0
  58. package/dist/commands/list.js.map +1 -0
  59. package/dist/commands/power.d.ts +5 -0
  60. package/dist/commands/power.d.ts.map +1 -0
  61. package/dist/commands/power.js +126 -0
  62. package/dist/commands/power.js.map +1 -0
  63. package/dist/commands/schedule.d.ts +5 -0
  64. package/dist/commands/schedule.d.ts.map +1 -0
  65. package/dist/commands/schedule.js +188 -0
  66. package/dist/commands/schedule.js.map +1 -0
  67. package/dist/commands/service.d.ts +5 -0
  68. package/dist/commands/service.d.ts.map +1 -0
  69. package/dist/commands/service.js +350 -0
  70. package/dist/commands/service.js.map +1 -0
  71. package/dist/commands/status.d.ts +5 -0
  72. package/dist/commands/status.d.ts.map +1 -0
  73. package/dist/commands/status.js +54 -0
  74. package/dist/commands/status.js.map +1 -0
  75. package/dist/commands.d.ts +5 -0
  76. package/dist/commands.d.ts.map +1 -0
  77. package/dist/commands.js +31 -0
  78. package/dist/commands.js.map +1 -0
  79. package/dist/discovery.d.ts +13 -0
  80. package/dist/discovery.d.ts.map +1 -0
  81. package/dist/discovery.js +130 -0
  82. package/dist/discovery.js.map +1 -0
  83. package/dist/geoipUtil.d.ts +8 -0
  84. package/dist/geoipUtil.d.ts.map +1 -0
  85. package/dist/geoipUtil.js +26 -0
  86. package/dist/geoipUtil.js.map +1 -0
  87. package/dist/lightControl.d.ts +114 -0
  88. package/dist/lightControl.d.ts.map +1 -0
  89. package/dist/lightControl.js +385 -0
  90. package/dist/lightControl.js.map +1 -0
  91. package/dist/types.d.ts +37 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/types.js +3 -0
  94. package/dist/types.js.map +1 -0
  95. package/package.json +75 -0
  96. package/scripts/create-launchd-service.sh +114 -0
  97. package/scripts/run-auto-cct.sh +43 -0
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+ /*
3
+ MIT License
4
+ Copyright (c) 2024 S. Zachariah Sprackett <zac@sprackett.com>
5
+ Copyright (c) 2025 Mahyar McDonald <github@hmmfn.com>
6
+
7
+ Control Aputure Amaran Lights via websocket to the amaran Desktop application.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+
25
+ Downloaded from: https://gist.github.com/zsprackett/29334b9be1e2bd90c1737bd0ba0eaf5c
26
+ */
27
+ var __importDefault = (this && this.__importDefault) || function (mod) {
28
+ return (mod && mod.__esModule) ? mod : { "default": mod };
29
+ };
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ const ws_1 = __importDefault(require("ws"));
32
+ class LightController {
33
+ /**
34
+ * Apply a command to all light devices with throttling.
35
+ * Only targets devices with node_ids matching the light pattern (e.g., '400J5-F2C008').
36
+ * Throttles commands with 250ms delay between each to avoid overwhelming the server.
37
+ *
38
+ * @param commandFn - Function that takes (nodeId, callback) and executes the command
39
+ * @param commandName - Display name for the command (for logging)
40
+ * @param getDisplayArgs - Optional function to get display arguments for logging
41
+ */
42
+ async applyToAllLights(commandFn, commandName, getDisplayArgs) {
43
+ if (!this.deviceList)
44
+ return;
45
+ // Filter devices: only those with node_id matching the light pattern
46
+ const lightDevices = this.deviceList.filter((device) => {
47
+ return device?.node_id && this.isLightNodeId(device.node_id);
48
+ });
49
+ if (lightDevices.length === 0) {
50
+ this.log(`No light devices found for ${commandName}`);
51
+ return;
52
+ }
53
+ this.log(`${commandName} for ${lightDevices.length} light(s)`);
54
+ const waitTimeMs = 250;
55
+ // Send commands with waitTimeMs throttling between each
56
+ for (let i = 0; i < lightDevices.length; i++) {
57
+ const device = lightDevices[i];
58
+ const displayName = device.device_name || device.name || device.node_id || 'Unknown';
59
+ const displayArgs = getDisplayArgs ? getDisplayArgs(device) : '';
60
+ console.log(` ${commandName} ${displayName} (${device.node_id})${displayArgs}`);
61
+ if (device.node_id) {
62
+ commandFn(device.node_id);
63
+ }
64
+ // Wait waitTimeMs before sending next command (skip delay after last one)
65
+ if (i < lightDevices.length - 1) {
66
+ await this.sleep(waitTimeMs);
67
+ }
68
+ }
69
+ }
70
+ /**
71
+ * Set CCT & Intensity for all lights in deviceList.
72
+ * Only targets devices with node_ids matching the light pattern (e.g., '400J5-F2C008').
73
+ * Throttles commands with 250ms delay between each to avoid overwhelming the server.
74
+ */
75
+ async setCCTAndIntensityForAllLights(cct, intensity, callback) {
76
+ await this.applyToAllLights((nodeId) => this.setCCT(nodeId, cct, intensity, callback), 'Setting CCT', () => ` to ${cct}K${intensity !== undefined ? ` at ${intensity / 10}%` : ''}`);
77
+ }
78
+ /**
79
+ * Turn on all lights.
80
+ */
81
+ async turnOnAllLights(callback) {
82
+ await this.applyToAllLights((nodeId) => this.turnLightOn(nodeId, callback), 'Turning on');
83
+ }
84
+ /**
85
+ * Turn off all lights.
86
+ */
87
+ async turnOffAllLights(callback) {
88
+ await this.applyToAllLights((nodeId) => this.turnLightOff(nodeId, callback), 'Turning off');
89
+ }
90
+ /**
91
+ * Toggle all lights.
92
+ */
93
+ async toggleAllLights(callback) {
94
+ await this.applyToAllLights((nodeId) => this.toggleLight(nodeId, callback), 'Toggling');
95
+ }
96
+ /**
97
+ * Set intensity for all lights.
98
+ */
99
+ async setIntensityForAllLights(intensity, callback) {
100
+ await this.applyToAllLights((nodeId) => this.setIntensity(nodeId, intensity, callback), 'Setting intensity', () => ` to ${intensity / 10}%`);
101
+ }
102
+ /**
103
+ * Increment intensity for all lights.
104
+ */
105
+ async incrementIntensityForAllLights(delta, callback) {
106
+ await this.applyToAllLights((nodeId) => this.incrementIntensity(nodeId, delta, callback), 'Incrementing intensity', () => ` by ${delta > 0 ? '+' : ''}${delta / 10}%`);
107
+ }
108
+ /**
109
+ * Increment CCT for all lights.
110
+ */
111
+ async incrementCCTForAllLights(delta, intensity, callback) {
112
+ await this.applyToAllLights((nodeId) => this.incrementCCT(nodeId, delta, intensity, callback), 'Incrementing CCT', () => ` by ${delta > 0 ? '+' : ''}${delta}K${intensity !== undefined ? ` at ${intensity / 10}%` : ''}`);
113
+ }
114
+ /**
115
+ * Set HSI color for all lights.
116
+ */
117
+ async setHSIForAllLights(hue, sat, intensity, cct, gm, callback) {
118
+ await this.applyToAllLights((nodeId) => this.setHSI(nodeId, hue, sat, intensity, cct, gm, callback), 'Setting HSI', () => ` to H:${hue} S:${sat} I:${intensity / 10}%`);
119
+ }
120
+ /**
121
+ * Set color for all lights.
122
+ */
123
+ async setColorForAllLights(color, intensity, callback) {
124
+ await this.applyToAllLights((nodeId) => this.setColor(nodeId, color, intensity, callback), 'Setting color', () => ` to ${color}${intensity !== undefined ? ` at ${intensity / 10}%` : ''}`);
125
+ }
126
+ /**
127
+ * Set system effect for all lights.
128
+ */
129
+ async setSystemEffectForAllLights(effectType, intensity, callback) {
130
+ await this.applyToAllLights((nodeId) => this.setSystemEffect(nodeId, effectType, intensity, callback), 'Setting effect', () => ` to ${effectType}${intensity !== undefined ? ` at ${intensity / 10}%` : ''}`);
131
+ }
132
+ /**
133
+ * Check if a node_id looks like a light device (not a group or other entity).
134
+ * Light node_ids typically follow pattern like '400J5-F2C008' (alphanumeric with dash).
135
+ */
136
+ isLightNodeId(nodeId) {
137
+ // Pattern: contains at least one dash and alphanumeric characters
138
+ // Excludes things like 'all', 'group1', etc.
139
+ const lightPattern = /^[A-Z0-9]+-[A-Z0-9]+$/i;
140
+ return lightPattern.test(nodeId);
141
+ }
142
+ /**
143
+ * Sleep utility for throttling commands
144
+ */
145
+ sleep(ms) {
146
+ return new Promise((resolve) => setTimeout(resolve, ms));
147
+ }
148
+ constructor(wsUrl, clientId, onInitialized, debug = false) {
149
+ this.clientId = 'unknown_client';
150
+ this.deviceList = [];
151
+ this.sceneList = [];
152
+ this.nodeConfigs = new Map();
153
+ this.commandCallbacks = new Map();
154
+ this.pendingQueue = [];
155
+ this.ws = new ws_1.default(wsUrl);
156
+ if (clientId) {
157
+ this.clientId = clientId;
158
+ }
159
+ this.debug = debug;
160
+ if (onInitialized) {
161
+ this.onInitializedCallback = onInitialized;
162
+ }
163
+ this.ws.on('open', () => {
164
+ this.log('Connected to WebSocket server');
165
+ // Flush any queued commands that were issued before the socket was open
166
+ this.flushPending();
167
+ this.onConnectionOpen();
168
+ });
169
+ this.ws.on('message', (data) => {
170
+ try {
171
+ const parsedData = JSON.parse(data.toString());
172
+ this.log('Received message from server:', parsedData);
173
+ const requestId = parsedData.request?.type;
174
+ if (parsedData.code !== 0) {
175
+ console.error('Error from server:', parsedData.message);
176
+ if (requestId && this.commandCallbacks.has(requestId)) {
177
+ this.commandCallbacks.get(requestId)?.(false, parsedData.message);
178
+ this.commandCallbacks.delete(requestId);
179
+ }
180
+ return;
181
+ }
182
+ if (requestId && this.commandCallbacks.has(requestId)) {
183
+ this.commandCallbacks.get(requestId)?.(true, parsedData.message, parsedData.data);
184
+ this.commandCallbacks.delete(requestId);
185
+ }
186
+ if (parsedData.request?.type) {
187
+ switch (parsedData.request.type) {
188
+ case 'get_device_list':
189
+ this.handleDeviceList(parsedData.data);
190
+ break;
191
+ case 'get_scene_list':
192
+ this.handleSceneList(parsedData.data);
193
+ break;
194
+ case 'get_node_config':
195
+ this.handleNodeConfig(parsedData.data);
196
+ break;
197
+ default:
198
+ this.log('Unknown response type');
199
+ }
200
+ }
201
+ }
202
+ catch (error) {
203
+ console.error('Error parsing message:', error);
204
+ }
205
+ });
206
+ this.ws.on('error', (error) => {
207
+ console.error('WebSocket error:', error);
208
+ });
209
+ this.ws.on('close', () => {
210
+ this.log('Disconnected from WebSocket server');
211
+ });
212
+ }
213
+ setClientId(clientId) {
214
+ this.clientId = clientId;
215
+ }
216
+ onConnectionOpen() {
217
+ this.getDeviceList();
218
+ }
219
+ sendCommand(nodeId, type, args, callback) {
220
+ if (this.ws.readyState === ws_1.default.OPEN) {
221
+ const command = {
222
+ version: 1,
223
+ client_id: this.clientId,
224
+ type,
225
+ node_id: nodeId,
226
+ args,
227
+ };
228
+ if (callback) {
229
+ this.commandCallbacks.set(type, callback);
230
+ }
231
+ this.ws.send(JSON.stringify(command));
232
+ this.log(`Sent command: ${type}`);
233
+ }
234
+ else {
235
+ // Queue the command to be sent when the socket opens
236
+ this.pendingQueue.push({ nodeId, type, args, callback });
237
+ this.log(`Queued command (socket not open yet): ${type}`);
238
+ }
239
+ }
240
+ handleDeviceList(data) {
241
+ this.deviceList = data.data;
242
+ this.log('Device List:', JSON.stringify(this.deviceList, null, 2));
243
+ this.getSceneList();
244
+ }
245
+ handleSceneList(data) {
246
+ this.sceneList = data.data;
247
+ this.log('Scene List:', JSON.stringify(this.sceneList, null, 2));
248
+ this.getNodeConfigs();
249
+ }
250
+ handleNodeConfig(data) {
251
+ const nodeId = data.node_id;
252
+ if (nodeId) {
253
+ this.nodeConfigs.set(nodeId, data.data);
254
+ this.log('Node Config:', JSON.stringify(data.data, null, 2));
255
+ if (this.nodeConfigs.size === this.deviceList.length) {
256
+ this.log('All node configurations have been gathered');
257
+ if (this.onInitializedCallback) {
258
+ this.onInitializedCallback();
259
+ }
260
+ }
261
+ }
262
+ }
263
+ getNodeConfigs() {
264
+ this.deviceList.forEach((device) => {
265
+ if (device.node_id) {
266
+ this.getNodeConfig(device.node_id);
267
+ }
268
+ });
269
+ }
270
+ getDeviceList(callback) {
271
+ this.sendCommand(undefined, 'get_device_list', {}, callback);
272
+ }
273
+ getSceneList(callback) {
274
+ this.sendCommand(undefined, 'get_scene_list', {}, callback);
275
+ }
276
+ getNodeConfig(nodeId, callback) {
277
+ this.sendCommand(nodeId, 'get_node_config', {}, callback);
278
+ }
279
+ turnLightOn(nodeId, callback) {
280
+ this.sendCommand(nodeId, 'set_sleep', { sleep: false }, callback);
281
+ }
282
+ turnLightOff(nodeId, callback) {
283
+ this.sendCommand(nodeId, 'set_sleep', { sleep: true }, callback);
284
+ }
285
+ getLightSleepStatus(nodeId, callback) {
286
+ this.sendCommand(nodeId, 'get_sleep', {}, callback);
287
+ }
288
+ toggleLight(nodeId, callback) {
289
+ this.sendCommand(nodeId, 'toggle_sleep', undefined, callback);
290
+ }
291
+ setIntensity(nodeId, intensity, callback) {
292
+ this.sendCommand(nodeId, 'set_intensity', { intensity }, callback);
293
+ }
294
+ incrementIntensity(nodeId, delta, callback) {
295
+ this.sendCommand(nodeId, 'increment_intensity', { delta }, callback);
296
+ }
297
+ setCCT(nodeId, cct, intensity, callback) {
298
+ const args = { cct };
299
+ if (intensity !== undefined) {
300
+ args.intensity = intensity;
301
+ }
302
+ this.sendCommand(nodeId, 'set_cct', args, callback);
303
+ }
304
+ incrementCCT(nodeId, delta, intensity, callback) {
305
+ const args = { delta };
306
+ if (intensity !== undefined) {
307
+ args.intensity = intensity;
308
+ }
309
+ this.sendCommand(nodeId, 'increment_cct', args, callback);
310
+ }
311
+ setHSI(nodeId, hue, sat, intensity, cct, gm, callback) {
312
+ const args = { hue, sat, intensity };
313
+ if (cct !== undefined) {
314
+ args.cct = cct;
315
+ }
316
+ if (gm !== undefined) {
317
+ args.gm = gm;
318
+ }
319
+ this.sendCommand(nodeId, 'set_hsi', args, callback);
320
+ }
321
+ setColor(nodeId, color, intensity, callback) {
322
+ const args = { color };
323
+ if (intensity !== undefined) {
324
+ args.intensity = intensity;
325
+ }
326
+ this.sendCommand(nodeId, 'set_color', args, callback);
327
+ }
328
+ setSystemEffect(nodeId, effectType, intensity, callback) {
329
+ const args = { effect_type: effectType };
330
+ if (intensity !== undefined) {
331
+ args.intensity = intensity;
332
+ }
333
+ this.sendCommand(nodeId, 'set_system_effect', args, callback);
334
+ }
335
+ async disconnect() {
336
+ if (this.ws.readyState === ws_1.default.OPEN) {
337
+ await this.waitForPendingCommands(5000);
338
+ this.ws.close();
339
+ this.log('WebSocket connection closed');
340
+ }
341
+ else {
342
+ console.error('WebSocket is not open or already closed');
343
+ }
344
+ }
345
+ waitForPendingCommands(timeout) {
346
+ return new Promise((resolve) => {
347
+ const start = Date.now();
348
+ const checkPendingCommands = () => {
349
+ if (this.commandCallbacks.size === 0 || Date.now() - start >= timeout) {
350
+ resolve();
351
+ }
352
+ else {
353
+ setTimeout(checkPendingCommands, 100);
354
+ }
355
+ };
356
+ checkPendingCommands();
357
+ });
358
+ }
359
+ // Getters
360
+ getDevices() {
361
+ return this.deviceList;
362
+ }
363
+ getScenes() {
364
+ return this.sceneList;
365
+ }
366
+ getNode(nodeId) {
367
+ return this.nodeConfigs.get(nodeId);
368
+ }
369
+ log(...args) {
370
+ if (this.debug) {
371
+ console.log(...args);
372
+ }
373
+ }
374
+ flushPending() {
375
+ if (this.pendingQueue.length === 0)
376
+ return;
377
+ const pending = [...this.pendingQueue];
378
+ this.pendingQueue.length = 0;
379
+ for (const p of pending) {
380
+ this.sendCommand(p.nodeId, p.type, p.args, p.callback);
381
+ }
382
+ }
383
+ }
384
+ exports.default = LightController;
385
+ //# sourceMappingURL=lightControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lightControl.js","sourceRoot":"","sources":["../src/lightControl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type LightController from './lightControl';
2
+ export type { LightController };
3
+ export interface Device {
4
+ node_id?: string;
5
+ device_name?: string;
6
+ name?: string;
7
+ id?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ export type CommandCallback = (success: boolean, message: string, data?: unknown) => void;
11
+ export interface Config {
12
+ wsUrl?: string;
13
+ latitude?: number;
14
+ longitude?: number;
15
+ [key: string]: unknown;
16
+ }
17
+ export interface CommandDeps {
18
+ createController: (wsUrl?: string, clientId?: string, debug?: boolean) => Promise<LightController>;
19
+ findDevice: (controller: LightController, deviceQuery: string) => Device | null;
20
+ asyncCommand: <T extends unknown[]>(fn: (...args: T) => Promise<void>) => (...args: T) => Promise<void>;
21
+ saveWsUrl?: (url: string) => void;
22
+ loadConfig?: () => Config | null;
23
+ }
24
+ export interface CommandOptions {
25
+ url?: string;
26
+ clientId?: string;
27
+ debug?: boolean;
28
+ intensity?: string;
29
+ interval?: string;
30
+ follow?: boolean;
31
+ errors?: boolean;
32
+ lat?: string;
33
+ lon?: string;
34
+ date?: string;
35
+ [key: string]: unknown;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,eAAe,MAAM,gBAAgB,CAAC;AAElD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,MAAM,WAAW,MAAM;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAE1F,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,gBAAgB,EAAE,CAChB,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,OAAO,KACZ,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9B,UAAU,EAAE,CAAC,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAChF,YAAY,EAAE,CAAC,CAAC,SAAS,OAAO,EAAE,EAChC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,KAC9B,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "amaran-light-cli",
3
+ "version": "1.0.2",
4
+ "description": "Command line tool for controlling Aputure Amaran lights via WebSocket to a local Amaran desktop app.",
5
+ "main": "dist/lightControl.js",
6
+ "types": "dist/lightControl.d.ts",
7
+ "bin": {
8
+ "amaran-cli": "dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/cli.js",
13
+ "dev": "ts-node src/cli.ts",
14
+ "test": "jest",
15
+ "test:watch": "jest --watch",
16
+ "test:coverage": "jest --coverage",
17
+ "clean": "rm -rf dist",
18
+ "prepublishOnly": "npm run clean && npm run build",
19
+ "lint": "biome lint src/",
20
+ "lint:fix": "biome lint --apply src/",
21
+ "format": "biome format --write src/",
22
+ "format:check": "biome format src/",
23
+ "check": "biome check src/",
24
+ "check:fix": "biome check --apply src/"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "scripts",
29
+ "README.md",
30
+ "LICENSE",
31
+ "CHANGELOG.md"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/theontho/amaran-cli.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/theontho/amaran-cli/issues"
39
+ },
40
+ "homepage": "https://github.com/theontho/amaran-cli#readme",
41
+ "keywords": [
42
+ "amaran",
43
+ "aputure",
44
+ "lighting",
45
+ "cli",
46
+ "websocket",
47
+ "smart-home",
48
+ "home-automation",
49
+ "circadian"
50
+ ],
51
+ "author": "Mahyar McDonald <github@hmmfn.com>",
52
+ "license": "MIT",
53
+ "engines": {
54
+ "node": ">=14.0.0"
55
+ },
56
+ "dependencies": {
57
+ "chalk": "^4.1.2",
58
+ "commander": "^11.1.0",
59
+ "geoip-lite": "^1.4.10",
60
+ "suncalc": "^1.9.0",
61
+ "ws": "^8.14.2"
62
+ },
63
+ "devDependencies": {
64
+ "@biomejs/biome": "^2.3.1",
65
+ "@types/geoip-lite": "^1.4.4",
66
+ "@types/jest": "^30.0.0",
67
+ "@types/node": "^20.8.0",
68
+ "@types/suncalc": "^1.9.0",
69
+ "@types/ws": "^8.5.8",
70
+ "jest": "^30.2.0",
71
+ "ts-jest": "^29.4.5",
72
+ "ts-node": "^10.9.1",
73
+ "typescript": "^5.2.2"
74
+ }
75
+ }
@@ -0,0 +1,114 @@
1
+ #!/bin/bash
2
+
3
+ # Script to create a launchd service for auto-cct
4
+ # Usage: ./scripts/create-launchd-service.sh
5
+
6
+ set -e
7
+
8
+ # Check if amaran-cli is globally installed first
9
+ if command -v amaran-cli >/dev/null 2>&1; then
10
+ AMARAN_CLI=$(which amaran-cli)
11
+ IS_GLOBAL=true
12
+ echo "Found global installation: $AMARAN_CLI"
13
+ else
14
+ # Fall back to local development build
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
17
+ AMARAN_CLI="$PROJECT_DIR/dist/cli.js"
18
+ IS_GLOBAL=false
19
+
20
+ # Check if the CLI is built
21
+ if [ ! -f "$AMARAN_CLI" ]; then
22
+ echo "Error: amaran-cli not found at $AMARAN_CLI"
23
+ echo "Please either:"
24
+ echo " 1. Install globally: npm install -g ."
25
+ echo " 2. Or build locally: npm run build"
26
+ exit 1
27
+ fi
28
+ echo "Using local development build: $AMARAN_CLI"
29
+ fi
30
+
31
+ # Plist file path
32
+ PLIST_NAME="com.hmmfn.amaran.circadian-service"
33
+ PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_NAME.plist"
34
+
35
+ # Create the plist content
36
+ if [ "$IS_GLOBAL" = true ]; then
37
+ # For global installation, use the executable directly
38
+ cat > "$PLIST_PATH" << EOF
39
+ <?xml version="1.0" encoding="UTF-8"?>
40
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
41
+ <plist version="1.0">
42
+ <dict>
43
+ <key>Label</key>
44
+ <string>$PLIST_NAME</string>
45
+ <key>ProgramArguments</key>
46
+ <array>
47
+ <string>$AMARAN_CLI</string>
48
+ <string>auto-cct</string>
49
+ </array>
50
+ <key>StartInterval</key>
51
+ <integer>60</integer>
52
+ <key>RunAtLoad</key>
53
+ <true/>
54
+ <key>KeepAlive</key>
55
+ <false/>
56
+ <key>StandardOutPath</key>
57
+ <string>$HOME/Library/Logs/amaran-circadian-service.log</string>
58
+ <key>StandardErrorPath</key>
59
+ <string>$HOME/Library/Logs/amaran-circadian-service-error.log</string>
60
+ </dict>
61
+ </plist>
62
+ EOF
63
+ else
64
+ # For local development, use node to run the script
65
+ cat > "$PLIST_PATH" << EOF
66
+ <?xml version="1.0" encoding="UTF-8"?>
67
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
68
+ <plist version="1.0">
69
+ <dict>
70
+ <key>Label</key>
71
+ <string>$PLIST_NAME</string>
72
+ <key>ProgramArguments</key>
73
+ <array>
74
+ <string>/usr/local/bin/node</string>
75
+ <string>$AMARAN_CLI</string>
76
+ <string>auto-cct</string>
77
+ </array>
78
+ <key>StartInterval</key>
79
+ <integer>60</integer>
80
+ <key>RunAtLoad</key>
81
+ <true/>
82
+ <key>KeepAlive</key>
83
+ <false/>
84
+ <key>StandardOutPath</key>
85
+ <string>$HOME/Library/Logs/amaran-circadian-service.log</string>
86
+ <key>StandardErrorPath</key>
87
+ <string>$HOME/Library/Logs/amaran-circadian-service-error.log</string>
88
+ <key>WorkingDirectory</key>
89
+ <string>$PROJECT_DIR</string>
90
+ </dict>
91
+ </plist>
92
+ EOF
93
+ fi
94
+
95
+ echo "Created launchd plist at: $PLIST_PATH"
96
+ echo "Installation type: $([ "$IS_GLOBAL" = true ] && echo "Global" || echo "Local development")"
97
+ echo "CLI path: $AMARAN_CLI"
98
+
99
+ # Load the service
100
+ launchctl load "$PLIST_PATH"
101
+ echo "Loaded launchd circadian lighting service: $PLIST_NAME"
102
+
103
+ echo ""
104
+ echo "Circadian lighting service commands:"
105
+ echo " Start: launchctl start $PLIST_NAME"
106
+ echo " Stop: launchctl stop $PLIST_NAME"
107
+ echo " Unload: launchctl unload $PLIST_PATH"
108
+ echo " Status: launchctl list | grep $PLIST_NAME"
109
+ echo ""
110
+ echo "Logs:"
111
+ echo " Output: tail -f $HOME/Library/Logs/amaran-circadian-service.log"
112
+ echo " Errors: tail -f $HOME/Library/Logs/amaran-circadian-service-error.log"
113
+
114
+ chmod +x /Users/mac/Documents/src/amaran-cli/scripts/create-launchd-service.sh