@homebridge-eufy-security/eufy-security-client 3.7.2-dev.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/.prettierignore/342/200/216 +8 -0
- package/.prettierrc +11 -0
- package/LICENSE +21 -0
- package/README.md +970 -0
- package/build/error.d.ts +138 -0
- package/build/error.js +190 -0
- package/build/error.js.map +1 -0
- package/build/eufysecurity.d.ts +180 -0
- package/build/eufysecurity.js +3148 -0
- package/build/eufysecurity.js.map +1 -0
- package/build/http/api.d.ts +119 -0
- package/build/http/api.js +1877 -0
- package/build/http/api.js.map +1 -0
- package/build/http/cache.d.ts +8 -0
- package/build/http/cache.js +34 -0
- package/build/http/cache.js.map +1 -0
- package/build/http/const.d.ts +8 -0
- package/build/http/const.js +3054 -0
- package/build/http/const.js.map +1 -0
- package/build/http/device.d.ts +490 -0
- package/build/http/device.js +5256 -0
- package/build/http/device.js.map +1 -0
- package/build/http/error.d.ts +73 -0
- package/build/http/error.js +101 -0
- package/build/http/error.js.map +1 -0
- package/build/http/index.d.ts +10 -0
- package/build/http/index.js +30 -0
- package/build/http/index.js.map +1 -0
- package/build/http/interfaces.d.ts +248 -0
- package/build/http/interfaces.js +3 -0
- package/build/http/interfaces.js.map +1 -0
- package/build/http/models.d.ts +608 -0
- package/build/http/models.js +3 -0
- package/build/http/models.js.map +1 -0
- package/build/http/parameter.d.ts +7 -0
- package/build/http/parameter.js +119 -0
- package/build/http/parameter.js.map +1 -0
- package/build/http/station.d.ts +382 -0
- package/build/http/station.js +15735 -0
- package/build/http/station.js.map +1 -0
- package/build/http/types.d.ts +1358 -0
- package/build/http/types.js +10333 -0
- package/build/http/types.js.map +1 -0
- package/build/http/utils.d.ts +89 -0
- package/build/http/utils.js +916 -0
- package/build/http/utils.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.js +29 -0
- package/build/index.js.map +1 -0
- package/build/interfaces.d.ts +147 -0
- package/build/interfaces.js +7 -0
- package/build/interfaces.js.map +1 -0
- package/build/logging.d.ts +36 -0
- package/build/logging.js +119 -0
- package/build/logging.js.map +1 -0
- package/build/mqtt/interface.d.ts +6 -0
- package/build/mqtt/interface.js +3 -0
- package/build/mqtt/interface.js.map +1 -0
- package/build/mqtt/model.d.ts +24 -0
- package/build/mqtt/model.js +3 -0
- package/build/mqtt/model.js.map +1 -0
- package/build/mqtt/mqtt-eufy.crt +79 -0
- package/build/mqtt/proto/lock.proto +33 -0
- package/build/mqtt/service.d.ts +28 -0
- package/build/mqtt/service.js +196 -0
- package/build/mqtt/service.js.map +1 -0
- package/build/p2p/ble.d.ts +59 -0
- package/build/p2p/ble.js +281 -0
- package/build/p2p/ble.js.map +1 -0
- package/build/p2p/error.d.ts +49 -0
- package/build/p2p/error.js +69 -0
- package/build/p2p/error.js.map +1 -0
- package/build/p2p/index.d.ts +8 -0
- package/build/p2p/index.js +28 -0
- package/build/p2p/index.js.map +1 -0
- package/build/p2p/interfaces.d.ts +423 -0
- package/build/p2p/interfaces.js +3 -0
- package/build/p2p/interfaces.js.map +1 -0
- package/build/p2p/models.d.ts +295 -0
- package/build/p2p/models.js +3 -0
- package/build/p2p/models.js.map +1 -0
- package/build/p2p/session.d.ts +186 -0
- package/build/p2p/session.js +3737 -0
- package/build/p2p/session.js.map +1 -0
- package/build/p2p/talkback.d.ts +8 -0
- package/build/p2p/talkback.js +23 -0
- package/build/p2p/talkback.js.map +1 -0
- package/build/p2p/types.d.ts +1164 -0
- package/build/p2p/types.js +1219 -0
- package/build/p2p/types.js.map +1 -0
- package/build/p2p/utils.d.ts +72 -0
- package/build/p2p/utils.js +865 -0
- package/build/p2p/utils.js.map +1 -0
- package/build/push/client.d.ts +49 -0
- package/build/push/client.js +344 -0
- package/build/push/client.js.map +1 -0
- package/build/push/error.d.ts +73 -0
- package/build/push/error.js +101 -0
- package/build/push/error.js.map +1 -0
- package/build/push/index.d.ts +6 -0
- package/build/push/index.js +26 -0
- package/build/push/index.js.map +1 -0
- package/build/push/interfaces.d.ts +19 -0
- package/build/push/interfaces.js +3 -0
- package/build/push/interfaces.js.map +1 -0
- package/build/push/models.d.ts +328 -0
- package/build/push/models.js +38 -0
- package/build/push/models.js.map +1 -0
- package/build/push/parser.d.ts +25 -0
- package/build/push/parser.js +231 -0
- package/build/push/parser.js.map +1 -0
- package/build/push/proto/checkin.proto +266 -0
- package/build/push/proto/mcs.proto +328 -0
- package/build/push/service.d.ts +46 -0
- package/build/push/service.js +965 -0
- package/build/push/service.js.map +1 -0
- package/build/push/types.d.ts +220 -0
- package/build/push/types.js +244 -0
- package/build/push/types.js.map +1 -0
- package/build/push/utils.d.ts +7 -0
- package/build/push/utils.js +116 -0
- package/build/push/utils.js.map +1 -0
- package/build/utils.d.ts +115 -0
- package/build/utils.js +438 -0
- package/build/utils.js.map +1 -0
- package/eslint.config.mts +68 -0
- package/jest.config.js +14 -0
- package/package.json +85 -0
- package/scripts/cut_release.sh +31 -0
|
@@ -0,0 +1,916 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getWaitSeconds = exports.isSmartLockNotification = exports.switchSmartLockNotification = exports.getLockEventType = exports.getFloodLightT8425Notification = exports.isFloodlightT8425NotificationEnabled = exports.getIndoorNotification = exports.isIndoorNotificationEnabled = exports.getIndoorS350DetectionMode = exports.isIndoorS350DetectionModeEnabled = exports.getT8110DetectionMode = exports.isT8110DetectionModeEnabled = exports.getT8170DetectionMode = exports.isT8170DetectionModeEnabled = exports.decryptTrackerData = exports.isPrioritySourceType = exports.getImage = exports.getImagePath = exports.decodeImage = exports.getImageKey = exports.getImageSeed = exports.getImageBaseCode = exports.getIdSuffix = exports.randomNumber = exports.hexStringScheduleToSchedule = exports.hexWeek = exports.hexTime = exports.hexDate = exports.encodePasscode = exports.ParsePayload = exports.WritePayload = exports.getAdvancedLockTimezone = exports.getEufyTimezone = exports.getHB3DetectionMode = exports.isHB3DetectionModeEnabled = exports.isDeliveryPackageType = exports.getDistances = exports.getBlocklist = exports.decryptAPIData = exports.encryptAPIData = exports.calculateCellularSignalLevel = exports.calculateWifiSignalLevel = exports.switchNotificationMode = exports.isNotificationSwitchMode = exports.getImageFilePath = exports.getAbsoluteFilePath = exports.getTimezoneGMTString = exports.pad = exports.isGreaterEqualMinVersion = exports.normalizeVersionString = void 0;
|
|
7
|
+
exports.getRandomPhoneModel = exports.loadEventImage = exports.loadImageOverP2P = void 0;
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
9
|
+
const const_1 = require("./const");
|
|
10
|
+
const md5_1 = __importDefault(require("crypto-js/md5"));
|
|
11
|
+
const enc_hex_1 = __importDefault(require("crypto-js/enc-hex"));
|
|
12
|
+
const sha256_1 = __importDefault(require("crypto-js/sha256"));
|
|
13
|
+
const types_1 = require("./types");
|
|
14
|
+
const error_1 = require("../error");
|
|
15
|
+
const error_2 = require("./error");
|
|
16
|
+
const types_2 = require("./../push/types");
|
|
17
|
+
const logging_1 = require("../logging");
|
|
18
|
+
const utils_1 = require("../utils");
|
|
19
|
+
const normalizeVersionString = function (version) {
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* Normalise version strings into an array of integers, otherwise if a version was not found it returns null
|
|
23
|
+
* Example of a version is 1.4.30.33
|
|
24
|
+
*
|
|
25
|
+
* @param version
|
|
26
|
+
*/
|
|
27
|
+
const match = version.match(/\d+(?:\.\d+)+/);
|
|
28
|
+
if (match == null)
|
|
29
|
+
return null;
|
|
30
|
+
else {
|
|
31
|
+
return match[0].split(".").map(Number);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
exports.normalizeVersionString = normalizeVersionString;
|
|
35
|
+
const isGreaterEqualMinVersion = function (minimal_version, current_version) {
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* Test the minimal version set is working with the current version by return true if it is equal or greater than min version.
|
|
39
|
+
*
|
|
40
|
+
* @param minimal_version
|
|
41
|
+
* @param current_version
|
|
42
|
+
*/
|
|
43
|
+
const min_version = (0, exports.normalizeVersionString)(minimal_version);
|
|
44
|
+
const actual_version = (0, exports.normalizeVersionString)(current_version);
|
|
45
|
+
// Failed to parse actually version
|
|
46
|
+
if (actual_version === null)
|
|
47
|
+
return false;
|
|
48
|
+
// Failed to a parse min version but the current did, so we assume it is greater
|
|
49
|
+
if (min_version === null)
|
|
50
|
+
return true;
|
|
51
|
+
const version_slots = Math.min(min_version.length, actual_version.length);
|
|
52
|
+
let i;
|
|
53
|
+
// Loop for each slot to ensure it is greater or equal
|
|
54
|
+
for (i = 0; i < version_slots; i += 1) {
|
|
55
|
+
if (min_version[i] !== actual_version[i]) {
|
|
56
|
+
return min_version[i] < actual_version[i];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// If none of the slots are different but the length is the same, it is most likely the slots are the same
|
|
60
|
+
if (min_version.length === actual_version.length) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return min_version.length < actual_version.length;
|
|
64
|
+
};
|
|
65
|
+
exports.isGreaterEqualMinVersion = isGreaterEqualMinVersion;
|
|
66
|
+
const pad = function (num) {
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
* Convert the number to be absolute, round down and return "0" if lower than 10 or "" otherwise
|
|
70
|
+
* Seems to be used in a scenario where need to add a zero decimal to format a 2 digit string
|
|
71
|
+
*
|
|
72
|
+
* @param num
|
|
73
|
+
*/
|
|
74
|
+
const norm = Math.floor(Math.abs(num));
|
|
75
|
+
return (norm < 10 ? "0" : "") + norm;
|
|
76
|
+
};
|
|
77
|
+
exports.pad = pad;
|
|
78
|
+
const getTimezoneGMTString = function () {
|
|
79
|
+
/**
|
|
80
|
+
* Get timezone to string
|
|
81
|
+
*
|
|
82
|
+
*/
|
|
83
|
+
const tzo = -new Date().getTimezoneOffset();
|
|
84
|
+
const dif = tzo >= 0 ? "+" : "-";
|
|
85
|
+
return `GMT${dif}${(0, exports.pad)(tzo / 60)}:${(0, exports.pad)(tzo % 60)}`;
|
|
86
|
+
};
|
|
87
|
+
exports.getTimezoneGMTString = getTimezoneGMTString;
|
|
88
|
+
const getAbsoluteFilePath = function (device_type, channel, filename) {
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
* Create the path based on two different devices
|
|
92
|
+
*
|
|
93
|
+
* @param device_type
|
|
94
|
+
* @param channel
|
|
95
|
+
* @param filename
|
|
96
|
+
*/
|
|
97
|
+
// TODO : might need to extend to others device with local storage? not sure why only floodlight
|
|
98
|
+
const prefix = device_type === types_1.DeviceType.FLOODLIGHT ? const_1.PATH_DATA_CAMERA : const_1.PATH_MMC_CAMERA;
|
|
99
|
+
return `${prefix}${String(channel).padStart(2, "0")}/${filename}.dat`;
|
|
100
|
+
};
|
|
101
|
+
exports.getAbsoluteFilePath = getAbsoluteFilePath;
|
|
102
|
+
const getImageFilePath = function (device_type, channel, filename) {
|
|
103
|
+
/**
|
|
104
|
+
*
|
|
105
|
+
* Create the image path from a video filename
|
|
106
|
+
*
|
|
107
|
+
* @param device_type
|
|
108
|
+
* @param channel
|
|
109
|
+
* @param filename
|
|
110
|
+
*/
|
|
111
|
+
// TODO : might need to extend to others device with local storage? not sure why only floodlight
|
|
112
|
+
const prefix = device_type === types_1.DeviceType.FLOODLIGHT ? const_1.PATH_DATA_VIDEO : const_1.PATH_MMC_VIDEO;
|
|
113
|
+
return `${prefix}/${filename}_c${String(channel).padStart(2, "0")}.jpg`;
|
|
114
|
+
};
|
|
115
|
+
exports.getImageFilePath = getImageFilePath;
|
|
116
|
+
const isNotificationSwitchMode = function (value, mode) {
|
|
117
|
+
/**
|
|
118
|
+
*
|
|
119
|
+
* Check if the mode is set to notification
|
|
120
|
+
*
|
|
121
|
+
* @param value
|
|
122
|
+
* @param mode
|
|
123
|
+
*/
|
|
124
|
+
if (value === 1)
|
|
125
|
+
value = 240;
|
|
126
|
+
return (value & mode) !== 0;
|
|
127
|
+
};
|
|
128
|
+
exports.isNotificationSwitchMode = isNotificationSwitchMode;
|
|
129
|
+
const switchNotificationMode = function (currentValue, mode, enable) {
|
|
130
|
+
let result = 0;
|
|
131
|
+
if (!enable && currentValue === 1 /* ALL */) {
|
|
132
|
+
currentValue = 240;
|
|
133
|
+
}
|
|
134
|
+
if (enable) {
|
|
135
|
+
result = mode | currentValue;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
result = ~mode & currentValue;
|
|
139
|
+
}
|
|
140
|
+
if ((0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.SCHEDULE) &&
|
|
141
|
+
(0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.APP) &&
|
|
142
|
+
(0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.GEOFENCE) &&
|
|
143
|
+
(0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.KEYPAD)) {
|
|
144
|
+
result = 1; /* ALL */
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
};
|
|
148
|
+
exports.switchNotificationMode = switchNotificationMode;
|
|
149
|
+
// TODO : remove device , not needed
|
|
150
|
+
const calculateWifiSignalLevel = function (device, rssi) {
|
|
151
|
+
/**
|
|
152
|
+
* Calculate the signal strength based on the RSSI
|
|
153
|
+
*
|
|
154
|
+
* Using this scale for reference
|
|
155
|
+
* Excellent/Very Strong (-30 dBm to -50 dBm)
|
|
156
|
+
* Good/Strong (-50 dBm to -60 dBm)
|
|
157
|
+
* Fair/Good (-60 dBm to -67 dBm)
|
|
158
|
+
* Weak/Fair (-67 dBm to -70 dBm)
|
|
159
|
+
* Very Weak/Poor (-70 dBm to -80 dBm)
|
|
160
|
+
* Unusable (-80 dBm to -90 dBm or lower)
|
|
161
|
+
*
|
|
162
|
+
*/
|
|
163
|
+
if (rssi >= -50)
|
|
164
|
+
return types_1.SignalLevel.FULL;
|
|
165
|
+
else if (rssi < -50 && rssi >= -60)
|
|
166
|
+
return types_1.SignalLevel.STRONG;
|
|
167
|
+
else if (rssi < -60 && rssi >= -67)
|
|
168
|
+
return types_1.SignalLevel.NORMAL;
|
|
169
|
+
else if (rssi < -67 && rssi >= -80)
|
|
170
|
+
return types_1.SignalLevel.WEAK;
|
|
171
|
+
else
|
|
172
|
+
return types_1.SignalLevel.NO_SIGNAL;
|
|
173
|
+
};
|
|
174
|
+
exports.calculateWifiSignalLevel = calculateWifiSignalLevel;
|
|
175
|
+
const calculateCellularSignalLevel = function (rssi) {
|
|
176
|
+
/**
|
|
177
|
+
* Calculate the signal strength from the RSSI ( this has a different scale than wifi )
|
|
178
|
+
*
|
|
179
|
+
* Excellent (>-65 to -70 dBm)
|
|
180
|
+
* Good (-70 to -85 dBm)
|
|
181
|
+
* Fair (-85 to -95 dBm)
|
|
182
|
+
* Poor (-95 to -100 dBm)
|
|
183
|
+
* Unusable/No Signal (<-100 to -110 dBm)
|
|
184
|
+
*
|
|
185
|
+
*/
|
|
186
|
+
if (rssi >= 0)
|
|
187
|
+
return types_1.SignalLevel.NO_SIGNAL;
|
|
188
|
+
if (rssi >= -70)
|
|
189
|
+
return types_1.SignalLevel.FULL;
|
|
190
|
+
else if (rssi < -70 && rssi >= -85)
|
|
191
|
+
return types_1.SignalLevel.STRONG;
|
|
192
|
+
else if (rssi < -85 && rssi >= -95)
|
|
193
|
+
return types_1.SignalLevel.NORMAL;
|
|
194
|
+
else if (rssi < -95 && rssi >= -100)
|
|
195
|
+
return types_1.SignalLevel.WEAK;
|
|
196
|
+
else
|
|
197
|
+
return types_1.SignalLevel.NO_SIGNAL;
|
|
198
|
+
};
|
|
199
|
+
exports.calculateCellularSignalLevel = calculateCellularSignalLevel;
|
|
200
|
+
const encryptAPIData = (data, key) => {
|
|
201
|
+
const cipher = (0, crypto_1.createCipheriv)("aes-256-cbc", key, key.subarray(0, 16));
|
|
202
|
+
return cipher.update(data, "utf8", "base64") + cipher.final("base64");
|
|
203
|
+
};
|
|
204
|
+
exports.encryptAPIData = encryptAPIData;
|
|
205
|
+
const decryptAPIData = (data, key) => {
|
|
206
|
+
const cipher = (0, crypto_1.createDecipheriv)("aes-256-cbc", key, key.subarray(0, 16));
|
|
207
|
+
return Buffer.concat([cipher.update(data, "base64"), cipher.final()]);
|
|
208
|
+
};
|
|
209
|
+
exports.decryptAPIData = decryptAPIData;
|
|
210
|
+
const getBlocklist = function (distanceArray) {
|
|
211
|
+
/**
|
|
212
|
+
* It looks like it taken from the decompiled app from Eufy in the file SimpleDetectionGroup.java
|
|
213
|
+
*
|
|
214
|
+
* From asking, AI, this function it creates a bitmask representing which radar points meet that distance requirement.
|
|
215
|
+
* Finally, it applies a specific bitwise transformation to that mask.
|
|
216
|
+
*
|
|
217
|
+
* Potential description: Generates radar configuration parameters based on distance thresholds.
|
|
218
|
+
*
|
|
219
|
+
* * @param {number[]} distanceArray - An array of integers representing distances.
|
|
220
|
+
* * @returns {number[]} A list of 5 bitmask integers.
|
|
221
|
+
*/
|
|
222
|
+
const requestParams = [];
|
|
223
|
+
for (let threshold = 1; threshold <= 5; threshold++) {
|
|
224
|
+
let bitmask = 0;
|
|
225
|
+
let bitPosition = 1;
|
|
226
|
+
// Iterate through each distance in the array
|
|
227
|
+
for (const distance of distanceArray) {
|
|
228
|
+
if (distance >= threshold) {
|
|
229
|
+
bitmask |= bitPosition;
|
|
230
|
+
}
|
|
231
|
+
// Shift bitPosition left by 1 (multiply by 2)
|
|
232
|
+
bitPosition <<= 1;
|
|
233
|
+
}
|
|
234
|
+
let finalValue = 0;
|
|
235
|
+
// Logic for specific bit patterns
|
|
236
|
+
if (bitmask === 0) {
|
|
237
|
+
finalValue = 0xffff; // 65535
|
|
238
|
+
}
|
|
239
|
+
else if (bitmask !== 0xff && bitmask !== 0xffff) {
|
|
240
|
+
// Flip the bits and add the 0xFF00 (65280) high-byte padding
|
|
241
|
+
finalValue = (bitmask ^ 0xff) + 0xff00;
|
|
242
|
+
}
|
|
243
|
+
requestParams.push(finalValue);
|
|
244
|
+
}
|
|
245
|
+
return requestParams;
|
|
246
|
+
};
|
|
247
|
+
exports.getBlocklist = getBlocklist;
|
|
248
|
+
const getDistances = function (rawDistanceData) {
|
|
249
|
+
/**
|
|
250
|
+
* It looks like it taken from the decompiled app from Eufy in the file SimpleDetectionGroup.java
|
|
251
|
+
*
|
|
252
|
+
* From asking AI:
|
|
253
|
+
* Processes raw radar sensor data to map object detections into spatial sectors.
|
|
254
|
+
* This method iterates through a list of distance data, where each element represents
|
|
255
|
+
* a depth level and its bits represent angular sectors. It inverts the bitmask,
|
|
256
|
+
* identifies active detections via bit-shifting, and updates a collection of
|
|
257
|
+
* RadarSelectInfo objects with the corresponding angle and proximity distance.
|
|
258
|
+
*
|
|
259
|
+
* @param rawDistanceData A list of integers where each bit represents a detection
|
|
260
|
+
* at a specific angle, and the list index represents depth.
|
|
261
|
+
*/
|
|
262
|
+
const radarSectors = [3, 3, 3, 3, 3, 3, 3, 3];
|
|
263
|
+
let distanceStep = 0;
|
|
264
|
+
for (const rawValue of rawDistanceData) {
|
|
265
|
+
// Bitwise NOT/XOR to invert the signal (common in hardware where 0=detected)
|
|
266
|
+
let invertedBits = rawValue ^ 65535;
|
|
267
|
+
distanceStep++;
|
|
268
|
+
if (invertedBits !== 0) {
|
|
269
|
+
for (let i = 0; i < radarSectors.length; i++) {
|
|
270
|
+
const isObjectDetected = invertedBits & 1; // Check if the lowest bit is set
|
|
271
|
+
// If the bit was 1, mark this sector with the current distance
|
|
272
|
+
if (isObjectDetected > 0) {
|
|
273
|
+
radarSectors[i] = distanceStep;
|
|
274
|
+
}
|
|
275
|
+
// Shift bits to check the next angle in the next iteration
|
|
276
|
+
invertedBits = invertedBits >> 1;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return radarSectors;
|
|
281
|
+
};
|
|
282
|
+
exports.getDistances = getDistances;
|
|
283
|
+
const isDeliveryPackageType = function (value) {
|
|
284
|
+
/**
|
|
285
|
+
* Seems to be coming from EventData.java
|
|
286
|
+
*
|
|
287
|
+
*/
|
|
288
|
+
return (value & 65536) == 65536;
|
|
289
|
+
};
|
|
290
|
+
exports.isDeliveryPackageType = isDeliveryPackageType;
|
|
291
|
+
const isHB3DetectionModeEnabled = function (value, type) {
|
|
292
|
+
/**
|
|
293
|
+
* Detection if Mode is enabled
|
|
294
|
+
*
|
|
295
|
+
*/
|
|
296
|
+
const prefixCode = (type & value) == type;
|
|
297
|
+
if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
|
|
298
|
+
return prefixCode && (0, exports.isDeliveryPackageType)(value);
|
|
299
|
+
}
|
|
300
|
+
else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
|
|
301
|
+
return prefixCode && (value & 1) == 1;
|
|
302
|
+
}
|
|
303
|
+
return prefixCode;
|
|
304
|
+
};
|
|
305
|
+
exports.isHB3DetectionModeEnabled = isHB3DetectionModeEnabled;
|
|
306
|
+
const getHB3DetectionMode = function (value, type, enable) {
|
|
307
|
+
let result = 0;
|
|
308
|
+
if (!enable) {
|
|
309
|
+
if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
|
|
310
|
+
const tmp = (type & value) == type ? type ^ value : value;
|
|
311
|
+
result = (0, exports.isDeliveryPackageType)(value) ? tmp ^ 65536 : tmp;
|
|
312
|
+
}
|
|
313
|
+
else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
|
|
314
|
+
const tmp = (type & value) == type ? type ^ value : value;
|
|
315
|
+
result = (value & 1) == 1 ? tmp ^ 1 : tmp;
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
result = type ^ value;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
|
|
323
|
+
result = type | value | 65536;
|
|
324
|
+
}
|
|
325
|
+
else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
|
|
326
|
+
result = type | value | 1;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
result = type | value;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
};
|
|
334
|
+
exports.getHB3DetectionMode = getHB3DetectionMode;
|
|
335
|
+
const getEufyTimezone = function () {
|
|
336
|
+
for (const timezone of const_1.timeZoneData) {
|
|
337
|
+
if (timezone.timeId === Intl.DateTimeFormat().resolvedOptions().timeZone) {
|
|
338
|
+
return timezone;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return undefined;
|
|
342
|
+
};
|
|
343
|
+
exports.getEufyTimezone = getEufyTimezone;
|
|
344
|
+
const getAdvancedLockTimezone = function (stationSN) {
|
|
345
|
+
const timezone = (0, exports.getEufyTimezone)();
|
|
346
|
+
if (timezone !== undefined) {
|
|
347
|
+
// TODO: make this a method to check whatever we need to check for the station
|
|
348
|
+
if (stationSN.startsWith("T8520") && (0, exports.isGreaterEqualMinVersion)("1.2.8.6", stationSN))
|
|
349
|
+
return `${timezone.timeZoneGMT}|1.${timezone.timeSn}`;
|
|
350
|
+
else
|
|
351
|
+
return timezone.timeZoneGMT;
|
|
352
|
+
}
|
|
353
|
+
return "";
|
|
354
|
+
};
|
|
355
|
+
exports.getAdvancedLockTimezone = getAdvancedLockTimezone;
|
|
356
|
+
class WritePayload {
|
|
357
|
+
split_byte = -95;
|
|
358
|
+
data = Buffer.from([]);
|
|
359
|
+
write(bytes) {
|
|
360
|
+
const tmp_data = Buffer.from(bytes);
|
|
361
|
+
this.data = Buffer.concat([
|
|
362
|
+
this.data,
|
|
363
|
+
Buffer.from([this.split_byte]),
|
|
364
|
+
Buffer.from([tmp_data.length & 255]),
|
|
365
|
+
tmp_data,
|
|
366
|
+
]);
|
|
367
|
+
this.split_byte += 1;
|
|
368
|
+
}
|
|
369
|
+
getData() {
|
|
370
|
+
return this.data;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
exports.WritePayload = WritePayload;
|
|
374
|
+
class ParsePayload {
|
|
375
|
+
/**
|
|
376
|
+
* extract specific pieces of data from a binary buffer
|
|
377
|
+
*
|
|
378
|
+
* @private
|
|
379
|
+
*/
|
|
380
|
+
data;
|
|
381
|
+
constructor(data) {
|
|
382
|
+
this.data = data;
|
|
383
|
+
}
|
|
384
|
+
readUint32BE(indexValue) {
|
|
385
|
+
return this.readData(indexValue).readUint32BE();
|
|
386
|
+
}
|
|
387
|
+
readUint32LE(indexValue) {
|
|
388
|
+
return this.readData(indexValue).readUint32LE();
|
|
389
|
+
}
|
|
390
|
+
readUint16BE(indexValue) {
|
|
391
|
+
return this.readData(indexValue).readUint16BE();
|
|
392
|
+
}
|
|
393
|
+
readUint16LE(indexValue) {
|
|
394
|
+
return this.readData(indexValue).readUint16LE();
|
|
395
|
+
}
|
|
396
|
+
readString(indexValue) {
|
|
397
|
+
return this.readData(indexValue).toString();
|
|
398
|
+
}
|
|
399
|
+
readStringHex(indexValue) {
|
|
400
|
+
return this.readData(indexValue).toString("hex");
|
|
401
|
+
}
|
|
402
|
+
readInt8(indexValue) {
|
|
403
|
+
let dataPosition = this.getDataPosition(indexValue);
|
|
404
|
+
if (dataPosition == -1) {
|
|
405
|
+
return 0;
|
|
406
|
+
}
|
|
407
|
+
dataPosition = dataPosition + 2;
|
|
408
|
+
if (dataPosition >= this.data.length) {
|
|
409
|
+
return 0;
|
|
410
|
+
}
|
|
411
|
+
return this.data.readInt8(dataPosition);
|
|
412
|
+
}
|
|
413
|
+
readData(indexValue) {
|
|
414
|
+
let dataPosition = this.getDataPosition(indexValue);
|
|
415
|
+
if (dataPosition == -1) {
|
|
416
|
+
return Buffer.from("");
|
|
417
|
+
}
|
|
418
|
+
dataPosition++;
|
|
419
|
+
if (dataPosition >= this.data.length) {
|
|
420
|
+
return Buffer.from("");
|
|
421
|
+
}
|
|
422
|
+
const nextStep = this.getNextStep(indexValue, dataPosition, this.data);
|
|
423
|
+
let tmp;
|
|
424
|
+
if (nextStep == 1) {
|
|
425
|
+
tmp = this.data.readInt8(dataPosition);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
tmp = this.data.readUint16LE(dataPosition);
|
|
429
|
+
}
|
|
430
|
+
if (dataPosition + nextStep + tmp > this.data.length) {
|
|
431
|
+
return Buffer.from("");
|
|
432
|
+
}
|
|
433
|
+
return this.data.subarray(dataPosition + nextStep, dataPosition + nextStep + tmp);
|
|
434
|
+
}
|
|
435
|
+
getDataPosition(indexValue) {
|
|
436
|
+
if (this.data && this.data.length >= 1) {
|
|
437
|
+
for (let currentPosition = 0; currentPosition < this.data.length;) {
|
|
438
|
+
if (this.data.readInt8(currentPosition) == indexValue) {
|
|
439
|
+
return currentPosition;
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
const value = this.data.readInt8(currentPosition);
|
|
443
|
+
currentPosition++;
|
|
444
|
+
if (currentPosition >= this.data.length) {
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
const nextStep = this.getNextStep(value, currentPosition, this.data);
|
|
448
|
+
if (currentPosition + nextStep >= this.data.length) {
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
if (nextStep == 1) {
|
|
452
|
+
currentPosition = this.data.readInt8(currentPosition) + currentPosition + nextStep;
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
currentPosition = this.data.readUint16LE(currentPosition) + currentPosition + nextStep;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return -1;
|
|
461
|
+
}
|
|
462
|
+
getNextStep(indexValue, position, data) {
|
|
463
|
+
const newPosition = position + 1 + data.readUInt8(position);
|
|
464
|
+
return newPosition == data.length || newPosition > data.length || data.readInt8(newPosition) == indexValue + 1
|
|
465
|
+
? 1
|
|
466
|
+
: 2;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
exports.ParsePayload = ParsePayload;
|
|
470
|
+
const encodePasscode = function (pass) {
|
|
471
|
+
/**
|
|
472
|
+
* Encode the passcode for smart lock
|
|
473
|
+
*
|
|
474
|
+
*/
|
|
475
|
+
let result = "";
|
|
476
|
+
for (let i = 0; i < pass.length; i++)
|
|
477
|
+
result += pass.charCodeAt(i).toString(16);
|
|
478
|
+
return result;
|
|
479
|
+
};
|
|
480
|
+
exports.encodePasscode = encodePasscode;
|
|
481
|
+
const hexDate = function (date) {
|
|
482
|
+
const buf = Buffer.allocUnsafe(4);
|
|
483
|
+
buf.writeUint8(date.getDate());
|
|
484
|
+
buf.writeUint8(date.getMonth() + 1, 1);
|
|
485
|
+
buf.writeUint16BE(date.getFullYear(), 2);
|
|
486
|
+
return buf.readUInt32LE().toString(16).padStart(8, "0");
|
|
487
|
+
};
|
|
488
|
+
exports.hexDate = hexDate;
|
|
489
|
+
const hexTime = function (date) {
|
|
490
|
+
const buf = Buffer.allocUnsafe(2);
|
|
491
|
+
buf.writeUint8(date.getHours());
|
|
492
|
+
buf.writeUint8(date.getMinutes(), 1);
|
|
493
|
+
return buf.readUInt16BE().toString(16).padStart(4, "0");
|
|
494
|
+
};
|
|
495
|
+
exports.hexTime = hexTime;
|
|
496
|
+
const hexWeek = function (schedule) {
|
|
497
|
+
const SUNDAY = 1;
|
|
498
|
+
const MONDAY = 2;
|
|
499
|
+
const TUESDAY = 4;
|
|
500
|
+
const WEDNESDAY = 8;
|
|
501
|
+
const THURSDAY = 16;
|
|
502
|
+
const FRIDAY = 32;
|
|
503
|
+
const SATURDAY = 64;
|
|
504
|
+
let result = 0;
|
|
505
|
+
if (schedule.week !== undefined) {
|
|
506
|
+
if (schedule.week.sunday) {
|
|
507
|
+
result |= SUNDAY;
|
|
508
|
+
}
|
|
509
|
+
if (schedule.week.monday) {
|
|
510
|
+
result |= MONDAY;
|
|
511
|
+
}
|
|
512
|
+
if (schedule.week.tuesday) {
|
|
513
|
+
result |= TUESDAY;
|
|
514
|
+
}
|
|
515
|
+
if (schedule.week.wednesday) {
|
|
516
|
+
result |= WEDNESDAY;
|
|
517
|
+
}
|
|
518
|
+
if (schedule.week.thursday) {
|
|
519
|
+
result |= THURSDAY;
|
|
520
|
+
}
|
|
521
|
+
if (schedule.week.friday) {
|
|
522
|
+
result |= FRIDAY;
|
|
523
|
+
}
|
|
524
|
+
if (schedule.week.saturday) {
|
|
525
|
+
result |= SATURDAY;
|
|
526
|
+
}
|
|
527
|
+
return result.toString(16);
|
|
528
|
+
}
|
|
529
|
+
return "ff";
|
|
530
|
+
};
|
|
531
|
+
exports.hexWeek = hexWeek;
|
|
532
|
+
const hexStringScheduleToSchedule = function (startDay, startTime, endDay, endTime, week) {
|
|
533
|
+
const SUNDAY = 1;
|
|
534
|
+
const MONDAY = 2;
|
|
535
|
+
const TUESDAY = 4;
|
|
536
|
+
const WEDNESDAY = 8;
|
|
537
|
+
const THURSDAY = 16;
|
|
538
|
+
const FRIDAY = 32;
|
|
539
|
+
const SATURDAY = 64;
|
|
540
|
+
const weekNumber = Number.parseInt(week, 16);
|
|
541
|
+
return {
|
|
542
|
+
startDateTime: startDay === "00000000"
|
|
543
|
+
? undefined
|
|
544
|
+
: new Date(Number.parseInt(`${startDay.substring(2, 4)}${startDay.substring(0, 2)}`, 16), Number.parseInt(startDay.substring(4, 6), 16) - 1, Number.parseInt(startDay.substring(6, 8), 16), Number.parseInt(startTime.substring(0, 2), 16), Number.parseInt(startTime.substring(2, 4), 16)),
|
|
545
|
+
endDateTime: endDay === "ffffffff"
|
|
546
|
+
? undefined
|
|
547
|
+
: new Date(Number.parseInt(`${endDay.substring(2, 4)}${endDay.substring(0, 2)}`, 16), Number.parseInt(endDay.substring(4, 6), 16) - 1, Number.parseInt(endDay.substring(6, 8), 16), Number.parseInt(endTime.substring(0, 2), 16), Number.parseInt(endTime.substring(2, 4), 16)),
|
|
548
|
+
week: {
|
|
549
|
+
monday: (weekNumber & MONDAY) == MONDAY,
|
|
550
|
+
tuesday: (weekNumber & TUESDAY) == TUESDAY,
|
|
551
|
+
wednesday: (weekNumber & WEDNESDAY) == WEDNESDAY,
|
|
552
|
+
thursday: (weekNumber & THURSDAY) == THURSDAY,
|
|
553
|
+
friday: (weekNumber & FRIDAY) == FRIDAY,
|
|
554
|
+
saturday: (weekNumber & SATURDAY) == SATURDAY,
|
|
555
|
+
sunday: (weekNumber & SUNDAY) == SUNDAY,
|
|
556
|
+
},
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
exports.hexStringScheduleToSchedule = hexStringScheduleToSchedule;
|
|
560
|
+
const randomNumber = function (min, max) {
|
|
561
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
562
|
+
};
|
|
563
|
+
exports.randomNumber = randomNumber;
|
|
564
|
+
const getIdSuffix = function (p2pDid) {
|
|
565
|
+
let result = 0;
|
|
566
|
+
const match = p2pDid.match(/^[A-Z]+-(\d+)-[A-Z]+$/);
|
|
567
|
+
if (match?.length == 2) {
|
|
568
|
+
const num1 = Number.parseInt(match[1][0]);
|
|
569
|
+
const num2 = Number.parseInt(match[1][1]);
|
|
570
|
+
const num3 = Number.parseInt(match[1][3]);
|
|
571
|
+
const num4 = Number.parseInt(match[1][5]);
|
|
572
|
+
result = num1 + num2 + num3;
|
|
573
|
+
if (num3 < 5) {
|
|
574
|
+
result = result + num3;
|
|
575
|
+
}
|
|
576
|
+
result = result + num4;
|
|
577
|
+
}
|
|
578
|
+
return result;
|
|
579
|
+
};
|
|
580
|
+
exports.getIdSuffix = getIdSuffix;
|
|
581
|
+
const getImageBaseCode = function (serialNumber, p2pDid) {
|
|
582
|
+
let nr = 0;
|
|
583
|
+
try {
|
|
584
|
+
nr = Number.parseInt(`0x${serialNumber[serialNumber.length - 1]}`);
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
const error = (0, error_1.ensureError)(err);
|
|
588
|
+
throw new error_2.ImageBaseCodeError("Error generating image base code", {
|
|
589
|
+
cause: error,
|
|
590
|
+
context: { serialnumber: serialNumber, p2pDid: p2pDid },
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
nr = (nr + 10) % 10;
|
|
594
|
+
const base = serialNumber.substring(nr);
|
|
595
|
+
return `${base}${(0, exports.getIdSuffix)(p2pDid)}`;
|
|
596
|
+
};
|
|
597
|
+
exports.getImageBaseCode = getImageBaseCode;
|
|
598
|
+
const getImageSeed = function (p2pDid, code) {
|
|
599
|
+
try {
|
|
600
|
+
const nCode = Number.parseInt(code.substring(2));
|
|
601
|
+
const prefix = 1000 - (0, exports.getIdSuffix)(p2pDid);
|
|
602
|
+
return (0, md5_1.default)(`${prefix}${nCode}`).toString(enc_hex_1.default).toUpperCase();
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
const error = (0, error_1.ensureError)(err);
|
|
606
|
+
throw new error_2.ImageBaseCodeError("Error generating image seed", {
|
|
607
|
+
cause: error,
|
|
608
|
+
context: { p2pDid: p2pDid, code: code },
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
exports.getImageSeed = getImageSeed;
|
|
613
|
+
const getImageKey = function (serialNumber, p2pDid, code) {
|
|
614
|
+
const baseCode = (0, exports.getImageBaseCode)(serialNumber, p2pDid);
|
|
615
|
+
const seed = (0, exports.getImageSeed)(p2pDid, code);
|
|
616
|
+
const data = `01${baseCode}${seed}`;
|
|
617
|
+
const hash = (0, sha256_1.default)(data);
|
|
618
|
+
const hashBytes = [...Buffer.from(hash.toString(enc_hex_1.default), "hex")];
|
|
619
|
+
const startByte = hashBytes[10];
|
|
620
|
+
for (let i = 0; i < 32; i++) {
|
|
621
|
+
const byte = hashBytes[i];
|
|
622
|
+
let fixed_byte = startByte;
|
|
623
|
+
if (i < 31) {
|
|
624
|
+
fixed_byte = hashBytes[i + 1];
|
|
625
|
+
}
|
|
626
|
+
if (i == 31 || (i & 1) != 0) {
|
|
627
|
+
hashBytes[10] = fixed_byte;
|
|
628
|
+
if (126 < byte || 126 < hashBytes[10]) {
|
|
629
|
+
if (byte < hashBytes[10] || byte - hashBytes[10] == 0) {
|
|
630
|
+
hashBytes[i] = hashBytes[10] - byte;
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
hashBytes[i] = byte - hashBytes[10];
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
else if (byte < 125 || fixed_byte < 125) {
|
|
638
|
+
hashBytes[i] = fixed_byte + byte;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return `${Buffer.from(hashBytes.slice(16)).toString("hex").toUpperCase()}`;
|
|
642
|
+
};
|
|
643
|
+
exports.getImageKey = getImageKey;
|
|
644
|
+
const decodeImage = function (p2pDid, data) {
|
|
645
|
+
if (data.length >= 12) {
|
|
646
|
+
const header = data.subarray(0, 12).toString();
|
|
647
|
+
if (header === "eufysecurity") {
|
|
648
|
+
const serialNumber = data.subarray(13, 29).toString();
|
|
649
|
+
const code = data.subarray(30, 40).toString();
|
|
650
|
+
const imageKey = (0, exports.getImageKey)(serialNumber, p2pDid, code);
|
|
651
|
+
const otherData = data.subarray(41);
|
|
652
|
+
const encryptedData = otherData.subarray(0, 256);
|
|
653
|
+
const cipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", Buffer.from(imageKey, "utf-8").subarray(0, 16), null);
|
|
654
|
+
cipher.setAutoPadding(false);
|
|
655
|
+
const decryptedData = Buffer.concat([cipher.update(encryptedData), cipher.final()]);
|
|
656
|
+
decryptedData.copy(otherData);
|
|
657
|
+
return otherData;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return data;
|
|
661
|
+
};
|
|
662
|
+
exports.decodeImage = decodeImage;
|
|
663
|
+
const getImagePath = function (path) {
|
|
664
|
+
const splitPath = path.split("~");
|
|
665
|
+
if (splitPath.length === 2) {
|
|
666
|
+
return splitPath[1];
|
|
667
|
+
}
|
|
668
|
+
return path;
|
|
669
|
+
};
|
|
670
|
+
exports.getImagePath = getImagePath;
|
|
671
|
+
// TODO: make up some testing
|
|
672
|
+
const getImage = async function (api, serial, url) {
|
|
673
|
+
const { default: imageType } = await import("image-type");
|
|
674
|
+
const image = await api.getImage(serial, url);
|
|
675
|
+
const type = await imageType(image);
|
|
676
|
+
return {
|
|
677
|
+
data: image,
|
|
678
|
+
type: type !== null && type !== undefined ? type : { ext: "unknown", mime: "application/octet-stream" },
|
|
679
|
+
};
|
|
680
|
+
};
|
|
681
|
+
exports.getImage = getImage;
|
|
682
|
+
const isPrioritySourceType = function (current, update) {
|
|
683
|
+
return (((current === "http" || current === "p2p" || current === "push" || current === "mqtt" || current === undefined) &&
|
|
684
|
+
(update === "p2p" || update === "push" || update === "mqtt")) ||
|
|
685
|
+
((current === "http" || current === undefined) && update === "http"));
|
|
686
|
+
};
|
|
687
|
+
exports.isPrioritySourceType = isPrioritySourceType;
|
|
688
|
+
const decryptTrackerData = (data, key) => {
|
|
689
|
+
const decipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", key, null);
|
|
690
|
+
decipher.setAutoPadding(false);
|
|
691
|
+
return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
692
|
+
};
|
|
693
|
+
exports.decryptTrackerData = decryptTrackerData;
|
|
694
|
+
// TODO: this seems to be used before above
|
|
695
|
+
const isT8170DetectionModeEnabled = function (value, type) {
|
|
696
|
+
return (type & value) == type;
|
|
697
|
+
};
|
|
698
|
+
exports.isT8170DetectionModeEnabled = isT8170DetectionModeEnabled;
|
|
699
|
+
// TODO this seems like getHB3DetectionMode
|
|
700
|
+
const getT8170DetectionMode = function (value, type, enable) {
|
|
701
|
+
let result = 0;
|
|
702
|
+
if (Object.values(types_1.T8170DetectionTypes).includes(type) &&
|
|
703
|
+
Object.values(types_1.T8170DetectionTypes).includes(value) &&
|
|
704
|
+
!enable)
|
|
705
|
+
return value;
|
|
706
|
+
if (!enable) {
|
|
707
|
+
result = type ^ value;
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
result = type | value;
|
|
711
|
+
}
|
|
712
|
+
return result;
|
|
713
|
+
};
|
|
714
|
+
exports.getT8170DetectionMode = getT8170DetectionMode;
|
|
715
|
+
// TODO: Tidy up!!
|
|
716
|
+
const isT8110DetectionModeEnabled = function (value, type) {
|
|
717
|
+
return (type & value) == type;
|
|
718
|
+
};
|
|
719
|
+
exports.isT8110DetectionModeEnabled = isT8110DetectionModeEnabled;
|
|
720
|
+
const getT8110DetectionMode = function (value, type, enable) {
|
|
721
|
+
let result = 0;
|
|
722
|
+
if (Object.values(types_1.EufyCamC35DetectionTypes).includes(type) &&
|
|
723
|
+
Object.values(types_1.EufyCamC35DetectionTypes).includes(value) &&
|
|
724
|
+
!enable)
|
|
725
|
+
return value;
|
|
726
|
+
if (!enable) {
|
|
727
|
+
result = type ^ value;
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
result = type | value;
|
|
731
|
+
}
|
|
732
|
+
return result;
|
|
733
|
+
};
|
|
734
|
+
exports.getT8110DetectionMode = getT8110DetectionMode;
|
|
735
|
+
// TODO: this is like isT8170DetectionModeEnabled
|
|
736
|
+
const isIndoorS350DetectionModeEnabled = function (value, type) {
|
|
737
|
+
return (type & value) == type;
|
|
738
|
+
};
|
|
739
|
+
exports.isIndoorS350DetectionModeEnabled = isIndoorS350DetectionModeEnabled;
|
|
740
|
+
// TODO: this is like getT8170DetectionMode
|
|
741
|
+
const getIndoorS350DetectionMode = function (value, type, enable) {
|
|
742
|
+
let result = 0;
|
|
743
|
+
if (Object.values(types_1.IndoorS350DetectionTypes).includes(type) &&
|
|
744
|
+
Object.values(types_1.IndoorS350DetectionTypes).includes(value) &&
|
|
745
|
+
!enable)
|
|
746
|
+
return value;
|
|
747
|
+
if (!enable) {
|
|
748
|
+
result = type ^ value;
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
result = type | value;
|
|
752
|
+
}
|
|
753
|
+
return result;
|
|
754
|
+
};
|
|
755
|
+
exports.getIndoorS350DetectionMode = getIndoorS350DetectionMode;
|
|
756
|
+
// TODO: this is like isT8170DetectionModeEnabled
|
|
757
|
+
const isIndoorNotificationEnabled = function (value, type) {
|
|
758
|
+
return (type & value) == type;
|
|
759
|
+
};
|
|
760
|
+
exports.isIndoorNotificationEnabled = isIndoorNotificationEnabled;
|
|
761
|
+
// TODO: this is like getT8170DetectionMode
|
|
762
|
+
const getIndoorNotification = function (value, type, enable) {
|
|
763
|
+
let result = 0;
|
|
764
|
+
if (!enable) {
|
|
765
|
+
result = (type ^ value) + 800;
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
result = type | value;
|
|
769
|
+
}
|
|
770
|
+
return result;
|
|
771
|
+
};
|
|
772
|
+
exports.getIndoorNotification = getIndoorNotification;
|
|
773
|
+
// TODO: this is like isT8170DetectionModeEnabled
|
|
774
|
+
const isFloodlightT8425NotificationEnabled = function (value, type) {
|
|
775
|
+
return (type & value) == type;
|
|
776
|
+
};
|
|
777
|
+
exports.isFloodlightT8425NotificationEnabled = isFloodlightT8425NotificationEnabled;
|
|
778
|
+
// TODO: this is like getT8170DetectionMode
|
|
779
|
+
const getFloodLightT8425Notification = function (value, type, enable) {
|
|
780
|
+
let result = 0;
|
|
781
|
+
if (!enable) {
|
|
782
|
+
result = type ^ value;
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
result = type | value;
|
|
786
|
+
}
|
|
787
|
+
return result;
|
|
788
|
+
};
|
|
789
|
+
exports.getFloodLightT8425Notification = getFloodLightT8425Notification;
|
|
790
|
+
const getLockEventType = function (event) {
|
|
791
|
+
switch (event) {
|
|
792
|
+
case types_2.LockPushEvent.AUTO_LOCK:
|
|
793
|
+
case types_2.LockPushEvent.AUTO_UNLOCK:
|
|
794
|
+
return 1;
|
|
795
|
+
case types_2.LockPushEvent.MANUAL_LOCK:
|
|
796
|
+
case types_2.LockPushEvent.MANUAL_UNLOCK:
|
|
797
|
+
return 2;
|
|
798
|
+
case types_2.LockPushEvent.APP_LOCK:
|
|
799
|
+
case types_2.LockPushEvent.APP_UNLOCK:
|
|
800
|
+
return 3;
|
|
801
|
+
case types_2.LockPushEvent.PW_LOCK:
|
|
802
|
+
case types_2.LockPushEvent.PW_UNLOCK:
|
|
803
|
+
return 4;
|
|
804
|
+
case types_2.LockPushEvent.FINGER_LOCK:
|
|
805
|
+
case types_2.LockPushEvent.FINGERPRINT_UNLOCK:
|
|
806
|
+
return 5;
|
|
807
|
+
case types_2.LockPushEvent.TEMPORARY_PW_LOCK:
|
|
808
|
+
case types_2.LockPushEvent.TEMPORARY_PW_UNLOCK:
|
|
809
|
+
return 6;
|
|
810
|
+
case types_2.LockPushEvent.KEYPAD_LOCK:
|
|
811
|
+
return 7;
|
|
812
|
+
}
|
|
813
|
+
return 0;
|
|
814
|
+
};
|
|
815
|
+
exports.getLockEventType = getLockEventType;
|
|
816
|
+
// TODO: this is like getT8170DetectionMode
|
|
817
|
+
const switchSmartLockNotification = function (currentValue, mode, enable) {
|
|
818
|
+
let result = 0;
|
|
819
|
+
if (enable) {
|
|
820
|
+
result = mode | currentValue;
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
result = ~mode & currentValue;
|
|
824
|
+
}
|
|
825
|
+
return result;
|
|
826
|
+
};
|
|
827
|
+
exports.switchSmartLockNotification = switchSmartLockNotification;
|
|
828
|
+
// TODO: this is like isT8170DetectionModeEnabled
|
|
829
|
+
const isSmartLockNotification = function (value, mode) {
|
|
830
|
+
return (value & mode) !== 0;
|
|
831
|
+
};
|
|
832
|
+
exports.isSmartLockNotification = isSmartLockNotification;
|
|
833
|
+
const getWaitSeconds = (device) => {
|
|
834
|
+
let seconds = 60;
|
|
835
|
+
const workingMode = device.getPropertyValue(types_1.PropertyName.DevicePowerWorkingMode);
|
|
836
|
+
if (workingMode !== undefined && workingMode === 2) {
|
|
837
|
+
const customValue = device.getPropertyValue(types_1.PropertyName.DeviceRecordingClipLength);
|
|
838
|
+
if (customValue !== undefined) {
|
|
839
|
+
seconds = customValue;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return seconds;
|
|
843
|
+
};
|
|
844
|
+
exports.getWaitSeconds = getWaitSeconds;
|
|
845
|
+
const loadImageOverP2P = function (station, device, id, p2pTimeouts) {
|
|
846
|
+
if (station.hasCommand(types_1.CommandName.StationDatabaseQueryLatestInfo) && p2pTimeouts.get(id) === undefined) {
|
|
847
|
+
const seconds = (0, exports.getWaitSeconds)(device);
|
|
848
|
+
p2pTimeouts.set(id, setTimeout(async () => {
|
|
849
|
+
station.databaseQueryLatestInfo();
|
|
850
|
+
p2pTimeouts.delete(id);
|
|
851
|
+
}, seconds * 1000));
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
exports.loadImageOverP2P = loadImageOverP2P;
|
|
855
|
+
const loadEventImage = function (station, api, device, message, p2pTimeouts) {
|
|
856
|
+
if (message.notification_style === types_1.NotificationType.MOST_EFFICIENT) {
|
|
857
|
+
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
if (!(0, utils_1.isEmpty)(message.pic_url)) {
|
|
861
|
+
(0, exports.getImage)(api, device.getSerial(), message.pic_url)
|
|
862
|
+
.then((image) => {
|
|
863
|
+
if (image.data.length > 0) {
|
|
864
|
+
if (p2pTimeouts.get(device.getSerial()) !== undefined) {
|
|
865
|
+
clearTimeout(p2pTimeouts.get(device.getSerial()));
|
|
866
|
+
p2pTimeouts.delete(device.getSerial());
|
|
867
|
+
}
|
|
868
|
+
device.updateProperty(types_1.PropertyName.DevicePicture, image, true);
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
//fallback
|
|
872
|
+
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
|
|
873
|
+
}
|
|
874
|
+
})
|
|
875
|
+
.catch((err) => {
|
|
876
|
+
const error = (0, error_1.ensureError)(err);
|
|
877
|
+
logging_1.rootHTTPLogger.debug(`Device load event image - Fallback Error`, {
|
|
878
|
+
error: (0, utils_1.getError)(error),
|
|
879
|
+
stationSN: station.getSerial(),
|
|
880
|
+
deviceSN: device.getSerial(),
|
|
881
|
+
message: JSON.stringify(message),
|
|
882
|
+
});
|
|
883
|
+
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
//fallback
|
|
888
|
+
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
exports.loadEventImage = loadEventImage;
|
|
893
|
+
const getRandomPhoneModel = function () {
|
|
894
|
+
/**
|
|
895
|
+
* Generate a random phone model based on a structure
|
|
896
|
+
*/
|
|
897
|
+
const brandKeys = Object.keys(const_1.PhoneModelStructure);
|
|
898
|
+
const randomBrandName = brandKeys[Math.floor(Math.random() * brandKeys.length)];
|
|
899
|
+
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
900
|
+
let part1 = "";
|
|
901
|
+
let part2 = "";
|
|
902
|
+
const dataBrand = const_1.PhoneModelStructure[randomBrandName];
|
|
903
|
+
if (dataBrand.first && dataBrand.second) {
|
|
904
|
+
part1 = pick(dataBrand.first);
|
|
905
|
+
part2 = pick(dataBrand.second);
|
|
906
|
+
}
|
|
907
|
+
if (dataBrand.numbers && dataBrand.letters) {
|
|
908
|
+
const minNum = Math.pow(10, dataBrand.numbers - 1);
|
|
909
|
+
const maxNum = Math.pow(10, dataBrand.numbers) - 1;
|
|
910
|
+
part1 = String(Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
|
|
911
|
+
part2 = pick(dataBrand.letters);
|
|
912
|
+
}
|
|
913
|
+
return `${randomBrandName}${part1}${part2}`.trim();
|
|
914
|
+
};
|
|
915
|
+
exports.getRandomPhoneModel = getRandomPhoneModel;
|
|
916
|
+
//# sourceMappingURL=utils.js.map
|