meross
Version:
A command-line tool for configuring and managing Meross smart home devices.
66 lines (65 loc) • 3.18 kB
JavaScript
;
import pkg from '../package.json' with { type: 'json' };
import { program } from 'commander';
import TerminalKit from 'terminal-kit';
const { terminal } = TerminalKit;
import { printDeviceTable, printWifiListTable, progressFunctionWithMessage } from './cli.js';
import { HTTPTransport, Device, computeDevicePassword, Namespace, computePresharedPrivateKey, generateKeyPair } from '@meross/lib';
program
.version(pkg.version)
.arguments('[options]')
.option('-a, --ip <ip>', 'Send command to device with this IP address', '10.10.10.1')
.option('-u, --user <user-id>', 'Integer id. Used by devices connected to the Meross Cloud', parseInt, 0)
.option('-k, --key <shared-key>', 'Shared key for generating signatures', 'meross')
.option('--private-key [private-key]', `Private key for ECDH key exchange. If not provided a new one will be generated`)
.option('--with-wifi', 'List WIFI Access Points near the device')
.option('--with-ability', 'List device ability list')
.option('-q, --quiet', 'Suppress all output', false)
.parse(process.argv);
const options = program.opts();
const { ip, user: userId, key } = options;
const { quiet } = options;
try {
const transport = new HTTPTransport({ url: `http://${ip}/config`, credentials: { userId, key } });
const device = new Device();
device.setTransport(transport);
const deviceInformation = await device.fetchDeviceInfo();
const devicePassword = computeDevicePassword(deviceInformation.system.hardware.macAddress, key, deviceInformation.system.firmware.userId);
const { withAbility = false } = options;
let deviceAbility = await device.fetchDeviceAbilities();
if (!quiet) {
await printDeviceTable(deviceInformation, withAbility ? deviceAbility : undefined, devicePassword);
}
// check if we neet to exchange public keys
if (device.hasAbility(Namespace.ENCRYPT_ECDHE) && !device.encryptionKeys.sharedKey) {
let { privateKey } = options;
if (privateKey === true) {
const { privateKey: generatedPrivateKey } = await generateKeyPair();
privateKey = generatedPrivateKey.toString('base64');
}
if (!privateKey) {
// use precomputed private key
privateKey = computePresharedPrivateKey(device.id, key, device.hardware.macAddress);
}
await device.setPrivateKey(Buffer.from(privateKey, 'base64'));
const exchangeKeys = () => device.exchangeKeys();
await (quiet ? exchangeKeys() : progressFunctionWithMessage(exchangeKeys, 'Exchanging public keys'));
}
const { withWifi = false } = options;
if (withWifi) {
const fetchNearbyWifi = () => device.fetchNearbyWifi();
const wifiList = await (quiet ? fetchNearbyWifi() : progressFunctionWithMessage(() => fetchNearbyWifi(), 'Getting WIFI list'));
if (!quiet && wifiList) {
await printWifiListTable(wifiList);
}
}
}
catch (error) {
terminal.red(`${error.message}\n`);
if (process.env.LOG_LEVEL) {
terminal.red('Error stack:\n');
terminal.red(error.stack);
}
process.exit(1);
}