iobroker.eusec 1.2.0 → 1.3.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/LICENSE +1 -1
- package/README.md +47 -114
- package/admin/i18n/de/translations.json +252 -1
- package/admin/i18n/en/translations.json +252 -1
- package/admin/i18n/es/translations.json +252 -1
- package/admin/i18n/fr/translations.json +252 -1
- package/admin/i18n/it/translations.json +252 -1
- package/admin/i18n/nl/translations.json +252 -1
- package/admin/i18n/pl/translations.json +252 -1
- package/admin/i18n/pt/translations.json +252 -1
- package/admin/i18n/ru/translations.json +252 -1
- package/admin/i18n/uk/translations.json +275 -24
- package/admin/i18n/zh-cn/translations.json +252 -1
- package/admin/jsonConfig.json +1015 -0
- package/admin/words.js +3297 -17
- package/build/lib/log.js +1 -0
- package/build/lib/log.js.map +1 -1
- package/build/lib/types.js +6 -5
- package/build/lib/types.js.map +2 -2
- package/build/lib/utils.js +51 -41
- package/build/lib/utils.js.map +2 -2
- package/build/lib/video.js +148 -20
- package/build/lib/video.js.map +3 -3
- package/build/main.js +550 -169
- package/build/main.js.map +3 -3
- package/io-package.json +51 -52
- package/package.json +40 -37
- package/build/lib/tools.js +0 -94
- package/build/lib/tools.js.map +0 -7
- package/build/lib/web.js +0 -64
- package/build/lib/web.js.map +0 -7
package/build/main.js
CHANGED
|
@@ -5,6 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
8
12
|
var __copyProps = (to, from, except, desc) => {
|
|
9
13
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
14
|
for (let key of __getOwnPropNames(from))
|
|
@@ -14,43 +18,65 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
18
|
return to;
|
|
15
19
|
};
|
|
16
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
17
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
18
26
|
mod
|
|
19
27
|
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var main_exports = {};
|
|
30
|
+
__export(main_exports, {
|
|
31
|
+
euSec: () => euSec
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(main_exports);
|
|
20
34
|
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
21
35
|
var path = __toESM(require("path"));
|
|
22
36
|
var import_eufy_security_client = require("eufy-security-client");
|
|
23
37
|
var import_i18n_iso_countries = require("i18n-iso-countries");
|
|
24
38
|
var import_i18n_iso_languages = require("@cospired/i18n-iso-languages");
|
|
25
|
-
var import_fs_extra = __toESM(require("fs-extra"));
|
|
26
39
|
var import_util = __toESM(require("util"));
|
|
27
40
|
var import_child_process = __toESM(require("child_process"));
|
|
28
41
|
var import_go2rtc_static = __toESM(require("go2rtc-static"));
|
|
29
|
-
var
|
|
42
|
+
var import_ffmpeg_for_homebridge = __toESM(require("ffmpeg-for-homebridge"));
|
|
30
43
|
var import_types = require("./lib/types");
|
|
31
44
|
var import_utils = require("./lib/utils");
|
|
32
45
|
var import_log = require("./lib/log");
|
|
33
46
|
var import_video = require("./lib/video");
|
|
34
47
|
class euSec extends utils.Adapter {
|
|
48
|
+
eufy;
|
|
49
|
+
/*private downloadEvent: {
|
|
50
|
+
[index: string]: NodeJS.Timeout;
|
|
51
|
+
} = {};*/
|
|
52
|
+
persistentFile = "adapter.json";
|
|
53
|
+
persistentDriverFile = "driver.json";
|
|
54
|
+
logger;
|
|
55
|
+
persistentData = {
|
|
56
|
+
version: ""
|
|
57
|
+
};
|
|
58
|
+
captchaId = null;
|
|
59
|
+
verify_code = false;
|
|
60
|
+
skipInit = false;
|
|
35
61
|
constructor(options = {}) {
|
|
36
62
|
super({
|
|
37
63
|
...options,
|
|
38
64
|
name: "eusec"
|
|
39
65
|
});
|
|
40
|
-
this.persistentData = {
|
|
41
|
-
version: ""
|
|
42
|
-
};
|
|
43
|
-
this.captchaId = null;
|
|
44
|
-
this.verify_code = false;
|
|
45
|
-
const data_dir = utils.getAbsoluteInstanceDataDir(this);
|
|
46
|
-
this.persistentFile = path.join(data_dir, "adapter.json");
|
|
47
|
-
if (!import_fs_extra.default.existsSync(data_dir))
|
|
48
|
-
import_fs_extra.default.mkdirSync(data_dir);
|
|
49
66
|
this.on("ready", this.onReady.bind(this));
|
|
50
67
|
this.on("stateChange", this.onStateChange.bind(this));
|
|
68
|
+
this.on("message", this.onMessage.bind(this));
|
|
51
69
|
this.on("unload", this.onUnload.bind(this));
|
|
52
70
|
}
|
|
71
|
+
restartAdapter() {
|
|
72
|
+
this.skipInit = true;
|
|
73
|
+
this.restart();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Is called when databases are connected and adapter received configuration.
|
|
77
|
+
*/
|
|
53
78
|
async onReady() {
|
|
79
|
+
var _a;
|
|
54
80
|
this.logger = new import_log.ioBrokerLogger(this.log);
|
|
55
81
|
await this.setObjectNotExistsAsync("verify_code", {
|
|
56
82
|
type: "state",
|
|
@@ -157,132 +183,209 @@ class euSec extends utils.Adapter {
|
|
|
157
183
|
this.logger.error("Reset sensor states - Error", error);
|
|
158
184
|
}
|
|
159
185
|
try {
|
|
160
|
-
if (
|
|
161
|
-
const fileContent =
|
|
162
|
-
this.persistentData = JSON.parse(fileContent);
|
|
186
|
+
if (await this.fileExistsAsync(this.namespace, this.persistentFile)) {
|
|
187
|
+
const fileContent = await this.readFileAsync(this.namespace, this.persistentFile);
|
|
188
|
+
this.persistentData = JSON.parse(fileContent.file.toString("utf8"));
|
|
163
189
|
}
|
|
164
190
|
} catch (error) {
|
|
165
|
-
this.logger.debug("No stored data from last exit found.", error);
|
|
166
|
-
}
|
|
167
|
-
this.subscribeStates("verify_code");
|
|
168
|
-
this.subscribeStates("captcha");
|
|
169
|
-
const systemConfig = await this.getForeignObjectAsync("system.config");
|
|
170
|
-
let countryCode = void 0;
|
|
171
|
-
let languageCode = void 0;
|
|
172
|
-
if (systemConfig) {
|
|
173
|
-
countryCode = (0, import_i18n_iso_countries.getAlpha2Code)(systemConfig.common.country, "en");
|
|
174
|
-
if ((0, import_i18n_iso_languages.isValid)(systemConfig.common.language))
|
|
175
|
-
languageCode = systemConfig.common.language;
|
|
176
|
-
}
|
|
177
|
-
if (this.config.hostname === "") {
|
|
178
|
-
this.config.hostname = import_os.default.hostname();
|
|
191
|
+
this.logger.debug("No adapter stored data from last exit found.", error);
|
|
179
192
|
}
|
|
193
|
+
let persistentDriverData = "{}";
|
|
180
194
|
try {
|
|
181
|
-
if (this.
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
this.logger.debug(`Handling of adapter update - currentVersion: ${currentVersion} previousVersion: ${previousVersion}`);
|
|
185
|
-
if (previousVersion < currentVersion) {
|
|
186
|
-
await (0, import_utils.handleUpdate)(this, this.logger, previousVersion);
|
|
187
|
-
this.persistentData.version = this.version;
|
|
188
|
-
this.writePersistentData();
|
|
189
|
-
}
|
|
195
|
+
if (await this.fileExistsAsync(this.namespace, this.persistentDriverFile)) {
|
|
196
|
+
const fileContent = await this.readFileAsync(this.namespace, this.persistentDriverFile);
|
|
197
|
+
persistentDriverData = fileContent.file.toString("utf8");
|
|
190
198
|
}
|
|
191
199
|
} catch (error) {
|
|
192
|
-
this.logger.
|
|
200
|
+
this.logger.debug("No driver stored data from last exit found.", error);
|
|
193
201
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
202
|
+
this.subscribeStates("verify_code");
|
|
203
|
+
this.subscribeStates("captcha");
|
|
204
|
+
const hosts = await this.getForeignObjectsAsync("system.host.*", "host");
|
|
205
|
+
if (hosts !== void 0 && hosts !== null && Object.values(hosts).length !== 0) {
|
|
206
|
+
if (this.config.hostname === "") {
|
|
207
|
+
this.config.hostname = Object.values(hosts)[0].native.os.hostname;
|
|
208
|
+
}
|
|
209
|
+
const nodeVersion = Object.values(hosts)[0].native.process.versions.node;
|
|
210
|
+
const nodeMajorVersion = nodeVersion.split(".")[0];
|
|
211
|
+
let fixNeeded;
|
|
212
|
+
switch (parseInt(nodeMajorVersion)) {
|
|
213
|
+
case 18:
|
|
214
|
+
fixNeeded = nodeVersion.localeCompare("18.19.1", void 0, { numeric: true, sensitivity: "base" });
|
|
215
|
+
break;
|
|
216
|
+
case 20:
|
|
217
|
+
fixNeeded = nodeVersion.localeCompare("20.11.1", void 0, { numeric: true, sensitivity: "base" });
|
|
218
|
+
break;
|
|
219
|
+
default:
|
|
220
|
+
fixNeeded = nodeVersion.localeCompare("21.6.2", void 0, { numeric: true, sensitivity: "base" });
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
if (fixNeeded >= 0) {
|
|
224
|
+
const adapter = await this.getForeignObjectAsync(`system.adapter.${this.namespace}`);
|
|
225
|
+
if (adapter !== void 0 && adapter !== null) {
|
|
226
|
+
if (!((_a = adapter.common.nodeProcessParams) == null ? void 0 : _a.includes("--security-revert=CVE-2023-46809"))) {
|
|
227
|
+
adapter.common.nodeProcessParams = ["--security-revert=CVE-2023-46809"];
|
|
228
|
+
await this.setForeignObjectAsync(`system.adapter.${this.namespace}`, adapter);
|
|
229
|
+
this.log.warn("Required fix to use livestreaming with this version of Node.js (CVE-2023-46809) applied. Restart of the adapter initiated to activate the fix.");
|
|
230
|
+
this.restartAdapter();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
197
234
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
pollingIntervalMinutes: this.config.pollingInterval,
|
|
207
|
-
acceptInvitations: this.config.acceptInvitations
|
|
208
|
-
};
|
|
209
|
-
this.eufy = await import_eufy_security_client.EufySecurity.initialize(config, this.logger);
|
|
210
|
-
this.eufy.on("station added", (station) => this.onStationAdded(station));
|
|
211
|
-
this.eufy.on("device added", (device) => this.onDeviceAdded(device));
|
|
212
|
-
this.eufy.on("station removed", (station) => this.onStationRemoved(station));
|
|
213
|
-
this.eufy.on("device removed", (device) => this.onDeviceRemoved(device));
|
|
214
|
-
this.eufy.on("push message", (messages) => this.handlePushNotification(messages));
|
|
215
|
-
this.eufy.on("push connect", () => this.onPushConnect());
|
|
216
|
-
this.eufy.on("push close", () => this.onPushClose());
|
|
217
|
-
this.eufy.on("mqtt connect", () => this.onMQTTConnect());
|
|
218
|
-
this.eufy.on("mqtt close", () => this.onMQTTClose());
|
|
219
|
-
this.eufy.on("connect", () => this.onConnect());
|
|
220
|
-
this.eufy.on("close", () => this.onClose());
|
|
221
|
-
this.eufy.on("device property changed", (device, name, value) => this.onDevicePropertyChanged(device, name, value));
|
|
222
|
-
this.eufy.on("station command result", (station, result) => this.onStationCommandResult(station, result));
|
|
223
|
-
this.eufy.on("station livestream start", (station, device, metadata, videostream, audiostream) => this.onStationLivestreamStart(station, device, metadata, videostream, audiostream));
|
|
224
|
-
this.eufy.on("station livestream stop", (station, device) => this.onStationLivestreamStop(station, device));
|
|
225
|
-
this.eufy.on("station rtsp url", (station, device, value) => this.onStationRTSPUrl(station, device, value));
|
|
226
|
-
this.eufy.on("station property changed", (station, name, value) => this.onStationPropertyChanged(station, name, value));
|
|
227
|
-
this.eufy.on("station connect", (station) => this.onStationConnect(station));
|
|
228
|
-
this.eufy.on("station close", (station) => this.onStationClose(station));
|
|
229
|
-
this.eufy.on("tfa request", () => this.onTFARequest());
|
|
230
|
-
this.eufy.on("captcha request", (captchaId, captcha) => this.onCaptchaRequest(captchaId, captcha));
|
|
231
|
-
this.eufy.setCameraMaxLivestreamDuration(this.config.maxLivestreamDuration);
|
|
232
|
-
await this.eufy.connect();
|
|
233
|
-
if (import_go2rtc_static.default) {
|
|
234
|
-
const go2rtcConfig = {
|
|
235
|
-
"api": {
|
|
236
|
-
"listen": `:${this.config.go2rtc_api_port}`
|
|
237
|
-
},
|
|
238
|
-
"rtsp": {
|
|
239
|
-
"listen": `:${this.config.go2rtc_rtsp_port}`
|
|
240
|
-
},
|
|
241
|
-
"srtp": {
|
|
242
|
-
"listen": `:${this.config.go2rtc_srtp_port}`
|
|
243
|
-
},
|
|
244
|
-
"webrtc": {
|
|
245
|
-
"listen": `:${this.config.go2rtc_webrtc_port}`
|
|
246
|
-
},
|
|
247
|
-
"streams": {}
|
|
248
|
-
};
|
|
249
|
-
if (this.config.go2rtc_rtsp_username !== "" && this.config.go2rtc_rtsp_password !== "") {
|
|
250
|
-
go2rtcConfig.rtsp.username = this.config.go2rtc_rtsp_username;
|
|
251
|
-
go2rtcConfig.rtsp.password = this.config.go2rtc_rtsp_password;
|
|
235
|
+
if (!this.skipInit) {
|
|
236
|
+
const systemConfig = await this.getForeignObjectAsync("system.config");
|
|
237
|
+
let countryCode = void 0;
|
|
238
|
+
let languageCode = void 0;
|
|
239
|
+
if (systemConfig) {
|
|
240
|
+
countryCode = (0, import_i18n_iso_countries.getAlpha2Code)(systemConfig.common.country, "en");
|
|
241
|
+
if ((0, import_i18n_iso_languages.isValid)(systemConfig.common.language))
|
|
242
|
+
languageCode = systemConfig.common.language;
|
|
252
243
|
}
|
|
253
|
-
|
|
254
|
-
|
|
244
|
+
if (this.config.country !== "iobroker") {
|
|
245
|
+
countryCode = this.config.country;
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
if (this.persistentData.version !== this.version) {
|
|
249
|
+
const currentVersion = Number.parseFloat((0, import_utils.removeLastChar)(this.version, "."));
|
|
250
|
+
const previousVersion = this.persistentData.version !== "" && this.persistentData.version !== void 0 ? Number.parseFloat((0, import_utils.removeLastChar)(this.persistentData.version, ".")) : 0;
|
|
251
|
+
this.logger.debug(`Handling of adapter update - currentVersion: ${currentVersion} previousVersion: ${previousVersion}`);
|
|
252
|
+
if (previousVersion < currentVersion) {
|
|
253
|
+
await (0, import_utils.handleUpdate)(this, this.logger, previousVersion, currentVersion);
|
|
254
|
+
this.persistentData.version = this.version;
|
|
255
|
+
await this.writePersistentData();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
this.logger.error(`Handling of adapter update - Error:`, error);
|
|
260
|
+
}
|
|
261
|
+
let connectionType = import_eufy_security_client.P2PConnectionType.QUICKEST;
|
|
262
|
+
if (this.config.p2pConnectionType === "only_local") {
|
|
263
|
+
connectionType = import_eufy_security_client.P2PConnectionType.ONLY_LOCAL;
|
|
264
|
+
}
|
|
265
|
+
if (this.config.username !== "" && this.config.password !== "") {
|
|
266
|
+
const config = {
|
|
267
|
+
username: this.config.username,
|
|
268
|
+
password: this.config.password,
|
|
269
|
+
country: countryCode,
|
|
270
|
+
language: languageCode,
|
|
271
|
+
persistentData: persistentDriverData,
|
|
272
|
+
eventDurationSeconds: this.config.eventDuration,
|
|
273
|
+
p2pConnectionSetup: connectionType,
|
|
274
|
+
pollingIntervalMinutes: this.config.pollingInterval,
|
|
275
|
+
acceptInvitations: this.config.acceptInvitations,
|
|
276
|
+
logging: {
|
|
277
|
+
level: this.log.level === "silly" ? import_eufy_security_client.LogLevel.Trace : this.log.level === "debug" ? import_eufy_security_client.LogLevel.Debug : this.log.level === "info" ? import_eufy_security_client.LogLevel.Info : this.log.level === "warn" ? import_eufy_security_client.LogLevel.Warn : this.log.level === "error" ? import_eufy_security_client.LogLevel.Error : import_eufy_security_client.LogLevel.Info
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
this.eufy = await import_eufy_security_client.EufySecurity.initialize(config, this.logger);
|
|
281
|
+
this.eufy.on("persistent data", (data) => this.onPersistentData(data));
|
|
282
|
+
this.eufy.on("station added", (station) => this.onStationAdded(station));
|
|
283
|
+
this.eufy.on("device added", (device) => this.onDeviceAdded(device));
|
|
284
|
+
this.eufy.on("station removed", (station) => this.onStationRemoved(station));
|
|
285
|
+
this.eufy.on("device removed", (device) => this.onDeviceRemoved(device));
|
|
286
|
+
this.eufy.on("push message", (messages) => this.handlePushNotification(messages));
|
|
287
|
+
this.eufy.on("push connect", () => this.onPushConnect());
|
|
288
|
+
this.eufy.on("push close", () => this.onPushClose());
|
|
289
|
+
this.eufy.on("mqtt connect", () => this.onMQTTConnect());
|
|
290
|
+
this.eufy.on("mqtt close", () => this.onMQTTClose());
|
|
291
|
+
this.eufy.on("connect", () => this.onConnect());
|
|
292
|
+
this.eufy.on("close", () => this.onClose());
|
|
293
|
+
this.eufy.on("device property changed", (device, name, value) => this.onDevicePropertyChanged(device, name, value));
|
|
294
|
+
this.eufy.on("station command result", (station, result) => this.onStationCommandResult(station, result));
|
|
295
|
+
this.eufy.on("station livestream start", (station, device, metadata, videostream, audiostream) => this.onStationLivestreamStart(station, device, metadata, videostream, audiostream));
|
|
296
|
+
this.eufy.on("station livestream stop", (station, device) => this.onStationLivestreamStop(station, device));
|
|
297
|
+
this.eufy.on("station rtsp url", (station, device, value) => this.onStationRTSPUrl(station, device, value));
|
|
298
|
+
this.eufy.on("station property changed", (station, name, value) => this.onStationPropertyChanged(station, name, value));
|
|
299
|
+
this.eufy.on("station connect", (station) => this.onStationConnect(station));
|
|
300
|
+
this.eufy.on("station close", (station) => this.onStationClose(station));
|
|
301
|
+
this.eufy.on("tfa request", () => this.onTFARequest());
|
|
302
|
+
this.eufy.on("captcha request", (captchaId, captcha) => this.onCaptchaRequest(captchaId, captcha));
|
|
303
|
+
this.eufy.setCameraMaxLivestreamDuration(this.config.maxLivestreamDuration);
|
|
304
|
+
await this.eufy.connect();
|
|
305
|
+
if (import_go2rtc_static.default) {
|
|
306
|
+
const go2rtcConfig = {
|
|
307
|
+
"api": {
|
|
308
|
+
"listen": `:${this.config.go2rtc_api_port}`
|
|
309
|
+
},
|
|
310
|
+
"rtsp": {
|
|
311
|
+
"listen": `:${this.config.go2rtc_rtsp_port}`
|
|
312
|
+
},
|
|
313
|
+
"srtp": {
|
|
314
|
+
"listen": `:${this.config.go2rtc_srtp_port}`
|
|
315
|
+
},
|
|
316
|
+
"webrtc": {
|
|
317
|
+
"listen": `:${this.config.go2rtc_webrtc_port}`
|
|
318
|
+
},
|
|
319
|
+
"ffmpeg": {
|
|
320
|
+
"bin": import_ffmpeg_for_homebridge.default !== "" && import_ffmpeg_for_homebridge.default !== void 0 ? import_ffmpeg_for_homebridge.default : "ffmpeg"
|
|
321
|
+
},
|
|
322
|
+
"streams": {}
|
|
323
|
+
/*"log": {
|
|
324
|
+
"level": "debug", // default level
|
|
325
|
+
"api": "debug",
|
|
326
|
+
"exec": "debug",
|
|
327
|
+
"ngrok": "debug",
|
|
328
|
+
"rtsp": "debug",
|
|
329
|
+
"streams": "debug",
|
|
330
|
+
"webrtc": "debug",
|
|
331
|
+
}*/
|
|
332
|
+
};
|
|
333
|
+
if (this.config.go2rtc_rtsp_username !== "" && this.config.go2rtc_rtsp_password !== "") {
|
|
334
|
+
go2rtcConfig.rtsp.username = this.config.go2rtc_rtsp_username;
|
|
335
|
+
go2rtcConfig.rtsp.password = this.config.go2rtc_rtsp_password;
|
|
336
|
+
}
|
|
337
|
+
for (const device of await this.eufy.getDevices()) {
|
|
338
|
+
go2rtcConfig.streams[device.getSerial()] = null;
|
|
339
|
+
}
|
|
340
|
+
const go2rtc = import_child_process.default.spawn(import_go2rtc_static.default, ["-config", JSON.stringify(go2rtcConfig)], { shell: false, detached: false, windowsHide: true });
|
|
341
|
+
go2rtc.on("error", (error) => {
|
|
342
|
+
this.log.error(`go2rtc error: ${error}`);
|
|
343
|
+
});
|
|
344
|
+
go2rtc.stdout.setEncoding("utf8");
|
|
345
|
+
go2rtc.stdout.on("data", (data) => {
|
|
346
|
+
this.log.info(`go2rtc started: ${data}`);
|
|
347
|
+
});
|
|
348
|
+
go2rtc.stderr.setEncoding("utf8");
|
|
349
|
+
go2rtc.stderr.on("data", (data) => {
|
|
350
|
+
this.log.error(`go2rtc error: ${data}`);
|
|
351
|
+
});
|
|
352
|
+
go2rtc.on("close", (exitcode) => {
|
|
353
|
+
this.log.info(`go2rtc terminated with exitcode ${exitcode}`);
|
|
354
|
+
});
|
|
355
|
+
process.on("exit", () => {
|
|
356
|
+
go2rtc.kill();
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const channels = await this.getChannelsAsync();
|
|
361
|
+
for (const channel of channels) {
|
|
362
|
+
if (channel.common.name === "unknown") {
|
|
363
|
+
const states = await this.getStatesAsync(`${channel._id}.*`);
|
|
364
|
+
if (Object.keys(states).length === 0) {
|
|
365
|
+
await this.delObjectAsync(channel._id);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
255
368
|
}
|
|
256
|
-
const go2rtc = import_child_process.default.spawn(import_go2rtc_static.default, ["-config", JSON.stringify(go2rtcConfig)], { shell: false, detached: false, windowsHide: true });
|
|
257
|
-
go2rtc.on("error", (error) => {
|
|
258
|
-
this.log.error(`go2rtc error: ${error}`);
|
|
259
|
-
});
|
|
260
|
-
go2rtc.stdout.setEncoding("utf8");
|
|
261
|
-
go2rtc.stdout.on("data", (data) => {
|
|
262
|
-
this.log.info(`go2rtc started: ${data}`);
|
|
263
|
-
});
|
|
264
|
-
go2rtc.stderr.setEncoding("utf8");
|
|
265
|
-
go2rtc.stderr.on("data", (data) => {
|
|
266
|
-
this.log.error(`go2rtc error: ${data}`);
|
|
267
|
-
});
|
|
268
|
-
go2rtc.on("close", (exitcode) => {
|
|
269
|
-
this.log.info(`go2rtc terminated with exitcode ${exitcode}`);
|
|
270
|
-
});
|
|
271
|
-
process.on("exit", () => {
|
|
272
|
-
go2rtc.kill();
|
|
273
|
-
});
|
|
274
369
|
}
|
|
275
370
|
}
|
|
276
|
-
writePersistentData() {
|
|
371
|
+
async writePersistentData() {
|
|
277
372
|
try {
|
|
278
|
-
|
|
373
|
+
await this.writeFileAsync(this.namespace, this.persistentFile, JSON.stringify(this.persistentData));
|
|
279
374
|
} catch (error) {
|
|
280
375
|
this.logger.error(`writePersistentData() - Error: ${error}`);
|
|
281
376
|
}
|
|
282
377
|
}
|
|
378
|
+
onPersistentData(data) {
|
|
379
|
+
this.writeFileAsync(this.namespace, this.persistentDriverFile, data).catch((error) => {
|
|
380
|
+
this.logger.error(`writePersistentDriverData() - Error: ${error}`);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Is called when adapter shuts down - callback has to be called under any circumstances!
|
|
385
|
+
*/
|
|
283
386
|
async onUnload(callback) {
|
|
284
387
|
try {
|
|
285
|
-
this.writePersistentData();
|
|
388
|
+
await this.writePersistentData();
|
|
286
389
|
if (this.eufy) {
|
|
287
390
|
if (this.eufy.isConnected())
|
|
288
391
|
await this.setStateAsync("info.connection", { val: false, ack: true }).catch();
|
|
@@ -294,6 +397,23 @@ class euSec extends utils.Adapter {
|
|
|
294
397
|
callback();
|
|
295
398
|
}
|
|
296
399
|
}
|
|
400
|
+
// If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
|
|
401
|
+
// You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
|
|
402
|
+
// /**
|
|
403
|
+
// * Is called if a subscribed object changes
|
|
404
|
+
// */
|
|
405
|
+
// private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {
|
|
406
|
+
// if (obj) {
|
|
407
|
+
// // The object was changed
|
|
408
|
+
// this.log.info(`object ${id} changed: ${JSON.stringify(obj)}`);
|
|
409
|
+
// } else {
|
|
410
|
+
// // The object was deleted
|
|
411
|
+
// this.log.info(`object ${id} deleted`);
|
|
412
|
+
// }
|
|
413
|
+
// }
|
|
414
|
+
/**
|
|
415
|
+
* Is called if a subscribed state changes
|
|
416
|
+
*/
|
|
297
417
|
async onStateChange(id, state) {
|
|
298
418
|
if (state) {
|
|
299
419
|
if (!id || state.ack) {
|
|
@@ -412,6 +532,9 @@ class euSec extends utils.Adapter {
|
|
|
412
532
|
case import_types.DeviceStateID.SET_PRIVACY_ANGLE:
|
|
413
533
|
await station.setPrivacyAngle(device);
|
|
414
534
|
break;
|
|
535
|
+
case import_types.DeviceStateID.OPEN_BOX:
|
|
536
|
+
await station.open(device);
|
|
537
|
+
break;
|
|
415
538
|
}
|
|
416
539
|
} catch (error) {
|
|
417
540
|
this.logger.error(`cameras - Error:`, error);
|
|
@@ -421,6 +544,183 @@ class euSec extends utils.Adapter {
|
|
|
421
544
|
this.logger.debug(`state ${id} deleted`);
|
|
422
545
|
}
|
|
423
546
|
}
|
|
547
|
+
/**
|
|
548
|
+
* Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...
|
|
549
|
+
* Using this method requires "common.message" property to be set to true in io-package.json
|
|
550
|
+
*/
|
|
551
|
+
async onMessage(obj) {
|
|
552
|
+
if (typeof obj === "object" && obj.message) {
|
|
553
|
+
try {
|
|
554
|
+
if (obj.command === "quickResponse") {
|
|
555
|
+
this.log.debug(`quickResponse command - message: ${JSON.stringify(obj.message)}`);
|
|
556
|
+
if (typeof obj.message === "object" && typeof obj.message.station_sn === "string" && obj.message.station_sn !== "" && typeof obj.message.device_sn === "string" && obj.message.device_sn !== "" && typeof obj.message.voice_id === "number") {
|
|
557
|
+
try {
|
|
558
|
+
const station = await this.eufy.getStation(obj.message.station_sn);
|
|
559
|
+
const device = await this.eufy.getDevice(obj.message.device_sn);
|
|
560
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceQuickResponse)) {
|
|
561
|
+
await station.quickResponse(device, obj.message.voice_id);
|
|
562
|
+
if (obj.callback)
|
|
563
|
+
this.sendTo(obj.from, obj.command, {
|
|
564
|
+
sended: true,
|
|
565
|
+
result: "quickResponse command sended"
|
|
566
|
+
}, obj.callback);
|
|
567
|
+
} else {
|
|
568
|
+
if (obj.callback)
|
|
569
|
+
this.sendTo(obj.from, obj.command, {
|
|
570
|
+
sended: false,
|
|
571
|
+
result: "quickResponse command not supported by specified device"
|
|
572
|
+
}, obj.callback);
|
|
573
|
+
}
|
|
574
|
+
} catch (error) {
|
|
575
|
+
if (error instanceof import_eufy_security_client.StationNotFoundError) {
|
|
576
|
+
if (obj.callback)
|
|
577
|
+
this.sendTo(obj.from, obj.command, {
|
|
578
|
+
sended: false,
|
|
579
|
+
result: "quickResponse command not sended because specified station doesn't exists"
|
|
580
|
+
}, obj.callback);
|
|
581
|
+
} else if (error instanceof import_eufy_security_client.DeviceNotFoundError) {
|
|
582
|
+
if (obj.callback)
|
|
583
|
+
this.sendTo(obj.from, obj.command, {
|
|
584
|
+
sended: false,
|
|
585
|
+
result: "quickResponse command not sended because specified device doesn't exists"
|
|
586
|
+
}, obj.callback);
|
|
587
|
+
} else {
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
} else {
|
|
592
|
+
if (obj.callback)
|
|
593
|
+
this.sendTo(obj.from, obj.command, {
|
|
594
|
+
sended: false,
|
|
595
|
+
result: "quickResponse command not sended because some required parameters are missing"
|
|
596
|
+
}, obj.callback);
|
|
597
|
+
}
|
|
598
|
+
} else if (obj.command === "getQuickResponseVoices") {
|
|
599
|
+
this.log.debug(`getQuickResponseVoices command - message: ${JSON.stringify(obj.message)}`);
|
|
600
|
+
if (typeof obj.message === "object" && typeof obj.message.device_sn === "string" && obj.message.device_sn !== "") {
|
|
601
|
+
const voices = await this.eufy.getApi().getVoices(obj.message.device_sn);
|
|
602
|
+
if (obj.callback)
|
|
603
|
+
this.sendTo(obj.from, obj.command, {
|
|
604
|
+
sended: true,
|
|
605
|
+
result: voices
|
|
606
|
+
}, obj.callback);
|
|
607
|
+
} else {
|
|
608
|
+
if (obj.callback)
|
|
609
|
+
this.sendTo(obj.from, obj.command, {
|
|
610
|
+
sended: false,
|
|
611
|
+
result: "getQuickResponseVoices command not sended because some required parameters are missing"
|
|
612
|
+
}, obj.callback);
|
|
613
|
+
}
|
|
614
|
+
} else if (obj.command === "snooze") {
|
|
615
|
+
this.log.debug(`snooze command - message: ${JSON.stringify(obj.message)}`);
|
|
616
|
+
if (typeof obj.message === "object" && typeof obj.message.station_sn === "string" && obj.message.station_sn !== "" && typeof obj.message.device_sn === "string" && obj.message.device_sn !== "" && typeof obj.message.snooze_time === "number" && (obj.message.snooze_chime === void 0 || typeof obj.message.snooze_chime === "boolean") && (obj.message.snooze_homebase === void 0 || typeof obj.message.snooze_homebase === "boolean") && (obj.message.snooze_motion === void 0 || typeof obj.message.snooze_motion === "boolean")) {
|
|
617
|
+
try {
|
|
618
|
+
const station = await this.eufy.getStation(obj.message.station_sn);
|
|
619
|
+
const device = await this.eufy.getDevice(obj.message.device_sn);
|
|
620
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceSnooze)) {
|
|
621
|
+
await station.snooze(device, {
|
|
622
|
+
snooze_time: obj.message.snooze_time,
|
|
623
|
+
snooze_chime: obj.message.snooze_chime,
|
|
624
|
+
snooze_homebase: obj.message.snooze_homebase,
|
|
625
|
+
snooze_motion: obj.message.snooze_motion
|
|
626
|
+
});
|
|
627
|
+
if (obj.callback)
|
|
628
|
+
this.sendTo(obj.from, obj.command, {
|
|
629
|
+
sended: true,
|
|
630
|
+
result: "snooze command sended"
|
|
631
|
+
}, obj.callback);
|
|
632
|
+
} else {
|
|
633
|
+
if (obj.callback)
|
|
634
|
+
this.sendTo(obj.from, obj.command, {
|
|
635
|
+
sended: false,
|
|
636
|
+
result: "snooze command not supported by specified device"
|
|
637
|
+
}, obj.callback);
|
|
638
|
+
}
|
|
639
|
+
} catch (error) {
|
|
640
|
+
if (error instanceof import_eufy_security_client.StationNotFoundError) {
|
|
641
|
+
if (obj.callback)
|
|
642
|
+
this.sendTo(obj.from, obj.command, {
|
|
643
|
+
sended: false,
|
|
644
|
+
result: "snooze command not sended because specified station doesn't exists"
|
|
645
|
+
}, obj.callback);
|
|
646
|
+
} else if (error instanceof import_eufy_security_client.DeviceNotFoundError) {
|
|
647
|
+
if (obj.callback)
|
|
648
|
+
this.sendTo(obj.from, obj.command, {
|
|
649
|
+
sended: false,
|
|
650
|
+
result: "snooze command not sended because specified device doesn't exists"
|
|
651
|
+
}, obj.callback);
|
|
652
|
+
} else {
|
|
653
|
+
throw error;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
} else {
|
|
657
|
+
if (obj.callback)
|
|
658
|
+
this.sendTo(obj.from, obj.command, {
|
|
659
|
+
sended: false,
|
|
660
|
+
result: "snooze command not sended because some required parameters are missing"
|
|
661
|
+
}, obj.callback);
|
|
662
|
+
}
|
|
663
|
+
} else if (obj.command === "chime") {
|
|
664
|
+
this.log.debug(`snooze command - message: ${JSON.stringify(obj.message)}`);
|
|
665
|
+
if (typeof obj.message === "object" && typeof obj.message.station_sn === "string" && obj.message.station_sn !== "" && (obj.message.ringtone === void 0 || typeof obj.message.ringtone === "number")) {
|
|
666
|
+
try {
|
|
667
|
+
const station = await this.eufy.getStation(obj.message.station_sn);
|
|
668
|
+
if (station.hasCommand(import_eufy_security_client.CommandName.StationChime)) {
|
|
669
|
+
await station.chimeHomebase(obj.message.ringtone !== void 0 && typeof obj.message.ringtone === "number" ? obj.message.ringtone : 0);
|
|
670
|
+
if (obj.callback)
|
|
671
|
+
this.sendTo(obj.from, obj.command, {
|
|
672
|
+
sended: true,
|
|
673
|
+
result: "chime command sended"
|
|
674
|
+
}, obj.callback);
|
|
675
|
+
} else {
|
|
676
|
+
if (obj.callback)
|
|
677
|
+
this.sendTo(obj.from, obj.command, {
|
|
678
|
+
sended: false,
|
|
679
|
+
result: "chime command not supported by specified station"
|
|
680
|
+
}, obj.callback);
|
|
681
|
+
}
|
|
682
|
+
if (obj.callback)
|
|
683
|
+
this.sendTo(obj.from, obj.command, "chime command sended", obj.callback);
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (error instanceof import_eufy_security_client.StationNotFoundError) {
|
|
686
|
+
if (obj.callback)
|
|
687
|
+
this.sendTo(obj.from, obj.command, {
|
|
688
|
+
sended: false,
|
|
689
|
+
result: "snooze command not sended because specified station doesn't exists"
|
|
690
|
+
}, obj.callback);
|
|
691
|
+
} else {
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
} else if (obj.command === "pollRefresh") {
|
|
697
|
+
this.log.debug(`pollRefresh command`);
|
|
698
|
+
await this.eufy.refreshCloudData();
|
|
699
|
+
if (obj.callback)
|
|
700
|
+
this.sendTo(obj.from, obj.command, {
|
|
701
|
+
sended: true,
|
|
702
|
+
result: "pollRefresh command sended"
|
|
703
|
+
}, obj.callback);
|
|
704
|
+
} else {
|
|
705
|
+
const errorMessage = `Received unknown message: ${JSON.stringify(obj.message)}`;
|
|
706
|
+
this.log.warn(errorMessage);
|
|
707
|
+
if (obj.callback)
|
|
708
|
+
this.sendTo(obj.from, obj.command, {
|
|
709
|
+
sended: false,
|
|
710
|
+
result: errorMessage
|
|
711
|
+
}, obj.callback);
|
|
712
|
+
}
|
|
713
|
+
} catch (error) {
|
|
714
|
+
const errorMessage = `Error during processing of received message: ${error instanceof Error ? `${error.name} - ${error.message}` : error}`;
|
|
715
|
+
this.log.error(errorMessage);
|
|
716
|
+
if (obj.callback)
|
|
717
|
+
this.sendTo(obj.from, obj.command, {
|
|
718
|
+
sended: false,
|
|
719
|
+
result: errorMessage
|
|
720
|
+
}, obj.callback);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
424
724
|
getStateCommon(property) {
|
|
425
725
|
const state = {
|
|
426
726
|
name: property.label,
|
|
@@ -428,7 +728,7 @@ class euSec extends utils.Adapter {
|
|
|
428
728
|
role: "state",
|
|
429
729
|
read: property.readable,
|
|
430
730
|
write: property.writeable,
|
|
431
|
-
def: property.default
|
|
731
|
+
def: property.type === "object" && typeof property.default === "object" ? JSON.stringify(property.default) : property.default
|
|
432
732
|
};
|
|
433
733
|
switch (property.type) {
|
|
434
734
|
case "number": {
|
|
@@ -689,6 +989,19 @@ class euSec extends utils.Adapter {
|
|
|
689
989
|
native: {}
|
|
690
990
|
});
|
|
691
991
|
}
|
|
992
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceOpen)) {
|
|
993
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.OPEN_BOX), {
|
|
994
|
+
type: "state",
|
|
995
|
+
common: {
|
|
996
|
+
name: "Open Box",
|
|
997
|
+
type: "boolean",
|
|
998
|
+
role: "button.start",
|
|
999
|
+
read: false,
|
|
1000
|
+
write: true
|
|
1001
|
+
},
|
|
1002
|
+
native: {}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
692
1005
|
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceStartLivestream)) {
|
|
693
1006
|
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.START_STREAM), {
|
|
694
1007
|
type: "state",
|
|
@@ -831,10 +1144,38 @@ class euSec extends utils.Adapter {
|
|
|
831
1144
|
this.delObjectAsync(station.getStateID("", 0), { recursive: true }).catch((error) => {
|
|
832
1145
|
this.logger.error(`Error deleting states of removed station`, error);
|
|
833
1146
|
});
|
|
834
|
-
|
|
1147
|
+
this.delFileAsync(this.namespace, station.getSerial()).catch((error) => {
|
|
835
1148
|
this.logger.error(`Error deleting fs contents of removed station`, error);
|
|
836
1149
|
});
|
|
837
1150
|
}
|
|
1151
|
+
/*private async downloadEventVideo(device: Device, event_time: number, full_path: string | undefined, cipher_id: number | undefined): Promise<void> {
|
|
1152
|
+
this.logger.debug(`Device: ${device.getSerial()} full_path: ${full_path} cipher_id: ${cipher_id}`);
|
|
1153
|
+
try {
|
|
1154
|
+
if (!isEmpty(full_path) && cipher_id !== undefined) {
|
|
1155
|
+
const station = await this.eufy.getStation(device.getStationSerial());
|
|
1156
|
+
|
|
1157
|
+
if (station !== undefined) {
|
|
1158
|
+
if (this.downloadEvent[device.getSerial()])
|
|
1159
|
+
clearTimeout(this.downloadEvent[device.getSerial()]);
|
|
1160
|
+
|
|
1161
|
+
let videoLength = getVideoClipLength(device);
|
|
1162
|
+
const time_passed = (new Date().getTime() - new Date(event_time).getTime()) / 1000;
|
|
1163
|
+
|
|
1164
|
+
if (time_passed >= videoLength)
|
|
1165
|
+
videoLength = 1;
|
|
1166
|
+
else
|
|
1167
|
+
videoLength = videoLength - time_passed;
|
|
1168
|
+
|
|
1169
|
+
this.logger.info(`Downloading video event for device ${device.getSerial()} in ${videoLength} seconds...`);
|
|
1170
|
+
this.downloadEvent[device.getSerial()] = setTimeout(async () => {
|
|
1171
|
+
station.startDownload(device, full_path!, cipher_id);
|
|
1172
|
+
}, videoLength * 1000);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
this.logger.error(`Device: ${device.getSerial()} - Error`, error);
|
|
1177
|
+
}
|
|
1178
|
+
}*/
|
|
838
1179
|
async handlePushNotification(message) {
|
|
839
1180
|
try {
|
|
840
1181
|
if (message.device_sn !== void 0) {
|
|
@@ -895,8 +1236,10 @@ class euSec extends utils.Adapter {
|
|
|
895
1236
|
const reg = new RegExp(`^${this.namespace}.[0-9A-Z]+.[a-z]+.[0-9A-Z]+$`);
|
|
896
1237
|
for (const id of allDevices) {
|
|
897
1238
|
if (id._id.match(reg)) {
|
|
898
|
-
const
|
|
899
|
-
|
|
1239
|
+
const values = id._id.split(".");
|
|
1240
|
+
const stateChannel = values[3];
|
|
1241
|
+
const serial = values[4];
|
|
1242
|
+
if (!deviceSerials.includes(serial) || deviceSerials.includes(serial) && devices[deviceSerials.indexOf(serial)].getStateChannel() !== "unknown" && stateChannel === "unknown") {
|
|
900
1243
|
await this.delObjectAsync(id._id, { recursive: true });
|
|
901
1244
|
}
|
|
902
1245
|
}
|
|
@@ -947,41 +1290,29 @@ class euSec extends utils.Adapter {
|
|
|
947
1290
|
} catch (error) {
|
|
948
1291
|
this.log.error(`Delete obsolete properties ERROR - ${JSON.stringify(error)}`);
|
|
949
1292
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
if (
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
import_fs_extra.default.removeSync(path.join(dir_path, content, dir, file));
|
|
967
|
-
deletedFiles++;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
if (deletedFiles === files.length) {
|
|
971
|
-
import_fs_extra.default.removeSync(path.join(dir_path, content, dir));
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
}
|
|
1293
|
+
try {
|
|
1294
|
+
const contents = await this.readDirAsync(this.namespace, "");
|
|
1295
|
+
for (const content of contents.filter((fn) => fn.file.match("^T[0-9A-Z]+$") !== null && fn.isDir)) {
|
|
1296
|
+
if (!stationSerials.includes(content.file)) {
|
|
1297
|
+
await this.delFileAsync(this.namespace, content.file);
|
|
1298
|
+
} else {
|
|
1299
|
+
const dirContents = await this.readDirAsync(this.namespace, content.file);
|
|
1300
|
+
for (const dir of dirContents.filter((fn) => Object.values(import_types.DataLocation).includes(fn.file) && fn.isDir)) {
|
|
1301
|
+
const files = await this.readDirAsync(this.namespace, path.join(content.file, dir.file));
|
|
1302
|
+
let deletedFiles = 0;
|
|
1303
|
+
for (const file of files.filter((fn) => !deviceSerials.includes(fn.file.substring(0, 16)) && !fn.isDir)) {
|
|
1304
|
+
await this.delFileAsync(this.namespace, path.join(content.file, dir.file, file.file));
|
|
1305
|
+
deletedFiles++;
|
|
1306
|
+
}
|
|
1307
|
+
if (deletedFiles === files.length) {
|
|
1308
|
+
await this.delFileAsync(this.namespace, path.join(content.file, dir.file));
|
|
975
1309
|
}
|
|
976
1310
|
}
|
|
977
1311
|
}
|
|
978
|
-
resolve();
|
|
979
|
-
} catch (error) {
|
|
980
|
-
reject(error);
|
|
981
1312
|
}
|
|
982
|
-
}
|
|
983
|
-
this.log.error(`Delete obsolete directories/files ERROR - ${
|
|
984
|
-
}
|
|
1313
|
+
} catch (error) {
|
|
1314
|
+
this.log.error(`Delete obsolete directories/files ERROR - ${error}`);
|
|
1315
|
+
}
|
|
985
1316
|
}
|
|
986
1317
|
async onClose() {
|
|
987
1318
|
await this.setStateAsync("info.connection", { val: false, ack: true }).catch();
|
|
@@ -1074,16 +1405,7 @@ class euSec extends utils.Adapter {
|
|
|
1074
1405
|
await this.setStateAsync("info.mqtt_connection", { val: false, ack: true });
|
|
1075
1406
|
}
|
|
1076
1407
|
async onStationCommandResult(station, result) {
|
|
1077
|
-
if (result.return_code !== 0 && result.command_type
|
|
1078
|
-
this.logger.debug(`Station: ${station.getSerial()} command ${import_eufy_security_client.CommandType[result.command_type]} failed with error: ${import_eufy_security_client.ErrorCode[result.return_code]} (${result.return_code}) fallback to RTMP livestream...`);
|
|
1079
|
-
try {
|
|
1080
|
-
const device = await this.eufy.getStationDevice(station.getSerial(), result.channel);
|
|
1081
|
-
if (device.isCamera())
|
|
1082
|
-
this.eufy.startCloudLivestream(device.getSerial());
|
|
1083
|
-
} catch (error) {
|
|
1084
|
-
this.logger.error(`Station: ${station.getSerial()} command ${import_eufy_security_client.CommandType[result.command_type]} RTMP fallback failed - Error ${error}`);
|
|
1085
|
-
}
|
|
1086
|
-
} else if (result.return_code !== 0 && result.command_type !== import_eufy_security_client.CommandType.P2P_QUERY_STATUS_IN_LOCK) {
|
|
1408
|
+
if (result.return_code !== 0 && result.command_type !== import_eufy_security_client.CommandType.P2P_QUERY_STATUS_IN_LOCK) {
|
|
1087
1409
|
this.logger.error(`Station: ${station.getSerial()} command ${import_eufy_security_client.CommandType[result.command_type]} failed with error: ${import_eufy_security_client.ErrorCode[result.return_code]} (${result.return_code})`);
|
|
1088
1410
|
}
|
|
1089
1411
|
}
|
|
@@ -1122,12 +1444,12 @@ class euSec extends utils.Adapter {
|
|
|
1122
1444
|
try {
|
|
1123
1445
|
const picture = value;
|
|
1124
1446
|
const fileName = `${device.getSerial()}.${picture.type.ext}`;
|
|
1125
|
-
const filePath = path.join(
|
|
1126
|
-
if (!
|
|
1127
|
-
|
|
1447
|
+
const filePath = path.join(device.getStationSerial(), import_types.DataLocation.LAST_EVENT);
|
|
1448
|
+
if (!await this.fileExistsAsync(this.namespace, filePath)) {
|
|
1449
|
+
await this.mkdirAsync(this.namespace, filePath);
|
|
1128
1450
|
}
|
|
1129
|
-
await
|
|
1130
|
-
await
|
|
1451
|
+
await this.writeFileAsync(this.namespace, path.join(filePath, fileName), picture.data);
|
|
1452
|
+
await this.setStateAsync(device.getStateID(import_types.DeviceStateID.PICTURE_URL), `/files/${this.namespace}/${device.getStationSerial()}/${import_types.DataLocation.LAST_EVENT}/${device.getSerial()}.${picture.type.ext}`, true);
|
|
1131
1453
|
await (0, import_utils.setStateChangedAsync)(this, device.getStateID(import_types.DeviceStateID.PICTURE_HTML), (0, import_utils.getImageAsHTML)(picture.data, picture.type.mime));
|
|
1132
1454
|
} catch (err) {
|
|
1133
1455
|
const error = (0, import_eufy_security_client.ensureError)(err);
|
|
@@ -1174,7 +1496,9 @@ class euSec extends utils.Adapter {
|
|
|
1174
1496
|
try {
|
|
1175
1497
|
this.setStateAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM), { val: `${this.config.https ? "https" : "http"}://${this.config.hostname}:${this.config.go2rtc_api_port}/stream.html?src=${device.getSerial()}`, ack: true });
|
|
1176
1498
|
this.setStateAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM_RTSP), { val: `rtsp://${this.config.hostname}:${this.config.go2rtc_rtsp_port}/${device.getSerial()}`, ack: true });
|
|
1177
|
-
await (0, import_video.
|
|
1499
|
+
await (0, import_video.streamToGo2rtc)(device.getSerial(), videostream, audiostream, this.logger, this.config, this.namespace, metadata).catch((error) => {
|
|
1500
|
+
this.logger.debug(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Stopping livestream...`, error);
|
|
1501
|
+
});
|
|
1178
1502
|
} catch (error) {
|
|
1179
1503
|
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Stopping livestream...`, error);
|
|
1180
1504
|
this.eufy.stopStationLivestream(device.getSerial()).catch(async (error2) => {
|
|
@@ -1186,6 +1510,59 @@ class euSec extends utils.Adapter {
|
|
|
1186
1510
|
this.delStateAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM));
|
|
1187
1511
|
this.delStateAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM_RTSP));
|
|
1188
1512
|
}
|
|
1513
|
+
/*private async onStationDownloadFinish(_station: Station, _device: Device): Promise<void> {
|
|
1514
|
+
//this.logger.trace(`Station: ${station.getSerial()} channel: ${channel}`);
|
|
1515
|
+
}*/
|
|
1516
|
+
/*private async onStationDownloadStart(station: Station, device: Device, metadata: StreamMetadata, videostream: Readable, audiostream: Readable): Promise<void> {
|
|
1517
|
+
try {
|
|
1518
|
+
//TODO: Deactivated because the decryption of the download has changed.
|
|
1519
|
+
await removeFiles(this, station.getSerial(), DataLocation.TEMP, device.getSerial()).catch();
|
|
1520
|
+
const file_path = getDataFilePath(this, station.getSerial(), DataLocation.TEMP, `${device.getSerial()}${STREAM_FILE_NAME_EXT}`);
|
|
1521
|
+
|
|
1522
|
+
await ffmpegStreamToHls(this.config, this.namespace, metadata, videostream, audiostream, file_path, this.logger)
|
|
1523
|
+
.then(async () => {
|
|
1524
|
+
if (fse.pathExistsSync(file_path)) {
|
|
1525
|
+
await removeFiles(this, station.getSerial(), DataLocation.LAST_EVENT, device.getSerial());
|
|
1526
|
+
return true;
|
|
1527
|
+
}
|
|
1528
|
+
return false;
|
|
1529
|
+
})
|
|
1530
|
+
.then(async (result) => {
|
|
1531
|
+
if (result)
|
|
1532
|
+
await moveFiles(this, station.getSerial(), device.getSerial(), DataLocation.TEMP, DataLocation.LAST_EVENT);
|
|
1533
|
+
return result;
|
|
1534
|
+
})
|
|
1535
|
+
.then(async (result) => {
|
|
1536
|
+
if (result) {
|
|
1537
|
+
const filename_without_ext = getDataFilePath(this, station.getSerial(), DataLocation.LAST_EVENT, device.getSerial());
|
|
1538
|
+
setStateAsync(this, device.getStateID(DeviceStateID.LAST_EVENT_VIDEO_URL), "Last captured video URL", `/${this.namespace}/${station.getSerial()}/${DataLocation.LAST_EVENT}/${device.getSerial()}${STREAM_FILE_NAME_EXT}`, "url");
|
|
1539
|
+
if (fse.pathExistsSync(`${filename_without_ext}${STREAM_FILE_NAME_EXT}`))
|
|
1540
|
+
await ffmpegPreviewImage(this.config, `${filename_without_ext}${STREAM_FILE_NAME_EXT}`, `${filename_without_ext}${IMAGE_FILE_JPEG_EXT}`, this.logger)
|
|
1541
|
+
.then(() => {
|
|
1542
|
+
setStateAsync(this, device.getStateID(DeviceStateID.LAST_EVENT_PIC_URL), "Last event picture URL", `/${this.namespace}/${station.getSerial()}/${DataLocation.LAST_EVENT}/${device.getSerial()}${IMAGE_FILE_JPEG_EXT}`, "url");
|
|
1543
|
+
try {
|
|
1544
|
+
if (fse.existsSync(`${filename_without_ext}${IMAGE_FILE_JPEG_EXT}`)) {
|
|
1545
|
+
const image_data = getImageAsHTML(fse.readFileSync(`${filename_without_ext}${IMAGE_FILE_JPEG_EXT}`));
|
|
1546
|
+
setStateAsync(this, device.getStateID(DeviceStateID.LAST_EVENT_PIC_HTML), "Last event picture HTML image", image_data, "html");
|
|
1547
|
+
}
|
|
1548
|
+
} catch (error) {
|
|
1549
|
+
this.logger.error(`Station: ${station.getSerial()} device: ${device.getSerial()} - Error`, error);
|
|
1550
|
+
}
|
|
1551
|
+
})
|
|
1552
|
+
.catch((error) => {
|
|
1553
|
+
this.logger.error(`ffmpegPreviewImage - station: ${station.getSerial()} device: ${device.getSerial()} - Error`, error);
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
})
|
|
1557
|
+
.catch(async (error) => {
|
|
1558
|
+
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Cancelling download...`, error);
|
|
1559
|
+
await this.eufy.cancelStationDownload(device.getSerial());
|
|
1560
|
+
});
|
|
1561
|
+
} catch(error) {
|
|
1562
|
+
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Cancelling download...`, error);
|
|
1563
|
+
await this.eufy.cancelStationDownload(device.getSerial());
|
|
1564
|
+
}
|
|
1565
|
+
}*/
|
|
1189
1566
|
onStationRTSPUrl(station, device, value) {
|
|
1190
1567
|
(0, import_utils.setStateChangedAsync)(this, device.getStateID(import_types.DeviceStateID.RTSP_STREAM_URL), value);
|
|
1191
1568
|
}
|
|
@@ -1233,4 +1610,8 @@ if (require.main !== module) {
|
|
|
1233
1610
|
} else {
|
|
1234
1611
|
(() => new euSec())();
|
|
1235
1612
|
}
|
|
1613
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1614
|
+
0 && (module.exports = {
|
|
1615
|
+
euSec
|
|
1616
|
+
});
|
|
1236
1617
|
//# sourceMappingURL=main.js.map
|