import { EcoFlowClient } from '../client.js';
export const getDeviceStatusTool = {
name: 'ecoflow_get_device_status',
description: 'Get comprehensive status for an EcoFlow device including battery level, input/output power, temperatures, and all available metrics.',
inputSchema: {
type: 'object' as const,
properties: {
serial_number: {
type: 'string',
description: 'The device serial number (e.g., R351ZCB5HG123456)'
}
},
required: ['serial_number']
}
};
interface StatusArgs {
serial_number: string;
}
interface ParsedStatus {
battery?: {
level?: number;
capacity?: number;
remainingCapacity?: number;
cycles?: number;
temperature?: number;
health?: number;
};
power?: {
inputWatts?: number;
outputWatts?: number;
solarInputWatts?: number;
acInputWatts?: number;
};
outputs?: {
acEnabled?: boolean;
dcEnabled?: boolean;
usbEnabled?: boolean;
};
charging?: {
isCharging?: boolean;
remainingTime?: number;
maxChargeSoc?: number;
minDischargeSoc?: number;
};
raw?: Record<string, unknown>;
}
function parseDeviceStatus(quota: Record<string, unknown>): ParsedStatus {
const status: ParsedStatus = {
battery: {},
power: {},
outputs: {},
charging: {},
raw: quota
};
// Common quota keys across different EcoFlow devices
// Battery info
if (quota['bms_bmsStatus.soc'] !== undefined) {
status.battery!.level = quota['bms_bmsStatus.soc'] as number;
} else if (quota['pd.soc'] !== undefined) {
status.battery!.level = quota['pd.soc'] as number;
} else if (quota['soc'] !== undefined) {
status.battery!.level = quota['soc'] as number;
}
if (quota['bms_bmsStatus.designCap'] !== undefined) {
status.battery!.capacity = quota['bms_bmsStatus.designCap'] as number;
}
if (quota['bms_bmsStatus.remainCap'] !== undefined) {
status.battery!.remainingCapacity = quota['bms_bmsStatus.remainCap'] as number;
}
if (quota['bms_bmsStatus.cycles'] !== undefined) {
status.battery!.cycles = quota['bms_bmsStatus.cycles'] as number;
}
if (quota['bms_bmsStatus.temp'] !== undefined) {
status.battery!.temperature = quota['bms_bmsStatus.temp'] as number;
}
if (quota['bms_bmsStatus.soh'] !== undefined) {
status.battery!.health = quota['bms_bmsStatus.soh'] as number;
}
// Power info
if (quota['pd.wattsInSum'] !== undefined) {
status.power!.inputWatts = quota['pd.wattsInSum'] as number;
} else if (quota['inv.inputWatts'] !== undefined) {
status.power!.inputWatts = quota['inv.inputWatts'] as number;
}
if (quota['pd.wattsOutSum'] !== undefined) {
status.power!.outputWatts = quota['pd.wattsOutSum'] as number;
} else if (quota['inv.outputWatts'] !== undefined) {
status.power!.outputWatts = quota['inv.outputWatts'] as number;
}
// Solar input
if (quota['mppt.inWatts'] !== undefined) {
status.power!.solarInputWatts = quota['mppt.inWatts'] as number;
} else if (quota['pd.pv1InputWatts'] !== undefined) {
const pv1 = (quota['pd.pv1InputWatts'] as number) || 0;
const pv2 = (quota['pd.pv2InputWatts'] as number) || 0;
status.power!.solarInputWatts = pv1 + pv2;
}
// AC input
if (quota['inv.acInWatts'] !== undefined) {
status.power!.acInputWatts = quota['inv.acInWatts'] as number;
}
// Output states
if (quota['inv.cfgAcEnabled'] !== undefined) {
status.outputs!.acEnabled = (quota['inv.cfgAcEnabled'] as number) === 1;
} else if (quota['pd.acEnabled'] !== undefined) {
status.outputs!.acEnabled = (quota['pd.acEnabled'] as number) === 1;
}
if (quota['pd.dcOutState'] !== undefined) {
status.outputs!.dcEnabled = (quota['pd.dcOutState'] as number) === 1;
} else if (quota['mppt.dcChgCurrent'] !== undefined) {
status.outputs!.dcEnabled = (quota['mppt.dcChgCurrent'] as number) > 0;
}
if (quota['pd.usb1Watts'] !== undefined || quota['pd.usb2Watts'] !== undefined) {
const usb1 = (quota['pd.usb1Watts'] as number) || 0;
const usb2 = (quota['pd.usb2Watts'] as number) || 0;
status.outputs!.usbEnabled = usb1 > 0 || usb2 > 0;
}
// Charging info
if (quota['pd.chgState'] !== undefined) {
status.charging!.isCharging = (quota['pd.chgState'] as number) === 1;
}
if (quota['pd.remainTime'] !== undefined) {
status.charging!.remainingTime = quota['pd.remainTime'] as number;
}
if (quota['pd.maxChgSoc'] !== undefined) {
status.charging!.maxChargeSoc = quota['pd.maxChgSoc'] as number;
}
if (quota['pd.minDsgSoc'] !== undefined) {
status.charging!.minDischargeSoc = quota['pd.minDsgSoc'] as number;
}
return status;
}
export async function executeGetDeviceStatus(
client: EcoFlowClient,
args: StatusArgs
): Promise<string> {
try {
const quota = await client.getDeviceQuotaAll(args.serial_number);
const status = parseDeviceStatus(quota);
// Create a cleaner output without empty objects
const output: Record<string, unknown> = {
serialNumber: args.serial_number
};
if (Object.keys(status.battery || {}).length > 0) {
output.battery = status.battery;
}
if (Object.keys(status.power || {}).length > 0) {
output.power = status.power;
}
if (Object.keys(status.outputs || {}).length > 0) {
output.outputs = status.outputs;
}
if (Object.keys(status.charging || {}).length > 0) {
output.charging = status.charging;
}
// Include raw data count for reference
output.rawDataFields = Object.keys(quota).length;
return JSON.stringify(output, null, 2);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to get device status: ${message}`);
}
}