edilkamin 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/cli.js CHANGED
@@ -39,9 +39,48 @@ const promptPassword = () => {
39
39
  * @param command The command to which options should be added.
40
40
  * @returns The command with options added.
41
41
  */
42
- const addCommonOptions = (command) => command
42
+ const addAuthOptions = (command) => command
43
43
  .requiredOption("-u, --username <username>", "Username")
44
44
  .option("-p, --password <password>", "Password");
45
+ /**
46
+ * Adds MAC address option to a command.
47
+ * @param command The command to which the MAC address option should be added.
48
+ * @returns The command with the MAC address option added.
49
+ */
50
+ const addMacOption = (command) => command.requiredOption("-m, --mac <macAddress>", "MAC address of the device");
51
+ /**
52
+ * Handles common authentication and API initialization logic.
53
+ * @param options The options passed from the CLI command.
54
+ * @returns An object containing the normalized MAC, JWT token, and configured API instance.
55
+ */
56
+ const initializeCommand = (options) => __awaiter(void 0, void 0, void 0, function* () {
57
+ const { username, password, mac } = options;
58
+ const normalizedMac = mac.replace(/:/g, "");
59
+ const pwd = password || (yield promptPassword());
60
+ const jwtToken = yield signIn(username, pwd);
61
+ const api = configure();
62
+ return { normalizedMac, jwtToken, api };
63
+ });
64
+ /**
65
+ * Executes a getter command by handling common steps (authentication, API initialization).
66
+ * @param options The options passed from the CLI command.
67
+ * @param getter A function to call on the configured API object.
68
+ */
69
+ const executeGetter = (options, getter) => __awaiter(void 0, void 0, void 0, function* () {
70
+ const { normalizedMac, jwtToken, api } = yield initializeCommand(options);
71
+ const result = yield getter(api, jwtToken, normalizedMac);
72
+ console.log(result);
73
+ });
74
+ /**
75
+ * Executes a setter command by handling common steps (authentication, API initialization).
76
+ * @param options The options passed from the CLI command.
77
+ * @param setter A function to call on the configured API object.
78
+ */
79
+ const executeSetter = (options, setter) => __awaiter(void 0, void 0, void 0, function* () {
80
+ const { normalizedMac, jwtToken, api } = yield initializeCommand(options);
81
+ const result = yield setter(api, jwtToken, normalizedMac, options.value);
82
+ console.log(result);
83
+ });
45
84
  const createProgram = () => {
46
85
  const program = new Command();
47
86
  program
@@ -49,25 +88,52 @@ const createProgram = () => {
49
88
  .description("CLI tool for interacting with the Edilkamin API")
50
89
  .version(version);
51
90
  // Command: signIn
52
- addCommonOptions(program.command("signIn").description("Sign in and retrieve a JWT token")).action((options) => __awaiter(void 0, void 0, void 0, function* () {
91
+ addAuthOptions(program.command("signIn").description("Sign in and retrieve a JWT token")).action((options) => __awaiter(void 0, void 0, void 0, function* () {
53
92
  const { username, password } = options;
54
93
  const pwd = password || (yield promptPassword());
55
94
  const jwtToken = yield signIn(username, pwd);
56
95
  console.log("JWT Token:", jwtToken);
57
96
  }));
58
- // Command: deviceInfo
59
- addCommonOptions(program
60
- .command("deviceInfo")
61
- .description("Retrieve device info for a specific MAC address")
62
- .requiredOption("-m, --mac <macAddress>", "MAC address of the device")).action((options) => __awaiter(void 0, void 0, void 0, function* () {
63
- const { username, password, mac } = options;
64
- const normalizedMac = mac.replace(/:/g, "");
65
- const pwd = password || (yield promptPassword());
66
- const jwtToken = yield signIn(username, pwd);
67
- const api = configure(); // Use the default API configuration
68
- const deviceInfo = yield api.deviceInfo(jwtToken, normalizedMac);
69
- console.log("Device Info:", deviceInfo.data);
70
- }));
97
+ // Generic getter commands
98
+ [
99
+ {
100
+ commandName: "deviceInfo",
101
+ description: "Retrieve device info for a specific MAC address",
102
+ getter: (api, jwtToken, mac) => api.deviceInfo(jwtToken, mac),
103
+ },
104
+ {
105
+ commandName: "getPower",
106
+ description: "Retrieve device power status",
107
+ getter: (api, jwtToken, mac) => api.getPower(jwtToken, mac),
108
+ },
109
+ {
110
+ commandName: "getEnvironmentTemperature",
111
+ description: "Retrieve environment temperature",
112
+ getter: (api, jwtToken, mac) => api.getEnvironmentTemperature(jwtToken, mac),
113
+ },
114
+ {
115
+ commandName: "getTargetTemperature",
116
+ description: "Retrieve target temperature",
117
+ getter: (api, jwtToken, mac) => api.getTargetTemperature(jwtToken, mac),
118
+ },
119
+ ].forEach(({ commandName, description, getter }) => {
120
+ addMacOption(addAuthOptions(program.command(commandName).description(description))).action((options) => executeGetter(options, getter));
121
+ });
122
+ // Generic setter commands
123
+ [
124
+ {
125
+ commandName: "setPower",
126
+ description: "Set the power state of the device (1 for ON, 0 for OFF)",
127
+ setter: (api, jwtToken, mac, value) => api.setPower(jwtToken, mac, value),
128
+ },
129
+ {
130
+ commandName: "setTargetTemperature",
131
+ description: "Set the target temperature (degree celsius) for a device",
132
+ setter: (api, jwtToken, mac, value) => api.setTargetTemperature(jwtToken, mac, value),
133
+ },
134
+ ].forEach(({ commandName, description, setter }) => {
135
+ addMacOption(addAuthOptions(program.command(commandName).description(description)).requiredOption("-v, --value <number>", "Value to set", parseFloat)).action((options) => executeSetter(options, setter));
136
+ });
71
137
  return program;
72
138
  };
73
139
  const main = () => {
@@ -1,4 +1,4 @@
1
1
  export { API_URL } from "./constants";
2
2
  export { configure, signIn } from "./library";
3
3
  export { CommandsType, DeviceInfoType, StatusType, TemperaturesType, UserParametersType, } from "./types";
4
- export declare const deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<import("./types").DeviceInfoType, any>>, setPower: (jwtToken: string, macAddress: string, value: number) => Promise<import("axios").AxiosResponse<any, any>>, setPowerOff: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>, setPowerOn: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
4
+ export declare const deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("./types").DeviceInfoType>, setPower: (jwtToken: string, macAddress: string, value: number) => Promise<import("axios").AxiosResponse<any, any>>, setPowerOff: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>, setPowerOn: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>, getPower: (jwtToken: string, macAddress: string) => Promise<boolean>, getEnvironmentTemperature: (jwtToken: string, macAddress: string) => Promise<number>, getTargetTemperature: (jwtToken: string, macAddress: string) => Promise<number>, setTargetTemperature: (jwtToken: string, macAddress: string, temperature: number) => Promise<import("axios").AxiosResponse<any, any>>;
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { configure } from "./library";
2
2
  export { API_URL } from "./constants";
3
3
  export { configure, signIn } from "./library";
4
- export const { deviceInfo, setPower, setPowerOff, setPowerOn } = configure();
4
+ export const { deviceInfo, setPower, setPowerOff, setPowerOn, getPower, getEnvironmentTemperature, getTargetTemperature, setTargetTemperature, } = configure();
@@ -17,10 +17,25 @@ declare const createAuthService: (auth: typeof amplifyAuth) => {
17
17
  signIn: (username: string, password: string) => Promise<string>;
18
18
  };
19
19
  declare const signIn: (username: string, password: string) => Promise<string>;
20
+ /**
21
+ * Configures the library for API interactions.
22
+ * Initializes API methods with a specified base URL.
23
+ *
24
+ * @param {string} [baseURL=API_URL] - The base URL for the API.
25
+ * @returns {object} - An object containing methods for interacting with the API.
26
+ *
27
+ * @example
28
+ * const api = configure();
29
+ * const power = await api.getPower(jwtToken, macAddress);
30
+ */
20
31
  declare const configure: (baseURL?: string) => {
21
- deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<DeviceInfoType, any>>;
32
+ deviceInfo: (jwtToken: string, macAddress: string) => Promise<DeviceInfoType>;
22
33
  setPower: (jwtToken: string, macAddress: string, value: number) => Promise<import("axios").AxiosResponse<any, any>>;
23
34
  setPowerOff: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
24
35
  setPowerOn: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
36
+ getPower: (jwtToken: string, macAddress: string) => Promise<boolean>;
37
+ getEnvironmentTemperature: (jwtToken: string, macAddress: string) => Promise<number>;
38
+ getTargetTemperature: (jwtToken: string, macAddress: string) => Promise<number>;
39
+ setTargetTemperature: (jwtToken: string, macAddress: string, temperature: number) => Promise<import("axios").AxiosResponse<any, any>>;
25
40
  };
26
41
  export { configure, createAuthService, headers, signIn };
@@ -59,26 +59,138 @@ const createAuthService = (auth) => {
59
59
  };
60
60
  // Create the default auth service using amplifyAuth
61
61
  const { signIn } = createAuthService(amplifyAuth);
62
- const deviceInfo = (axiosInstance) => (jwtToken, macAddress) => axiosInstance.get(`device/${macAddress}/info`, {
63
- headers: headers(jwtToken),
62
+ const deviceInfo = (axiosInstance) =>
63
+ /**
64
+ * Retrieves information about a device by its MAC address.
65
+ *
66
+ * @param {string} jwtToken - The JWT token for authentication.
67
+ * @param {string} macAddress - The MAC address of the device.
68
+ * @returns {Promise<DeviceInfoType>} - A promise that resolves to the device info.
69
+ */
70
+ (jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
71
+ const response = yield axiosInstance.get(`device/${macAddress}/info`, {
72
+ headers: headers(jwtToken),
73
+ });
74
+ return response.data;
64
75
  });
65
76
  const mqttCommand = (axiosInstance) =>
66
77
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
78
  (jwtToken, macAddress, payload) => axiosInstance.put("mqtt/command", Object.assign({ mac_address: macAddress }, payload), { headers: headers(jwtToken) });
68
- const setPower = (axiosInstance) => (jwtToken, macAddress, value) => mqttCommand(axiosInstance)(jwtToken, macAddress, { name: "power", value });
69
- const setPowerOn = (axiosInstance) => (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 1);
70
- const setPowerOff = (axiosInstance) => (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 0);
79
+ const setPower = (axiosInstance) =>
80
+ /**
81
+ * Sends a command to set the power state of a device.
82
+ *
83
+ * @param {string} jwtToken - The JWT token for authentication.
84
+ * @param {string} macAddress - The MAC address of the device.
85
+ * @param {number} value - The desired power state (1 for ON, 0 for OFF).
86
+ * @returns {Promise<string>} - A promise that resolves to the command response.
87
+ */
88
+ (jwtToken, macAddress, value) => mqttCommand(axiosInstance)(jwtToken, macAddress, { name: "power", value });
89
+ const setPowerOn = (axiosInstance) =>
90
+ /**
91
+ * Turns a device ON by setting its power state.
92
+ *
93
+ * @param {string} jwtToken - The JWT token for authentication.
94
+ * @param {string} macAddress - The MAC address of the device.
95
+ * @returns {Promise<string>} - A promise that resolves to the command response.
96
+ *
97
+ * @example
98
+ * const response = await api.setPowerOn(jwtToken, macAddress);
99
+ * console.log(response);
100
+ */
101
+ (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 1);
102
+ const setPowerOff = (axiosInstance) =>
103
+ /**
104
+ * Turns a device OFF by setting its power state.
105
+ *
106
+ * @param {string} jwtToken - The JWT token for authentication.
107
+ * @param {string} macAddress - The MAC address of the device.
108
+ * @returns {Promise<string>} - A promise that resolves to the command response.
109
+ *
110
+ * @example
111
+ * const response = await api.setPowerOff(jwtToken, macAddress);
112
+ * console.log(response);
113
+ */
114
+ (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 0);
115
+ const getPower = (axiosInstance) =>
116
+ /**
117
+ * Retrieves the power status of the device.
118
+ *
119
+ * @param {string} jwtToken - The JWT token for authentication.
120
+ * @param {string} macAddress - The MAC address of the device.
121
+ * @returns {Promise<boolean>} - A promise that resolves to the power status.
122
+ */
123
+ (jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
124
+ const info = yield deviceInfo(axiosInstance)(jwtToken, macAddress);
125
+ return info.status.commands.power;
126
+ });
127
+ const getEnvironmentTemperature = (axiosInstance) =>
128
+ /**
129
+ * Retrieves the environment temperature from the device's sensors.
130
+ *
131
+ * @param {string} jwtToken - The JWT token for authentication.
132
+ * @param {string} macAddress - The MAC address of the device.
133
+ * @returns {Promise<number>} - A promise that resolves to the temperature value.
134
+ */
135
+ (jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
136
+ const info = yield deviceInfo(axiosInstance)(jwtToken, macAddress);
137
+ return info.status.temperatures.enviroment;
138
+ });
139
+ const getTargetTemperature = (axiosInstance) =>
140
+ /**
141
+ * Retrieves the target temperature value set on the device.
142
+ *
143
+ * @param {string} jwtToken - The JWT token for authentication.
144
+ * @param {string} macAddress - The MAC address of the device.
145
+ * @returns {Promise<number>} - A promise that resolves to the target temperature (degree celsius).
146
+ */
147
+ (jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
148
+ const info = yield deviceInfo(axiosInstance)(jwtToken, macAddress);
149
+ return info.nvm.user_parameters.enviroment_1_temperature;
150
+ });
151
+ const setTargetTemperature = (axiosInstance) =>
152
+ /**
153
+ * Sends a command to set the target temperature (degree celsius) of a device.
154
+ *
155
+ * @param {string} jwtToken - The JWT token for authentication.
156
+ * @param {string} macAddress - The MAC address of the device.
157
+ * @param {number} temperature - The desired target temperature (degree celsius).
158
+ * @returns {Promise<string>} - A promise that resolves to the command response.
159
+ */
160
+ (jwtToken, macAddress, temperature) => mqttCommand(axiosInstance)(jwtToken, macAddress, {
161
+ name: "enviroment_1_temperature",
162
+ value: temperature,
163
+ });
164
+ /**
165
+ * Configures the library for API interactions.
166
+ * Initializes API methods with a specified base URL.
167
+ *
168
+ * @param {string} [baseURL=API_URL] - The base URL for the API.
169
+ * @returns {object} - An object containing methods for interacting with the API.
170
+ *
171
+ * @example
172
+ * const api = configure();
173
+ * const power = await api.getPower(jwtToken, macAddress);
174
+ */
71
175
  const configure = (baseURL = API_URL) => {
72
176
  const axiosInstance = axios.create({ baseURL });
73
177
  const deviceInfoInstance = deviceInfo(axiosInstance);
74
178
  const setPowerInstance = setPower(axiosInstance);
75
179
  const setPowerOffInstance = setPowerOff(axiosInstance);
76
180
  const setPowerOnInstance = setPowerOn(axiosInstance);
181
+ const getPowerInstance = getPower(axiosInstance);
182
+ const getEnvironmentTemperatureInstance = getEnvironmentTemperature(axiosInstance);
183
+ const getTargetTemperatureInstance = getTargetTemperature(axiosInstance);
184
+ const setTargetTemperatureInstance = setTargetTemperature(axiosInstance);
77
185
  return {
78
186
  deviceInfo: deviceInfoInstance,
79
187
  setPower: setPowerInstance,
80
188
  setPowerOff: setPowerOffInstance,
81
189
  setPowerOn: setPowerOnInstance,
190
+ getPower: getPowerInstance,
191
+ getEnvironmentTemperature: getEnvironmentTemperatureInstance,
192
+ getTargetTemperature: getTargetTemperatureInstance,
193
+ setTargetTemperature: setTargetTemperatureInstance,
82
194
  };
83
195
  };
84
196
  export { configure, createAuthService, headers, signIn };
@@ -14,6 +14,7 @@ import { configure, createAuthService } from "../src/library";
14
14
  import { API_URL } from "./constants";
15
15
  describe("library", () => {
16
16
  let axiosStub;
17
+ const expectedToken = "mockJwtToken";
17
18
  beforeEach(() => {
18
19
  axiosStub = sinon.stub(axios, "create").returns({
19
20
  get: sinon.stub(),
@@ -28,7 +29,6 @@ describe("library", () => {
28
29
  it("should sign in and return the JWT token", () => __awaiter(void 0, void 0, void 0, function* () {
29
30
  const expectedUsername = "testuser";
30
31
  const expectedPassword = "testpassword";
31
- const expectedToken = "mockJwtToken";
32
32
  const signIn = sinon.stub().resolves({ isSignedIn: true });
33
33
  const signOut = sinon.stub();
34
34
  const fetchAuthSession = sinon.stub().resolves({
@@ -53,7 +53,6 @@ describe("library", () => {
53
53
  it("should throw an error if sign-in fails", () => __awaiter(void 0, void 0, void 0, function* () {
54
54
  const expectedUsername = "testuser";
55
55
  const expectedPassword = "testpassword";
56
- const expectedToken = "mockJwtToken";
57
56
  const signIn = sinon.stub().resolves({ isSignedIn: false });
58
57
  const signOut = sinon.stub();
59
58
  const fetchAuthSession = sinon.stub().resolves({
@@ -75,6 +74,16 @@ describe("library", () => {
75
74
  }));
76
75
  });
77
76
  describe("configure", () => {
77
+ const expectedApi = [
78
+ "deviceInfo",
79
+ "setPower",
80
+ "setPowerOff",
81
+ "setPowerOn",
82
+ "getPower",
83
+ "getEnvironmentTemperature",
84
+ "getTargetTemperature",
85
+ "setTargetTemperature",
86
+ ];
78
87
  it("should create API methods with the correct baseURL", () => {
79
88
  const baseURL = "https://example.com/api";
80
89
  const api = configure(baseURL);
@@ -85,12 +94,7 @@ describe("library", () => {
85
94
  },
86
95
  ],
87
96
  ]);
88
- assert.deepEqual(Object.keys(api), [
89
- "deviceInfo",
90
- "setPower",
91
- "setPowerOff",
92
- "setPowerOn",
93
- ]);
97
+ assert.deepEqual(Object.keys(api), expectedApi);
94
98
  });
95
99
  it("should create API methods with the default baseURL", () => {
96
100
  const api = configure();
@@ -101,20 +105,28 @@ describe("library", () => {
101
105
  },
102
106
  ],
103
107
  ]);
104
- assert.deepEqual(Object.keys(api), [
105
- "deviceInfo",
106
- "setPower",
107
- "setPowerOff",
108
- "setPowerOn",
109
- ]);
108
+ assert.deepEqual(Object.keys(api), expectedApi);
110
109
  });
111
110
  });
112
111
  describe("API Methods", () => {
112
+ const mockDeviceInfo = {
113
+ status: {
114
+ commands: {
115
+ power: true,
116
+ },
117
+ temperatures: {
118
+ enviroment: 19,
119
+ },
120
+ },
121
+ nvm: {
122
+ user_parameters: {
123
+ enviroment_1_temperature: 22,
124
+ },
125
+ },
126
+ };
113
127
  it("should call axios for deviceInfo", () => __awaiter(void 0, void 0, void 0, function* () {
114
- const expectedDevice = { id: "123", name: "Mock Device" };
115
- const expectedToken = "mockToken";
116
128
  const mockAxios = {
117
- get: sinon.stub().resolves({ data: expectedDevice }),
129
+ get: sinon.stub().resolves({ data: mockDeviceInfo }),
118
130
  };
119
131
  axiosStub.returns(mockAxios);
120
132
  const api = configure("https://example.com/api");
@@ -125,7 +137,7 @@ describe("library", () => {
125
137
  { headers: { Authorization: `Bearer ${expectedToken}` } },
126
138
  ],
127
139
  ]);
128
- assert.deepEqual(result.data, expectedDevice);
140
+ assert.deepEqual(result, mockDeviceInfo);
129
141
  }));
130
142
  // Tests for setPowerOn and setPowerOff
131
143
  [
@@ -164,5 +176,70 @@ describe("library", () => {
164
176
  assert.equal(result.status, 200);
165
177
  }));
166
178
  });
179
+ const getterTests = [
180
+ {
181
+ method: "getPower",
182
+ call: (api, token, mac) => api.getPower(token, mac),
183
+ expectedResult: true,
184
+ },
185
+ {
186
+ method: "getEnvironmentTemperature",
187
+ call: (api, token, mac) => api.getEnvironmentTemperature(token, mac),
188
+ expectedResult: 19,
189
+ },
190
+ {
191
+ method: "getTargetTemperature",
192
+ call: (api, token, mac) => api.getTargetTemperature(token, mac),
193
+ expectedResult: 22,
194
+ },
195
+ ];
196
+ getterTests.forEach(({ method, call, expectedResult }) => {
197
+ it(`should call axios and return the correct value for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
198
+ const mockAxios = {
199
+ get: sinon.stub().resolves({ data: mockDeviceInfo }),
200
+ };
201
+ axiosStub.returns(mockAxios);
202
+ const api = configure("https://example.com/api");
203
+ const result = yield call(api, expectedToken, "mockMacAddress");
204
+ assert.deepEqual(mockAxios.get.args, [
205
+ [
206
+ "device/mockMacAddress/info",
207
+ { headers: { Authorization: `Bearer ${expectedToken}` } },
208
+ ],
209
+ ]);
210
+ assert.equal(result, expectedResult);
211
+ }));
212
+ });
213
+ // Setter tests
214
+ const setterTests = [
215
+ {
216
+ method: "setTargetTemperature",
217
+ call: (api, token, mac, value) => api.setTargetTemperature(token, mac, value),
218
+ payload: {
219
+ name: "enviroment_1_temperature",
220
+ value: 20,
221
+ },
222
+ },
223
+ ];
224
+ setterTests.forEach(({ method, call, payload }) => {
225
+ it(`should call axios and send the correct payload for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
226
+ const mockAxios = {
227
+ put: sinon.stub().resolves({ status: 200 }),
228
+ };
229
+ axiosStub.returns(mockAxios);
230
+ const api = configure("https://example.com/api");
231
+ const result = yield call(api, expectedToken, "mockMacAddress", payload.value);
232
+ assert.deepEqual(mockAxios.put.args, [
233
+ [
234
+ "mqtt/command",
235
+ Object.assign({ mac_address: "mockMacAddress" }, payload),
236
+ {
237
+ headers: { Authorization: `Bearer ${expectedToken}` },
238
+ },
239
+ ],
240
+ ]);
241
+ assert.equal(result.status, 200);
242
+ }));
243
+ });
167
244
  });
168
245
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edilkamin",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
package/src/cli.ts CHANGED
@@ -32,11 +32,78 @@ const promptPassword = (): Promise<string> => {
32
32
  * @param command The command to which options should be added.
33
33
  * @returns The command with options added.
34
34
  */
35
- const addCommonOptions = (command: Command): Command =>
35
+ const addAuthOptions = (command: Command): Command =>
36
36
  command
37
37
  .requiredOption("-u, --username <username>", "Username")
38
38
  .option("-p, --password <password>", "Password");
39
39
 
40
+ /**
41
+ * Adds MAC address option to a command.
42
+ * @param command The command to which the MAC address option should be added.
43
+ * @returns The command with the MAC address option added.
44
+ */
45
+ const addMacOption = (command: Command): Command =>
46
+ command.requiredOption("-m, --mac <macAddress>", "MAC address of the device");
47
+
48
+ /**
49
+ * Handles common authentication and API initialization logic.
50
+ * @param options The options passed from the CLI command.
51
+ * @returns An object containing the normalized MAC, JWT token, and configured API instance.
52
+ */
53
+ const initializeCommand = async (options: {
54
+ username: string;
55
+ password?: string;
56
+ mac: string;
57
+ }): Promise<{
58
+ normalizedMac: string;
59
+ jwtToken: string;
60
+ api: ReturnType<typeof configure>;
61
+ }> => {
62
+ const { username, password, mac } = options;
63
+ const normalizedMac = mac.replace(/:/g, "");
64
+ const pwd = password || (await promptPassword());
65
+ const jwtToken = await signIn(username, pwd);
66
+ const api = configure();
67
+ return { normalizedMac, jwtToken, api };
68
+ };
69
+
70
+ /**
71
+ * Executes a getter command by handling common steps (authentication, API initialization).
72
+ * @param options The options passed from the CLI command.
73
+ * @param getter A function to call on the configured API object.
74
+ */
75
+ const executeGetter = async (
76
+ options: { username: string; password?: string; mac: string },
77
+ getter: (
78
+ api: ReturnType<typeof configure>,
79
+ jwtToken: string,
80
+ mac: string
81
+ ) => Promise<unknown>
82
+ ): Promise<void> => {
83
+ const { normalizedMac, jwtToken, api } = await initializeCommand(options);
84
+ const result = await getter(api, jwtToken, normalizedMac);
85
+ console.log(result);
86
+ };
87
+
88
+ /**
89
+ * Executes a setter command by handling common steps (authentication, API initialization).
90
+ * @param options The options passed from the CLI command.
91
+ * @param setter A function to call on the configured API object.
92
+ */
93
+ const executeSetter = async (
94
+ options: { username: string; password?: string; mac: string; value: number },
95
+ setter: (
96
+ api: ReturnType<typeof configure>,
97
+ jwtToken: string,
98
+ mac: string,
99
+ value: number
100
+ ) => Promise<unknown>
101
+ ): Promise<void> => {
102
+ const { normalizedMac, jwtToken, api } = await initializeCommand(options);
103
+ const result = await setter(api, jwtToken, normalizedMac, options.value);
104
+ console.log(result);
105
+ };
106
+
40
107
  const createProgram = (): Command => {
41
108
  const program = new Command();
42
109
  program
@@ -44,7 +111,7 @@ const createProgram = (): Command => {
44
111
  .description("CLI tool for interacting with the Edilkamin API")
45
112
  .version(version);
46
113
  // Command: signIn
47
- addCommonOptions(
114
+ addAuthOptions(
48
115
  program.command("signIn").description("Sign in and retrieve a JWT token")
49
116
  ).action(async (options) => {
50
117
  const { username, password } = options;
@@ -52,21 +119,79 @@ const createProgram = (): Command => {
52
119
  const jwtToken = await signIn(username, pwd);
53
120
  console.log("JWT Token:", jwtToken);
54
121
  });
55
- // Command: deviceInfo
56
- addCommonOptions(
57
- program
58
- .command("deviceInfo")
59
- .description("Retrieve device info for a specific MAC address")
60
- .requiredOption("-m, --mac <macAddress>", "MAC address of the device")
61
- ).action(async (options) => {
62
- const { username, password, mac } = options;
63
- const normalizedMac = mac.replace(/:/g, "");
64
- const pwd = password || (await promptPassword());
65
- const jwtToken = await signIn(username, pwd);
66
- const api = configure(); // Use the default API configuration
67
- const deviceInfo = await api.deviceInfo(jwtToken, normalizedMac);
68
- console.log("Device Info:", deviceInfo.data);
122
+ // Generic getter commands
123
+ [
124
+ {
125
+ commandName: "deviceInfo",
126
+ description: "Retrieve device info for a specific MAC address",
127
+ getter: (
128
+ api: ReturnType<typeof configure>,
129
+ jwtToken: string,
130
+ mac: string
131
+ ) => api.deviceInfo(jwtToken, mac),
132
+ },
133
+ {
134
+ commandName: "getPower",
135
+ description: "Retrieve device power status",
136
+ getter: (
137
+ api: ReturnType<typeof configure>,
138
+ jwtToken: string,
139
+ mac: string
140
+ ) => api.getPower(jwtToken, mac),
141
+ },
142
+ {
143
+ commandName: "getEnvironmentTemperature",
144
+ description: "Retrieve environment temperature",
145
+ getter: (
146
+ api: ReturnType<typeof configure>,
147
+ jwtToken: string,
148
+ mac: string
149
+ ) => api.getEnvironmentTemperature(jwtToken, mac),
150
+ },
151
+ {
152
+ commandName: "getTargetTemperature",
153
+ description: "Retrieve target temperature",
154
+ getter: (
155
+ api: ReturnType<typeof configure>,
156
+ jwtToken: string,
157
+ mac: string
158
+ ) => api.getTargetTemperature(jwtToken, mac),
159
+ },
160
+ ].forEach(({ commandName, description, getter }) => {
161
+ addMacOption(
162
+ addAuthOptions(program.command(commandName).description(description))
163
+ ).action((options) => executeGetter(options, getter));
69
164
  });
165
+ // Generic setter commands
166
+ [
167
+ {
168
+ commandName: "setPower",
169
+ description: "Set the power state of the device (1 for ON, 0 for OFF)",
170
+ setter: (
171
+ api: ReturnType<typeof configure>,
172
+ jwtToken: string,
173
+ mac: string,
174
+ value: number
175
+ ) => api.setPower(jwtToken, mac, value),
176
+ },
177
+ {
178
+ commandName: "setTargetTemperature",
179
+ description: "Set the target temperature (degree celsius) for a device",
180
+ setter: (
181
+ api: ReturnType<typeof configure>,
182
+ jwtToken: string,
183
+ mac: string,
184
+ value: number
185
+ ) => api.setTargetTemperature(jwtToken, mac, value),
186
+ },
187
+ ].forEach(({ commandName, description, setter }) => {
188
+ addMacOption(
189
+ addAuthOptions(
190
+ program.command(commandName).description(description)
191
+ ).requiredOption("-v, --value <number>", "Value to set", parseFloat)
192
+ ).action((options) => executeSetter(options, setter));
193
+ });
194
+
70
195
  return program;
71
196
  };
72
197
 
package/src/index.ts CHANGED
@@ -10,4 +10,13 @@ export {
10
10
  UserParametersType,
11
11
  } from "./types";
12
12
 
13
- export const { deviceInfo, setPower, setPowerOff, setPowerOn } = configure();
13
+ export const {
14
+ deviceInfo,
15
+ setPower,
16
+ setPowerOff,
17
+ setPowerOn,
18
+ getPower,
19
+ getEnvironmentTemperature,
20
+ getTargetTemperature,
21
+ setTargetTemperature,
22
+ } = configure();
@@ -7,6 +7,7 @@ import { API_URL } from "./constants";
7
7
 
8
8
  describe("library", () => {
9
9
  let axiosStub: sinon.SinonStub;
10
+ const expectedToken = "mockJwtToken";
10
11
 
11
12
  beforeEach(() => {
12
13
  axiosStub = sinon.stub(axios, "create").returns({
@@ -24,7 +25,6 @@ describe("library", () => {
24
25
  it("should sign in and return the JWT token", async () => {
25
26
  const expectedUsername = "testuser";
26
27
  const expectedPassword = "testpassword";
27
- const expectedToken = "mockJwtToken";
28
28
  const signIn = sinon.stub().resolves({ isSignedIn: true });
29
29
  const signOut = sinon.stub();
30
30
  const fetchAuthSession = sinon.stub().resolves({
@@ -53,7 +53,6 @@ describe("library", () => {
53
53
  it("should throw an error if sign-in fails", async () => {
54
54
  const expectedUsername = "testuser";
55
55
  const expectedPassword = "testpassword";
56
- const expectedToken = "mockJwtToken";
57
56
  const signIn = sinon.stub().resolves({ isSignedIn: false });
58
57
  const signOut = sinon.stub();
59
58
  const fetchAuthSession = sinon.stub().resolves({
@@ -79,6 +78,16 @@ describe("library", () => {
79
78
  });
80
79
 
81
80
  describe("configure", () => {
81
+ const expectedApi = [
82
+ "deviceInfo",
83
+ "setPower",
84
+ "setPowerOff",
85
+ "setPowerOn",
86
+ "getPower",
87
+ "getEnvironmentTemperature",
88
+ "getTargetTemperature",
89
+ "setTargetTemperature",
90
+ ];
82
91
  it("should create API methods with the correct baseURL", () => {
83
92
  const baseURL = "https://example.com/api";
84
93
  const api = configure(baseURL);
@@ -89,12 +98,7 @@ describe("library", () => {
89
98
  },
90
99
  ],
91
100
  ]);
92
- assert.deepEqual(Object.keys(api), [
93
- "deviceInfo",
94
- "setPower",
95
- "setPowerOff",
96
- "setPowerOn",
97
- ]);
101
+ assert.deepEqual(Object.keys(api), expectedApi);
98
102
  });
99
103
  it("should create API methods with the default baseURL", () => {
100
104
  const api = configure();
@@ -105,21 +109,30 @@ describe("library", () => {
105
109
  },
106
110
  ],
107
111
  ]);
108
- assert.deepEqual(Object.keys(api), [
109
- "deviceInfo",
110
- "setPower",
111
- "setPowerOff",
112
- "setPowerOn",
113
- ]);
112
+ assert.deepEqual(Object.keys(api), expectedApi);
114
113
  });
115
114
  });
116
115
 
117
116
  describe("API Methods", () => {
117
+ const mockDeviceInfo = {
118
+ status: {
119
+ commands: {
120
+ power: true,
121
+ },
122
+ temperatures: {
123
+ enviroment: 19,
124
+ },
125
+ },
126
+ nvm: {
127
+ user_parameters: {
128
+ enviroment_1_temperature: 22,
129
+ },
130
+ },
131
+ };
132
+
118
133
  it("should call axios for deviceInfo", async () => {
119
- const expectedDevice = { id: "123", name: "Mock Device" };
120
- const expectedToken = "mockToken";
121
134
  const mockAxios = {
122
- get: sinon.stub().resolves({ data: expectedDevice }),
135
+ get: sinon.stub().resolves({ data: mockDeviceInfo }),
123
136
  };
124
137
  axiosStub.returns(mockAxios);
125
138
  const api = configure("https://example.com/api");
@@ -130,7 +143,7 @@ describe("library", () => {
130
143
  { headers: { Authorization: `Bearer ${expectedToken}` } },
131
144
  ],
132
145
  ]);
133
- assert.deepEqual(result.data, expectedDevice);
146
+ assert.deepEqual(result, mockDeviceInfo);
134
147
  });
135
148
 
136
149
  // Tests for setPowerOn and setPowerOff
@@ -173,5 +186,91 @@ describe("library", () => {
173
186
  assert.equal(result.status, 200);
174
187
  });
175
188
  });
189
+
190
+ const getterTests = [
191
+ {
192
+ method: "getPower",
193
+ call: (api: ReturnType<typeof configure>, token: string, mac: string) =>
194
+ api.getPower(token, mac),
195
+ expectedResult: true,
196
+ },
197
+ {
198
+ method: "getEnvironmentTemperature",
199
+ call: (api: ReturnType<typeof configure>, token: string, mac: string) =>
200
+ api.getEnvironmentTemperature(token, mac),
201
+ expectedResult: 19,
202
+ },
203
+ {
204
+ method: "getTargetTemperature",
205
+ call: (api: ReturnType<typeof configure>, token: string, mac: string) =>
206
+ api.getTargetTemperature(token, mac),
207
+ expectedResult: 22,
208
+ },
209
+ ];
210
+ getterTests.forEach(({ method, call, expectedResult }) => {
211
+ it(`should call axios and return the correct value for ${method}`, async () => {
212
+ const mockAxios = {
213
+ get: sinon.stub().resolves({ data: mockDeviceInfo }),
214
+ };
215
+ axiosStub.returns(mockAxios);
216
+ const api = configure("https://example.com/api");
217
+
218
+ const result = await call(api, expectedToken, "mockMacAddress");
219
+
220
+ assert.deepEqual(mockAxios.get.args, [
221
+ [
222
+ "device/mockMacAddress/info",
223
+ { headers: { Authorization: `Bearer ${expectedToken}` } },
224
+ ],
225
+ ]);
226
+ assert.equal(result, expectedResult);
227
+ });
228
+ });
229
+ // Setter tests
230
+ const setterTests = [
231
+ {
232
+ method: "setTargetTemperature",
233
+ call: (
234
+ api: ReturnType<typeof configure>,
235
+ token: string,
236
+ mac: string,
237
+ value: number
238
+ ) => api.setTargetTemperature(token, mac, value),
239
+ payload: {
240
+ name: "enviroment_1_temperature",
241
+ value: 20,
242
+ },
243
+ },
244
+ ];
245
+ setterTests.forEach(({ method, call, payload }) => {
246
+ it(`should call axios and send the correct payload for ${method}`, async () => {
247
+ const mockAxios = {
248
+ put: sinon.stub().resolves({ status: 200 }),
249
+ };
250
+ axiosStub.returns(mockAxios);
251
+ const api = configure("https://example.com/api");
252
+
253
+ const result = await call(
254
+ api,
255
+ expectedToken,
256
+ "mockMacAddress",
257
+ payload.value
258
+ );
259
+
260
+ assert.deepEqual(mockAxios.put.args, [
261
+ [
262
+ "mqtt/command",
263
+ {
264
+ mac_address: "mockMacAddress",
265
+ ...payload,
266
+ },
267
+ {
268
+ headers: { Authorization: `Bearer ${expectedToken}` },
269
+ },
270
+ ],
271
+ ]);
272
+ assert.equal(result.status, 200);
273
+ });
274
+ });
176
275
  });
177
276
  });
package/src/library.ts CHANGED
@@ -61,10 +61,23 @@ const createAuthService = (auth: typeof amplifyAuth) => {
61
61
  const { signIn } = createAuthService(amplifyAuth);
62
62
 
63
63
  const deviceInfo =
64
- (axiosInstance: AxiosInstance) => (jwtToken: string, macAddress: string) =>
65
- axiosInstance.get<DeviceInfoType>(`device/${macAddress}/info`, {
66
- headers: headers(jwtToken),
67
- });
64
+ (axiosInstance: AxiosInstance) =>
65
+ /**
66
+ * Retrieves information about a device by its MAC address.
67
+ *
68
+ * @param {string} jwtToken - The JWT token for authentication.
69
+ * @param {string} macAddress - The MAC address of the device.
70
+ * @returns {Promise<DeviceInfoType>} - A promise that resolves to the device info.
71
+ */
72
+ async (jwtToken: string, macAddress: string) => {
73
+ const response = await axiosInstance.get<DeviceInfoType>(
74
+ `device/${macAddress}/info`,
75
+ {
76
+ headers: headers(jwtToken),
77
+ }
78
+ );
79
+ return response.data;
80
+ };
68
81
 
69
82
  const mqttCommand =
70
83
  (axiosInstance: AxiosInstance) =>
@@ -78,27 +91,138 @@ const mqttCommand =
78
91
 
79
92
  const setPower =
80
93
  (axiosInstance: AxiosInstance) =>
94
+ /**
95
+ * Sends a command to set the power state of a device.
96
+ *
97
+ * @param {string} jwtToken - The JWT token for authentication.
98
+ * @param {string} macAddress - The MAC address of the device.
99
+ * @param {number} value - The desired power state (1 for ON, 0 for OFF).
100
+ * @returns {Promise<string>} - A promise that resolves to the command response.
101
+ */
81
102
  (jwtToken: string, macAddress: string, value: number) =>
82
103
  mqttCommand(axiosInstance)(jwtToken, macAddress, { name: "power", value });
83
104
 
84
105
  const setPowerOn =
85
- (axiosInstance: AxiosInstance) => (jwtToken: string, macAddress: string) =>
106
+ (axiosInstance: AxiosInstance) =>
107
+ /**
108
+ * Turns a device ON by setting its power state.
109
+ *
110
+ * @param {string} jwtToken - The JWT token for authentication.
111
+ * @param {string} macAddress - The MAC address of the device.
112
+ * @returns {Promise<string>} - A promise that resolves to the command response.
113
+ *
114
+ * @example
115
+ * const response = await api.setPowerOn(jwtToken, macAddress);
116
+ * console.log(response);
117
+ */
118
+ (jwtToken: string, macAddress: string) =>
86
119
  setPower(axiosInstance)(jwtToken, macAddress, 1);
120
+
87
121
  const setPowerOff =
88
- (axiosInstance: AxiosInstance) => (jwtToken: string, macAddress: string) =>
122
+ (axiosInstance: AxiosInstance) =>
123
+ /**
124
+ * Turns a device OFF by setting its power state.
125
+ *
126
+ * @param {string} jwtToken - The JWT token for authentication.
127
+ * @param {string} macAddress - The MAC address of the device.
128
+ * @returns {Promise<string>} - A promise that resolves to the command response.
129
+ *
130
+ * @example
131
+ * const response = await api.setPowerOff(jwtToken, macAddress);
132
+ * console.log(response);
133
+ */
134
+ (jwtToken: string, macAddress: string) =>
89
135
  setPower(axiosInstance)(jwtToken, macAddress, 0);
90
136
 
137
+ const getPower =
138
+ (axiosInstance: AxiosInstance) =>
139
+ /**
140
+ * Retrieves the power status of the device.
141
+ *
142
+ * @param {string} jwtToken - The JWT token for authentication.
143
+ * @param {string} macAddress - The MAC address of the device.
144
+ * @returns {Promise<boolean>} - A promise that resolves to the power status.
145
+ */
146
+ async (jwtToken: string, macAddress: string): Promise<boolean> => {
147
+ const info = await deviceInfo(axiosInstance)(jwtToken, macAddress);
148
+ return info.status.commands.power;
149
+ };
150
+
151
+ const getEnvironmentTemperature =
152
+ (axiosInstance: AxiosInstance) =>
153
+ /**
154
+ * Retrieves the environment temperature from the device's sensors.
155
+ *
156
+ * @param {string} jwtToken - The JWT token for authentication.
157
+ * @param {string} macAddress - The MAC address of the device.
158
+ * @returns {Promise<number>} - A promise that resolves to the temperature value.
159
+ */
160
+ async (jwtToken: string, macAddress: string): Promise<number> => {
161
+ const info = await deviceInfo(axiosInstance)(jwtToken, macAddress);
162
+ return info.status.temperatures.enviroment;
163
+ };
164
+
165
+ const getTargetTemperature =
166
+ (axiosInstance: AxiosInstance) =>
167
+ /**
168
+ * Retrieves the target temperature value set on the device.
169
+ *
170
+ * @param {string} jwtToken - The JWT token for authentication.
171
+ * @param {string} macAddress - The MAC address of the device.
172
+ * @returns {Promise<number>} - A promise that resolves to the target temperature (degree celsius).
173
+ */
174
+ async (jwtToken: string, macAddress: string): Promise<number> => {
175
+ const info = await deviceInfo(axiosInstance)(jwtToken, macAddress);
176
+ return info.nvm.user_parameters.enviroment_1_temperature;
177
+ };
178
+
179
+ const setTargetTemperature =
180
+ (axiosInstance: AxiosInstance) =>
181
+ /**
182
+ * Sends a command to set the target temperature (degree celsius) of a device.
183
+ *
184
+ * @param {string} jwtToken - The JWT token for authentication.
185
+ * @param {string} macAddress - The MAC address of the device.
186
+ * @param {number} temperature - The desired target temperature (degree celsius).
187
+ * @returns {Promise<string>} - A promise that resolves to the command response.
188
+ */
189
+ (jwtToken: string, macAddress: string, temperature: number) =>
190
+ mqttCommand(axiosInstance)(jwtToken, macAddress, {
191
+ name: "enviroment_1_temperature",
192
+ value: temperature,
193
+ });
194
+
195
+ /**
196
+ * Configures the library for API interactions.
197
+ * Initializes API methods with a specified base URL.
198
+ *
199
+ * @param {string} [baseURL=API_URL] - The base URL for the API.
200
+ * @returns {object} - An object containing methods for interacting with the API.
201
+ *
202
+ * @example
203
+ * const api = configure();
204
+ * const power = await api.getPower(jwtToken, macAddress);
205
+ */
91
206
  const configure = (baseURL: string = API_URL) => {
92
207
  const axiosInstance = axios.create({ baseURL });
93
208
  const deviceInfoInstance = deviceInfo(axiosInstance);
94
209
  const setPowerInstance = setPower(axiosInstance);
95
210
  const setPowerOffInstance = setPowerOff(axiosInstance);
96
211
  const setPowerOnInstance = setPowerOn(axiosInstance);
212
+ const getPowerInstance = getPower(axiosInstance);
213
+ const getEnvironmentTemperatureInstance =
214
+ getEnvironmentTemperature(axiosInstance);
215
+ const getTargetTemperatureInstance = getTargetTemperature(axiosInstance);
216
+ const setTargetTemperatureInstance = setTargetTemperature(axiosInstance);
97
217
  return {
98
218
  deviceInfo: deviceInfoInstance,
99
219
  setPower: setPowerInstance,
100
220
  setPowerOff: setPowerOffInstance,
101
221
  setPowerOn: setPowerOnInstance,
222
+ getPower: getPowerInstance,
223
+ getEnvironmentTemperature: getEnvironmentTemperatureInstance,
224
+ getTargetTemperature: getTargetTemperatureInstance,
225
+ setTargetTemperature: setTargetTemperatureInstance,
102
226
  };
103
227
  };
104
228