amaran-light-cli
Version:
Command line tool for controlling Aputure Amaran lights via WebSocket to a local Amaran desktop app.
149 lines • 7.83 kB
JavaScript
import chalk from 'chalk';
import { VALIDATION_RANGES } from '../../deviceControl/constants.js';
import { addStandardOptions, commandCallbackPromise, getLightDevices, runDeviceAction } from '../cmdUtils.js';
export function registerCct(program, deps) {
const { asyncCommand } = deps;
addStandardOptions(program
.command('cct [temperature] [device]')
.usage('[temperature] [device] [options]')
.description(`Set or get color temperature in Kelvin (${VALIDATION_RANGES.cct.min}-${VALIDATION_RANGES.cct.max}). Omit device or use "all" for all lights.`))
.option('-i, --intensity <value>', `Also set intensity (${VALIDATION_RANGES.intensity.min}-${VALIDATION_RANGES.intensity.max})`)
.option('-g, --get', 'Get current CCT and intensity instead of setting')
.action(asyncCommand(handleCct(deps)));
}
function handleCct(deps) {
return async (tempStr, deviceQuery, options) => {
if (options.get) {
const targetDevice = deviceQuery ?? tempStr;
return runDeviceAction({
deps,
options,
deviceQuery: targetDevice,
actionName: 'get temperature',
}, async (device, controller) => {
return new Promise((resolve) => {
controller.getCCT(device.node_id, (success, message, data) => {
const displayName = device.device_name || device.name || device.id || device.node_id || 'Unknown';
if (!success) {
console.error(chalk.red(`✗ ${displayName}: Failed to get CCT: ${message}`));
resolve();
return;
}
// Handle potential nesting: { data: { data: 1700 } } or { data: { cct: 1700 } }
let state = data;
if (state && typeof state === 'object' && 'data' in state) {
const innerData = state.data;
// If nested data is just a number, that's our CCT
if (typeof innerData === 'number') {
state = { cct: innerData };
}
else {
state = innerData;
}
}
// biome-ignore lint/suspicious/noExplicitAny: Data from server is dynamic
const s = state;
// Some servers return the value directly or in a 'cct' property
const cctValue = typeof state === 'number' ? state : s?.cct;
let output = `✓ ${displayName}: ${cctValue || 'unknown'}K`;
if (s?.intensity !== undefined) {
output += ` at ${s.intensity / 10}% intensity`;
}
console.log(chalk.green(output));
resolve();
});
});
}, async (controller) => {
const devices = controller.getDevices();
if (devices.length === 0) {
console.log(chalk.yellow('No devices found'));
return;
}
// Filter for light devices only, skipping groups like 'ALL'
const lightDevices = getLightDevices(devices);
if (lightDevices.length === 0) {
console.log(chalk.yellow('No light devices found'));
return;
}
for (const device of lightDevices) {
if (device.node_id) {
await new Promise((resolve) => {
controller.getCCT(device.node_id, (success, message, data) => {
const displayName = device.device_name || device.name || device.id || device.node_id || 'Unknown';
if (success) {
let state = data;
if (state && typeof state === 'object' && 'data' in state) {
const innerData = state.data;
if (typeof innerData === 'number') {
state = { cct: innerData };
}
else {
state = innerData;
}
}
// biome-ignore lint/suspicious/noExplicitAny: Data from server is dynamic
const s = state;
const cctValue = typeof state === 'number' ? state : s?.cct;
let output = `✓ ${displayName}: ${cctValue || 'unknown'}K`;
if (s?.intensity !== undefined) {
output += ` at ${s.intensity / 10}% intensity`;
}
console.log(chalk.green(output));
}
else {
console.error(chalk.red(`✗ ${displayName}: Failed to get CCT: ${message}`));
}
resolve();
});
});
}
}
});
}
if (!tempStr) {
console.error(chalk.red('Error: temperature is required unless using --get'));
process.exit(1);
}
const temperature = parseInt(tempStr, 10);
if (Number.isNaN(temperature) ||
temperature < VALIDATION_RANGES.cct.min ||
temperature > VALIDATION_RANGES.cct.max) {
console.error(chalk.red(`Temperature must be between ${VALIDATION_RANGES.cct.min}K and ${VALIDATION_RANGES.cct.max}K`));
process.exit(1);
}
let intensity;
if (options.intensity) {
intensity = parseInt(options.intensity, 10);
if (Number.isNaN(intensity) ||
intensity < VALIDATION_RANGES.intensity.min ||
intensity > VALIDATION_RANGES.intensity.max) {
console.error(chalk.red(`Intensity must be a number between ${VALIDATION_RANGES.intensity.min} and ${VALIDATION_RANGES.intensity.max}`));
process.exit(1);
}
intensity = intensity * 10;
}
return runDeviceAction({
deps,
options,
deviceQuery,
actionName: 'set temperature',
onSuccess: (device) => {
const displayName = device.device_name || device.name || device.id || device.node_id || 'Unknown';
let msg = `✓ ${displayName} temperature set to ${temperature}K`;
if (intensity !== undefined) {
msg += ` at ${intensity / 10}% intensity`;
}
return msg;
},
}, (device, controller) => {
return commandCallbackPromise((callback) => controller.setCCT(device.node_id, temperature, intensity, callback));
}, async (controller) => {
await controller.setCCTAndIntensityForAllLights(temperature, intensity, (success, message) => {
if (!success)
console.error(`✗ Failed to set temperature: ${message}`);
});
});
};
}
export default registerCct;
//# sourceMappingURL=cct.js.map