edilkamin 1.10.0 → 1.10.1
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/cjs/package.json +1 -1
- package/dist/cjs/src/cli.js +105 -0
- package/dist/cjs/src/index.d.ts +2 -1
- package/dist/cjs/src/index.js +4 -1
- package/dist/cjs/src/library.d.ts +10 -1
- package/dist/cjs/src/library.js +199 -0
- package/dist/cjs/src/library.test.js +223 -0
- package/dist/cjs/src/types.d.ts +127 -1
- package/dist/cjs/src/types.js +64 -0
- package/dist/esm/package.json +1 -1
- package/dist/esm/src/cli.js +105 -0
- package/dist/esm/src/index.d.ts +2 -1
- package/dist/esm/src/index.js +1 -0
- package/dist/esm/src/library.d.ts +10 -1
- package/dist/esm/src/library.js +199 -0
- package/dist/esm/src/library.test.js +223 -0
- package/dist/esm/src/types.d.ts +127 -1
- package/dist/esm/src/types.js +63 -1
- package/package.json +1 -1
- package/src/cli.ts +156 -0
- package/src/index.ts +10 -0
- package/src/library.test.ts +290 -0
- package/src/library.ts +258 -0
- package/src/types.ts +180 -0
package/dist/cjs/package.json
CHANGED
package/dist/cjs/src/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ const package_json_1 = require("../package.json");
|
|
|
20
20
|
const constants_1 = require("./constants");
|
|
21
21
|
const library_1 = require("./library");
|
|
22
22
|
const token_storage_1 = require("./token-storage");
|
|
23
|
+
const types_1 = require("./types");
|
|
23
24
|
const promptPassword = () => {
|
|
24
25
|
const rl = readline_1.default.createInterface({
|
|
25
26
|
input: process.stdin,
|
|
@@ -228,6 +229,84 @@ const createProgram = () => {
|
|
|
228
229
|
description: "Retrieve estimated pellet autonomy time",
|
|
229
230
|
getter: (api, jwtToken, mac) => api.getPelletAutonomyTime(jwtToken, mac),
|
|
230
231
|
},
|
|
232
|
+
// Statistics getters
|
|
233
|
+
{
|
|
234
|
+
commandName: "getTotalCounters",
|
|
235
|
+
description: "Get lifetime operating counters (power-ons, runtime by power level)",
|
|
236
|
+
getter: (api, jwtToken, mac) => api.getTotalCounters(jwtToken, mac),
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
commandName: "getServiceCounters",
|
|
240
|
+
description: "Get service counters (runtime since last maintenance)",
|
|
241
|
+
getter: (api, jwtToken, mac) => api.getServiceCounters(jwtToken, mac),
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
commandName: "getRegenerationData",
|
|
245
|
+
description: "Get regeneration and maintenance data",
|
|
246
|
+
getter: (api, jwtToken, mac) => api.getRegenerationData(jwtToken, mac),
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
commandName: "getServiceTime",
|
|
250
|
+
description: "Get total service time in hours",
|
|
251
|
+
getter: (api, jwtToken, mac) => api.getServiceTime(jwtToken, mac),
|
|
252
|
+
},
|
|
253
|
+
// Analytics getters
|
|
254
|
+
{
|
|
255
|
+
commandName: "getTotalOperatingHours",
|
|
256
|
+
description: "Get total operating hours across all power levels",
|
|
257
|
+
getter: (api, jwtToken, mac) => api.getTotalOperatingHours(jwtToken, mac),
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
commandName: "getPowerDistribution",
|
|
261
|
+
description: "Get power level usage distribution as percentages",
|
|
262
|
+
getter: (api, jwtToken, mac) => __awaiter(void 0, void 0, void 0, function* () {
|
|
263
|
+
const result = yield api.getPowerDistribution(jwtToken, mac);
|
|
264
|
+
return {
|
|
265
|
+
p1: `${result.p1.toFixed(1)}%`,
|
|
266
|
+
p2: `${result.p2.toFixed(1)}%`,
|
|
267
|
+
p3: `${result.p3.toFixed(1)}%`,
|
|
268
|
+
p4: `${result.p4.toFixed(1)}%`,
|
|
269
|
+
p5: `${result.p5.toFixed(1)}%`,
|
|
270
|
+
};
|
|
271
|
+
}),
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
commandName: "getServiceStatus",
|
|
275
|
+
description: "Get service status including whether maintenance is due",
|
|
276
|
+
getter: (api, jwtToken, mac) => api.getServiceStatus(jwtToken, mac),
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
commandName: "getUsageAnalytics",
|
|
280
|
+
description: "Get comprehensive usage analytics in single response",
|
|
281
|
+
getter: (api, jwtToken, mac) => __awaiter(void 0, void 0, void 0, function* () {
|
|
282
|
+
var _a;
|
|
283
|
+
const analytics = yield api.getUsageAnalytics(jwtToken, mac);
|
|
284
|
+
return {
|
|
285
|
+
lifetime: {
|
|
286
|
+
powerOnCount: analytics.totalPowerOns,
|
|
287
|
+
totalOperatingHours: analytics.totalOperatingHours,
|
|
288
|
+
blackoutCount: analytics.blackoutCount,
|
|
289
|
+
},
|
|
290
|
+
powerDistribution: {
|
|
291
|
+
p1: `${analytics.powerDistribution.p1.toFixed(1)}%`,
|
|
292
|
+
p2: `${analytics.powerDistribution.p2.toFixed(1)}%`,
|
|
293
|
+
p3: `${analytics.powerDistribution.p3.toFixed(1)}%`,
|
|
294
|
+
p4: `${analytics.powerDistribution.p4.toFixed(1)}%`,
|
|
295
|
+
p5: `${analytics.powerDistribution.p5.toFixed(1)}%`,
|
|
296
|
+
},
|
|
297
|
+
service: {
|
|
298
|
+
totalServiceHours: analytics.serviceStatus.totalServiceHours,
|
|
299
|
+
hoursSinceLastService: analytics.serviceStatus.hoursSinceService,
|
|
300
|
+
thresholdHours: analytics.serviceStatus.serviceThresholdHours,
|
|
301
|
+
isServiceDue: analytics.serviceStatus.isServiceDue,
|
|
302
|
+
lastMaintenanceDate: ((_a = analytics.lastMaintenanceDate) === null || _a === void 0 ? void 0 : _a.toISOString()) || "Never",
|
|
303
|
+
},
|
|
304
|
+
alarms: {
|
|
305
|
+
totalCount: analytics.alarmCount,
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}),
|
|
309
|
+
},
|
|
231
310
|
].forEach(({ commandName, description, getter }) => {
|
|
232
311
|
addLegacyOption(addMacOption(addAuthOptions(program.command(commandName).description(description)))).action((options) => executeGetter(options, getter));
|
|
233
312
|
});
|
|
@@ -409,6 +488,32 @@ const createProgram = () => {
|
|
|
409
488
|
const result = yield api.setTargetTemperature(jwtToken, normalizedMac, index, value);
|
|
410
489
|
console.log(JSON.stringify(result, null, 2));
|
|
411
490
|
}));
|
|
491
|
+
// Alarm history command with human-readable descriptions
|
|
492
|
+
addLegacyOption(addMacOption(addAuthOptions(program
|
|
493
|
+
.command("getAlarmHistory")
|
|
494
|
+
.description("Get alarm history log with human-readable descriptions")))).action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
495
|
+
const { username, password, mac, legacy = false } = options;
|
|
496
|
+
const normalizedMac = mac.replace(/:/g, "");
|
|
497
|
+
const storage = (0, token_storage_1.createFileStorage)();
|
|
498
|
+
(0, library_1.configureAmplify)(storage);
|
|
499
|
+
let jwtToken;
|
|
500
|
+
try {
|
|
501
|
+
jwtToken = yield (0, library_1.getSession)(false, legacy);
|
|
502
|
+
}
|
|
503
|
+
catch (_a) {
|
|
504
|
+
if (!username) {
|
|
505
|
+
throw new Error("No session found. Please provide --username to sign in.");
|
|
506
|
+
}
|
|
507
|
+
const pwd = password || (yield promptPassword());
|
|
508
|
+
jwtToken = yield (0, library_1.signIn)(username, pwd, legacy);
|
|
509
|
+
}
|
|
510
|
+
const apiUrl = legacy ? constants_1.OLD_API_URL : constants_1.NEW_API_URL;
|
|
511
|
+
const api = (0, library_1.configure)(apiUrl);
|
|
512
|
+
const result = yield api.getAlarmHistory(jwtToken, normalizedMac);
|
|
513
|
+
// Format alarms with human-readable descriptions
|
|
514
|
+
const formattedAlarms = result.alarms.map((alarm) => (Object.assign(Object.assign({}, alarm), { typeName: types_1.AlarmCode[alarm.type] || "UNKNOWN", description: types_1.AlarmDescriptions[alarm.type] || "Unknown alarm", date: new Date(alarm.timestamp * 1000).toISOString() })));
|
|
515
|
+
console.log(JSON.stringify(Object.assign(Object.assign({}, result), { alarms: formattedAlarms }), null, 2));
|
|
516
|
+
}));
|
|
412
517
|
// Command: register
|
|
413
518
|
addLegacyOption(addAuthOptions(program
|
|
414
519
|
.command("register")
|
package/dist/cjs/src/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export { decompressBuffer, isBuffer, processResponse } from "./buffer-utils";
|
|
|
3
3
|
export { API_URL, NEW_API_URL, OLD_API_URL } from "./constants";
|
|
4
4
|
export { configure, getSession, signIn } from "./library";
|
|
5
5
|
export { serialNumberDisplay, serialNumberFromHex, serialNumberToHex, } from "./serial-utils";
|
|
6
|
-
export { BufferEncodedType, CommandsType, DeviceAssociationBody, DeviceAssociationResponse, DeviceInfoRawType, DeviceInfoType, DiscoveredDevice, EditDeviceAssociationBody, StatusType, TemperaturesType, UserParametersType, } from "./types";
|
|
6
|
+
export { AlarmEntryType, AlarmsLogType, BufferEncodedType, CommandsType, DeviceAssociationBody, DeviceAssociationResponse, DeviceInfoRawType, DeviceInfoType, DiscoveredDevice, EditDeviceAssociationBody, PowerDistributionType, RegenerationDataType, ServiceCountersType, ServiceStatusType, StatusCountersType, StatusType, TemperaturesType, TotalCountersType, UsageAnalyticsType, UserParametersType, } from "./types";
|
|
7
|
+
export { AlarmCode, AlarmDescriptions } from "./types";
|
|
7
8
|
export declare const deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("./types").DeviceInfoType>, registerDevice: (jwtToken: string, macAddress: string, serialNumber: string, deviceName?: string, deviceRoom?: string) => Promise<import("./types").DeviceAssociationResponse>, editDevice: (jwtToken: string, macAddress: string, deviceName?: string, deviceRoom?: string) => Promise<import("./types").DeviceAssociationResponse>, setPower: (jwtToken: string, macAddress: string, value: number) => Promise<unknown>, setPowerOff: (jwtToken: string, macAddress: string) => Promise<unknown>, setPowerOn: (jwtToken: string, macAddress: string) => Promise<unknown>, getPower: (jwtToken: string, macAddress: string) => Promise<boolean>, getEnvironmentTemperature: (jwtToken: string, macAddress: string) => Promise<number>, getTargetTemperature: (jwtToken: string, macAddress: string, envIndex: 1 | 2 | 3) => Promise<number>, setTargetTemperature: (jwtToken: string, macAddress: string, envIndex: 1 | 2 | 3, temperature: number) => Promise<unknown>;
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.setTargetTemperature = exports.getTargetTemperature = exports.getEnvironmentTemperature = exports.getPower = exports.setPowerOn = exports.setPowerOff = exports.setPower = exports.editDevice = exports.registerDevice = exports.deviceInfo = exports.serialNumberToHex = exports.serialNumberFromHex = exports.serialNumberDisplay = exports.signIn = exports.getSession = exports.configure = exports.OLD_API_URL = exports.NEW_API_URL = exports.API_URL = exports.processResponse = exports.isBuffer = exports.decompressBuffer = exports.bleToWifiMac = void 0;
|
|
4
|
+
exports.setTargetTemperature = exports.getTargetTemperature = exports.getEnvironmentTemperature = exports.getPower = exports.setPowerOn = exports.setPowerOff = exports.setPower = exports.editDevice = exports.registerDevice = exports.deviceInfo = exports.AlarmDescriptions = exports.AlarmCode = exports.serialNumberToHex = exports.serialNumberFromHex = exports.serialNumberDisplay = exports.signIn = exports.getSession = exports.configure = exports.OLD_API_URL = exports.NEW_API_URL = exports.API_URL = exports.processResponse = exports.isBuffer = exports.decompressBuffer = exports.bleToWifiMac = void 0;
|
|
5
5
|
const library_1 = require("./library");
|
|
6
6
|
var bluetooth_utils_1 = require("./bluetooth-utils");
|
|
7
7
|
Object.defineProperty(exports, "bleToWifiMac", { enumerable: true, get: function () { return bluetooth_utils_1.bleToWifiMac; } });
|
|
@@ -21,4 +21,7 @@ var serial_utils_1 = require("./serial-utils");
|
|
|
21
21
|
Object.defineProperty(exports, "serialNumberDisplay", { enumerable: true, get: function () { return serial_utils_1.serialNumberDisplay; } });
|
|
22
22
|
Object.defineProperty(exports, "serialNumberFromHex", { enumerable: true, get: function () { return serial_utils_1.serialNumberFromHex; } });
|
|
23
23
|
Object.defineProperty(exports, "serialNumberToHex", { enumerable: true, get: function () { return serial_utils_1.serialNumberToHex; } });
|
|
24
|
+
var types_1 = require("./types");
|
|
25
|
+
Object.defineProperty(exports, "AlarmCode", { enumerable: true, get: function () { return types_1.AlarmCode; } });
|
|
26
|
+
Object.defineProperty(exports, "AlarmDescriptions", { enumerable: true, get: function () { return types_1.AlarmDescriptions; } });
|
|
24
27
|
_a = (0, library_1.configure)(), exports.deviceInfo = _a.deviceInfo, exports.registerDevice = _a.registerDevice, exports.editDevice = _a.editDevice, exports.setPower = _a.setPower, exports.setPowerOff = _a.setPowerOff, exports.setPowerOn = _a.setPowerOn, exports.getPower = _a.getPower, exports.getEnvironmentTemperature = _a.getEnvironmentTemperature, exports.getTargetTemperature = _a.getTargetTemperature, exports.setTargetTemperature = _a.setTargetTemperature;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as amplifyAuth from "aws-amplify/auth";
|
|
2
|
-
import { DeviceAssociationResponse, DeviceInfoType } from "./types";
|
|
2
|
+
import { AlarmsLogType, DeviceAssociationResponse, DeviceInfoType, PowerDistributionType, RegenerationDataType, ServiceCountersType, ServiceStatusType, TotalCountersType, UsageAnalyticsType } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Generates headers with a JWT token for authenticated requests.
|
|
5
5
|
* @param {string} jwtToken - The JWT token for authorization.
|
|
@@ -81,5 +81,14 @@ declare const configure: (baseURL?: string) => {
|
|
|
81
81
|
getLanguage: (jwtToken: string, macAddress: string) => Promise<number>;
|
|
82
82
|
getPelletInReserve: (jwtToken: string, macAddress: string) => Promise<boolean>;
|
|
83
83
|
getPelletAutonomyTime: (jwtToken: string, macAddress: string) => Promise<number>;
|
|
84
|
+
getTotalCounters: (jwtToken: string, macAddress: string) => Promise<TotalCountersType>;
|
|
85
|
+
getServiceCounters: (jwtToken: string, macAddress: string) => Promise<ServiceCountersType>;
|
|
86
|
+
getAlarmHistory: (jwtToken: string, macAddress: string) => Promise<AlarmsLogType>;
|
|
87
|
+
getRegenerationData: (jwtToken: string, macAddress: string) => Promise<RegenerationDataType>;
|
|
88
|
+
getServiceTime: (jwtToken: string, macAddress: string) => Promise<number>;
|
|
89
|
+
getTotalOperatingHours: (jwtToken: string, macAddress: string) => Promise<number>;
|
|
90
|
+
getPowerDistribution: (jwtToken: string, macAddress: string) => Promise<PowerDistributionType>;
|
|
91
|
+
getServiceStatus: (jwtToken: string, macAddress: string, thresholdHours?: number) => Promise<ServiceStatusType>;
|
|
92
|
+
getUsageAnalytics: (jwtToken: string, macAddress: string, serviceThreshold?: number) => Promise<UsageAnalyticsType>;
|
|
84
93
|
};
|
|
85
94
|
export { configure, configureAmplify, createAuthService, getSession, headers, signIn, };
|
package/dist/cjs/src/library.js
CHANGED
|
@@ -514,6 +514,194 @@ const getPelletAutonomyTime = (baseURL) =>
|
|
|
514
514
|
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
515
515
|
return info.status.pellet.autonomy_time;
|
|
516
516
|
});
|
|
517
|
+
const getTotalCounters = (baseURL) =>
|
|
518
|
+
/**
|
|
519
|
+
* Retrieves lifetime operating counters.
|
|
520
|
+
* Includes power-on count and runtime hours per power level.
|
|
521
|
+
* These counters are never reset.
|
|
522
|
+
*
|
|
523
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
524
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
525
|
+
* @returns {Promise<TotalCountersType>} - Lifetime operating statistics.
|
|
526
|
+
*/
|
|
527
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
528
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
529
|
+
return info.nvm.total_counters;
|
|
530
|
+
});
|
|
531
|
+
const getServiceCounters = (baseURL) =>
|
|
532
|
+
/**
|
|
533
|
+
* Retrieves service counters (runtime since last maintenance).
|
|
534
|
+
* These counters track hours per power level since last service reset.
|
|
535
|
+
*
|
|
536
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
537
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
538
|
+
* @returns {Promise<ServiceCountersType>} - Service tracking statistics.
|
|
539
|
+
*/
|
|
540
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
541
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
542
|
+
return info.nvm.service_counters;
|
|
543
|
+
});
|
|
544
|
+
const getAlarmHistory = (baseURL) =>
|
|
545
|
+
/**
|
|
546
|
+
* Retrieves the alarm history log.
|
|
547
|
+
* Contains a circular buffer of recent alarms with timestamps.
|
|
548
|
+
*
|
|
549
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
550
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
551
|
+
* @returns {Promise<AlarmsLogType>} - Alarm history log.
|
|
552
|
+
*/
|
|
553
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
554
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
555
|
+
return info.nvm.alarms_log;
|
|
556
|
+
});
|
|
557
|
+
const getRegenerationData = (baseURL) =>
|
|
558
|
+
/**
|
|
559
|
+
* Retrieves regeneration and maintenance data.
|
|
560
|
+
* Includes blackout counter and last intervention timestamp.
|
|
561
|
+
*
|
|
562
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
563
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
564
|
+
* @returns {Promise<RegenerationDataType>} - Maintenance tracking data.
|
|
565
|
+
*/
|
|
566
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
567
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
568
|
+
return info.nvm.regeneration;
|
|
569
|
+
});
|
|
570
|
+
const getServiceTime = (baseURL) =>
|
|
571
|
+
/**
|
|
572
|
+
* Retrieves the total service time in hours.
|
|
573
|
+
*
|
|
574
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
575
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
576
|
+
* @returns {Promise<number>} - Total service hours.
|
|
577
|
+
*/
|
|
578
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
579
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
580
|
+
return info.status.counters.service_time;
|
|
581
|
+
});
|
|
582
|
+
/**
|
|
583
|
+
* Default service threshold in hours (from OEM parameters).
|
|
584
|
+
* Most devices use 2000 hours.
|
|
585
|
+
*/
|
|
586
|
+
const DEFAULT_SERVICE_THRESHOLD = 2000;
|
|
587
|
+
const getTotalOperatingHours = (baseURL) =>
|
|
588
|
+
/**
|
|
589
|
+
* Calculates total operating hours across all power levels.
|
|
590
|
+
*
|
|
591
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
592
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
593
|
+
* @returns {Promise<number>} - Total operating hours.
|
|
594
|
+
*/
|
|
595
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
596
|
+
const counters = yield getTotalCounters(baseURL)(jwtToken, macAddress);
|
|
597
|
+
return (counters.p1_working_time +
|
|
598
|
+
counters.p2_working_time +
|
|
599
|
+
counters.p3_working_time +
|
|
600
|
+
counters.p4_working_time +
|
|
601
|
+
counters.p5_working_time);
|
|
602
|
+
});
|
|
603
|
+
const getPowerDistribution = (baseURL) =>
|
|
604
|
+
/**
|
|
605
|
+
* Calculates power level usage distribution as percentages.
|
|
606
|
+
*
|
|
607
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
608
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
609
|
+
* @returns {Promise<PowerDistributionType>} - Percentage time at each power level.
|
|
610
|
+
*/
|
|
611
|
+
(jwtToken, macAddress) => __awaiter(void 0, void 0, void 0, function* () {
|
|
612
|
+
const counters = yield getTotalCounters(baseURL)(jwtToken, macAddress);
|
|
613
|
+
const total = counters.p1_working_time +
|
|
614
|
+
counters.p2_working_time +
|
|
615
|
+
counters.p3_working_time +
|
|
616
|
+
counters.p4_working_time +
|
|
617
|
+
counters.p5_working_time;
|
|
618
|
+
if (total === 0) {
|
|
619
|
+
return { p1: 0, p2: 0, p3: 0, p4: 0, p5: 0 };
|
|
620
|
+
}
|
|
621
|
+
return {
|
|
622
|
+
p1: (counters.p1_working_time / total) * 100,
|
|
623
|
+
p2: (counters.p2_working_time / total) * 100,
|
|
624
|
+
p3: (counters.p3_working_time / total) * 100,
|
|
625
|
+
p4: (counters.p4_working_time / total) * 100,
|
|
626
|
+
p5: (counters.p5_working_time / total) * 100,
|
|
627
|
+
};
|
|
628
|
+
});
|
|
629
|
+
const getServiceStatus = (baseURL) =>
|
|
630
|
+
/**
|
|
631
|
+
* Calculates service status including whether maintenance is due.
|
|
632
|
+
*
|
|
633
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
634
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
635
|
+
* @param {number} [thresholdHours=2000] - Service threshold in hours.
|
|
636
|
+
* @returns {Promise<ServiceStatusType>} - Service status with computed fields.
|
|
637
|
+
*/
|
|
638
|
+
(jwtToken_1, macAddress_1, ...args_1) => __awaiter(void 0, [jwtToken_1, macAddress_1, ...args_1], void 0, function* (jwtToken, macAddress, thresholdHours = DEFAULT_SERVICE_THRESHOLD) {
|
|
639
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
640
|
+
const serviceCounters = info.nvm.service_counters;
|
|
641
|
+
const hoursSinceService = serviceCounters.p1_working_time +
|
|
642
|
+
serviceCounters.p2_working_time +
|
|
643
|
+
serviceCounters.p3_working_time +
|
|
644
|
+
serviceCounters.p4_working_time +
|
|
645
|
+
serviceCounters.p5_working_time;
|
|
646
|
+
return {
|
|
647
|
+
totalServiceHours: info.status.counters.service_time,
|
|
648
|
+
hoursSinceService,
|
|
649
|
+
serviceThresholdHours: thresholdHours,
|
|
650
|
+
isServiceDue: hoursSinceService >= thresholdHours,
|
|
651
|
+
};
|
|
652
|
+
});
|
|
653
|
+
const getUsageAnalytics = (baseURL) =>
|
|
654
|
+
/**
|
|
655
|
+
* Retrieves comprehensive usage analytics in a single call.
|
|
656
|
+
* Combines multiple statistics into a unified analytics object.
|
|
657
|
+
*
|
|
658
|
+
* @param {string} jwtToken - The JWT token for authentication.
|
|
659
|
+
* @param {string} macAddress - The MAC address of the device.
|
|
660
|
+
* @param {number} [serviceThreshold=2000] - Service threshold in hours.
|
|
661
|
+
* @returns {Promise<UsageAnalyticsType>} - Comprehensive usage analytics.
|
|
662
|
+
*/
|
|
663
|
+
(jwtToken_1, macAddress_1, ...args_1) => __awaiter(void 0, [jwtToken_1, macAddress_1, ...args_1], void 0, function* (jwtToken, macAddress, serviceThreshold = DEFAULT_SERVICE_THRESHOLD) {
|
|
664
|
+
const info = yield deviceInfo(baseURL)(jwtToken, macAddress);
|
|
665
|
+
const totalCounters = info.nvm.total_counters;
|
|
666
|
+
const serviceCounters = info.nvm.service_counters;
|
|
667
|
+
const regeneration = info.nvm.regeneration;
|
|
668
|
+
const alarmsLog = info.nvm.alarms_log;
|
|
669
|
+
const totalOperatingHours = totalCounters.p1_working_time +
|
|
670
|
+
totalCounters.p2_working_time +
|
|
671
|
+
totalCounters.p3_working_time +
|
|
672
|
+
totalCounters.p4_working_time +
|
|
673
|
+
totalCounters.p5_working_time;
|
|
674
|
+
const hoursSinceService = serviceCounters.p1_working_time +
|
|
675
|
+
serviceCounters.p2_working_time +
|
|
676
|
+
serviceCounters.p3_working_time +
|
|
677
|
+
serviceCounters.p4_working_time +
|
|
678
|
+
serviceCounters.p5_working_time;
|
|
679
|
+
const powerDistribution = totalOperatingHours === 0
|
|
680
|
+
? { p1: 0, p2: 0, p3: 0, p4: 0, p5: 0 }
|
|
681
|
+
: {
|
|
682
|
+
p1: (totalCounters.p1_working_time / totalOperatingHours) * 100,
|
|
683
|
+
p2: (totalCounters.p2_working_time / totalOperatingHours) * 100,
|
|
684
|
+
p3: (totalCounters.p3_working_time / totalOperatingHours) * 100,
|
|
685
|
+
p4: (totalCounters.p4_working_time / totalOperatingHours) * 100,
|
|
686
|
+
p5: (totalCounters.p5_working_time / totalOperatingHours) * 100,
|
|
687
|
+
};
|
|
688
|
+
return {
|
|
689
|
+
totalPowerOns: totalCounters.power_ons,
|
|
690
|
+
totalOperatingHours,
|
|
691
|
+
powerDistribution,
|
|
692
|
+
serviceStatus: {
|
|
693
|
+
totalServiceHours: info.status.counters.service_time,
|
|
694
|
+
hoursSinceService,
|
|
695
|
+
serviceThresholdHours: serviceThreshold,
|
|
696
|
+
isServiceDue: hoursSinceService >= serviceThreshold,
|
|
697
|
+
},
|
|
698
|
+
blackoutCount: regeneration.blackout_counter,
|
|
699
|
+
lastMaintenanceDate: regeneration.last_intervention > 0
|
|
700
|
+
? new Date(regeneration.last_intervention * 1000)
|
|
701
|
+
: null,
|
|
702
|
+
alarmCount: alarmsLog.number,
|
|
703
|
+
};
|
|
704
|
+
});
|
|
517
705
|
const registerDevice = (baseURL) =>
|
|
518
706
|
/**
|
|
519
707
|
* Registers a device with the user's account.
|
|
@@ -613,5 +801,16 @@ const configure = (baseURL = constants_1.API_URL) => ({
|
|
|
613
801
|
getLanguage: getLanguage(baseURL),
|
|
614
802
|
getPelletInReserve: getPelletInReserve(baseURL),
|
|
615
803
|
getPelletAutonomyTime: getPelletAutonomyTime(baseURL),
|
|
804
|
+
// Statistics getters
|
|
805
|
+
getTotalCounters: getTotalCounters(baseURL),
|
|
806
|
+
getServiceCounters: getServiceCounters(baseURL),
|
|
807
|
+
getAlarmHistory: getAlarmHistory(baseURL),
|
|
808
|
+
getRegenerationData: getRegenerationData(baseURL),
|
|
809
|
+
getServiceTime: getServiceTime(baseURL),
|
|
810
|
+
// Analytics functions
|
|
811
|
+
getTotalOperatingHours: getTotalOperatingHours(baseURL),
|
|
812
|
+
getPowerDistribution: getPowerDistribution(baseURL),
|
|
813
|
+
getServiceStatus: getServiceStatus(baseURL),
|
|
814
|
+
getUsageAnalytics: getUsageAnalytics(baseURL),
|
|
616
815
|
});
|
|
617
816
|
exports.configure = configure;
|
|
@@ -220,6 +220,17 @@ describe("library", () => {
|
|
|
220
220
|
"getLanguage",
|
|
221
221
|
"getPelletInReserve",
|
|
222
222
|
"getPelletAutonomyTime",
|
|
223
|
+
// Statistics getters
|
|
224
|
+
"getTotalCounters",
|
|
225
|
+
"getServiceCounters",
|
|
226
|
+
"getAlarmHistory",
|
|
227
|
+
"getRegenerationData",
|
|
228
|
+
"getServiceTime",
|
|
229
|
+
// Analytics functions
|
|
230
|
+
"getTotalOperatingHours",
|
|
231
|
+
"getPowerDistribution",
|
|
232
|
+
"getServiceStatus",
|
|
233
|
+
"getUsageAnalytics",
|
|
223
234
|
];
|
|
224
235
|
it("should create API methods with the correct baseURL", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
225
236
|
const baseURL = "https://example.com/api/";
|
|
@@ -791,6 +802,218 @@ describe("library", () => {
|
|
|
791
802
|
assert_1.strict.equal(result, 240);
|
|
792
803
|
}));
|
|
793
804
|
});
|
|
805
|
+
describe("statistics getters", () => {
|
|
806
|
+
const mockDeviceInfoWithStats = {
|
|
807
|
+
status: {
|
|
808
|
+
commands: { power: true },
|
|
809
|
+
temperatures: { board: 25, enviroment: 20 },
|
|
810
|
+
flags: { is_pellet_in_reserve: false },
|
|
811
|
+
pellet: { autonomy_time: 900 },
|
|
812
|
+
counters: { service_time: 1108 },
|
|
813
|
+
},
|
|
814
|
+
nvm: {
|
|
815
|
+
user_parameters: {
|
|
816
|
+
language: 1,
|
|
817
|
+
is_auto: false,
|
|
818
|
+
is_fahrenheit: false,
|
|
819
|
+
is_sound_active: false,
|
|
820
|
+
enviroment_1_temperature: 19,
|
|
821
|
+
enviroment_2_temperature: 20,
|
|
822
|
+
enviroment_3_temperature: 20,
|
|
823
|
+
manual_power: 1,
|
|
824
|
+
fan_1_ventilation: 3,
|
|
825
|
+
fan_2_ventilation: 0,
|
|
826
|
+
fan_3_ventilation: 0,
|
|
827
|
+
is_standby_active: false,
|
|
828
|
+
standby_waiting_time: 60,
|
|
829
|
+
},
|
|
830
|
+
total_counters: {
|
|
831
|
+
power_ons: 278,
|
|
832
|
+
p1_working_time: 833,
|
|
833
|
+
p2_working_time: 15,
|
|
834
|
+
p3_working_time: 19,
|
|
835
|
+
p4_working_time: 8,
|
|
836
|
+
p5_working_time: 17,
|
|
837
|
+
},
|
|
838
|
+
service_counters: {
|
|
839
|
+
p1_working_time: 100,
|
|
840
|
+
p2_working_time: 10,
|
|
841
|
+
p3_working_time: 5,
|
|
842
|
+
p4_working_time: 2,
|
|
843
|
+
p5_working_time: 1,
|
|
844
|
+
},
|
|
845
|
+
alarms_log: {
|
|
846
|
+
number: 2,
|
|
847
|
+
index: 2,
|
|
848
|
+
alarms: [
|
|
849
|
+
{ type: 3, timestamp: 1700000000 },
|
|
850
|
+
{ type: 21, timestamp: 1700001000 },
|
|
851
|
+
],
|
|
852
|
+
},
|
|
853
|
+
regeneration: {
|
|
854
|
+
time: 0,
|
|
855
|
+
last_intervention: 1577836800,
|
|
856
|
+
daylight_time_flag: 0,
|
|
857
|
+
blackout_counter: 43,
|
|
858
|
+
airkare_working_hours_counter: 0,
|
|
859
|
+
},
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
it("should get total counters", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
863
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
864
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
865
|
+
const result = yield api.getTotalCounters(expectedToken, "00:11:22:33:44:55");
|
|
866
|
+
assert_1.strict.deepEqual(result, mockDeviceInfoWithStats.nvm.total_counters);
|
|
867
|
+
}));
|
|
868
|
+
it("should get service counters", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
869
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
870
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
871
|
+
const result = yield api.getServiceCounters(expectedToken, "00:11:22:33:44:55");
|
|
872
|
+
assert_1.strict.deepEqual(result, mockDeviceInfoWithStats.nvm.service_counters);
|
|
873
|
+
}));
|
|
874
|
+
it("should get alarm history", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
875
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
876
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
877
|
+
const result = yield api.getAlarmHistory(expectedToken, "00:11:22:33:44:55");
|
|
878
|
+
assert_1.strict.deepEqual(result, mockDeviceInfoWithStats.nvm.alarms_log);
|
|
879
|
+
}));
|
|
880
|
+
it("should get regeneration data", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
881
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
882
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
883
|
+
const result = yield api.getRegenerationData(expectedToken, "00:11:22:33:44:55");
|
|
884
|
+
assert_1.strict.deepEqual(result, mockDeviceInfoWithStats.nvm.regeneration);
|
|
885
|
+
}));
|
|
886
|
+
it("should get service time", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
887
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
888
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
889
|
+
const result = yield api.getServiceTime(expectedToken, "00:11:22:33:44:55");
|
|
890
|
+
assert_1.strict.equal(result, 1108);
|
|
891
|
+
}));
|
|
892
|
+
});
|
|
893
|
+
describe("analytics functions", () => {
|
|
894
|
+
const mockDeviceInfoWithStats = {
|
|
895
|
+
status: {
|
|
896
|
+
commands: { power: true },
|
|
897
|
+
temperatures: { board: 25, enviroment: 20 },
|
|
898
|
+
flags: { is_pellet_in_reserve: false },
|
|
899
|
+
pellet: { autonomy_time: 900 },
|
|
900
|
+
counters: { service_time: 1108 },
|
|
901
|
+
},
|
|
902
|
+
nvm: {
|
|
903
|
+
user_parameters: {
|
|
904
|
+
language: 1,
|
|
905
|
+
is_auto: false,
|
|
906
|
+
is_fahrenheit: false,
|
|
907
|
+
is_sound_active: false,
|
|
908
|
+
enviroment_1_temperature: 19,
|
|
909
|
+
enviroment_2_temperature: 20,
|
|
910
|
+
enviroment_3_temperature: 20,
|
|
911
|
+
manual_power: 1,
|
|
912
|
+
fan_1_ventilation: 3,
|
|
913
|
+
fan_2_ventilation: 0,
|
|
914
|
+
fan_3_ventilation: 0,
|
|
915
|
+
is_standby_active: false,
|
|
916
|
+
standby_waiting_time: 60,
|
|
917
|
+
},
|
|
918
|
+
total_counters: {
|
|
919
|
+
power_ons: 278,
|
|
920
|
+
p1_working_time: 833,
|
|
921
|
+
p2_working_time: 15,
|
|
922
|
+
p3_working_time: 19,
|
|
923
|
+
p4_working_time: 8,
|
|
924
|
+
p5_working_time: 17,
|
|
925
|
+
},
|
|
926
|
+
service_counters: {
|
|
927
|
+
p1_working_time: 100,
|
|
928
|
+
p2_working_time: 10,
|
|
929
|
+
p3_working_time: 5,
|
|
930
|
+
p4_working_time: 2,
|
|
931
|
+
p5_working_time: 1,
|
|
932
|
+
},
|
|
933
|
+
alarms_log: {
|
|
934
|
+
number: 2,
|
|
935
|
+
index: 2,
|
|
936
|
+
alarms: [
|
|
937
|
+
{ type: 3, timestamp: 1700000000 },
|
|
938
|
+
{ type: 21, timestamp: 1700001000 },
|
|
939
|
+
],
|
|
940
|
+
},
|
|
941
|
+
regeneration: {
|
|
942
|
+
time: 0,
|
|
943
|
+
last_intervention: 1577836800,
|
|
944
|
+
daylight_time_flag: 0,
|
|
945
|
+
blackout_counter: 43,
|
|
946
|
+
airkare_working_hours_counter: 0,
|
|
947
|
+
},
|
|
948
|
+
},
|
|
949
|
+
};
|
|
950
|
+
it("should calculate total operating hours", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
951
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
952
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
953
|
+
const result = yield api.getTotalOperatingHours(expectedToken, "00:11:22:33:44:55");
|
|
954
|
+
// 833 + 15 + 19 + 8 + 17 = 892
|
|
955
|
+
assert_1.strict.equal(result, 892);
|
|
956
|
+
}));
|
|
957
|
+
it("should calculate power distribution percentages", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
958
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
959
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
960
|
+
const result = yield api.getPowerDistribution(expectedToken, "00:11:22:33:44:55");
|
|
961
|
+
// Total: 892 hours
|
|
962
|
+
assert_1.strict.ok(result.p1 > 90); // 833/892 = 93.4%
|
|
963
|
+
assert_1.strict.ok(result.p2 < 5); // 15/892 = 1.7%
|
|
964
|
+
// Sum should be ~100%
|
|
965
|
+
const sum = result.p1 + result.p2 + result.p3 + result.p4 + result.p5;
|
|
966
|
+
assert_1.strict.ok(Math.abs(sum - 100) < 0.1);
|
|
967
|
+
}));
|
|
968
|
+
it("should handle zero operating hours in power distribution", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
969
|
+
const zeroHoursInfo = Object.assign(Object.assign({}, mockDeviceInfoWithStats), { nvm: Object.assign(Object.assign({}, mockDeviceInfoWithStats.nvm), { total_counters: {
|
|
970
|
+
power_ons: 0,
|
|
971
|
+
p1_working_time: 0,
|
|
972
|
+
p2_working_time: 0,
|
|
973
|
+
p3_working_time: 0,
|
|
974
|
+
p4_working_time: 0,
|
|
975
|
+
p5_working_time: 0,
|
|
976
|
+
} }) });
|
|
977
|
+
fetchStub.resolves(mockResponse(zeroHoursInfo));
|
|
978
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
979
|
+
const result = yield api.getPowerDistribution(expectedToken, "00:11:22:33:44:55");
|
|
980
|
+
assert_1.strict.deepEqual(result, { p1: 0, p2: 0, p3: 0, p4: 0, p5: 0 });
|
|
981
|
+
}));
|
|
982
|
+
it("should calculate service status", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
983
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
984
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
985
|
+
const result = yield api.getServiceStatus(expectedToken, "00:11:22:33:44:55");
|
|
986
|
+
assert_1.strict.equal(result.totalServiceHours, 1108);
|
|
987
|
+
// 100 + 10 + 5 + 2 + 1 = 118 hours since service
|
|
988
|
+
assert_1.strict.equal(result.hoursSinceService, 118);
|
|
989
|
+
assert_1.strict.equal(result.isServiceDue, false); // 118 < 2000
|
|
990
|
+
}));
|
|
991
|
+
it("should indicate service is due when threshold exceeded", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
992
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
993
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
994
|
+
// Use threshold of 100 hours
|
|
995
|
+
const result = yield api.getServiceStatus(expectedToken, "00:11:22:33:44:55", 100);
|
|
996
|
+
assert_1.strict.equal(result.isServiceDue, true); // 118 >= 100
|
|
997
|
+
}));
|
|
998
|
+
it("should get comprehensive usage analytics", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
999
|
+
fetchStub.resolves(mockResponse(mockDeviceInfoWithStats));
|
|
1000
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
1001
|
+
const result = yield api.getUsageAnalytics(expectedToken, "00:11:22:33:44:55");
|
|
1002
|
+
assert_1.strict.equal(result.totalPowerOns, 278);
|
|
1003
|
+
assert_1.strict.equal(result.totalOperatingHours, 892);
|
|
1004
|
+
assert_1.strict.equal(result.blackoutCount, 43);
|
|
1005
|
+
assert_1.strict.equal(result.alarmCount, 2);
|
|
1006
|
+
assert_1.strict.ok(result.lastMaintenanceDate instanceof Date);
|
|
1007
|
+
assert_1.strict.equal(result.serviceStatus.isServiceDue, false);
|
|
1008
|
+
}));
|
|
1009
|
+
it("should handle null lastMaintenanceDate when timestamp is 0", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1010
|
+
const noMaintenanceInfo = Object.assign(Object.assign({}, mockDeviceInfoWithStats), { nvm: Object.assign(Object.assign({}, mockDeviceInfoWithStats.nvm), { regeneration: Object.assign(Object.assign({}, mockDeviceInfoWithStats.nvm.regeneration), { last_intervention: 0 }) }) });
|
|
1011
|
+
fetchStub.resolves(mockResponse(noMaintenanceInfo));
|
|
1012
|
+
const api = (0, library_1.configure)(constants_1.API_URL);
|
|
1013
|
+
const result = yield api.getUsageAnalytics(expectedToken, "00:11:22:33:44:55");
|
|
1014
|
+
assert_1.strict.equal(result.lastMaintenanceDate, null);
|
|
1015
|
+
}));
|
|
1016
|
+
});
|
|
794
1017
|
describe("Error Handling", () => {
|
|
795
1018
|
const errorTests = [
|
|
796
1019
|
{ status: 400, statusText: "Bad Request" },
|