UNPKG

amaran-light-cli

Version:

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

111 lines 5.08 kB
import chalk from 'chalk'; import { parseStrictNumber } from '../parseUtils.js'; export function registerWeather(program, deps) { const { asyncCommand } = deps; program .command('weather') .description('Get current weather for location and its effect on lighting') .option('-y, --lat <latitude>', 'Manual latitude (-90 to 90)') .option('-x, --lon <longitude>', 'Manual longitude (-180 to 180)') .option('-i, --ip <ip>', 'Override IP address for geoip lookup') .option('--privacy-off', 'Show full IP address and precise coordinates', false) .option('-d, --debug', 'Enable debug mode') .action(asyncCommand(handleWeather(deps))); } function handleWeather(deps) { const { loadConfig } = deps; return async (options) => { const { privacyOff } = options; const { getLocationFromIP } = await import('../../daylightSimulation/geoipUtil.js'); const { getWeatherData } = await import('../../daylightSimulation/weatherUtil.js'); const { formatLocation } = await import('../../daylightSimulation/privacyUtil.js'); let lat; let lon; let source = ''; // 1. Check CLI options if (options.lat !== undefined && options.lon !== undefined) { try { lat = parseStrictNumber(options.lat, 'Latitude'); lon = parseStrictNumber(options.lon, 'Longitude'); } catch (error) { console.error(chalk.red(error.message)); process.exit(1); } if (lat < -90 || lat > 90) { console.error(chalk.red('Latitude must be between -90 and 90')); process.exit(1); } if (lon < -180 || lon > 180) { console.error(chalk.red('Longitude must be between -180 and 180')); process.exit(1); } source = 'manual'; } // 2. Check config else if (loadConfig) { const config = loadConfig(); if (typeof config?.latitude === 'number' && typeof config?.longitude === 'number') { lat = config.latitude; lon = config.longitude; source = 'config'; } } // 3. Check GeoIP if (lat === undefined || lon === undefined) { let ip = options.ip; if (!ip) { try { const res = await fetch('https://api.ipify.org?format=json'); const data = await res.json(); ip = data.ip; } catch (_err) { ip = '127.0.0.1'; } } const location = getLocationFromIP(ip); if (location?.ll) { [lat, lon] = location.ll; source = `geoip (${ip})`; } } if (lat === undefined || lon === undefined) { console.error(chalk.red('Could not determine location. Use --lat and --lon or configure defaults.')); process.exit(1); } const weather = await getWeatherData(lat, lon, new Date(), options.debug); const description = weather.description || weather.raw?.current_condition?.[0].weatherDesc?.[0]?.value; console.log(chalk.blue(`Weather for ${formatLocation(lat, lon, source, privacyOff)}`)); if (description || weather.temp_C) { const tempC = weather.temp_C || weather.raw?.current_condition?.[0].temp_C; console.log(chalk.gray(` Current: ${description || 'Unknown'}, ${tempC || '?'}°C`)); } const now = new Date(); console.log(chalk.gray(` Current Time: ${now.toLocaleTimeString()}`)); const sourceDesc = weather.source === 'api' ? 'wttr.in API (Current Condition)' : weather.source === 'forecast' ? 'Hourly Forecast (Cache)' : 'Cache (Current Condition)'; console.log(chalk.gray(` Source: ${sourceDesc}`)); if (weather.effectiveTime) { const timeInfo = [weather.effectiveTime]; if (weather.dataTimestamp) { const diffMs = now.getTime() - weather.dataTimestamp; const diffMins = Math.round(Math.abs(diffMs) / 60000); const relativeStr = diffMs >= 0 ? `${diffMins}m ago` : `in ${diffMins}m`; timeInfo.push(`(${relativeStr})`); } console.log(chalk.gray(` Weather Time: ${timeInfo.join(' ')}`)); } console.log(chalk.blue(' Lighting Parameters:')); console.log(chalk.gray(` Cloud Cover: ${Math.round((weather.cloudCover ?? 0) * 100)}%`)); console.log(chalk.gray(` Precipitation: ${weather.precipitation ?? 'none'}`)); if (options.debug && weather.raw) { console.log(chalk.gray(' Full data:'), JSON.stringify(weather.raw.current_condition[0], null, 2)); } }; } export default registerWeather; //# sourceMappingURL=weather.js.map