iobroker.eusec 1.1.0 → 1.1.2
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/README.md +13 -0
- package/admin/i18n/uk/translations.json +26 -0
- package/build/lib/interfaces.js +16 -2
- package/build/lib/interfaces.js.map +7 -1
- package/build/lib/log.js +70 -48
- package/build/lib/log.js.map +7 -1
- package/build/lib/tools.js +79 -84
- package/build/lib/tools.js.map +7 -1
- package/build/lib/types.js +92 -61
- package/build/lib/types.js.map +7 -1
- package/build/lib/utils.js +239 -234
- package/build/lib/utils.js.map +7 -1
- package/build/lib/video.js +243 -258
- package/build/lib/video.js.map +7 -1
- package/build/lib/web.js +58 -84
- package/build/lib/web.js.map +7 -1
- package/build/main.js +1177 -1421
- package/build/main.js.map +7 -1
- package/io-package.json +32 -4
- package/package.json +20 -42
package/build/main.js
CHANGED
|
@@ -1,1481 +1,1237 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}));
|
|
16
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
-
}) : function(o, v) {
|
|
19
|
-
o["default"] = v;
|
|
20
|
-
});
|
|
21
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
|
-
if (mod && mod.__esModule) return mod;
|
|
23
|
-
var result = {};
|
|
24
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
25
|
-
__setModuleDefault(result, mod);
|
|
26
|
-
return result;
|
|
27
|
-
};
|
|
28
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
29
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
30
15
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
18
|
+
mod
|
|
19
|
+
));
|
|
20
|
+
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
21
|
+
var path = __toESM(require("path"));
|
|
22
|
+
var import_eufy_security_client = require("eufy-security-client");
|
|
23
|
+
var import_i18n_iso_countries = require("i18n-iso-countries");
|
|
24
|
+
var import_i18n_iso_languages = require("@cospired/i18n-iso-languages");
|
|
25
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
26
|
+
var import_util = __toESM(require("util"));
|
|
27
|
+
var import_child_process = __toESM(require("child_process"));
|
|
28
|
+
var import_go2rtc_static = __toESM(require("go2rtc-static"));
|
|
29
|
+
var import_os = __toESM(require("os"));
|
|
30
|
+
var import_types = require("./lib/types");
|
|
31
|
+
var import_utils = require("./lib/utils");
|
|
32
|
+
var import_log = require("./lib/log");
|
|
33
|
+
var import_video = require("./lib/video");
|
|
47
34
|
class euSec extends utils.Adapter {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
super({
|
|
37
|
+
...options,
|
|
38
|
+
name: "eusec"
|
|
39
|
+
});
|
|
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
|
+
this.on("ready", this.onReady.bind(this));
|
|
50
|
+
this.on("stateChange", this.onStateChange.bind(this));
|
|
51
|
+
this.on("unload", this.onUnload.bind(this));
|
|
52
|
+
}
|
|
53
|
+
async onReady() {
|
|
54
|
+
this.logger = new import_log.ioBrokerLogger(this.log);
|
|
55
|
+
await this.setObjectNotExistsAsync("verify_code", {
|
|
56
|
+
type: "state",
|
|
57
|
+
common: {
|
|
58
|
+
name: "2FA verification code",
|
|
59
|
+
type: "string",
|
|
60
|
+
role: "state",
|
|
61
|
+
read: true,
|
|
62
|
+
write: true
|
|
63
|
+
},
|
|
64
|
+
native: {}
|
|
65
|
+
});
|
|
66
|
+
await this.setObjectNotExistsAsync("received_captcha_html", {
|
|
67
|
+
type: "state",
|
|
68
|
+
common: {
|
|
69
|
+
name: "Received captcha image HTML",
|
|
70
|
+
type: "string",
|
|
71
|
+
role: "state",
|
|
72
|
+
read: true,
|
|
73
|
+
write: false
|
|
74
|
+
},
|
|
75
|
+
native: {}
|
|
76
|
+
});
|
|
77
|
+
await this.setObjectNotExistsAsync("captcha", {
|
|
78
|
+
type: "state",
|
|
79
|
+
common: {
|
|
80
|
+
name: "Enter captcha",
|
|
81
|
+
type: "string",
|
|
82
|
+
role: "state",
|
|
83
|
+
read: true,
|
|
84
|
+
write: true
|
|
85
|
+
},
|
|
86
|
+
native: {}
|
|
87
|
+
});
|
|
88
|
+
await this.setObjectNotExistsAsync("info", {
|
|
89
|
+
type: "channel",
|
|
90
|
+
common: {
|
|
91
|
+
name: "info"
|
|
92
|
+
},
|
|
93
|
+
native: {}
|
|
94
|
+
});
|
|
95
|
+
await this.setObjectNotExistsAsync("info.connection", {
|
|
96
|
+
type: "state",
|
|
97
|
+
common: {
|
|
98
|
+
name: "Global connection",
|
|
99
|
+
type: "boolean",
|
|
100
|
+
role: "indicator.connection",
|
|
101
|
+
read: true,
|
|
102
|
+
write: false
|
|
103
|
+
},
|
|
104
|
+
native: {}
|
|
105
|
+
});
|
|
106
|
+
await this.setStateAsync("info.connection", { val: false, ack: true });
|
|
107
|
+
await this.setObjectNotExistsAsync("info.push_connection", {
|
|
108
|
+
type: "state",
|
|
109
|
+
common: {
|
|
110
|
+
name: "Push notification connection",
|
|
111
|
+
type: "boolean",
|
|
112
|
+
role: "indicator.connection",
|
|
113
|
+
read: true,
|
|
114
|
+
write: false
|
|
115
|
+
},
|
|
116
|
+
native: {}
|
|
117
|
+
});
|
|
118
|
+
await this.setStateAsync("info.push_connection", { val: false, ack: true });
|
|
119
|
+
await this.setObjectNotExistsAsync("info.mqtt_connection", {
|
|
120
|
+
type: "state",
|
|
121
|
+
common: {
|
|
122
|
+
name: "MQTT connection",
|
|
123
|
+
type: "boolean",
|
|
124
|
+
role: "indicator.connection",
|
|
125
|
+
read: true,
|
|
126
|
+
write: false
|
|
127
|
+
},
|
|
128
|
+
native: {}
|
|
129
|
+
});
|
|
130
|
+
await this.setStateAsync("info.mqtt_connection", { val: false, ack: true });
|
|
131
|
+
try {
|
|
132
|
+
const connection = await this.getStatesAsync("*.connection");
|
|
133
|
+
if (connection)
|
|
134
|
+
Object.keys(connection).forEach(async (id) => {
|
|
135
|
+
await this.setStateAsync(id, { val: false, ack: true });
|
|
52
136
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
};
|
|
56
|
-
this.captchaId = null;
|
|
57
|
-
this.verify_code = false;
|
|
58
|
-
const data_dir = utils.getAbsoluteInstanceDataDir(this);
|
|
59
|
-
this.persistentFile = path.join(data_dir, "adapter.json");
|
|
60
|
-
if (!fs_extra_1.default.existsSync(data_dir))
|
|
61
|
-
fs_extra_1.default.mkdirSync(data_dir);
|
|
62
|
-
this.on("ready", this.onReady.bind(this));
|
|
63
|
-
this.on("stateChange", this.onStateChange.bind(this));
|
|
64
|
-
// this.on("objectChange", this.onObjectChange.bind(this));
|
|
65
|
-
// this.on("message", this.onMessage.bind(this));
|
|
66
|
-
this.on("unload", this.onUnload.bind(this));
|
|
137
|
+
} catch (error) {
|
|
138
|
+
this.logger.error("Reset connection states - Error", error);
|
|
67
139
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
common: {
|
|
87
|
-
name: "Received captcha image HTML",
|
|
88
|
-
type: "string",
|
|
89
|
-
role: "state",
|
|
90
|
-
read: true,
|
|
91
|
-
write: false,
|
|
92
|
-
},
|
|
93
|
-
native: {},
|
|
94
|
-
});
|
|
95
|
-
await this.setObjectNotExistsAsync("captcha", {
|
|
96
|
-
type: "state",
|
|
97
|
-
common: {
|
|
98
|
-
name: "Enter captcha",
|
|
99
|
-
type: "string",
|
|
100
|
-
role: "state",
|
|
101
|
-
read: true,
|
|
102
|
-
write: true,
|
|
103
|
-
},
|
|
104
|
-
native: {},
|
|
105
|
-
});
|
|
106
|
-
await this.setObjectNotExistsAsync("info", {
|
|
107
|
-
type: "channel",
|
|
108
|
-
common: {
|
|
109
|
-
name: "info"
|
|
110
|
-
},
|
|
111
|
-
native: {},
|
|
112
|
-
});
|
|
113
|
-
await this.setObjectNotExistsAsync("info.connection", {
|
|
114
|
-
type: "state",
|
|
115
|
-
common: {
|
|
116
|
-
name: "Global connection",
|
|
117
|
-
type: "boolean",
|
|
118
|
-
role: "indicator.connection",
|
|
119
|
-
read: true,
|
|
120
|
-
write: false,
|
|
121
|
-
},
|
|
122
|
-
native: {},
|
|
123
|
-
});
|
|
124
|
-
await this.setStateAsync("info.connection", { val: false, ack: true });
|
|
125
|
-
await this.setObjectNotExistsAsync("info.push_connection", {
|
|
126
|
-
type: "state",
|
|
127
|
-
common: {
|
|
128
|
-
name: "Push notification connection",
|
|
129
|
-
type: "boolean",
|
|
130
|
-
role: "indicator.connection",
|
|
131
|
-
read: true,
|
|
132
|
-
write: false,
|
|
133
|
-
},
|
|
134
|
-
native: {},
|
|
135
|
-
});
|
|
136
|
-
await this.setStateAsync("info.push_connection", { val: false, ack: true });
|
|
137
|
-
await this.setObjectNotExistsAsync("info.mqtt_connection", {
|
|
138
|
-
type: "state",
|
|
139
|
-
common: {
|
|
140
|
-
name: "MQTT connection",
|
|
141
|
-
type: "boolean",
|
|
142
|
-
role: "indicator.connection",
|
|
143
|
-
read: true,
|
|
144
|
-
write: false,
|
|
145
|
-
},
|
|
146
|
-
native: {},
|
|
147
|
-
});
|
|
148
|
-
await this.setStateAsync("info.mqtt_connection", { val: false, ack: true });
|
|
149
|
-
try {
|
|
150
|
-
const connection = await this.getStatesAsync("*.connection");
|
|
151
|
-
if (connection)
|
|
152
|
-
Object.keys(connection).forEach(async (id) => {
|
|
153
|
-
await this.setStateAsync(id, { val: false, ack: true });
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
catch (error) {
|
|
157
|
-
this.logger.error("Reset connection states - Error", error);
|
|
158
|
-
}
|
|
159
|
-
try {
|
|
160
|
-
const sensorList = [
|
|
161
|
-
eufy_security_client_1.PropertyName.DeviceMotionDetected,
|
|
162
|
-
eufy_security_client_1.PropertyName.DevicePersonDetected,
|
|
163
|
-
eufy_security_client_1.PropertyName.DeviceSoundDetected,
|
|
164
|
-
eufy_security_client_1.PropertyName.DeviceCryingDetected,
|
|
165
|
-
eufy_security_client_1.PropertyName.DevicePetDetected,
|
|
166
|
-
eufy_security_client_1.PropertyName.DeviceRinging
|
|
167
|
-
];
|
|
168
|
-
for (const sensorName of sensorList) {
|
|
169
|
-
const sensors = await this.getStatesAsync(`*.${(0, utils_1.convertCamelCaseToSnakeCase)(sensorName)}`);
|
|
170
|
-
if (sensors)
|
|
171
|
-
Object.keys(sensors).forEach(async (id) => {
|
|
172
|
-
await this.setStateAsync(id, { val: false, ack: true });
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
this.logger.error("Reset sensor states - Error", error);
|
|
178
|
-
}
|
|
179
|
-
try {
|
|
180
|
-
if (fs_extra_1.default.statSync(this.persistentFile).isFile()) {
|
|
181
|
-
const fileContent = fs_extra_1.default.readFileSync(this.persistentFile, "utf8");
|
|
182
|
-
this.persistentData = JSON.parse(fileContent);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
this.logger.debug("No stored data from last exit found.", error);
|
|
187
|
-
}
|
|
188
|
-
this.subscribeStates("verify_code");
|
|
189
|
-
this.subscribeStates("captcha");
|
|
190
|
-
const systemConfig = await this.getForeignObjectAsync("system.config");
|
|
191
|
-
let countryCode = undefined;
|
|
192
|
-
let languageCode = undefined;
|
|
193
|
-
if (systemConfig) {
|
|
194
|
-
countryCode = (0, i18n_iso_countries_1.getAlpha2Code)(systemConfig.common.country, "en");
|
|
195
|
-
if ((0, i18n_iso_languages_1.isValid)(systemConfig.common.language))
|
|
196
|
-
languageCode = systemConfig.common.language;
|
|
197
|
-
}
|
|
198
|
-
if (this.config.hostname === "") {
|
|
199
|
-
this.config.hostname = os_1.default.hostname();
|
|
200
|
-
}
|
|
201
|
-
// Handling adapter version update
|
|
202
|
-
try {
|
|
203
|
-
if (this.persistentData.version !== this.version) {
|
|
204
|
-
const currentVersion = Number.parseFloat((0, utils_1.removeLastChar)(this.version, "."));
|
|
205
|
-
const previousVersion = this.persistentData.version !== "" && this.persistentData.version !== undefined ? Number.parseFloat((0, utils_1.removeLastChar)(this.persistentData.version, ".")) : 0;
|
|
206
|
-
this.logger.debug(`Handling of adapter update - currentVersion: ${currentVersion} previousVersion: ${previousVersion}`);
|
|
207
|
-
if (previousVersion < currentVersion) {
|
|
208
|
-
await (0, utils_1.handleUpdate)(this, this.logger, previousVersion);
|
|
209
|
-
this.persistentData.version = this.version;
|
|
210
|
-
this.writePersistentData();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
this.logger.error(`Handling of adapter update - Error:`, error);
|
|
216
|
-
}
|
|
217
|
-
let connectionType = eufy_security_client_1.P2PConnectionType.QUICKEST;
|
|
218
|
-
if (this.config.p2pConnectionType === "only_local") {
|
|
219
|
-
connectionType = eufy_security_client_1.P2PConnectionType.ONLY_LOCAL;
|
|
220
|
-
}
|
|
221
|
-
const config = {
|
|
222
|
-
username: this.config.username,
|
|
223
|
-
password: this.config.password,
|
|
224
|
-
country: countryCode,
|
|
225
|
-
language: languageCode,
|
|
226
|
-
persistentDir: utils.getAbsoluteInstanceDataDir(this),
|
|
227
|
-
eventDurationSeconds: this.config.eventDuration,
|
|
228
|
-
p2pConnectionSetup: connectionType,
|
|
229
|
-
pollingIntervalMinutes: this.config.pollingInterval,
|
|
230
|
-
acceptInvitations: this.config.acceptInvitations,
|
|
231
|
-
};
|
|
232
|
-
this.eufy = await eufy_security_client_1.EufySecurity.initialize(config, this.logger);
|
|
233
|
-
this.eufy.on("station added", (station) => this.onStationAdded(station));
|
|
234
|
-
this.eufy.on("device added", (device) => this.onDeviceAdded(device));
|
|
235
|
-
this.eufy.on("station removed", (station) => this.onStationRemoved(station));
|
|
236
|
-
this.eufy.on("device removed", (device) => this.onDeviceRemoved(device));
|
|
237
|
-
this.eufy.on("push message", (messages) => this.handlePushNotification(messages));
|
|
238
|
-
this.eufy.on("push connect", () => this.onPushConnect());
|
|
239
|
-
this.eufy.on("push close", () => this.onPushClose());
|
|
240
|
-
this.eufy.on("mqtt connect", () => this.onMQTTConnect());
|
|
241
|
-
this.eufy.on("mqtt close", () => this.onMQTTClose());
|
|
242
|
-
this.eufy.on("connect", () => this.onConnect());
|
|
243
|
-
this.eufy.on("close", () => this.onClose());
|
|
244
|
-
this.eufy.on("device property changed", (device, name, value) => this.onDevicePropertyChanged(device, name, value));
|
|
245
|
-
this.eufy.on("station command result", (station, result) => this.onStationCommandResult(station, result));
|
|
246
|
-
//this.eufy.on("station download start", (station: Station, device: Device, metadata: StreamMetadata, videostream: Readable, audiostream: Readable) => this.onStationDownloadStart(station, device, metadata, videostream, audiostream));
|
|
247
|
-
//this.eufy.on("station download finish", (station: Station, device: Device) => this.onStationDownloadFinish(station, device));
|
|
248
|
-
this.eufy.on("station livestream start", (station, device, metadata, videostream, audiostream) => this.onStationLivestreamStart(station, device, metadata, videostream, audiostream));
|
|
249
|
-
this.eufy.on("station livestream stop", (station, device) => this.onStationLivestreamStop(station, device));
|
|
250
|
-
this.eufy.on("station rtsp url", (station, device, value) => this.onStationRTSPUrl(station, device, value));
|
|
251
|
-
this.eufy.on("station property changed", (station, name, value) => this.onStationPropertyChanged(station, name, value));
|
|
252
|
-
this.eufy.on("station connect", (station) => this.onStationConnect(station));
|
|
253
|
-
this.eufy.on("station close", (station) => this.onStationClose(station));
|
|
254
|
-
this.eufy.on("tfa request", () => this.onTFARequest());
|
|
255
|
-
this.eufy.on("captcha request", (captchaId, captcha) => this.onCaptchaRequest(captchaId, captcha));
|
|
256
|
-
this.eufy.setCameraMaxLivestreamDuration(this.config.maxLivestreamDuration);
|
|
257
|
-
await this.eufy.connect();
|
|
258
|
-
if (go2rtc_static_1.default) {
|
|
259
|
-
const go2rtcConfig = {
|
|
260
|
-
"api": {
|
|
261
|
-
"listen": `:${this.config.go2rtc_api_port}`
|
|
262
|
-
},
|
|
263
|
-
"rtsp": {
|
|
264
|
-
"listen": `:${this.config.go2rtc_rtsp_port}`
|
|
265
|
-
},
|
|
266
|
-
"srtp": {
|
|
267
|
-
"listen": `:${this.config.go2rtc_srtp_port}`
|
|
268
|
-
},
|
|
269
|
-
"webrtc": {
|
|
270
|
-
"listen": `:${this.config.go2rtc_webrtc_port}`
|
|
271
|
-
},
|
|
272
|
-
"streams": {}
|
|
273
|
-
};
|
|
274
|
-
if (this.config.go2rtc_rtsp_username !== "" && this.config.go2rtc_rtsp_password !== "") {
|
|
275
|
-
go2rtcConfig.rtsp.username = this.config.go2rtc_rtsp_username;
|
|
276
|
-
go2rtcConfig.rtsp.password = this.config.go2rtc_rtsp_password;
|
|
277
|
-
}
|
|
278
|
-
for (const device of await this.eufy.getDevices()) {
|
|
279
|
-
go2rtcConfig.streams[device.getSerial()] = null;
|
|
280
|
-
}
|
|
281
|
-
const go2rtc = child_process_1.default.spawn(go2rtc_static_1.default, ["-config", JSON.stringify(go2rtcConfig)], { shell: false, detached: false, windowsHide: true });
|
|
282
|
-
go2rtc.on("error", (error) => {
|
|
283
|
-
this.log.error(`go2rtc error: ${error}`);
|
|
284
|
-
});
|
|
285
|
-
go2rtc.stdout.setEncoding("utf8");
|
|
286
|
-
go2rtc.stdout.on("data", (data) => {
|
|
287
|
-
this.log.info(`go2rtc started: ${data}`);
|
|
288
|
-
});
|
|
289
|
-
go2rtc.stderr.setEncoding("utf8");
|
|
290
|
-
go2rtc.stderr.on("data", (data) => {
|
|
291
|
-
this.log.error(`go2rtc error: ${data}`);
|
|
292
|
-
});
|
|
293
|
-
go2rtc.on("close", (exitcode) => {
|
|
294
|
-
this.log.info(`go2rtc terminated with exitcode ${exitcode}`);
|
|
295
|
-
});
|
|
296
|
-
process.on("exit", () => {
|
|
297
|
-
go2rtc.kill();
|
|
298
|
-
});
|
|
299
|
-
}
|
|
140
|
+
try {
|
|
141
|
+
const sensorList = [
|
|
142
|
+
import_eufy_security_client.PropertyName.DeviceMotionDetected,
|
|
143
|
+
import_eufy_security_client.PropertyName.DevicePersonDetected,
|
|
144
|
+
import_eufy_security_client.PropertyName.DeviceSoundDetected,
|
|
145
|
+
import_eufy_security_client.PropertyName.DeviceCryingDetected,
|
|
146
|
+
import_eufy_security_client.PropertyName.DevicePetDetected,
|
|
147
|
+
import_eufy_security_client.PropertyName.DeviceRinging
|
|
148
|
+
];
|
|
149
|
+
for (const sensorName of sensorList) {
|
|
150
|
+
const sensors = await this.getStatesAsync(`*.${(0, import_utils.convertCamelCaseToSnakeCase)(sensorName)}`);
|
|
151
|
+
if (sensors)
|
|
152
|
+
Object.keys(sensors).forEach(async (id) => {
|
|
153
|
+
await this.setStateAsync(id, { val: false, ack: true });
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
this.logger.error("Reset sensor states - Error", error);
|
|
300
158
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
159
|
+
try {
|
|
160
|
+
if (import_fs_extra.default.statSync(this.persistentFile).isFile()) {
|
|
161
|
+
const fileContent = import_fs_extra.default.readFileSync(this.persistentFile, "utf8");
|
|
162
|
+
this.persistentData = JSON.parse(fileContent);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
this.logger.debug("No stored data from last exit found.", error);
|
|
308
166
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
this.eufy.removeAllListeners();
|
|
319
|
-
this.eufy.close();
|
|
320
|
-
}
|
|
321
|
-
callback();
|
|
322
|
-
}
|
|
323
|
-
catch (e) {
|
|
324
|
-
callback();
|
|
325
|
-
}
|
|
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;
|
|
326
176
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
// /**
|
|
330
|
-
// * Is called if a subscribed object changes
|
|
331
|
-
// */
|
|
332
|
-
// private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {
|
|
333
|
-
// if (obj) {
|
|
334
|
-
// // The object was changed
|
|
335
|
-
// this.log.info(`object ${id} changed: ${JSON.stringify(obj)}`);
|
|
336
|
-
// } else {
|
|
337
|
-
// // The object was deleted
|
|
338
|
-
// this.log.info(`object ${id} deleted`);
|
|
339
|
-
// }
|
|
340
|
-
// }
|
|
341
|
-
/**
|
|
342
|
-
* Is called if a subscribed state changes
|
|
343
|
-
*/
|
|
344
|
-
async onStateChange(id, state) {
|
|
345
|
-
if (state) {
|
|
346
|
-
// don't do anything if the state is acked
|
|
347
|
-
if (!id || state.ack) {
|
|
348
|
-
this.logger.debug(`state ${id} changed: ${state.val} (ack = ${state.ack}) was already acknowledged, ignore it...`);
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
this.logger.debug(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
|
|
352
|
-
const values = id.split(".");
|
|
353
|
-
const station_sn = values[2];
|
|
354
|
-
const device_type = values[3];
|
|
355
|
-
if (station_sn == "verify_code") {
|
|
356
|
-
if (this.eufy && this.verify_code) {
|
|
357
|
-
this.logger.info(`Verification code received, send it. (verify_code: ${state.val})`);
|
|
358
|
-
await this.eufy.connect({ verifyCode: state.val });
|
|
359
|
-
this.verify_code = false;
|
|
360
|
-
await this.delStateAsync(id);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
else if (station_sn == "captcha") {
|
|
364
|
-
if (this.eufy && this.captchaId) {
|
|
365
|
-
this.logger.info(`Captcha received, send it. (captcha: ${state.val})`);
|
|
366
|
-
await this.eufy.connect({
|
|
367
|
-
captcha: {
|
|
368
|
-
captchaCode: state.val,
|
|
369
|
-
captchaId: this.captchaId
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
this.captchaId = null;
|
|
373
|
-
await this.delStateAsync(id);
|
|
374
|
-
await this.delStateAsync("received_captcha_html");
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
else if (device_type == "station") {
|
|
378
|
-
try {
|
|
379
|
-
const station_state_name = values[4];
|
|
380
|
-
if (this.eufy) {
|
|
381
|
-
const obj = await this.getObjectAsync(id);
|
|
382
|
-
if (obj) {
|
|
383
|
-
if (obj.native.name !== undefined) {
|
|
384
|
-
await this.eufy.setStationProperty(station_sn, obj.native.name, state.val);
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
const station = await this.eufy.getStation(station_sn);
|
|
389
|
-
switch (station_state_name) {
|
|
390
|
-
case types_1.StationStateID.REBOOT:
|
|
391
|
-
await station.rebootHUB();
|
|
392
|
-
break;
|
|
393
|
-
case types_1.StationStateID.TRIGGER_ALARM_SOUND:
|
|
394
|
-
await station.triggerStationAlarmSound(this.config.alarmSoundDuration);
|
|
395
|
-
break;
|
|
396
|
-
case types_1.StationStateID.RESET_ALARM_SOUND:
|
|
397
|
-
await station.resetStationAlarmSound();
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
catch (error) {
|
|
403
|
-
this.logger.error(`station - Error:`, error);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
try {
|
|
408
|
-
const device_sn = values[4];
|
|
409
|
-
const obj = await this.getObjectAsync(id);
|
|
410
|
-
if (obj) {
|
|
411
|
-
if (obj.native.name !== undefined) {
|
|
412
|
-
try {
|
|
413
|
-
await this.eufy.setDeviceProperty(device_sn, obj.native.name, state.val);
|
|
414
|
-
}
|
|
415
|
-
catch (error) {
|
|
416
|
-
this.logger.error(`Error in setting property value (property: ${obj.native.name} value: ${state.val})`, error);
|
|
417
|
-
}
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
const device_state_name = values[5];
|
|
422
|
-
const station = await this.eufy.getStation(station_sn);
|
|
423
|
-
const device = await this.eufy.getDevice(device_sn);
|
|
424
|
-
switch (device_state_name) {
|
|
425
|
-
case types_1.DeviceStateID.START_STREAM:
|
|
426
|
-
await this.startLivestream(device_sn);
|
|
427
|
-
break;
|
|
428
|
-
case types_1.DeviceStateID.STOP_STREAM:
|
|
429
|
-
await this.stopLivestream(device_sn);
|
|
430
|
-
break;
|
|
431
|
-
case types_1.DeviceStateID.TRIGGER_ALARM_SOUND:
|
|
432
|
-
await station.triggerDeviceAlarmSound(device, this.config.alarmSoundDuration);
|
|
433
|
-
break;
|
|
434
|
-
case types_1.DeviceStateID.RESET_ALARM_SOUND:
|
|
435
|
-
await station.resetDeviceAlarmSound(device);
|
|
436
|
-
break;
|
|
437
|
-
case types_1.DeviceStateID.ROTATE_360:
|
|
438
|
-
await station.panAndTilt(device, eufy_security_client_1.PanTiltDirection.ROTATE360);
|
|
439
|
-
break;
|
|
440
|
-
case types_1.DeviceStateID.PAN_LEFT:
|
|
441
|
-
await station.panAndTilt(device, eufy_security_client_1.PanTiltDirection.LEFT);
|
|
442
|
-
break;
|
|
443
|
-
case types_1.DeviceStateID.PAN_RIGHT:
|
|
444
|
-
await station.panAndTilt(device, eufy_security_client_1.PanTiltDirection.RIGHT);
|
|
445
|
-
break;
|
|
446
|
-
case types_1.DeviceStateID.TILT_UP:
|
|
447
|
-
await station.panAndTilt(device, eufy_security_client_1.PanTiltDirection.UP);
|
|
448
|
-
break;
|
|
449
|
-
case types_1.DeviceStateID.TILT_DOWN:
|
|
450
|
-
await station.panAndTilt(device, eufy_security_client_1.PanTiltDirection.DOWN);
|
|
451
|
-
break;
|
|
452
|
-
case types_1.DeviceStateID.CALIBRATE:
|
|
453
|
-
if (device.isLock()) {
|
|
454
|
-
await station.calibrateLock(device);
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
await station.calibrate(device);
|
|
458
|
-
}
|
|
459
|
-
break;
|
|
460
|
-
case types_1.DeviceStateID.UNLOCK:
|
|
461
|
-
await station.unlock(device);
|
|
462
|
-
break;
|
|
463
|
-
case types_1.DeviceStateID.SET_DEFAULT_ANGLE:
|
|
464
|
-
await station.setDefaultAngle(device);
|
|
465
|
-
break;
|
|
466
|
-
case types_1.DeviceStateID.SET_PRIVACY_ANGLE:
|
|
467
|
-
await station.setPrivacyAngle(device);
|
|
468
|
-
break;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
catch (error) {
|
|
472
|
-
this.logger.error(`cameras - Error:`, error);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
// The state was deleted
|
|
478
|
-
this.logger.debug(`state ${id} deleted`);
|
|
479
|
-
}
|
|
177
|
+
if (this.config.hostname === "") {
|
|
178
|
+
this.config.hostname = import_os.default.hostname();
|
|
480
179
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
// this.log.info("send command");
|
|
491
|
-
// // Send response in callback if required
|
|
492
|
-
// if (obj.callback) this.sendTo(obj.from, obj.command, "Message received", obj.callback);
|
|
493
|
-
// }
|
|
494
|
-
// }
|
|
495
|
-
// }
|
|
496
|
-
getStateCommon(property) {
|
|
497
|
-
const state = {
|
|
498
|
-
name: property.label,
|
|
499
|
-
type: property.type,
|
|
500
|
-
role: "state",
|
|
501
|
-
read: property.readable,
|
|
502
|
-
write: property.writeable,
|
|
503
|
-
def: property.default
|
|
504
|
-
};
|
|
505
|
-
switch (property.type) {
|
|
506
|
-
case "number": {
|
|
507
|
-
const numberProperty = property;
|
|
508
|
-
state.min = numberProperty.min;
|
|
509
|
-
state.max = numberProperty.max;
|
|
510
|
-
state.states = numberProperty.states;
|
|
511
|
-
state.unit = numberProperty.unit;
|
|
512
|
-
state.step = numberProperty.steps;
|
|
513
|
-
state.role = types_1.RoleMapping[property.name] !== undefined ? types_1.RoleMapping[property.name] : "value";
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
516
|
-
case "string": {
|
|
517
|
-
state.role = types_1.RoleMapping[property.name] !== undefined ? types_1.RoleMapping[property.name] : "text";
|
|
518
|
-
break;
|
|
519
|
-
}
|
|
520
|
-
case "boolean": {
|
|
521
|
-
state.role = types_1.RoleMapping[property.name] !== undefined ? types_1.RoleMapping[property.name] : (property.writeable ? "switch.enable" : "state");
|
|
522
|
-
break;
|
|
523
|
-
}
|
|
180
|
+
try {
|
|
181
|
+
if (this.persistentData.version !== this.version) {
|
|
182
|
+
const currentVersion = Number.parseFloat((0, import_utils.removeLastChar)(this.version, "."));
|
|
183
|
+
const previousVersion = this.persistentData.version !== "" && this.persistentData.version !== void 0 ? Number.parseFloat((0, import_utils.removeLastChar)(this.persistentData.version, ".")) : 0;
|
|
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();
|
|
524
189
|
}
|
|
525
|
-
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
this.logger.error(`Handling of adapter update - Error:`, error);
|
|
526
193
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const id = device.getStateID((0, utils_1.convertCamelCaseToSnakeCase)(property.name));
|
|
531
|
-
const obj = await this.getObjectAsync(id);
|
|
532
|
-
if (obj) {
|
|
533
|
-
let changed = false;
|
|
534
|
-
if (obj.native.name !== undefined && obj.native.name !== property.name) {
|
|
535
|
-
obj.native.name = property.name;
|
|
536
|
-
changed = true;
|
|
537
|
-
}
|
|
538
|
-
if (obj.native.key !== undefined && obj.native.key !== property.key) {
|
|
539
|
-
obj.native.key = property.key;
|
|
540
|
-
changed = true;
|
|
541
|
-
}
|
|
542
|
-
if (obj.native.commandId !== undefined && obj.native.commandId !== property.commandId) {
|
|
543
|
-
obj.native.commandId = property.commandId;
|
|
544
|
-
changed = true;
|
|
545
|
-
}
|
|
546
|
-
if (obj.common !== undefined && !util_1.default.isDeepStrictEqual(obj.common, state)) {
|
|
547
|
-
changed = true;
|
|
548
|
-
}
|
|
549
|
-
if (changed) {
|
|
550
|
-
const propertyMetadata = device.getPropertiesMetadata()[property.name];
|
|
551
|
-
if (propertyMetadata !== undefined) {
|
|
552
|
-
const newState = this.getStateCommon(propertyMetadata);
|
|
553
|
-
obj.common = newState;
|
|
554
|
-
}
|
|
555
|
-
await this.setObjectAsync(id, obj);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
await this.setObjectNotExistsAsync(id, {
|
|
560
|
-
type: "state",
|
|
561
|
-
common: state,
|
|
562
|
-
native: {
|
|
563
|
-
key: property.key,
|
|
564
|
-
commandId: property.commandId,
|
|
565
|
-
name: property.name,
|
|
566
|
-
},
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
const value = device.getPropertyValue(property.name);
|
|
570
|
-
if (value !== undefined)
|
|
571
|
-
await (0, utils_1.setStateChangedAsync)(this, id, property.type === "string" && typeof value === "object" ? JSON.stringify(value) : value);
|
|
572
|
-
}
|
|
194
|
+
let connectionType = import_eufy_security_client.P2PConnectionType.QUICKEST;
|
|
195
|
+
if (this.config.p2pConnectionType === "only_local") {
|
|
196
|
+
connectionType = import_eufy_security_client.P2PConnectionType.ONLY_LOCAL;
|
|
573
197
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
read: false,
|
|
651
|
-
write: true,
|
|
652
|
-
},
|
|
653
|
-
native: {},
|
|
654
|
-
});
|
|
655
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.PAN_RIGHT), {
|
|
656
|
-
type: "state",
|
|
657
|
-
common: {
|
|
658
|
-
name: "Pan Right",
|
|
659
|
-
type: "boolean",
|
|
660
|
-
role: "button.start",
|
|
661
|
-
read: false,
|
|
662
|
-
write: true,
|
|
663
|
-
},
|
|
664
|
-
native: {},
|
|
665
|
-
});
|
|
666
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.ROTATE_360), {
|
|
667
|
-
type: "state",
|
|
668
|
-
common: {
|
|
669
|
-
name: "Rotate 360°",
|
|
670
|
-
type: "boolean",
|
|
671
|
-
role: "button.start",
|
|
672
|
-
read: false,
|
|
673
|
-
write: true,
|
|
674
|
-
},
|
|
675
|
-
native: {},
|
|
676
|
-
});
|
|
677
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.TILT_UP), {
|
|
678
|
-
type: "state",
|
|
679
|
-
common: {
|
|
680
|
-
name: "Tilt Up",
|
|
681
|
-
type: "boolean",
|
|
682
|
-
role: "button.start",
|
|
683
|
-
read: false,
|
|
684
|
-
write: true,
|
|
685
|
-
},
|
|
686
|
-
native: {},
|
|
687
|
-
});
|
|
688
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.TILT_DOWN), {
|
|
689
|
-
type: "state",
|
|
690
|
-
common: {
|
|
691
|
-
name: "Tilt Down",
|
|
692
|
-
type: "boolean",
|
|
693
|
-
role: "button.start",
|
|
694
|
-
read: false,
|
|
695
|
-
write: true,
|
|
696
|
-
},
|
|
697
|
-
native: {},
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
if (device.hasCommand(eufy_security_client_1.CommandName.DeviceLockCalibration)) {
|
|
701
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.CALIBRATE), {
|
|
702
|
-
type: "state",
|
|
703
|
-
common: {
|
|
704
|
-
name: "Calibrate Lock",
|
|
705
|
-
type: "boolean",
|
|
706
|
-
role: "button.start",
|
|
707
|
-
read: false,
|
|
708
|
-
write: true,
|
|
709
|
-
},
|
|
710
|
-
native: {},
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
if (device.hasCommand(eufy_security_client_1.CommandName.DeviceUnlock)) {
|
|
714
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.UNLOCK), {
|
|
715
|
-
type: "state",
|
|
716
|
-
common: {
|
|
717
|
-
name: "Unlock",
|
|
718
|
-
type: "boolean",
|
|
719
|
-
role: "button.start",
|
|
720
|
-
read: false,
|
|
721
|
-
write: true,
|
|
722
|
-
},
|
|
723
|
-
native: {},
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
if (device.hasCommand(eufy_security_client_1.CommandName.DeviceSetDefaultAngle)) {
|
|
727
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.SET_DEFAULT_ANGLE), {
|
|
728
|
-
type: "state",
|
|
729
|
-
common: {
|
|
730
|
-
name: "Set Default Angle",
|
|
731
|
-
type: "boolean",
|
|
732
|
-
role: "button.start",
|
|
733
|
-
read: false,
|
|
734
|
-
write: true,
|
|
735
|
-
},
|
|
736
|
-
native: {},
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
if (device.hasCommand(eufy_security_client_1.CommandName.DeviceSetPrivacyAngle)) {
|
|
740
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.SET_PRIVACY_ANGLE), {
|
|
741
|
-
type: "state",
|
|
742
|
-
common: {
|
|
743
|
-
name: "Set Default Angle",
|
|
744
|
-
type: "boolean",
|
|
745
|
-
role: "button.start",
|
|
746
|
-
read: false,
|
|
747
|
-
write: true,
|
|
748
|
-
},
|
|
749
|
-
native: {},
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
if (device.hasCommand(eufy_security_client_1.CommandName.DeviceCalibrate)) {
|
|
753
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.CALIBRATE), {
|
|
754
|
-
type: "state",
|
|
755
|
-
common: {
|
|
756
|
-
name: "Calibrate",
|
|
757
|
-
type: "boolean",
|
|
758
|
-
role: "button.start",
|
|
759
|
-
read: false,
|
|
760
|
-
write: true,
|
|
761
|
-
},
|
|
762
|
-
native: {},
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
if (device.hasCommand(eufy_security_client_1.CommandName.DeviceStartLivestream)) {
|
|
766
|
-
// Start Stream
|
|
767
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.START_STREAM), {
|
|
768
|
-
type: "state",
|
|
769
|
-
common: {
|
|
770
|
-
name: "Start stream",
|
|
771
|
-
type: "boolean",
|
|
772
|
-
role: "button.start",
|
|
773
|
-
read: false,
|
|
774
|
-
write: true,
|
|
775
|
-
},
|
|
776
|
-
native: {},
|
|
777
|
-
});
|
|
778
|
-
// Stop Stream
|
|
779
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.STOP_STREAM), {
|
|
780
|
-
type: "state",
|
|
781
|
-
common: {
|
|
782
|
-
name: "Stop stream",
|
|
783
|
-
type: "boolean",
|
|
784
|
-
role: "button.stop",
|
|
785
|
-
read: false,
|
|
786
|
-
write: true,
|
|
787
|
-
},
|
|
788
|
-
native: {},
|
|
789
|
-
});
|
|
790
|
-
// Livestream URL
|
|
791
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.LIVESTREAM), {
|
|
792
|
-
type: "state",
|
|
793
|
-
common: {
|
|
794
|
-
name: "Livestream URL",
|
|
795
|
-
type: "string",
|
|
796
|
-
role: "url",
|
|
797
|
-
read: true,
|
|
798
|
-
write: false,
|
|
799
|
-
},
|
|
800
|
-
native: {},
|
|
801
|
-
});
|
|
802
|
-
// Livestream RTSP URL
|
|
803
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.LIVESTREAM_RTSP), {
|
|
804
|
-
type: "state",
|
|
805
|
-
common: {
|
|
806
|
-
name: "Livestream RTSP URL",
|
|
807
|
-
type: "string",
|
|
808
|
-
role: "url",
|
|
809
|
-
read: true,
|
|
810
|
-
write: false,
|
|
811
|
-
},
|
|
812
|
-
native: {},
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
if (device.hasProperty(eufy_security_client_1.PropertyName.DeviceRTSPStream)) {
|
|
816
|
-
// RTSP Stream URL
|
|
817
|
-
await this.setObjectNotExistsAsync(device.getStateID(types_1.DeviceStateID.RTSP_STREAM_URL), {
|
|
818
|
-
type: "state",
|
|
819
|
-
common: {
|
|
820
|
-
name: "RTSP stream URL",
|
|
821
|
-
type: "string",
|
|
822
|
-
role: "url",
|
|
823
|
-
read: true,
|
|
824
|
-
write: false
|
|
825
|
-
},
|
|
826
|
-
native: {},
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
//TODO: Deactivated because the decryption of the download has changed.
|
|
830
|
-
/*if (device.hasCommand(CommandName.DeviceStartDownload)) {
|
|
831
|
-
// Last event video URL
|
|
832
|
-
await this.setObjectNotExistsAsync(device.getStateID(DeviceStateID.LAST_EVENT_VIDEO_URL), {
|
|
833
|
-
type: "state",
|
|
834
|
-
common: {
|
|
835
|
-
name: "Last event video URL",
|
|
836
|
-
type: "string",
|
|
837
|
-
role: "url",
|
|
838
|
-
read: true,
|
|
839
|
-
write: false,
|
|
840
|
-
def: ""
|
|
841
|
-
},
|
|
842
|
-
native: {},
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
// Last event picture URL
|
|
846
|
-
await this.setObjectNotExistsAsync(device.getStateID(DeviceStateID.LAST_EVENT_PIC_URL), {
|
|
847
|
-
type: "state",
|
|
848
|
-
common: {
|
|
849
|
-
name: "Last event picture URL",
|
|
850
|
-
type: "string",
|
|
851
|
-
role: "url",
|
|
852
|
-
read: true,
|
|
853
|
-
write: false,
|
|
854
|
-
def: ""
|
|
855
|
-
},
|
|
856
|
-
native: {},
|
|
857
|
-
});
|
|
858
|
-
|
|
859
|
-
// Last event picture HTML image
|
|
860
|
-
await this.setObjectNotExistsAsync(device.getStateID(DeviceStateID.LAST_EVENT_PIC_HTML), {
|
|
861
|
-
type: "state",
|
|
862
|
-
common: {
|
|
863
|
-
name: "Last event picture HTML image",
|
|
864
|
-
type: "string",
|
|
865
|
-
role: "html",
|
|
866
|
-
read: true,
|
|
867
|
-
write: false,
|
|
868
|
-
def: ""
|
|
869
|
-
},
|
|
870
|
-
native: {},
|
|
871
|
-
});
|
|
872
|
-
}*/
|
|
198
|
+
const config = {
|
|
199
|
+
username: this.config.username,
|
|
200
|
+
password: this.config.password,
|
|
201
|
+
country: countryCode,
|
|
202
|
+
language: languageCode,
|
|
203
|
+
persistentDir: utils.getAbsoluteInstanceDataDir(this),
|
|
204
|
+
eventDurationSeconds: this.config.eventDuration,
|
|
205
|
+
p2pConnectionSetup: connectionType,
|
|
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;
|
|
252
|
+
}
|
|
253
|
+
for (const device of await this.eufy.getDevices()) {
|
|
254
|
+
go2rtcConfig.streams[device.getSerial()] = null;
|
|
255
|
+
}
|
|
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
|
+
});
|
|
873
274
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
});
|
|
275
|
+
}
|
|
276
|
+
writePersistentData() {
|
|
277
|
+
try {
|
|
278
|
+
import_fs_extra.default.writeFileSync(this.persistentFile, JSON.stringify(this.persistentData));
|
|
279
|
+
} catch (error) {
|
|
280
|
+
this.logger.error(`writePersistentData() - Error: ${error}`);
|
|
881
281
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
}
|
|
914
|
-
// Reboot station
|
|
915
|
-
if (station.hasCommand(eufy_security_client_1.CommandName.StationReboot)) {
|
|
916
|
-
await this.setObjectNotExistsAsync(station.getStateID(types_1.StationStateID.REBOOT), {
|
|
917
|
-
type: "state",
|
|
918
|
-
common: {
|
|
919
|
-
name: "Reboot station",
|
|
920
|
-
type: "boolean",
|
|
921
|
-
role: "button.start",
|
|
922
|
-
read: false,
|
|
923
|
-
write: true,
|
|
924
|
-
},
|
|
925
|
-
native: {},
|
|
926
|
-
});
|
|
282
|
+
}
|
|
283
|
+
async onUnload(callback) {
|
|
284
|
+
try {
|
|
285
|
+
this.writePersistentData();
|
|
286
|
+
if (this.eufy) {
|
|
287
|
+
if (this.eufy.isConnected())
|
|
288
|
+
await this.setStateAsync("info.connection", { val: false, ack: true }).catch();
|
|
289
|
+
this.eufy.removeAllListeners();
|
|
290
|
+
this.eufy.close();
|
|
291
|
+
}
|
|
292
|
+
callback();
|
|
293
|
+
} catch (e) {
|
|
294
|
+
callback();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
async onStateChange(id, state) {
|
|
298
|
+
if (state) {
|
|
299
|
+
if (!id || state.ack) {
|
|
300
|
+
this.logger.debug(`state ${id} changed: ${state.val} (ack = ${state.ack}) was already acknowledged, ignore it...`);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.logger.debug(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
|
|
304
|
+
const values = id.split(".");
|
|
305
|
+
const station_sn = values[2];
|
|
306
|
+
const device_type = values[3];
|
|
307
|
+
if (station_sn == "verify_code") {
|
|
308
|
+
if (this.eufy && this.verify_code) {
|
|
309
|
+
this.logger.info(`Verification code received, send it. (verify_code: ${state.val})`);
|
|
310
|
+
await this.eufy.connect({ verifyCode: state.val });
|
|
311
|
+
this.verify_code = false;
|
|
312
|
+
await this.delStateAsync(id);
|
|
927
313
|
}
|
|
928
|
-
|
|
929
|
-
if (
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
});
|
|
941
|
-
await this.setObjectNotExistsAsync(station.getStateID(types_1.StationStateID.RESET_ALARM_SOUND), {
|
|
942
|
-
type: "state",
|
|
943
|
-
common: {
|
|
944
|
-
name: "Reset Alarm Sound",
|
|
945
|
-
type: "boolean",
|
|
946
|
-
role: "button.start",
|
|
947
|
-
read: false,
|
|
948
|
-
write: true,
|
|
949
|
-
},
|
|
950
|
-
native: {},
|
|
951
|
-
});
|
|
314
|
+
} else if (station_sn == "captcha") {
|
|
315
|
+
if (this.eufy && this.captchaId) {
|
|
316
|
+
this.logger.info(`Captcha received, send it. (captcha: ${state.val})`);
|
|
317
|
+
await this.eufy.connect({
|
|
318
|
+
captcha: {
|
|
319
|
+
captchaCode: state.val,
|
|
320
|
+
captchaId: this.captchaId
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
this.captchaId = null;
|
|
324
|
+
await this.delStateAsync(id);
|
|
325
|
+
await this.delStateAsync("received_captcha_html");
|
|
952
326
|
}
|
|
953
|
-
|
|
954
|
-
async onStationRemoved(station) {
|
|
955
|
-
this.delObjectAsync(station.getStateID("", 0), { recursive: true }).catch((error) => {
|
|
956
|
-
this.logger.error(`Error deleting states of removed station`, error);
|
|
957
|
-
});
|
|
958
|
-
fs_extra_1.default.remove(path.join(utils.getAbsoluteInstanceDataDir(this), station.getSerial())).catch((error) => {
|
|
959
|
-
this.logger.error(`Error deleting fs contents of removed station`, error);
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
/*private async downloadEventVideo(device: Device, event_time: number, full_path: string | undefined, cipher_id: number | undefined): Promise<void> {
|
|
963
|
-
this.logger.debug(`Device: ${device.getSerial()} full_path: ${full_path} cipher_id: ${cipher_id}`);
|
|
327
|
+
} else if (device_type == "station") {
|
|
964
328
|
try {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
329
|
+
const station_state_name = values[4];
|
|
330
|
+
if (this.eufy) {
|
|
331
|
+
const obj = await this.getObjectAsync(id);
|
|
332
|
+
if (obj) {
|
|
333
|
+
if (obj.native.name !== void 0) {
|
|
334
|
+
await this.eufy.setStationProperty(station_sn, obj.native.name, state.val);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const station = await this.eufy.getStation(station_sn);
|
|
339
|
+
switch (station_state_name) {
|
|
340
|
+
case import_types.StationStateID.REBOOT:
|
|
341
|
+
await station.rebootHUB();
|
|
342
|
+
break;
|
|
343
|
+
case import_types.StationStateID.TRIGGER_ALARM_SOUND:
|
|
344
|
+
await station.triggerStationAlarmSound(this.config.alarmSoundDuration);
|
|
345
|
+
break;
|
|
346
|
+
case import_types.StationStateID.RESET_ALARM_SOUND:
|
|
347
|
+
await station.resetStationAlarmSound();
|
|
348
|
+
break;
|
|
985
349
|
}
|
|
350
|
+
}
|
|
986
351
|
} catch (error) {
|
|
987
|
-
|
|
352
|
+
this.logger.error(`station - Error:`, error);
|
|
988
353
|
}
|
|
989
|
-
|
|
990
|
-
async handlePushNotification(message) {
|
|
354
|
+
} else {
|
|
991
355
|
try {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
//Do nothing
|
|
1003
|
-
}
|
|
1004
|
-
else {
|
|
1005
|
-
this.logger.error("Handling push notification - Error", error);
|
|
356
|
+
const device_sn = values[4];
|
|
357
|
+
const obj = await this.getObjectAsync(id);
|
|
358
|
+
if (obj) {
|
|
359
|
+
if (obj.native.name !== void 0) {
|
|
360
|
+
try {
|
|
361
|
+
await this.eufy.setDeviceProperty(device_sn, obj.native.name, obj.common.type === "object" ? JSON.parse(state.val) : state.val);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
this.logger.error(`Error in setting property value (property: ${obj.native.name} value: ${state.val})`, error);
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
1006
366
|
}
|
|
367
|
+
}
|
|
368
|
+
const device_state_name = values[5];
|
|
369
|
+
const station = await this.eufy.getStation(station_sn);
|
|
370
|
+
const device = await this.eufy.getDevice(device_sn);
|
|
371
|
+
switch (device_state_name) {
|
|
372
|
+
case import_types.DeviceStateID.START_STREAM:
|
|
373
|
+
await this.startLivestream(device_sn);
|
|
374
|
+
break;
|
|
375
|
+
case import_types.DeviceStateID.STOP_STREAM:
|
|
376
|
+
await this.stopLivestream(device_sn);
|
|
377
|
+
break;
|
|
378
|
+
case import_types.DeviceStateID.TRIGGER_ALARM_SOUND:
|
|
379
|
+
await station.triggerDeviceAlarmSound(device, this.config.alarmSoundDuration);
|
|
380
|
+
break;
|
|
381
|
+
case import_types.DeviceStateID.RESET_ALARM_SOUND:
|
|
382
|
+
await station.resetDeviceAlarmSound(device);
|
|
383
|
+
break;
|
|
384
|
+
case import_types.DeviceStateID.ROTATE_360:
|
|
385
|
+
await station.panAndTilt(device, import_eufy_security_client.PanTiltDirection.ROTATE360);
|
|
386
|
+
break;
|
|
387
|
+
case import_types.DeviceStateID.PAN_LEFT:
|
|
388
|
+
await station.panAndTilt(device, import_eufy_security_client.PanTiltDirection.LEFT);
|
|
389
|
+
break;
|
|
390
|
+
case import_types.DeviceStateID.PAN_RIGHT:
|
|
391
|
+
await station.panAndTilt(device, import_eufy_security_client.PanTiltDirection.RIGHT);
|
|
392
|
+
break;
|
|
393
|
+
case import_types.DeviceStateID.TILT_UP:
|
|
394
|
+
await station.panAndTilt(device, import_eufy_security_client.PanTiltDirection.UP);
|
|
395
|
+
break;
|
|
396
|
+
case import_types.DeviceStateID.TILT_DOWN:
|
|
397
|
+
await station.panAndTilt(device, import_eufy_security_client.PanTiltDirection.DOWN);
|
|
398
|
+
break;
|
|
399
|
+
case import_types.DeviceStateID.CALIBRATE:
|
|
400
|
+
if (device.isLock()) {
|
|
401
|
+
await station.calibrateLock(device);
|
|
402
|
+
} else {
|
|
403
|
+
await station.calibrate(device);
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
406
|
+
case import_types.DeviceStateID.UNLOCK:
|
|
407
|
+
await station.unlock(device);
|
|
408
|
+
break;
|
|
409
|
+
case import_types.DeviceStateID.SET_DEFAULT_ANGLE:
|
|
410
|
+
await station.setDefaultAngle(device);
|
|
411
|
+
break;
|
|
412
|
+
case import_types.DeviceStateID.SET_PRIVACY_ANGLE:
|
|
413
|
+
await station.setPrivacyAngle(device);
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
} catch (error) {
|
|
417
|
+
this.logger.error(`cameras - Error:`, error);
|
|
1007
418
|
}
|
|
419
|
+
}
|
|
420
|
+
} else {
|
|
421
|
+
this.logger.debug(`state ${id} deleted`);
|
|
1008
422
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
}
|
|
1052
|
-
catch (error) {
|
|
1053
|
-
this.log.error(`Delete obsolete stations ERROR - ${JSON.stringify(error)}`);
|
|
423
|
+
}
|
|
424
|
+
getStateCommon(property) {
|
|
425
|
+
const state = {
|
|
426
|
+
name: property.label,
|
|
427
|
+
type: property.type,
|
|
428
|
+
role: "state",
|
|
429
|
+
read: property.readable,
|
|
430
|
+
write: property.writeable,
|
|
431
|
+
def: property.default
|
|
432
|
+
};
|
|
433
|
+
switch (property.type) {
|
|
434
|
+
case "number": {
|
|
435
|
+
const numberProperty = property;
|
|
436
|
+
state.min = numberProperty.min;
|
|
437
|
+
state.max = numberProperty.max;
|
|
438
|
+
state.states = numberProperty.states;
|
|
439
|
+
state.unit = numberProperty.unit;
|
|
440
|
+
state.step = numberProperty.steps;
|
|
441
|
+
state.role = import_types.RoleMapping[property.name] !== void 0 ? import_types.RoleMapping[property.name] : "value";
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
case "string": {
|
|
445
|
+
state.role = import_types.RoleMapping[property.name] !== void 0 ? import_types.RoleMapping[property.name] : "text";
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
case "boolean": {
|
|
449
|
+
state.role = import_types.RoleMapping[property.name] !== void 0 ? import_types.RoleMapping[property.name] : property.writeable ? "switch.enable" : "state";
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return state;
|
|
454
|
+
}
|
|
455
|
+
async createAndSetState(device, property) {
|
|
456
|
+
if (property.name !== import_eufy_security_client.PropertyName.Type && property.name !== import_eufy_security_client.PropertyName.DeviceStationSN) {
|
|
457
|
+
const state = this.getStateCommon(property);
|
|
458
|
+
const id = device.getStateID((0, import_utils.convertCamelCaseToSnakeCase)(property.name));
|
|
459
|
+
const obj = await this.getObjectAsync(id);
|
|
460
|
+
if (obj) {
|
|
461
|
+
let changed = false;
|
|
462
|
+
if (obj.native.name !== void 0 && obj.native.name !== property.name) {
|
|
463
|
+
obj.native.name = property.name;
|
|
464
|
+
changed = true;
|
|
1054
465
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
const reg = new RegExp(`^${this.namespace}\.[0-9A-Z]+\.[a-z]+\.[0-9A-Z]+$`);
|
|
1059
|
-
allDevices.forEach((id) => {
|
|
1060
|
-
if (id._id.match(reg)) {
|
|
1061
|
-
const serial = id._id.split(".")[4];
|
|
1062
|
-
if (!deviceSerials.includes(serial)) {
|
|
1063
|
-
this.delObjectAsync(id._id, { recursive: true });
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
});
|
|
466
|
+
if (obj.native.key !== void 0 && obj.native.key !== property.key) {
|
|
467
|
+
obj.native.key = property.key;
|
|
468
|
+
changed = true;
|
|
1067
469
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
470
|
+
if (obj.native.commandId !== void 0 && obj.native.commandId !== property.commandId) {
|
|
471
|
+
obj.native.commandId = property.commandId;
|
|
472
|
+
changed = true;
|
|
1070
473
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
const all = await this.getStatesAsync("*");
|
|
1074
|
-
if (all) {
|
|
1075
|
-
Object.keys(all).forEach(async (stateid) => {
|
|
1076
|
-
var _a;
|
|
1077
|
-
const object = await this.getObjectAsync(stateid);
|
|
1078
|
-
if (((_a = object === null || object === void 0 ? void 0 : object.native) === null || _a === void 0 ? void 0 : _a.name) !== undefined) {
|
|
1079
|
-
const tmp = stateid.split(".");
|
|
1080
|
-
if (tmp.length >= 5) {
|
|
1081
|
-
const stationSerial = tmp[2];
|
|
1082
|
-
const deviceSerial = tmp[4];
|
|
1083
|
-
if (deviceSerial.match(/^[A-Z0-9]+/)) {
|
|
1084
|
-
// Device
|
|
1085
|
-
try {
|
|
1086
|
-
const device = await this.eufy.getDevice(deviceSerial);
|
|
1087
|
-
if (!device.hasProperty(object.native.name)) {
|
|
1088
|
-
this.delObjectAsync(stateid);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
catch (error) {
|
|
1092
|
-
if (error instanceof eufy_security_client_1.DeviceNotFoundError) {
|
|
1093
|
-
}
|
|
1094
|
-
else {
|
|
1095
|
-
this.log.error(`Delete obsolete properties ERROR - device - ${JSON.stringify(error)}`);
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
else {
|
|
1100
|
-
// Station
|
|
1101
|
-
try {
|
|
1102
|
-
const station = await this.eufy.getStation(stationSerial);
|
|
1103
|
-
if (!station.hasProperty(object.native.name)) {
|
|
1104
|
-
this.delObjectAsync(stateid);
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
catch (error) {
|
|
1108
|
-
if (error instanceof eufy_security_client_1.StationNotFoundError) {
|
|
1109
|
-
}
|
|
1110
|
-
else {
|
|
1111
|
-
this.log.error(`Delete obsolete properties ERROR - station - ${JSON.stringify(error)}`);
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
474
|
+
if (obj.common !== void 0 && !import_util.default.isDeepStrictEqual(obj.common, state)) {
|
|
475
|
+
changed = true;
|
|
1119
476
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
477
|
+
if (changed) {
|
|
478
|
+
const propertyMetadata = device.getPropertiesMetadata()[property.name];
|
|
479
|
+
if (propertyMetadata !== void 0) {
|
|
480
|
+
const newState = this.getStateCommon(propertyMetadata);
|
|
481
|
+
obj.common = newState;
|
|
482
|
+
}
|
|
483
|
+
await this.setObjectAsync(id, obj);
|
|
1122
484
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
else {
|
|
1133
|
-
for (const dir of fs_extra_1.default.readdirSync(path.join(dir_path, content))) {
|
|
1134
|
-
if (dir === types_1.DataLocation.LIVESTREAM || dir === types_1.DataLocation.LAST_LIVESTREAM || dir === types_1.DataLocation.TEMP) {
|
|
1135
|
-
fs_extra_1.default.removeSync(path.join(dir_path, content, dir));
|
|
1136
|
-
}
|
|
1137
|
-
else {
|
|
1138
|
-
const files = fs_extra_1.default.readdirSync(path.join(dir_path, content, dir));
|
|
1139
|
-
let deletedFiles = 0;
|
|
1140
|
-
for (const file of files) {
|
|
1141
|
-
if (!deviceSerials.includes(file.substring(0, 16))) {
|
|
1142
|
-
fs_extra_1.default.removeSync(path.join(dir_path, content, dir, file));
|
|
1143
|
-
deletedFiles++;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
if (deletedFiles === files.length) {
|
|
1147
|
-
fs_extra_1.default.removeSync(path.join(dir_path, content, dir));
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
resolve();
|
|
1155
|
-
}
|
|
1156
|
-
catch (error) {
|
|
1157
|
-
reject(error);
|
|
1158
|
-
}
|
|
1159
|
-
}).catch(error => {
|
|
1160
|
-
this.log.error(`Delete obsolete directories/files ERROR - ${JSON.stringify(error)}`);
|
|
485
|
+
} else {
|
|
486
|
+
await this.setObjectNotExistsAsync(id, {
|
|
487
|
+
type: "state",
|
|
488
|
+
common: state,
|
|
489
|
+
native: {
|
|
490
|
+
key: property.key,
|
|
491
|
+
commandId: property.commandId,
|
|
492
|
+
name: property.name
|
|
493
|
+
}
|
|
1161
494
|
});
|
|
495
|
+
}
|
|
496
|
+
const value = device.getPropertyValue(property.name);
|
|
497
|
+
if (value !== void 0)
|
|
498
|
+
await (0, import_utils.setStateChangedAsync)(this, id, (property.type === "string" || property.type === "object") && typeof value === "object" ? JSON.stringify(value) : value);
|
|
1162
499
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
500
|
+
}
|
|
501
|
+
async onDeviceAdded(device) {
|
|
502
|
+
this.logger.debug(`onDeviceAdded - device: ${device.getSerial()}`);
|
|
503
|
+
await this.setObjectNotExistsAsync(device.getStateID("", 0), {
|
|
504
|
+
type: "channel",
|
|
505
|
+
common: {
|
|
506
|
+
name: device.getStateChannel()
|
|
507
|
+
},
|
|
508
|
+
native: {}
|
|
509
|
+
});
|
|
510
|
+
await this.setObjectNotExistsAsync(device.getStateID("", 1), {
|
|
511
|
+
type: "device",
|
|
512
|
+
common: {
|
|
513
|
+
name: device.getName()
|
|
514
|
+
},
|
|
515
|
+
native: {}
|
|
516
|
+
});
|
|
517
|
+
const metadata = device.getPropertiesMetadata();
|
|
518
|
+
for (const property of Object.values(metadata)) {
|
|
519
|
+
if (property.name !== import_eufy_security_client.PropertyName.DevicePicture)
|
|
520
|
+
this.createAndSetState(device, property);
|
|
1165
521
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
522
|
+
if (device.hasProperty(import_eufy_security_client.PropertyName.DevicePicture)) {
|
|
523
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.PICTURE_URL), {
|
|
524
|
+
type: "state",
|
|
525
|
+
common: {
|
|
526
|
+
name: "Picture URL",
|
|
527
|
+
type: "string",
|
|
528
|
+
role: "url",
|
|
529
|
+
read: true,
|
|
530
|
+
write: false
|
|
531
|
+
},
|
|
532
|
+
native: {}
|
|
533
|
+
});
|
|
534
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.PICTURE_HTML), {
|
|
535
|
+
type: "state",
|
|
536
|
+
common: {
|
|
537
|
+
name: "Picture HTML image",
|
|
538
|
+
type: "string",
|
|
539
|
+
role: "html",
|
|
540
|
+
read: true,
|
|
541
|
+
write: false
|
|
542
|
+
},
|
|
543
|
+
native: {}
|
|
544
|
+
});
|
|
1168
545
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
546
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceTriggerAlarmSound)) {
|
|
547
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.TRIGGER_ALARM_SOUND), {
|
|
548
|
+
type: "state",
|
|
549
|
+
common: {
|
|
550
|
+
name: "Trigger Alarm Sound",
|
|
551
|
+
type: "boolean",
|
|
552
|
+
role: "button.start",
|
|
553
|
+
read: false,
|
|
554
|
+
write: true
|
|
555
|
+
},
|
|
556
|
+
native: {}
|
|
557
|
+
});
|
|
558
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.RESET_ALARM_SOUND), {
|
|
559
|
+
type: "state",
|
|
560
|
+
common: {
|
|
561
|
+
name: "Reset Alarm Sound",
|
|
562
|
+
type: "boolean",
|
|
563
|
+
role: "button.start",
|
|
564
|
+
read: false,
|
|
565
|
+
write: true
|
|
566
|
+
},
|
|
567
|
+
native: {}
|
|
568
|
+
});
|
|
1189
569
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
570
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DevicePanAndTilt)) {
|
|
571
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.PAN_LEFT), {
|
|
572
|
+
type: "state",
|
|
573
|
+
common: {
|
|
574
|
+
name: "Pan Left",
|
|
575
|
+
type: "boolean",
|
|
576
|
+
role: "button.start",
|
|
577
|
+
read: false,
|
|
578
|
+
write: true
|
|
579
|
+
},
|
|
580
|
+
native: {}
|
|
581
|
+
});
|
|
582
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.PAN_RIGHT), {
|
|
583
|
+
type: "state",
|
|
584
|
+
common: {
|
|
585
|
+
name: "Pan Right",
|
|
586
|
+
type: "boolean",
|
|
587
|
+
role: "button.start",
|
|
588
|
+
read: false,
|
|
589
|
+
write: true
|
|
590
|
+
},
|
|
591
|
+
native: {}
|
|
592
|
+
});
|
|
593
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.ROTATE_360), {
|
|
594
|
+
type: "state",
|
|
595
|
+
common: {
|
|
596
|
+
name: "Rotate 360\xB0",
|
|
597
|
+
type: "boolean",
|
|
598
|
+
role: "button.start",
|
|
599
|
+
read: false,
|
|
600
|
+
write: true
|
|
601
|
+
},
|
|
602
|
+
native: {}
|
|
603
|
+
});
|
|
604
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.TILT_UP), {
|
|
605
|
+
type: "state",
|
|
606
|
+
common: {
|
|
607
|
+
name: "Tilt Up",
|
|
608
|
+
type: "boolean",
|
|
609
|
+
role: "button.start",
|
|
610
|
+
read: false,
|
|
611
|
+
write: true
|
|
612
|
+
},
|
|
613
|
+
native: {}
|
|
614
|
+
});
|
|
615
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.TILT_DOWN), {
|
|
616
|
+
type: "state",
|
|
617
|
+
common: {
|
|
618
|
+
name: "Tilt Down",
|
|
619
|
+
type: "boolean",
|
|
620
|
+
role: "button.start",
|
|
621
|
+
read: false,
|
|
622
|
+
write: true
|
|
623
|
+
},
|
|
624
|
+
native: {}
|
|
625
|
+
});
|
|
1210
626
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
type: "boolean",
|
|
1224
|
-
role: "indicator.connection",
|
|
1225
|
-
read: true,
|
|
1226
|
-
write: false,
|
|
1227
|
-
},
|
|
1228
|
-
native: {},
|
|
1229
|
-
});
|
|
1230
|
-
await this.setStateAsync("info.mqtt_connection", { val: true, ack: true });
|
|
627
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceLockCalibration)) {
|
|
628
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.CALIBRATE), {
|
|
629
|
+
type: "state",
|
|
630
|
+
common: {
|
|
631
|
+
name: "Calibrate Lock",
|
|
632
|
+
type: "boolean",
|
|
633
|
+
role: "button.start",
|
|
634
|
+
read: false,
|
|
635
|
+
write: true
|
|
636
|
+
},
|
|
637
|
+
native: {}
|
|
638
|
+
});
|
|
1231
639
|
}
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
type: "boolean",
|
|
1245
|
-
role: "indicator.connection",
|
|
1246
|
-
read: true,
|
|
1247
|
-
write: false,
|
|
1248
|
-
},
|
|
1249
|
-
native: {},
|
|
1250
|
-
});
|
|
1251
|
-
await this.setStateAsync("info.mqtt_connection", { val: false, ack: true });
|
|
640
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceUnlock)) {
|
|
641
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.UNLOCK), {
|
|
642
|
+
type: "state",
|
|
643
|
+
common: {
|
|
644
|
+
name: "Unlock",
|
|
645
|
+
type: "boolean",
|
|
646
|
+
role: "button.start",
|
|
647
|
+
read: false,
|
|
648
|
+
write: true
|
|
649
|
+
},
|
|
650
|
+
native: {}
|
|
651
|
+
});
|
|
1252
652
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
else if (result.return_code !== 0 && result.command_type !== eufy_security_client_1.CommandType.P2P_QUERY_STATUS_IN_LOCK) {
|
|
1266
|
-
this.logger.error(`Station: ${station.getSerial()} command ${eufy_security_client_1.CommandType[result.command_type]} failed with error: ${eufy_security_client_1.ErrorCode[result.return_code]} (${result.return_code})`);
|
|
1267
|
-
}
|
|
653
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceSetDefaultAngle)) {
|
|
654
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.SET_DEFAULT_ANGLE), {
|
|
655
|
+
type: "state",
|
|
656
|
+
common: {
|
|
657
|
+
name: "Set Default Angle",
|
|
658
|
+
type: "boolean",
|
|
659
|
+
role: "button.start",
|
|
660
|
+
read: false,
|
|
661
|
+
write: true
|
|
662
|
+
},
|
|
663
|
+
native: {}
|
|
664
|
+
});
|
|
1268
665
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
}
|
|
1280
|
-
|
|
666
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceSetPrivacyAngle)) {
|
|
667
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.SET_PRIVACY_ANGLE), {
|
|
668
|
+
type: "state",
|
|
669
|
+
common: {
|
|
670
|
+
name: "Set Default Angle",
|
|
671
|
+
type: "boolean",
|
|
672
|
+
role: "button.start",
|
|
673
|
+
read: false,
|
|
674
|
+
write: true
|
|
675
|
+
},
|
|
676
|
+
native: {}
|
|
677
|
+
});
|
|
1281
678
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
679
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceCalibrate)) {
|
|
680
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.CALIBRATE), {
|
|
681
|
+
type: "state",
|
|
682
|
+
common: {
|
|
683
|
+
name: "Calibrate",
|
|
684
|
+
type: "boolean",
|
|
685
|
+
role: "button.start",
|
|
686
|
+
read: false,
|
|
687
|
+
write: true
|
|
688
|
+
},
|
|
689
|
+
native: {}
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
if (device.hasCommand(import_eufy_security_client.CommandName.DeviceStartLivestream)) {
|
|
693
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.START_STREAM), {
|
|
694
|
+
type: "state",
|
|
695
|
+
common: {
|
|
696
|
+
name: "Start stream",
|
|
697
|
+
type: "boolean",
|
|
698
|
+
role: "button.start",
|
|
699
|
+
read: false,
|
|
700
|
+
write: true
|
|
701
|
+
},
|
|
702
|
+
native: {}
|
|
703
|
+
});
|
|
704
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.STOP_STREAM), {
|
|
705
|
+
type: "state",
|
|
706
|
+
common: {
|
|
707
|
+
name: "Stop stream",
|
|
708
|
+
type: "boolean",
|
|
709
|
+
role: "button.stop",
|
|
710
|
+
read: false,
|
|
711
|
+
write: true
|
|
712
|
+
},
|
|
713
|
+
native: {}
|
|
714
|
+
});
|
|
715
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM), {
|
|
716
|
+
type: "state",
|
|
717
|
+
common: {
|
|
718
|
+
name: "Livestream URL",
|
|
719
|
+
type: "string",
|
|
720
|
+
role: "url",
|
|
721
|
+
read: true,
|
|
722
|
+
write: false
|
|
723
|
+
},
|
|
724
|
+
native: {}
|
|
725
|
+
});
|
|
726
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM_RTSP), {
|
|
727
|
+
type: "state",
|
|
728
|
+
common: {
|
|
729
|
+
name: "Livestream RTSP URL",
|
|
730
|
+
type: "string",
|
|
731
|
+
role: "url",
|
|
732
|
+
read: true,
|
|
733
|
+
write: false
|
|
734
|
+
},
|
|
735
|
+
native: {}
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
if (device.hasProperty(import_eufy_security_client.PropertyName.DeviceRTSPStream)) {
|
|
739
|
+
await this.setObjectNotExistsAsync(device.getStateID(import_types.DeviceStateID.RTSP_STREAM_URL), {
|
|
740
|
+
type: "state",
|
|
741
|
+
common: {
|
|
742
|
+
name: "RTSP stream URL",
|
|
743
|
+
type: "string",
|
|
744
|
+
role: "url",
|
|
745
|
+
read: true,
|
|
746
|
+
write: false
|
|
747
|
+
},
|
|
748
|
+
native: {}
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
async onDeviceRemoved(device) {
|
|
753
|
+
this.delObjectAsync(device.getStateID("", 0), { recursive: true }).catch((error) => {
|
|
754
|
+
this.logger.error(`Error deleting states of removed device`, error);
|
|
755
|
+
});
|
|
756
|
+
(0, import_utils.removeFiles)(this, device.getStationSerial(), import_types.DataLocation.LAST_EVENT, device.getSerial()).catch((error) => {
|
|
757
|
+
this.logger.error(`Error deleting fs contents of removed device`, error);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
async onStationAdded(station) {
|
|
761
|
+
this.subscribeStates(`${station.getStateID("", 0)}.*`);
|
|
762
|
+
await this.setObjectNotExistsAsync(station.getStateID("", 0), {
|
|
763
|
+
type: "device",
|
|
764
|
+
common: {
|
|
765
|
+
name: station.getName()
|
|
766
|
+
},
|
|
767
|
+
native: {}
|
|
768
|
+
});
|
|
769
|
+
await this.setObjectNotExistsAsync(station.getStateID("", 1), {
|
|
770
|
+
type: "channel",
|
|
771
|
+
common: {
|
|
772
|
+
name: station.getStateChannel()
|
|
773
|
+
},
|
|
774
|
+
native: {}
|
|
775
|
+
});
|
|
776
|
+
await this.setObjectNotExistsAsync(station.getStateID(import_types.StationStateID.CONNECTION), {
|
|
777
|
+
type: "state",
|
|
778
|
+
common: {
|
|
779
|
+
name: "Connection",
|
|
780
|
+
type: "boolean",
|
|
781
|
+
role: "indicator.connection",
|
|
782
|
+
read: true,
|
|
783
|
+
write: false
|
|
784
|
+
},
|
|
785
|
+
native: {}
|
|
786
|
+
});
|
|
787
|
+
await this.setStateAsync(station.getStateID(import_types.StationStateID.CONNECTION), { val: false, ack: true });
|
|
788
|
+
const metadata = station.getPropertiesMetadata();
|
|
789
|
+
for (const property of Object.values(metadata)) {
|
|
790
|
+
this.createAndSetState(station, property);
|
|
791
|
+
}
|
|
792
|
+
if (station.hasCommand(import_eufy_security_client.CommandName.StationReboot)) {
|
|
793
|
+
await this.setObjectNotExistsAsync(station.getStateID(import_types.StationStateID.REBOOT), {
|
|
794
|
+
type: "state",
|
|
795
|
+
common: {
|
|
796
|
+
name: "Reboot station",
|
|
797
|
+
type: "boolean",
|
|
798
|
+
role: "button.start",
|
|
799
|
+
read: false,
|
|
800
|
+
write: true
|
|
801
|
+
},
|
|
802
|
+
native: {}
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
if (station.hasCommand(import_eufy_security_client.CommandName.StationTriggerAlarmSound)) {
|
|
806
|
+
await this.setObjectNotExistsAsync(station.getStateID(import_types.StationStateID.TRIGGER_ALARM_SOUND), {
|
|
807
|
+
type: "state",
|
|
808
|
+
common: {
|
|
809
|
+
name: "Trigger Alarm Sound",
|
|
810
|
+
type: "boolean",
|
|
811
|
+
role: "button.start",
|
|
812
|
+
read: false,
|
|
813
|
+
write: true
|
|
814
|
+
},
|
|
815
|
+
native: {}
|
|
816
|
+
});
|
|
817
|
+
await this.setObjectNotExistsAsync(station.getStateID(import_types.StationStateID.RESET_ALARM_SOUND), {
|
|
818
|
+
type: "state",
|
|
819
|
+
common: {
|
|
820
|
+
name: "Reset Alarm Sound",
|
|
821
|
+
type: "boolean",
|
|
822
|
+
role: "button.start",
|
|
823
|
+
read: false,
|
|
824
|
+
write: true
|
|
825
|
+
},
|
|
826
|
+
native: {}
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
async onStationRemoved(station) {
|
|
831
|
+
this.delObjectAsync(station.getStateID("", 0), { recursive: true }).catch((error) => {
|
|
832
|
+
this.logger.error(`Error deleting states of removed station`, error);
|
|
833
|
+
});
|
|
834
|
+
import_fs_extra.default.remove(path.join(utils.getAbsoluteInstanceDataDir(this), station.getSerial())).catch((error) => {
|
|
835
|
+
this.logger.error(`Error deleting fs contents of removed station`, error);
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
async handlePushNotification(message) {
|
|
839
|
+
try {
|
|
840
|
+
if (message.device_sn !== void 0) {
|
|
841
|
+
}
|
|
842
|
+
} catch (error) {
|
|
843
|
+
if (error instanceof import_eufy_security_client.DeviceNotFoundError) {
|
|
844
|
+
} else {
|
|
845
|
+
this.logger.error("Handling push notification - Error", error);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
async onConnect() {
|
|
850
|
+
await this.setObjectNotExistsAsync("info", {
|
|
851
|
+
type: "channel",
|
|
852
|
+
common: {
|
|
853
|
+
name: "info"
|
|
854
|
+
},
|
|
855
|
+
native: {}
|
|
856
|
+
});
|
|
857
|
+
await this.setObjectNotExistsAsync("info.connection", {
|
|
858
|
+
type: "state",
|
|
859
|
+
common: {
|
|
860
|
+
name: "Global connection",
|
|
861
|
+
type: "boolean",
|
|
862
|
+
role: "indicator.connection",
|
|
863
|
+
read: true,
|
|
864
|
+
write: false
|
|
865
|
+
},
|
|
866
|
+
native: {}
|
|
867
|
+
});
|
|
868
|
+
await this.setStateAsync("info.connection", { val: true, ack: true });
|
|
869
|
+
const stations = await this.eufy.getStations();
|
|
870
|
+
const stationSerials = [];
|
|
871
|
+
for (const station of stations) {
|
|
872
|
+
stationSerials.push(station.getSerial());
|
|
873
|
+
}
|
|
874
|
+
const devices = await this.eufy.getDevices();
|
|
875
|
+
const deviceSerials = [];
|
|
876
|
+
for (const device of devices) {
|
|
877
|
+
deviceSerials.push(device.getSerial());
|
|
878
|
+
}
|
|
879
|
+
try {
|
|
880
|
+
const allDevices = await this.getDevicesAsync();
|
|
881
|
+
const reg = new RegExp(`^${this.namespace}.[0-9A-Z]+$`);
|
|
882
|
+
for (const id of allDevices) {
|
|
883
|
+
if (id._id.match(reg)) {
|
|
884
|
+
const serial = id._id.replace(`${this.namespace}.`, "");
|
|
885
|
+
if (!stationSerials.includes(serial)) {
|
|
886
|
+
await this.delObjectAsync(id._id, { recursive: true });
|
|
887
|
+
}
|
|
1315
888
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
889
|
+
}
|
|
890
|
+
} catch (error) {
|
|
891
|
+
this.log.error(`Delete obsolete stations ERROR - ${JSON.stringify(error)}`);
|
|
892
|
+
}
|
|
893
|
+
try {
|
|
894
|
+
const allDevices = await this.getDevicesAsync();
|
|
895
|
+
const reg = new RegExp(`^${this.namespace}.[0-9A-Z]+.[a-z]+.[0-9A-Z]+$`);
|
|
896
|
+
for (const id of allDevices) {
|
|
897
|
+
if (id._id.match(reg)) {
|
|
898
|
+
const serial = id._id.split(".")[4];
|
|
899
|
+
if (!deviceSerials.includes(serial)) {
|
|
900
|
+
await this.delObjectAsync(id._id, { recursive: true });
|
|
901
|
+
}
|
|
1318
902
|
}
|
|
903
|
+
}
|
|
904
|
+
} catch (error) {
|
|
905
|
+
this.log.error(`Delete obsolete devices ERROR - ${JSON.stringify(error)}`);
|
|
1319
906
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
907
|
+
try {
|
|
908
|
+
const all = await this.getStatesAsync("*");
|
|
909
|
+
if (all) {
|
|
910
|
+
Object.keys(all).forEach(async (stateid) => {
|
|
911
|
+
var _a;
|
|
912
|
+
const object = await this.getObjectAsync(stateid);
|
|
913
|
+
if (((_a = object == null ? void 0 : object.native) == null ? void 0 : _a.name) !== void 0) {
|
|
914
|
+
const tmp = stateid.split(".");
|
|
915
|
+
if (tmp.length >= 5) {
|
|
916
|
+
const stationSerial = tmp[2];
|
|
917
|
+
const deviceSerial = tmp[4];
|
|
918
|
+
if (deviceSerial.match(/^[A-Z0-9]+/)) {
|
|
919
|
+
try {
|
|
920
|
+
const device = await this.eufy.getDevice(deviceSerial);
|
|
921
|
+
if (!device.hasProperty(object.native.name)) {
|
|
922
|
+
this.delObjectAsync(stateid);
|
|
923
|
+
}
|
|
924
|
+
} catch (error) {
|
|
925
|
+
if (error instanceof import_eufy_security_client.DeviceNotFoundError) {
|
|
926
|
+
} else {
|
|
927
|
+
this.log.error(`Delete obsolete properties ERROR - device - ${JSON.stringify(error)}`);
|
|
928
|
+
}
|
|
1327
929
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
930
|
+
} else {
|
|
931
|
+
try {
|
|
932
|
+
const station = await this.eufy.getStation(stationSerial);
|
|
933
|
+
if (!station.hasProperty(object.native.name)) {
|
|
934
|
+
this.delObjectAsync(stateid);
|
|
935
|
+
}
|
|
936
|
+
} catch (error) {
|
|
937
|
+
if (error instanceof import_eufy_security_client.StationNotFoundError) {
|
|
938
|
+
} else {
|
|
939
|
+
this.log.error(`Delete obsolete properties ERROR - station - ${JSON.stringify(error)}`);
|
|
940
|
+
}
|
|
1330
941
|
}
|
|
942
|
+
}
|
|
1331
943
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
this.logger.error("Start livestream - Error", error);
|
|
1338
|
-
}
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
} catch (error) {
|
|
948
|
+
this.log.error(`Delete obsolete properties ERROR - ${JSON.stringify(error)}`);
|
|
1339
949
|
}
|
|
1340
|
-
async
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
950
|
+
new Promise(async (resolve, reject) => {
|
|
951
|
+
try {
|
|
952
|
+
const dir_path = path.join(utils.getAbsoluteInstanceDataDir(this));
|
|
953
|
+
if (import_fs_extra.default.existsSync(dir_path)) {
|
|
954
|
+
for (const content of import_fs_extra.default.readdirSync(dir_path).filter((fn) => fn.match("^T[0-9A-Z]+$") !== null)) {
|
|
955
|
+
if (!stationSerials.includes(content)) {
|
|
956
|
+
import_fs_extra.default.removeSync(path.join(dir_path, content));
|
|
957
|
+
} else {
|
|
958
|
+
for (const dir of import_fs_extra.default.readdirSync(path.join(dir_path, content))) {
|
|
959
|
+
if (dir === import_types.DataLocation.LIVESTREAM || dir === import_types.DataLocation.LAST_LIVESTREAM || dir === import_types.DataLocation.TEMP) {
|
|
960
|
+
import_fs_extra.default.removeSync(path.join(dir_path, content, dir));
|
|
961
|
+
} else {
|
|
962
|
+
const files = import_fs_extra.default.readdirSync(path.join(dir_path, content, dir));
|
|
963
|
+
let deletedFiles = 0;
|
|
964
|
+
for (const file of files) {
|
|
965
|
+
if (!deviceSerials.includes(file.substring(0, 16))) {
|
|
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
|
+
}
|
|
1351
973
|
}
|
|
974
|
+
}
|
|
1352
975
|
}
|
|
976
|
+
}
|
|
1353
977
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
978
|
+
resolve();
|
|
979
|
+
} catch (error) {
|
|
980
|
+
reject(error);
|
|
981
|
+
}
|
|
982
|
+
}).catch((error) => {
|
|
983
|
+
this.log.error(`Delete obsolete directories/files ERROR - ${JSON.stringify(error)}`);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
async onClose() {
|
|
987
|
+
await this.setStateAsync("info.connection", { val: false, ack: true }).catch();
|
|
988
|
+
}
|
|
989
|
+
getPersistentData() {
|
|
990
|
+
return this.persistentData;
|
|
991
|
+
}
|
|
992
|
+
async onPushConnect() {
|
|
993
|
+
await this.setObjectNotExistsAsync("info", {
|
|
994
|
+
type: "channel",
|
|
995
|
+
common: {
|
|
996
|
+
name: "info"
|
|
997
|
+
},
|
|
998
|
+
native: {}
|
|
999
|
+
});
|
|
1000
|
+
await this.setObjectNotExistsAsync("info.push_connection", {
|
|
1001
|
+
type: "state",
|
|
1002
|
+
common: {
|
|
1003
|
+
name: "Push notification connection",
|
|
1004
|
+
type: "boolean",
|
|
1005
|
+
role: "indicator.connection",
|
|
1006
|
+
read: true,
|
|
1007
|
+
write: false
|
|
1008
|
+
},
|
|
1009
|
+
native: {}
|
|
1010
|
+
});
|
|
1011
|
+
await this.setStateAsync("info.push_connection", { val: true, ack: true });
|
|
1012
|
+
}
|
|
1013
|
+
async onPushClose() {
|
|
1014
|
+
await this.setObjectNotExistsAsync("info", {
|
|
1015
|
+
type: "channel",
|
|
1016
|
+
common: {
|
|
1017
|
+
name: "info"
|
|
1018
|
+
},
|
|
1019
|
+
native: {}
|
|
1020
|
+
});
|
|
1021
|
+
await this.setObjectNotExistsAsync("info.push_connection", {
|
|
1022
|
+
type: "state",
|
|
1023
|
+
common: {
|
|
1024
|
+
name: "Push notification connection",
|
|
1025
|
+
type: "boolean",
|
|
1026
|
+
role: "indicator.connection",
|
|
1027
|
+
read: true,
|
|
1028
|
+
write: false
|
|
1029
|
+
},
|
|
1030
|
+
native: {}
|
|
1031
|
+
});
|
|
1032
|
+
await this.setStateAsync("info.push_connection", { val: false, ack: true });
|
|
1033
|
+
}
|
|
1034
|
+
async onMQTTConnect() {
|
|
1035
|
+
await this.setObjectNotExistsAsync("info", {
|
|
1036
|
+
type: "channel",
|
|
1037
|
+
common: {
|
|
1038
|
+
name: "info"
|
|
1039
|
+
},
|
|
1040
|
+
native: {}
|
|
1041
|
+
});
|
|
1042
|
+
await this.setObjectNotExistsAsync("info.mqtt_connection", {
|
|
1043
|
+
type: "state",
|
|
1044
|
+
common: {
|
|
1045
|
+
name: "MQTT connection",
|
|
1046
|
+
type: "boolean",
|
|
1047
|
+
role: "indicator.connection",
|
|
1048
|
+
read: true,
|
|
1049
|
+
write: false
|
|
1050
|
+
},
|
|
1051
|
+
native: {}
|
|
1052
|
+
});
|
|
1053
|
+
await this.setStateAsync("info.mqtt_connection", { val: true, ack: true });
|
|
1054
|
+
}
|
|
1055
|
+
async onMQTTClose() {
|
|
1056
|
+
await this.setObjectNotExistsAsync("info", {
|
|
1057
|
+
type: "channel",
|
|
1058
|
+
common: {
|
|
1059
|
+
name: "info"
|
|
1060
|
+
},
|
|
1061
|
+
native: {}
|
|
1062
|
+
});
|
|
1063
|
+
await this.setObjectNotExistsAsync("info.mqtt_connection", {
|
|
1064
|
+
type: "state",
|
|
1065
|
+
common: {
|
|
1066
|
+
name: "MQTT connection",
|
|
1067
|
+
type: "boolean",
|
|
1068
|
+
role: "indicator.connection",
|
|
1069
|
+
read: true,
|
|
1070
|
+
write: false
|
|
1071
|
+
},
|
|
1072
|
+
native: {}
|
|
1073
|
+
});
|
|
1074
|
+
await this.setStateAsync("info.mqtt_connection", { val: false, ack: true });
|
|
1075
|
+
}
|
|
1076
|
+
async onStationCommandResult(station, result) {
|
|
1077
|
+
if (result.return_code !== 0 && result.command_type === import_eufy_security_client.CommandType.CMD_START_REALTIME_MEDIA) {
|
|
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) {
|
|
1087
|
+
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})`);
|
|
1357
1088
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1089
|
+
}
|
|
1090
|
+
async onStationPropertyChanged(station, name, value) {
|
|
1091
|
+
const states = await this.getStatesAsync(`${station.getStateID("", 1)}.*`);
|
|
1092
|
+
for (const state in states) {
|
|
1093
|
+
const obj = await this.getObjectAsync(state);
|
|
1094
|
+
if (obj) {
|
|
1095
|
+
if (obj.native.name !== void 0 && obj.native.name === name) {
|
|
1096
|
+
await (0, import_utils.setStateChangedAsync)(this, state, (obj.common.type === "string" || obj.common.type === "object") && typeof value === "object" ? JSON.stringify(value) : value);
|
|
1097
|
+
return;
|
|
1367
1098
|
}
|
|
1368
|
-
|
|
1369
|
-
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Stopping livestream...`, error);
|
|
1370
|
-
await this.eufy.stopStationLivestream(device.getSerial());
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
onStationLivestreamStop(_station, device) {
|
|
1374
|
-
this.delStateAsync(device.getStateID(types_1.DeviceStateID.LIVESTREAM));
|
|
1375
|
-
this.delStateAsync(device.getStateID(types_1.DeviceStateID.LIVESTREAM_RTSP));
|
|
1099
|
+
}
|
|
1376
1100
|
}
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
.then(async (result) => {
|
|
1395
|
-
if (result)
|
|
1396
|
-
await moveFiles(this, station.getSerial(), device.getSerial(), DataLocation.TEMP, DataLocation.LAST_EVENT);
|
|
1397
|
-
return result;
|
|
1398
|
-
})
|
|
1399
|
-
.then(async (result) => {
|
|
1400
|
-
if (result) {
|
|
1401
|
-
const filename_without_ext = getDataFilePath(this, station.getSerial(), DataLocation.LAST_EVENT, device.getSerial());
|
|
1402
|
-
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");
|
|
1403
|
-
if (fse.pathExistsSync(`${filename_without_ext}${STREAM_FILE_NAME_EXT}`))
|
|
1404
|
-
await ffmpegPreviewImage(this.config, `${filename_without_ext}${STREAM_FILE_NAME_EXT}`, `${filename_without_ext}${IMAGE_FILE_JPEG_EXT}`, this.logger)
|
|
1405
|
-
.then(() => {
|
|
1406
|
-
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");
|
|
1407
|
-
try {
|
|
1408
|
-
if (fse.existsSync(`${filename_without_ext}${IMAGE_FILE_JPEG_EXT}`)) {
|
|
1409
|
-
const image_data = getImageAsHTML(fse.readFileSync(`${filename_without_ext}${IMAGE_FILE_JPEG_EXT}`));
|
|
1410
|
-
setStateAsync(this, device.getStateID(DeviceStateID.LAST_EVENT_PIC_HTML), "Last event picture HTML image", image_data, "html");
|
|
1411
|
-
}
|
|
1412
|
-
} catch (error) {
|
|
1413
|
-
this.logger.error(`Station: ${station.getSerial()} device: ${device.getSerial()} - Error`, error);
|
|
1414
|
-
}
|
|
1415
|
-
})
|
|
1416
|
-
.catch((error) => {
|
|
1417
|
-
this.logger.error(`ffmpegPreviewImage - station: ${station.getSerial()} device: ${device.getSerial()} - Error`, error);
|
|
1418
|
-
});
|
|
1419
|
-
}
|
|
1420
|
-
})
|
|
1421
|
-
.catch(async (error) => {
|
|
1422
|
-
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Cancelling download...`, error);
|
|
1423
|
-
await this.eufy.cancelStationDownload(device.getSerial());
|
|
1424
|
-
});
|
|
1425
|
-
} catch(error) {
|
|
1426
|
-
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Cancelling download...`, error);
|
|
1427
|
-
await this.eufy.cancelStationDownload(device.getSerial());
|
|
1101
|
+
this.logger.debug(`onStationPropertyChanged(): Property "${name}" not implemented in this adapter (station: ${station.getSerial()} value: ${JSON.stringify(value)})`);
|
|
1102
|
+
}
|
|
1103
|
+
async onDevicePropertyChanged(device, name, value) {
|
|
1104
|
+
const states = await this.getStatesAsync(`${device.getStateID("", 1)}.*`);
|
|
1105
|
+
for (const state in states) {
|
|
1106
|
+
const obj = await this.getObjectAsync(state);
|
|
1107
|
+
if (obj) {
|
|
1108
|
+
if (obj.native.name !== void 0 && obj.native.name === name) {
|
|
1109
|
+
await (0, import_utils.setStateChangedAsync)(this, state, (obj.common.type === "string" || obj.common.type === "object") && typeof value === "object" ? JSON.stringify(value) : value);
|
|
1110
|
+
switch (name) {
|
|
1111
|
+
case import_eufy_security_client.PropertyName.DeviceRTSPStream:
|
|
1112
|
+
if (value === false) {
|
|
1113
|
+
this.delStateAsync(device.getStateID(import_types.DeviceStateID.RTSP_STREAM_URL));
|
|
1114
|
+
}
|
|
1115
|
+
break;
|
|
1116
|
+
}
|
|
1117
|
+
return;
|
|
1428
1118
|
}
|
|
1429
|
-
|
|
1430
|
-
onStationRTSPUrl(station, device, value) {
|
|
1431
|
-
(0, utils_1.setStateChangedAsync)(this, device.getStateID(types_1.DeviceStateID.RTSP_STREAM_URL), value);
|
|
1119
|
+
}
|
|
1432
1120
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1121
|
+
if (name === import_eufy_security_client.PropertyName.DevicePicture) {
|
|
1122
|
+
try {
|
|
1123
|
+
const picture = value;
|
|
1124
|
+
const fileName = `${device.getSerial()}.${picture.type.ext}`;
|
|
1125
|
+
const filePath = path.join(utils.getAbsoluteInstanceDataDir(this), device.getStationSerial(), import_types.DataLocation.LAST_EVENT);
|
|
1126
|
+
if (!import_fs_extra.default.existsSync(filePath)) {
|
|
1127
|
+
import_fs_extra.default.mkdirSync(filePath, { mode: 509, recursive: true });
|
|
1128
|
+
}
|
|
1129
|
+
await import_fs_extra.default.writeFile(path.join(filePath, fileName), picture.data);
|
|
1130
|
+
await (0, import_utils.setStateChangedAsync)(this, device.getStateID(import_types.DeviceStateID.PICTURE_URL), `/${this.namespace}/${device.getStationSerial()}/${import_types.DataLocation.LAST_EVENT}/${device.getSerial()}.${picture.type.ext}`);
|
|
1131
|
+
await (0, import_utils.setStateChangedAsync)(this, device.getStateID(import_types.DeviceStateID.PICTURE_HTML), (0, import_utils.getImageAsHTML)(picture.data, picture.type.mime));
|
|
1132
|
+
} catch (err) {
|
|
1133
|
+
const error = (0, import_eufy_security_client.ensureError)(err);
|
|
1134
|
+
this.logger.error("onDevicePropertyChanged - Property picture - Error", error);
|
|
1135
|
+
}
|
|
1136
|
+
} else {
|
|
1137
|
+
this.logger.debug(`onDevicePropertyChanged(): Property "${name}" not implemented in this adapter (device: ${device.getSerial()} value: ${JSON.stringify(value)})`);
|
|
1446
1138
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1139
|
+
}
|
|
1140
|
+
async startLivestream(device_sn) {
|
|
1141
|
+
try {
|
|
1142
|
+
const device = await this.eufy.getDevice(device_sn);
|
|
1143
|
+
const station = await this.eufy.getStation(device.getStationSerial());
|
|
1144
|
+
if (station.isConnected() || station.isEnergySavingDevice()) {
|
|
1145
|
+
if (!station.isLiveStreaming(device)) {
|
|
1146
|
+
this.eufy.startStationLivestream(device_sn);
|
|
1147
|
+
} else {
|
|
1148
|
+
this.logger.warn(`The stream for the device ${device_sn} cannot be started, because it is already streaming!`);
|
|
1149
|
+
}
|
|
1150
|
+
} else {
|
|
1151
|
+
this.logger.warn(`The stream for the device ${device_sn} cannot be started, because there is no connection to station ${station.getSerial()}!`);
|
|
1152
|
+
}
|
|
1153
|
+
} catch (error) {
|
|
1154
|
+
this.logger.error("Start livestream - Error", error);
|
|
1460
1155
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1156
|
+
}
|
|
1157
|
+
async stopLivestream(device_sn) {
|
|
1158
|
+
try {
|
|
1159
|
+
const device = await this.eufy.getDevice(device_sn);
|
|
1160
|
+
const station = await this.eufy.getStation(device.getStationSerial());
|
|
1161
|
+
if (device.isCamera()) {
|
|
1162
|
+
const camera = device;
|
|
1163
|
+
if (await this.eufy.isStationConnected(device.getStationSerial()) && station.isLiveStreaming(camera)) {
|
|
1164
|
+
await this.eufy.stopStationLivestream(device_sn);
|
|
1165
|
+
} else {
|
|
1166
|
+
this.logger.warn(`The stream for the device ${device_sn} cannot be stopped, because it isn't streaming!`);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
} catch (error) {
|
|
1170
|
+
this.logger.error("Stop livestream - Error", error);
|
|
1464
1171
|
}
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1172
|
+
}
|
|
1173
|
+
async onStationLivestreamStart(station, device, metadata, videostream, audiostream) {
|
|
1174
|
+
try {
|
|
1175
|
+
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
|
+
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.ffmpegStreamToGo2rtc)(this.config, this.namespace, device.getSerial(), metadata, videostream, audiostream, this.logger).catch(async (error) => {
|
|
1178
|
+
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Stopping livestream...`, error);
|
|
1179
|
+
await this.eufy.stopStationLivestream(device.getSerial());
|
|
1180
|
+
});
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
this.logger.error(`Station: ${station.getSerial()} Device: ${device.getSerial()} - Error - Stopping livestream...`, error);
|
|
1183
|
+
await this.eufy.stopStationLivestream(device.getSerial());
|
|
1470
1184
|
}
|
|
1185
|
+
}
|
|
1186
|
+
onStationLivestreamStop(_station, device) {
|
|
1187
|
+
this.delStateAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM));
|
|
1188
|
+
this.delStateAsync(device.getStateID(import_types.DeviceStateID.LIVESTREAM_RTSP));
|
|
1189
|
+
}
|
|
1190
|
+
onStationRTSPUrl(station, device, value) {
|
|
1191
|
+
(0, import_utils.setStateChangedAsync)(this, device.getStateID(import_types.DeviceStateID.RTSP_STREAM_URL), value);
|
|
1192
|
+
}
|
|
1193
|
+
async onStationConnect(station) {
|
|
1194
|
+
await this.setObjectNotExistsAsync(station.getStateID(import_types.StationStateID.CONNECTION), {
|
|
1195
|
+
type: "state",
|
|
1196
|
+
common: {
|
|
1197
|
+
name: "Connection",
|
|
1198
|
+
type: "boolean",
|
|
1199
|
+
role: "indicator.connection",
|
|
1200
|
+
read: true,
|
|
1201
|
+
write: false
|
|
1202
|
+
},
|
|
1203
|
+
native: {}
|
|
1204
|
+
});
|
|
1205
|
+
await this.setStateAsync(station.getStateID(import_types.StationStateID.CONNECTION), { val: true, ack: true });
|
|
1206
|
+
}
|
|
1207
|
+
async onStationClose(station) {
|
|
1208
|
+
await this.setObjectNotExistsAsync(station.getStateID(import_types.StationStateID.CONNECTION), {
|
|
1209
|
+
type: "state",
|
|
1210
|
+
common: {
|
|
1211
|
+
name: "Connection",
|
|
1212
|
+
type: "boolean",
|
|
1213
|
+
role: "indicator.connection",
|
|
1214
|
+
read: true,
|
|
1215
|
+
write: false
|
|
1216
|
+
},
|
|
1217
|
+
native: {}
|
|
1218
|
+
});
|
|
1219
|
+
await this.setStateAsync(station.getStateID(import_types.StationStateID.CONNECTION), { val: false, ack: true });
|
|
1220
|
+
}
|
|
1221
|
+
onTFARequest() {
|
|
1222
|
+
this.logger.warn(`Two factor authentication request received, please enter valid verification code in state ${this.namespace}.verify_code`);
|
|
1223
|
+
this.verify_code = true;
|
|
1224
|
+
}
|
|
1225
|
+
onCaptchaRequest(captchaId, captcha) {
|
|
1226
|
+
this.captchaId = captchaId;
|
|
1227
|
+
this.logger.warn(`Captcha authentication request received, please enter valid captcha in state ${this.namespace}.captcha`);
|
|
1228
|
+
this.logger.warn(`Captcha: <img src="${captcha}">`);
|
|
1229
|
+
this.setStateAsync("received_captcha_html", { val: `<img src="${captcha}">`, ack: true });
|
|
1230
|
+
}
|
|
1471
1231
|
}
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
}
|
|
1477
|
-
else {
|
|
1478
|
-
// otherwise start the instance directly
|
|
1479
|
-
(() => new euSec())();
|
|
1232
|
+
if (require.main !== module) {
|
|
1233
|
+
module.exports = (options) => new euSec(options);
|
|
1234
|
+
} else {
|
|
1235
|
+
(() => new euSec())();
|
|
1480
1236
|
}
|
|
1481
|
-
//# sourceMappingURL=main.js.map
|
|
1237
|
+
//# sourceMappingURL=main.js.map
|