UNPKG

amaran-light-cli

Version:

Command line tool for controlling Aputure Amaran lights via WebSocket to a local Amaran desktop app.

279 lines 11.7 kB
import chalk from 'chalk'; import { getConfigPath, getConfigReadPath } from '../../config.js'; import { CURVE_HELP_TEXT } from '../../daylightSimulation/constants.js'; import { formatCoordinate } from '../../daylightSimulation/privacyUtil.js'; import { parseBooleanString, parseStrictInteger, parseStrictNumber } from '../parseUtils.js'; export default function registerConfig(program, deps) { const { asyncCommand } = deps; program .command('config') .description('Configure WebSocket URL and other settings') .option('-u, --url <url>', 'WebSocket URL (default: ws://localhost:60124)') .option('-c, --client-id <id>', 'Client ID (default: amaran-cli)') .option('-d, --debug <boolean>', 'Enable debug mode') .option('--lat <latitude>', 'Default latitude for auto-cct (overrides geoip)') .option('--lon <longitude>', 'Default longitude for auto-cct (overrides geoip)') .option('--cct-min <kelvin>', 'Minimum CCT for auto-cct in Kelvin (default: 2000)') .option('--cct-max <kelvin>', 'Maximum CCT for auto-cct in Kelvin (default: 6500)') .option('--intensity-min <percent>', 'Minimum intensity for auto-cct in percent (default: 5)') .option('--intensity-max <percent>', 'Maximum intensity for auto-cct in percent (default: 100)') .option('--default-curve <curve>', CURVE_HELP_TEXT) .option('--auto-start-app <boolean>', 'Automatically start Amaran desktop app on connection failure (default: true)') .option('--max-lux <number>', 'Maximum lux output of the setup (for auto-cct scaling)') .option('--weather <boolean>', 'Enable automatic weather fetching for auto-cct (default: false)') .option('--privacy-off', 'Show full coordinates and sensitive data', false) .option('--show', 'Show current configuration') .action(asyncCommand(handleConfig(deps))); } function handleConfig(deps) { const { loadConfig, saveConfig } = deps; if (!loadConfig) { throw new Error('loadConfig dependency is required'); } return async (options) => { const hasSetOptions = options.url !== undefined || options.clientId !== undefined || options.debug !== undefined || options.lat !== undefined || options.lon !== undefined || options.cctMin !== undefined || options.cctMax !== undefined || options.intensityMin !== undefined || options.intensityMax !== undefined || options.defaultCurve !== undefined || options.autoStartApp !== undefined || options.maxLux !== undefined || options.weather !== undefined; if (options.show || !hasSetOptions) { const config = loadConfig() || {}; const privacyOff = options.privacyOff === true; const readPath = getConfigReadPath(); console.log(chalk.blue('Current configuration:')); console.log(chalk.gray(`Config path: ${readPath ?? getConfigPath()}`)); if (readPath && readPath !== getConfigPath() && Object.keys(config).length > 0) { console.log(chalk.gray(`Run any config update to migrate this file to ${getConfigPath()}.`)); } const displayConfig = { ...config }; if (typeof displayConfig.latitude === 'number') { displayConfig.latitude = formatCoordinate(displayConfig.latitude, privacyOff); } if (typeof displayConfig.longitude === 'number') { displayConfig.longitude = formatCoordinate(displayConfig.longitude, privacyOff); } console.log(JSON.stringify(displayConfig, null, 2)); return; } const config = loadConfig() || {}; const changes = []; if (options.url) { config.wsUrl = options.url; changes.push(`WebSocket URL: ${options.url}`); } if (options.clientId) { config.clientId = options.clientId; changes.push(`Client ID: ${options.clientId}`); } if (options.debug !== undefined) { const value = options.debug; if (typeof value === 'boolean') { config.debug = value; } else { try { config.debug = parseBooleanString(value, 'debug'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } } changes.push(`Debug mode: ${config.debug ? 'enabled' : 'disabled'}`); } if (options.lat !== undefined) { let lat; try { lat = parseStrictNumber(options.lat, 'Latitude'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } if (Number.isNaN(lat) || lat < -90 || lat > 90) { console.error(chalk.red('Latitude must be between -90 and 90')); process.exit(1); } config.latitude = lat; changes.push(`Latitude: ${lat}`); } if (options.lon !== undefined) { let lon; try { lon = parseStrictNumber(options.lon, 'Longitude'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } if (Number.isNaN(lon) || lon < -180 || lon > 180) { console.error(chalk.red('Longitude must be between -180 and 180')); process.exit(1); } config.longitude = lon; changes.push(`Longitude: ${lon}`); } // Bounds validation helpers const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v)); if (options.cctMin !== undefined) { let k; try { k = parseStrictInteger(options.cctMin, 'cct-min'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } config.cctMin = clamp(k, 1000, 20000); changes.push(`CCT minimum: ${config.cctMin}K`); } if (options.cctMax !== undefined) { let k; try { k = parseStrictInteger(options.cctMax, 'cct-max'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } config.cctMax = clamp(k, 1000, 20000); changes.push(`CCT maximum: ${config.cctMax}K`); } if (options.intensityMin !== undefined) { let p; try { p = parseStrictNumber(options.intensityMin, 'intensity-min'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } config.intensityMin = clamp(p, 0, 100); changes.push(`Intensity minimum: ${config.intensityMin}%`); } if (options.intensityMax !== undefined) { let p; try { p = parseStrictNumber(options.intensityMax, 'intensity-max'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } config.intensityMax = clamp(p, 0, 100); changes.push(`Intensity maximum: ${config.intensityMax}%`); } // Handle default curve option if (options.defaultCurve !== undefined) { // dynamic import for ESM const { parseCurveType } = await import('../../daylightSimulation/cctUtil.js'); try { parseCurveType(options.defaultCurve); config.defaultCurve = options.defaultCurve; changes.push(`Default curve: ${config.defaultCurve}`); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } } // Handle auto-start-app option if (options.autoStartApp !== undefined) { const value = options.autoStartApp; if (typeof value === 'boolean') { config.autoStartApp = value; } else { try { config.autoStartApp = parseBooleanString(value, 'auto-start-app'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } } changes.push(`Auto-start app: ${config.autoStartApp ? 'enabled' : 'disabled'}`); } // Handle max-lux option if (options.maxLux !== undefined) { let valid = false; const luxVal = options.maxLux; // Try as simple number let luxNum; try { luxNum = parseStrictNumber(luxVal, 'max-lux'); } catch (_error) { luxNum = Number.NaN; } if (!Number.isNaN(luxNum) && luxNum > 0 && !luxVal.includes(':')) { config.maxLux = luxNum; changes.push(`Max Lux: ${luxNum}`); valid = true; } else { // Try as map const { parseMaxLuxMap } = await import('../../daylightSimulation/mathUtil.js'); const map = parseMaxLuxMap(luxVal); if (map) { config.maxLux = map; changes.push(`Max Lux Map: ${JSON.stringify(map)}`); valid = true; } } if (!valid) { console.error(chalk.red('max-lux must be a positive number OR a map string like "2700:8000,5600:10000"')); process.exit(1); } } // Handle weather option if (options.weather !== undefined) { const value = options.weather; if (typeof value === 'boolean') { config.weather = value; } else { try { config.weather = parseBooleanString(value, 'weather'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } } changes.push(`Default weather enabled: ${config.weather ? 'enabled' : 'disabled'}`); } // Ensure logical ordering if both sides provided if (config.cctMin !== undefined && config.cctMax !== undefined && config.cctMin !== null && config.cctMax !== null && config.cctMin > config.cctMax) { console.error(chalk.red('cct-min must be <= cct-max')); process.exit(1); } if (config.intensityMin !== undefined && config.intensityMin !== null && config.intensityMax !== undefined && config.intensityMax !== null && config.intensityMin > config.intensityMax) { console.error(chalk.red('intensity-min must be <= intensity-max')); process.exit(1); } if (typeof saveConfig === 'function') { saveConfig(config, changes); } else { throw new Error('saveConfig dependency is required'); } }; } //# sourceMappingURL=config.js.map