From 8b5299d1fbfc134d7f71af9ba7038ea26883151d Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Fri, 6 Dec 2024 11:06:33 +0100 Subject: [PATCH] :sparkles: Set target temperature Support setting the target temperature (degree celsius) of a device. Also add setTargetTemperature and setPower commands to the CLI. --- src/cli.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 1 + src/library.test.ts | 47 ++++++++++++++++++++++++++++++++++++++++ src/library.ts | 20 ++++++++++++++++- 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index 108cc83..3367dba 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -67,6 +67,29 @@ const executeGetter = async ( console.log(result); }; +/** + * Executes a setter command by handling common steps (authentication, API initialization). + * @param options The options passed from the CLI command. + * @param setter A function to call on the configured API object. + */ +const executeSetter = async ( + options: { username: string; password?: string; mac: string; value: number }, + setter: ( + api: ReturnType, + jwtToken: string, + mac: string, + value: number + ) => Promise +): Promise => { + const { username, password, mac, value } = options; + const normalizedMac = mac.replace(/:/g, ""); + const pwd = password || (await promptPassword()); + const jwtToken = await signIn(username, pwd); + const api = configure(); + const result = await setter(api, jwtToken, normalizedMac, value); + console.log(result); +}; + const createProgram = (): Command => { const program = new Command(); program @@ -125,6 +148,35 @@ const createProgram = (): Command => { addAuthOptions(program.command(commandName).description(description)) ).action((options) => executeGetter(options, getter)); }); + // Generic setter commands + [ + { + commandName: "setPower", + description: "Set the power state of the device (1 for ON, 0 for OFF)", + setter: ( + api: ReturnType, + jwtToken: string, + mac: string, + value: number + ) => api.setPower(jwtToken, mac, value), + }, + { + commandName: "setTargetTemperature", + description: "Set the target temperature (degree celsius) for a device", + setter: ( + api: ReturnType, + jwtToken: string, + mac: string, + value: number + ) => api.setTargetTemperature(jwtToken, mac, value), + }, + ].forEach(({ commandName, description, setter }) => { + addMacOption( + addAuthOptions( + program.command(commandName).description(description) + ).requiredOption("-v, --value ", "Value to set", parseFloat) + ).action((options) => executeSetter(options, setter)); + }); return program; }; diff --git a/src/index.ts b/src/index.ts index 1b7c23e..144d93f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,4 +18,5 @@ export const { getPower, getEnvironmentTemperature, getTargetTemperature, + setTargetTemperature, } = configure(); diff --git a/src/library.test.ts b/src/library.test.ts index 12b56a5..54396ca 100644 --- a/src/library.test.ts +++ b/src/library.test.ts @@ -86,6 +86,7 @@ describe("library", () => { "getPower", "getEnvironmentTemperature", "getTargetTemperature", + "setTargetTemperature", ]; it("should create API methods with the correct baseURL", () => { const baseURL = "https://example.com/api"; @@ -225,5 +226,51 @@ describe("library", () => { assert.equal(result, expectedResult); }); }); + // Setter tests + const setterTests = [ + { + method: "setTargetTemperature", + call: ( + api: ReturnType, + token: string, + mac: string, + value: number + ) => api.setTargetTemperature(token, mac, value), + payload: { + name: "enviroment_1_temperature", + value: 20, + }, + }, + ]; + setterTests.forEach(({ method, call, payload }) => { + it(`should call axios and send the correct payload for ${method}`, async () => { + const mockAxios = { + put: sinon.stub().resolves({ status: 200 }), + }; + axiosStub.returns(mockAxios); + const api = configure("https://example.com/api"); + + const result = await call( + api, + expectedToken, + "mockMacAddress", + payload.value + ); + + assert.deepEqual(mockAxios.put.args, [ + [ + "mqtt/command", + { + mac_address: "mockMacAddress", + ...payload, + }, + { + headers: { Authorization: `Bearer ${expectedToken}` }, + }, + ], + ]); + assert.equal(result.status, 200); + }); + }); }); }); diff --git a/src/library.ts b/src/library.ts index a1272e2..8d73603 100644 --- a/src/library.ts +++ b/src/library.ts @@ -169,13 +169,29 @@ const getTargetTemperature = * * @param {string} jwtToken - The JWT token for authentication. * @param {string} macAddress - The MAC address of the device. - * @returns {Promise} - A promise that resolves to the target temperature. + * @returns {Promise} - A promise that resolves to the target temperature (degree celsius). */ async (jwtToken: string, macAddress: string): Promise => { const info = await deviceInfo(axiosInstance)(jwtToken, macAddress); return info.nvm.user_parameters.enviroment_1_temperature; }; +const setTargetTemperature = + (axiosInstance: AxiosInstance) => + /** + * Sends a command to set the target temperature (degree celsius) of a device. + * + * @param {string} jwtToken - The JWT token for authentication. + * @param {string} macAddress - The MAC address of the device. + * @param {number} temperature - The desired target temperature (degree celsius). + * @returns {Promise} - A promise that resolves to the command response. + */ + (jwtToken: string, macAddress: string, temperature: number) => + mqttCommand(axiosInstance)(jwtToken, macAddress, { + name: "enviroment_1_temperature", + value: temperature, + }); + /** * Configures the library for API interactions. * Initializes API methods with a specified base URL. @@ -197,6 +213,7 @@ const configure = (baseURL: string = API_URL) => { const getEnvironmentTemperatureInstance = getEnvironmentTemperature(axiosInstance); const getTargetTemperatureInstance = getTargetTemperature(axiosInstance); + const setTargetTemperatureInstance = setTargetTemperature(axiosInstance); return { deviceInfo: deviceInfoInstance, setPower: setPowerInstance, @@ -205,6 +222,7 @@ const configure = (baseURL: string = API_URL) => { getPower: getPowerInstance, getEnvironmentTemperature: getEnvironmentTemperatureInstance, getTargetTemperature: getTargetTemperatureInstance, + setTargetTemperature: setTargetTemperatureInstance, }; };