Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/seven-crabs-enter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ecoflow-api/rest-client": minor
"@ecoflow-api/schemas": minor
"examples": minor
---

add getProperty method on the device to query for a specific property value
4 changes: 2 additions & 2 deletions packages/rest-client/src/__fixtures__/delta2Properties.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const propertiesFixture = {
code: "0",
message: "Success",
code: "0" as const,
message: "Success" as const,
data: {
"mppt.faultCode": 0,
"bms_emsStatus.maxChargeSoc": 80,
Expand Down
4 changes: 2 additions & 2 deletions packages/rest-client/src/__fixtures__/deltaProProperties.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const propertiesFixture = {
code: "0",
message: "Success",
code: "0" as const,
message: "Success" as const,
data: {
"pd.iconWifiMode": 0,
"mppt.faultCode": 0,
Expand Down
4 changes: 2 additions & 2 deletions packages/rest-client/src/__fixtures__/glacierProperties.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Note: This is a dummy data created based on the documents, it's not taken from a real device
// Maybe someone can provide the real data for this device.
export const glacierProperties = {
code: "0",
message: "Success",
code: "0" as const,
message: "Success" as const,
data: {
"bms_bmsStatus.amp": 20,
"bms_bmsStatus.bmsFault": 20,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const propertiesFixture = {
code: "0",
message: "Success",
code: "0" as const,
message: "Success" as const,
data: {
"20_1.pv2Temp": 240,
"20_1.invOutputWatts": 1710,
Expand Down
4 changes: 2 additions & 2 deletions packages/rest-client/src/__fixtures__/shpProperties.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const propertiesFixture = {
code: "0",
message: "Success",
code: "0" as const,
message: "Success" as const,
data: {
"heartbeat.errorCodes": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Expand Down
4 changes: 2 additions & 2 deletions packages/rest-client/src/__fixtures__/smartPlugProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ export const smartPlugProperties = {
};

export const devicePropertiesResponse = {
code: "0",
message: "success",
code: "0" as const,
message: "Success" as const,
data: smartPlugProperties,
};
22 changes: 14 additions & 8 deletions packages/rest-client/src/lib/devices/Delta2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ describe("Delta2", () => {
restClient = new RestClient(restClientOptions);
delta2 = new Delta2(restClient, validSn);

// @ts-ignore
restClient.setCommandPlain = jest.fn();
restClient.setCommandPlain = jest.fn<RestClient["setCommandPlain"]>();
restClient.getDevicePropertiesPlain = jest
.fn<RestClient["getDevicePropertiesPlain"]>()
.mockResolvedValue(propertiesFixture);
});

it("Should be able to construct an instance of Delta2", () => {
Expand All @@ -35,15 +37,19 @@ describe("Delta2", () => {
});

it("Should return data if api response could be parsed", async () => {
// @ts-ignore
restClient.getDevicePropertiesPlain = jest
.fn()
// @ts-ignore
.mockResolvedValue(propertiesFixture);

await expect(delta2.getProperties()).resolves.toBeDefined();
});

it("returns the requested property", async () => {
await expect(delta2.getProperty("bms_bmsStatus.f32ShowSoc")).resolves.toBe(
propertiesFixture.data["bms_bmsStatus.f32ShowSoc"],
);
});

it("returns undefined for non existing property", async () => {
await expect(delta2.getProperty("foobar")).resolves.toBeUndefined();
});

it("Should throw an error for invalid data received from api", async () => {
await getPropertiesFailsOnInvalidResponse(restClient, delta2);
});
Expand Down
22 changes: 14 additions & 8 deletions packages/rest-client/src/lib/devices/DeltaPro.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ describe("Delta Pro", () => {
restClient = new RestClient(restClientOptions);
device = new DeltaPro(restClient, validSn);

// @ts-ignore
restClient.setCommandPlain = jest.fn();
restClient.setCommandPlain = jest.fn<RestClient["setCommandPlain"]>();
restClient.getDevicePropertiesPlain = jest
.fn<RestClient["getDevicePropertiesPlain"]>()
.mockResolvedValue(propertiesFixture);
});

it("Should be able to construct an instance of Delta Pro", () => {
Expand All @@ -39,15 +41,19 @@ describe("Delta Pro", () => {
});

it("Should return data if api response could be parsed", async () => {
// @ts-ignore
restClient.getDevicePropertiesPlain = jest
.fn()
// @ts-ignore
.mockResolvedValue(propertiesFixture);

await expect(device.getProperties()).resolves.toBeDefined();
});

it("returns the requested property", async () => {
await expect(device.getProperty("bmsMaster.soc")).resolves.toBe(
propertiesFixture.data["bmsMaster.soc"],
);
});

it("returns undefined for non existing property", async () => {
await expect(device.getProperty("foobar")).resolves.toBeUndefined();
});

it("should enable xboost", async () => {
const enabled = 1;
const xboost = 1;
Expand Down
10 changes: 10 additions & 0 deletions packages/rest-client/src/lib/devices/Device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,14 @@ export abstract class Device<SerialNumber extends string, ParsedProperties> {
const response = await this.restClient.getDevicePropertiesPlain(this.sn);
return this.parseProperties(response.data);
}

/**
* Retrieves the specified property of a device, if present.
*/
async getProperty<K extends keyof ParsedProperties>(
property: K,
): Promise<ParsedProperties[K] | undefined> {
const response = await this.restClient.getDevicePropertiesPlain(this.sn);
return this.parseProperties(response.data)[property];
}
}
22 changes: 14 additions & 8 deletions packages/rest-client/src/lib/devices/Glacier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ describe("Glacier", () => {
restClient = new RestClient(restClientOptions);
glacier = new Glacier(restClient, validSn);

// @ts-ignore
restClient.setCommandPlain = jest.fn();
restClient.setCommandPlain = jest.fn<RestClient["setCommandPlain"]>();
restClient.getDevicePropertiesPlain = jest
.fn<RestClient["getDevicePropertiesPlain"]>()
.mockResolvedValue(glacierProperties);
});

it("Should be able to construct an instance of Glacier", () => {
Expand All @@ -34,6 +36,16 @@ describe("Glacier", () => {
}).toThrowError("Invalid serial number for Glacier device.");
});

it("returns the requested property", async () => {
await expect(glacier.getProperty("bms_emsStatus.dsgCmd")).resolves.toBe(
glacierProperties.data["bms_emsStatus.dsgCmd"],
);
});

it("returns undefined for non existing property", async () => {
await expect(glacier.getProperty("foobar")).resolves.toBeUndefined();
});

it("should set temperature for right, left and middle zones", async () => {
expect.assertions(1);
await glacier.setTemperature({
Expand Down Expand Up @@ -422,12 +434,6 @@ describe("Glacier", () => {
});

it("Should return data if api response could be parsed", async () => {
// @ts-ignore
restClient.getDevicePropertiesPlain = jest
.fn()
// @ts-ignore
.mockResolvedValue(glacierProperties);

await expect(glacier.getProperties()).resolves.toBeDefined();
});
});
22 changes: 14 additions & 8 deletions packages/rest-client/src/lib/devices/PowerStream.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ describe("PowerStream", () => {
restClient = new RestClient(restClientOptions);
powerStream = new PowerStream(restClient, validSn);

// @ts-ignore
restClient.setCommandPlain = jest.fn();
restClient.setCommandPlain = jest.fn<RestClient["setCommandPlain"]>();
restClient.getDevicePropertiesPlain = jest
.fn<RestClient["getDevicePropertiesPlain"]>()
.mockResolvedValue(propertiesFixture);
});

it("Should be able to construct an instance of PowerStream", () => {
Expand All @@ -34,6 +36,16 @@ describe("PowerStream", () => {
}).toThrowError("Invalid serial number for powerStream device.");
});

it("returns the requested property", async () => {
await expect(powerStream.getProperty("20_1.pv1InputWatts")).resolves.toBe(
propertiesFixture.data["20_1.pv1InputWatts"],
);
});

it("returns undefined for non existing property", async () => {
await expect(powerStream.getProperty("foobar")).resolves.toBeUndefined();
});

it("should set power supply priority", async () => {
expect.assertions(1);
const priority = "powerSupply";
Expand Down Expand Up @@ -164,12 +176,6 @@ describe("PowerStream", () => {
});

it("Should return data if api response could be parsed", async () => {
// @ts-ignore
restClient.getDevicePropertiesPlain = jest
.fn()
// @ts-ignore
.mockResolvedValue(propertiesFixture);

await expect(powerStream.getProperties()).resolves.toBeDefined();
});
});
22 changes: 14 additions & 8 deletions packages/rest-client/src/lib/devices/SmartHomePanel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ describe("SmartHomePanel", () => {
restClient = new RestClient(restClientOptions);
device = new SmartHomePanel(restClient, validSn);

// @ts-ignore
restClient.setCommandPlain = jest.fn();
restClient.setCommandPlain = jest.fn<RestClient["setCommandPlain"]>();
restClient.getDevicePropertiesPlain = jest
.fn<RestClient["getDevicePropertiesPlain"]>()
.mockResolvedValue(propertiesFixture);
});

it("Should be able to construct an instance of SmartHomePanel", () => {
Expand All @@ -39,15 +41,19 @@ describe("SmartHomePanel", () => {
});

it("Should return data if api response could be parsed", async () => {
// @ts-ignore
restClient.getDevicePropertiesPlain = jest
.fn()
// @ts-ignore
.mockResolvedValue(propertiesFixture);

await expect(device.getProperties()).resolves.toBeDefined();
});

it("returns the requested property", async () => {
await expect(device.getProperty("areaInfo.cmdSet")).resolves.toBe(
propertiesFixture.data["areaInfo.cmdSet"],
);
});

it("returns undefined for non existing property", async () => {
await expect(device.getProperty("foobar")).resolves.toBeUndefined();
});

it("should update rtc time", async () => {
const rtcTime = {
sec: 0,
Expand Down
31 changes: 15 additions & 16 deletions packages/rest-client/src/lib/devices/SmartPlug.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ describe("SmartPlug", () => {

restClient = new RestClient(restClientOptions);
smartPlug = new SmartPlug(restClient, validSn);

restClient.setCommandPlain = jest.fn<RestClient["setCommandPlain"]>();
restClient.getDevicePropertiesPlain = jest
.fn<RestClient["getDevicePropertiesPlain"]>()
.mockResolvedValue(devicePropertiesResponse);
});

it("Should be able to construct an instance of SmartPlug", () => {
Expand All @@ -33,8 +38,6 @@ describe("SmartPlug", () => {

it("Should be able to turn the smart plug on", async () => {
expect.assertions(1);
// @ts-ignore
restClient.setCommandPlain = jest.fn();

await smartPlug.switchOn();

Expand All @@ -49,8 +52,6 @@ describe("SmartPlug", () => {
//
it("Should be able to turn the smart plug off", async () => {
expect.assertions(1);
// @ts-ignore
restClient.setCommandPlain = jest.fn();
await smartPlug.switchOff();

expect(restClient.setCommandPlain).toHaveBeenCalledWith({
Expand All @@ -64,8 +65,6 @@ describe("SmartPlug", () => {

it("Should be able to delete Task", async () => {
expect.assertions(1);
// @ts-ignore
restClient.setCommandPlain = jest.fn();
await smartPlug.deleteTask(42);

expect(restClient.setCommandPlain).toHaveBeenCalledWith({
Expand All @@ -82,19 +81,21 @@ describe("SmartPlug", () => {
});

it("Should return data if api response could be parsed", async () => {
// @ts-ignore
restClient.getDevicePropertiesPlain = jest
.fn()
// @ts-ignore
.mockResolvedValue(devicePropertiesResponse);

await expect(smartPlug.getProperties()).resolves.toBeDefined();
});

it("returns the requested property", async () => {
await expect(smartPlug.getProperty("2_1.temp")).resolves.toBe(
devicePropertiesResponse.data["2_1.temp"],
);
});

it("returns undefined for non existing property", async () => {
await expect(smartPlug.getProperty("foobar")).resolves.toBeUndefined();
});

it("should set led brightness", async () => {
expect.assertions(1);
// @ts-ignore
restClient.setCommandPlain = jest.fn();
const brightness = 42;
await smartPlug.setLedBrightness(brightness);

Expand All @@ -109,8 +110,6 @@ describe("SmartPlug", () => {

it("should throw for an invalid brightness value", async () => {
expect.assertions(2);
// @ts-ignore
restClient.setCommandPlain = jest.fn();
await expect(smartPlug.setLedBrightness(5000)).rejects.toThrowError();
await expect(smartPlug.setLedBrightness(-1)).rejects.toThrowError();
});
Expand Down
Loading