iobroker.smartfriends 1.0.1 → 1.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,6 +33,11 @@ The adapter establishes a direct connection to the gateway to control and query
33
33
  Placeholder for the next version (at the beginning of the line):
34
34
  ### __WORK IN PROGRESS__
35
35
  -->
36
+ ### 1.1.0-alpha.1 (2025-12-28)
37
+
38
+ - (Black-Thunder) Refactored device handling: dynamic states, removed type whitelist, grouped devices under master ID
39
+ - (Black-Thunder) Handle device value updates now correctly
40
+
36
41
  ### 1.0.1 (2025-12-20)
37
42
 
38
43
  - (Black-Thunder) Increased robustness when communicating with the gateway
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "smartfriends",
4
- "version": "1.0.1",
4
+ "version": "1.1.0-alpha.1",
5
5
  "news": {
6
+ "1.1.0-alpha.1": {
7
+ "en": "Refactored device handling: dynamic states, removed type whitelist, grouped devices under master ID\nHandle device value updates now correctly",
8
+ "de": "Refactored Device Handling: dynamische Zustände, entfernte Typ Whitelist, gruppierte Geräte unter Master ID\nGerätewert-Updates jetzt korrekt ausschalten",
9
+ "ru": "Рефакторированная обработка устройств: динамические состояния, удаленный белый список типов, сгруппированные устройства под идентификатором Master ID\nОбновления стоимости устройства теперь правильно",
10
+ "pt": "Manipulação do dispositivo refatorado: estados dinâmicos, lista branca do tipo removido, dispositivos agrupados sob ID mestre\nGerenciar as atualizações de valor do dispositivo agora corretamente",
11
+ "nl": "Refactored device handling: dynamische toestanden, verwijderd type whitelist, gegroepeerde apparaten onder master ID\nHandle apparaat waarde updates nu correct",
12
+ "fr": "Manipulation de l'appareil refacturé : états dynamiques, liste blanche de type enlevé, dispositifs groupés sous Master ID\nGérer les mises à jour de la valeur du périphérique maintenant correctement",
13
+ "it": "Movimentazione del dispositivo refattore: stati dinamici, tipo rimosso whitelist, dispositivi raggruppati sotto master ID\nMantenere gli aggiornamenti del valore del dispositivo ora correttamente",
14
+ "es": "Manejo de dispositivo refactorizado: estados dinámicos, lista blanca de tipo eliminado, dispositivos agrupados bajo ID maestro\nActualizaciones de valor del dispositivo manual ahora correctamente",
15
+ "pl": "Przekształcona obsługa urządzenia: stany dynamiczne, usunięty biały typ, zgrupowane urządzenia pod master ID\nUchwyt aktualizacji wartości urządzenia teraz poprawnie",
16
+ "uk": "Рефакторний пристрій обробки: динамічні стани, видалений тип білий список, вбудовані пристрої під магістр ID\nОновлення значення ручного пристрою тепер правильно",
17
+ "zh-cn": "重构设备处理: 动态状态, 删除类型白名单, 主 ID 下分组设备\n现在正确处理设备值更新"
18
+ },
19
+ "1.1.0-alpha.0": {
20
+ "en": "Refactored device handling: dynamic states, removed type whitelist, grouped devices under master ID",
21
+ "de": "Überarbeitete Geräteverwaltung: dynamische Zustände, entfernte Typ-Whitelist, gruppierte Geräte unter Master-ID",
22
+ "ru": "Рефакторированная обработка устройств: динамические состояния, удаленный белый список типов, сгруппированные устройства под идентификатором Master ID",
23
+ "pt": "Manipulação do dispositivo refatorado: estados dinâmicos, lista branca do tipo removido, dispositivos agrupados sob ID mestre",
24
+ "nl": "Refactored device handling: dynamische toestanden, verwijderd type whitelist, gegroepeerde apparaten onder master ID",
25
+ "fr": "Manipulation de l'appareil refacturé : états dynamiques, liste blanche de type enlevé, dispositifs groupés sous Master ID",
26
+ "it": "Movimentazione del dispositivo refattore: stati dinamici, tipo rimosso whitelist, dispositivi raggruppati sotto master ID",
27
+ "es": "Manejo de dispositivo refactorizado: estados dinámicos, lista blanca de tipo eliminado, dispositivos agrupados bajo ID maestro",
28
+ "pl": "Przekształcona obsługa urządzenia: stany dynamiczne, usunięty biały typ, zgrupowane urządzenia pod master ID",
29
+ "uk": "Рефакторний пристрій обробки: динамічні стани, видалений тип білий список, вбудовані пристрої під магістр ID",
30
+ "zh-cn": "重构设备处理: 动态状态, 删除类型白名单, 主 ID 下分组设备"
31
+ },
6
32
  "1.0.1": {
7
33
  "en": "Increased robustness when communicating with the gateway\nAdded new option to ignore certificate errors",
8
34
  "de": "Erhöhte Robustheit bei der Kommunikation mit dem Gateway\nNeue Option hinzugefügt, um Zertifikatsfehler zu ignorieren",
@@ -1,25 +1,17 @@
1
1
  "use strict";
2
2
 
3
- //--------------------------------------------------
4
- //Copyright 2020 Pascâl Hartmann
5
- //See LICENSE File
6
- //--------------------------------------------------
7
- //Handles incoming messages from a SmartSocket and
8
- //emits Events defined in helpers/Events
9
- //This is an exmaple Class that implements the DataDelegateInterface which is required by the Socket
10
- //Implement an App in this Fashion
11
- //--------------------------------------------------
12
-
13
3
  const maxRetries = 3; // number of connection retries when connection was lost
14
4
  const reconnectInterval = 10 * 1000; // time (in ms) after which a single new reconnection try should be made
15
5
  const retryInterval = 30 * 60 * 1000; // time (in ms) after which new reconnection tries should be made
16
6
 
7
+ const commonDefines = require("./helpers/CommonDefines");
17
8
  const CommandFactory = require("./comunication/CommandFactory");
18
9
  const AllNewDeviceInfos = require("./comunication/comModel/responseBody/AllNewDeviceInfos");
19
10
  const JSONResponse = require("./comunication/comModel/JSONResponse");
20
11
  const SmartSocketFactory = require("./comunication/SmartSocketFactory");
21
12
  const CommonDefines = require("./helpers/CommonDefines");
22
- const DeviceManager = require("./DeviceManager");
13
+ const DeviceManager = require("./devices/DeviceManager");
14
+ const { SchellenbergMasterDevice } = require("./devices/SchellenbergMasterDevice");
23
15
 
24
16
  class SchellenbergBridge {
25
17
  constructor(adapter) {
@@ -39,6 +31,7 @@ class SchellenbergBridge {
39
31
  this.retryCounter = 0;
40
32
  this.stopRenewal = false;
41
33
  this.deviceManager = new DeviceManager(this.adapter);
34
+ this.deviceDefinitions = [];
42
35
  }
43
36
 
44
37
  async Connect() {
@@ -72,48 +65,148 @@ class SchellenbergBridge {
72
65
  );
73
66
  const response = await this.socket.sendAndRecieveCommand(command, this.loginResponse.sessionID);
74
67
 
75
- if (response?.response) {
76
- const parsedResponse = AllNewDeviceInfos.default.fromObject(response.response);
77
- await this.processAllNewDeviceInfos(parsedResponse);
68
+ if (!response?.response) {
69
+ return;
78
70
  }
71
+
72
+ const allNewDeviceInfosParsed = AllNewDeviceInfos.default.fromObject(response.response);
73
+ this.processCompatibilityConfiguration(allNewDeviceInfosParsed);
74
+ await this.processAllNewDeviceInfos(allNewDeviceInfosParsed);
75
+ this.processInitialDeviceValues(allNewDeviceInfosParsed);
79
76
  } catch (err) {
80
- this.adapter.log.error(`Connection failed: ${err.message}`);
81
- this.handleDisconnect();
77
+ const msg = err?.responseMessage || err.message || JSON.stringify(err);
78
+ this.adapter.log.error(`Connection failed: ${msg}`);
79
+
80
+ if (err?.response?.errorCode === 50 && err?.response?.remainingBlockDuration) {
81
+ {
82
+ this.adapter.log.error(
83
+ `Login to the gateway is currently blocked. Please try again in ${err?.response?.remainingBlockDuration} second(s)`,
84
+ );
85
+ }
86
+
87
+ this.handleDisconnect();
88
+ }
89
+ }
90
+ }
91
+
92
+ updateTimestamp(parsed) {
93
+ if (parsed.currentTimestamp) {
94
+ this.lastTimestamp = parsed.currentTimestamp;
95
+ this.adapter.log.debug(`Updated timestamp to ${this.lastTimestamp}`);
96
+ }
97
+ }
98
+
99
+ processCompatibilityConfiguration(parsed) {
100
+ if (this.deviceDefinitions?.length) {
101
+ return;
102
+ }
103
+
104
+ const standards = parsed.newCompatibilityConfiguration?.compatibleRadioStandards ?? [];
105
+ this.deviceDefinitions = [];
106
+
107
+ for (const standard of standards) {
108
+ for (const def of standard.compatibleDevices ?? []) {
109
+ if (def.deviceDesignation) {
110
+ this.deviceDefinitions.push(def);
111
+ }
112
+ }
113
+ }
114
+
115
+ this.adapter.log.debug(`Loaded ${this.deviceDefinitions.length} device definitions`);
116
+ }
117
+
118
+ processInitialDeviceValues(parsed) {
119
+ const values = parsed.newDeviceValues?.values ?? [];
120
+
121
+ for (const value of values) {
122
+ this.handleDeviceValue(value);
123
+ }
124
+ }
125
+
126
+ handleDeviceValue(deviceValue) {
127
+ if (!deviceValue || deviceValue.deviceID == null) {
128
+ this.adapter.log.debug("Invalid device value received, ignoring.");
129
+ return;
130
+ }
131
+
132
+ this.adapter.log.debug(`Device value update: deviceID=${deviceValue.deviceID}, value=${deviceValue.value}`);
133
+
134
+ this.deviceManager.updateDeviceValue(deviceValue);
135
+ }
136
+
137
+ handleDeviceInfo(deviceInfo) {
138
+ if (!deviceInfo || deviceInfo.deviceName || !deviceInfo.deviceDesignation) {
139
+ this.adapter.log.debug("Invalid device info received, ignoring.");
140
+ return;
82
141
  }
142
+
143
+ this.adapter.log.debug(`New device info received for deviceID=${deviceInfo.deviceID}`);
144
+ // TODO: implement updates of device info if needed
83
145
  }
84
146
 
85
147
  async processAllNewDeviceInfos(response) {
86
148
  try {
87
- const newDeviceInfos = response.newDeviceInfos.values;
88
- let knownDevices = 0;
89
-
90
- this.adapter.log.debug(`Received all devices:\r\n${JSON.stringify(newDeviceInfos)}`);
91
-
92
- for (const device of response.newDeviceInfos.values) {
93
- if (
94
- device.deviceTypClient &&
95
- (device.deviceTypClient.includes(CommonDefines.KnownDeviceTypes.AwningEngine.type) ||
96
- device.deviceTypClient.includes(CommonDefines.KnownDeviceTypes.RollingShutter.type))
97
- ) {
98
- knownDevices++;
99
- await this.deviceManager.createDevice({
100
- id: device.deviceID,
101
- name: device.deviceName,
102
- deviceType: device.deviceTypClient,
103
- designation: device.deviceDesignation,
104
- });
105
- this.adapter.log.info(
106
- `Device created: ${device.deviceName} (Type: ${device.deviceTypClient}, Device ID: ${device.deviceID})`,
107
- );
108
- } else {
149
+ const deviceInfos = response.newDeviceInfos?.values ?? [];
150
+ const createdMasters = [];
151
+
152
+ // 1️⃣ Child-Devices nach MasterID gruppieren
153
+ const devicesByMaster = {};
154
+ for (const device of deviceInfos) {
155
+ // Definition dynamisch zuweisen
156
+ device.definition = this.deviceDefinitions.find(d => d.deviceDesignation === device.deviceDesignation);
157
+ if (!device.definition) {
109
158
  this.adapter.log.debug(
110
- `Unsupported device type received: ${device.deviceName} (Type: ${device.deviceTypClient}, Device ID: ${device.deviceID}). Ignoring...`,
159
+ `Skipping device ${device.deviceName} (${device.deviceDesignation}) no definition found`,
111
160
  );
161
+ continue;
162
+ }
163
+
164
+ const masterId = device.masterDeviceID || device.deviceID;
165
+ if (!devicesByMaster[masterId]) {
166
+ devicesByMaster[masterId] = [];
167
+ }
168
+ devicesByMaster[masterId].push(device);
169
+ }
170
+
171
+ // 2️⃣ MasterDevices anlegen
172
+ for (const [masterId, childDevices] of Object.entries(devicesByMaster)) {
173
+ const masterName = childDevices[0].masterDeviceName || childDevices[0].deviceName;
174
+ const masterDevice = new SchellenbergMasterDevice(this.adapter, masterId, masterName, []);
175
+
176
+ // 3️⃣ Child-Devices unter Master anlegen
177
+ for (const child of childDevices) {
178
+ // Nur Devices mit definierbaren Control-States
179
+ const hasSwitching = child.definition.deviceType?.switchingValues?.length;
180
+ const isPosition = child.definition.deviceType?.kind === commonDefines.AdapterStateIDs.Position;
181
+
182
+ if (!hasSwitching && !isPosition) {
183
+ this.adapter.log.debug(
184
+ `Skipping device ${child.deviceName} (${child.deviceDesignation}) – no definable control states found`,
185
+ );
186
+ continue;
187
+ }
188
+
189
+ const schellenbergDevice = await this.deviceManager.createDevice({
190
+ id: child.deviceID,
191
+ name: child.deviceName,
192
+ deviceType: child.deviceTypClient ?? child.definition.deviceType?.kind ?? "unknown",
193
+ designation: child.deviceDesignation,
194
+ definition: child.definition,
195
+ masterPrefix: `${commonDefines.AdapterDatapointIDs.Devices}.${masterId}`, // States unter Master-Ordner
196
+ });
197
+
198
+ masterDevice.childDevices.push(schellenbergDevice);
199
+ this.adapter.log.info(`Device created: ${child.deviceName} (ID: ${child.deviceID})`);
200
+ }
201
+
202
+ if (masterDevice.childDevices?.length !== 0) {
203
+ await masterDevice.createMasterFolder();
204
+ createdMasters.push(masterDevice);
112
205
  }
113
206
  }
114
207
 
115
208
  this.adapter.log.info(
116
- `Processed ${newDeviceInfos.length} device(s) and added ${knownDevices} supported device(s). Adapter successfully started.`,
209
+ `Processed ${deviceInfos.length} device(s), created ${createdMasters.length} master device(s).`,
117
210
  );
118
211
  } catch (error) {
119
212
  this.adapter.log.error(`Error processing devices: ${error.message}`);
@@ -180,6 +273,7 @@ class SchellenbergBridge {
180
273
  [1]: r => {
181
274
  this.retryCounter = 0;
182
275
  this.resolveNextPromise(r);
276
+ this.updateTimestamp(r);
183
277
  },
184
278
  [2]: r => this.handleUpdate(r),
185
279
  [5]: r => this.handleSpecificResponseCode(r, 5),
@@ -239,12 +333,12 @@ class SchellenbergBridge {
239
333
  if (this.retryCounter < maxRetries) {
240
334
  this.retryCounter++;
241
335
  this.adapter.log.warn(`Reconnecting (try ${this.retryCounter} of ${maxRetries})...`);
242
- setTimeout(() => this.Connect(), reconnectInterval);
336
+ this.adapter.setTimeout(() => this.Connect(), reconnectInterval);
243
337
  } else {
244
338
  this.adapter.log.warn(
245
339
  `Connection to gateway lost, connection temporarily disabled! Trying again in ${retryInterval / (60 * 1000)} minutes.`,
246
340
  );
247
- setTimeout(() => this.Connect(), retryInterval);
341
+ this.adapter.setTimeout(() => this.Connect(), retryInterval);
248
342
  }
249
343
  }
250
344
 
@@ -272,7 +366,7 @@ class SchellenbergBridge {
272
366
 
273
367
  async handleLoginMessage(response) {
274
368
  if (response.sessionID && response.hardware && response.macAddress && response.shsVersion) {
275
- this.adapter.log.debug("Connection and login to gateway successful.");
369
+ this.adapter.log.debug(`Connection and login to gateway ${response.hardware} successful.`);
276
370
  this.loginResponse = response;
277
371
  this.retryCounter = 0;
278
372
 
@@ -309,14 +403,13 @@ class SchellenbergBridge {
309
403
  }
310
404
 
311
405
  handleUpdate(response) {
312
- if (response.responseMessage) {
313
- switch (response.responseMessage) {
314
- case "newDeviceValue":
315
- break;
316
- case "newDeviceInfo":
317
- break;
318
- default:
319
- break;
406
+ if (response && response.response && response.responseMessage) {
407
+ if (response.responseMessage === "newDeviceInfo") {
408
+ this.updateTimestamp(response);
409
+ this.handleDeviceInfo(response.response);
410
+ } else if (response.responseMessage === "newDeviceValue") {
411
+ this.updateTimestamp(response);
412
+ this.handleDeviceValue(response.response);
320
413
  }
321
414
  }
322
415
  }
@@ -327,7 +420,7 @@ class SchellenbergBridge {
327
420
  }
328
421
 
329
422
  this.adapter.log.warn(`Socket renewal was requested with reason: ${reason}`);
330
- setTimeout(() => {
423
+ this.adapter.setTimeout(() => {
331
424
  this.Connect();
332
425
  }, 1000);
333
426
  }
@@ -6,13 +6,14 @@
6
6
  //--------------------------------------------------
7
7
  //Uses Command Wrapper to generate JSON-Commands
8
8
 
9
- //exports.setDeviceValueCommand = exports.allNewInfoCommand = exports.loginCommand = exports.heloCommand = void 0;
10
9
  const JSONCommand = require("./comModel/JSONCommand.js");
11
10
  const JSONHelper = require("./comModel/JSONHelper.js");
11
+
12
12
  class CommandFactory {
13
13
  static createLoginCommand(username, digest, cSymbol, shcVersion, shApiVersion) {
14
- return new loginCommand(username, digest, cSymbol, shcVersion, shApiVersion);
14
+ return new LoginCommand(username, digest, cSymbol, shcVersion, shApiVersion);
15
15
  }
16
+
16
17
  static createAllNewInfoCmd(timestamp, compatibilityConfigurationVersion, languageTranslationVersion) {
17
18
  return new allNewInfoCommand(
18
19
  JSONHelper.default.dateToString(timestamp),
@@ -20,26 +21,33 @@ class CommandFactory {
20
21
  languageTranslationVersion,
21
22
  );
22
23
  }
24
+
23
25
  static createSetDeviceValueCmd(inDeviceId, inValue) {
24
26
  return new setDeviceValueCommand(inDeviceId, inValue);
25
27
  }
28
+
26
29
  static createupdateAllDeviceValues() {
27
30
  return new JSONCommand.default("keepalive");
28
31
  }
32
+
29
33
  static createGetComptibilityConfigurationCmd() {
30
34
  return new JSONCommand.default("getCompatibilityConfiguration");
31
35
  }
36
+
32
37
  static createLogoutCmd() {
33
38
  return new JSONCommand.default("logout");
34
39
  }
40
+
35
41
  static createKeepAliveCmd() {
36
42
  return new JSONCommand.default("keepalive");
37
43
  }
44
+
38
45
  static createHeloCmd(username) {
39
46
  return new heloCommand(username);
40
47
  }
41
48
  }
42
49
  exports.default = CommandFactory;
50
+
43
51
  class heloCommand extends JSONCommand.default {
44
52
  constructor(username) {
45
53
  super("helo");
@@ -47,7 +55,8 @@ class heloCommand extends JSONCommand.default {
47
55
  }
48
56
  }
49
57
  exports.heloCommand = heloCommand;
50
- class loginCommand extends JSONCommand.default {
58
+
59
+ class LoginCommand extends JSONCommand.default {
51
60
  constructor(username, digest, cSymbol, shcVersion, shApiVersion) {
52
61
  super("login");
53
62
  this.username = username;
@@ -57,7 +66,8 @@ class loginCommand extends JSONCommand.default {
57
66
  this.shApiVersion = shApiVersion;
58
67
  }
59
68
  }
60
- exports.loginCommand = loginCommand;
69
+ exports.LoginCommand = LoginCommand;
70
+
61
71
  class allNewInfoCommand extends JSONCommand.default {
62
72
  constructor(timestamp, compatibilityConfigurationVersion, languageTranslationVersion) {
63
73
  super("getAllNewInfos");
@@ -67,6 +77,7 @@ class allNewInfoCommand extends JSONCommand.default {
67
77
  }
68
78
  }
69
79
  exports.allNewInfoCommand = allNewInfoCommand;
80
+
70
81
  class setDeviceValueCommand extends JSONCommand.default {
71
82
  constructor(deviceID, value) {
72
83
  super("setDeviceValue");
@@ -75,49 +86,3 @@ class setDeviceValueCommand extends JSONCommand.default {
75
86
  }
76
87
  }
77
88
  exports.setDeviceValueCommand = setDeviceValueCommand;
78
- //TODO: implementation nedded
79
- //class executeDeviceCmdCmd extends Command{
80
- // constructor(){
81
- // super('')
82
- // }
83
- //}
84
- //class newDeviceCmd extends Command{
85
- // constructor(){
86
- // super('')
87
- // }
88
- //}
89
- //class changeDeviceCmd extends Command{
90
- // constructor(){
91
- // super('')
92
- // }
93
- //}
94
- //class changeRoomCmd extends Command{
95
- // constructor(){
96
- // super('')
97
- // }
98
- //}
99
- //class deleteRoomCmd extends Command{
100
- // constructor(){
101
- // super('')
102
- // }
103
- //}
104
- //class newSwitchingSequenceCmd extends Command{
105
- // constructor(){
106
- // super('')
107
- // }
108
- //}
109
- //class changeSwitchingSequenceCmd extends Command{
110
- // constructor(){
111
- // super('')
112
- // }
113
- //}
114
- //class deleteSwitchingSequenceCmd extends Command{
115
- // constructor(){
116
- // super('')
117
- // }
118
- //}
119
- //class activateSwitchingSequenceCmd extends Command{
120
- // constructor(){
121
- // super('')
122
- // }
123
- //}
@@ -10,32 +10,21 @@
10
10
  //--------------------------------------------------
11
11
 
12
12
  const crypto = require("crypto");
13
- const base_64 = require("base-64");
13
+
14
14
  class HashHelper {
15
15
  static calculateDigest(password, salt, sessionSalt) {
16
16
  const hashedPassword = this.getHash("sha256", password, salt);
17
17
  return this.getHash("sha1", hashedPassword, sessionSalt);
18
18
  }
19
- // https://stackoverflow.com/questions/3195865 modified because of javascript handling chars differently
20
- static string2Bin(str) {
21
- const result = [];
22
- for (let i = 0; i < str.length; i++) {
23
- const p = str.charCodeAt(i);
24
- if (p > 128) {
25
- result.push(p - 256);
26
- } else {
27
- result.push(p);
28
- }
29
- }
30
- return result;
31
- }
32
- static getHash(method, password, salt) {
33
- const decode = base_64.decode(salt);
34
- const saltArray = this.string2Bin(decode);
35
- const passwordArray = this.string2Bin(password);
36
- const pasConSalt = passwordArray.concat(saltArray);
37
- const cryptHash = crypto.createHash(method).update(new Uint8Array(pasConSalt));
38
- return cryptHash.digest("base64");
19
+
20
+ static getHash(method, password, saltBase64) {
21
+ const saltBuffer = Buffer.from(saltBase64, "base64");
22
+ const passwordBuffer = Buffer.from(password, "utf8");
23
+
24
+ const combined = Buffer.concat([passwordBuffer, saltBuffer]);
25
+
26
+ return crypto.createHash(method).update(combined).digest("base64");
39
27
  }
40
28
  }
29
+
41
30
  exports.default = HashHelper;
@@ -8,7 +8,7 @@
8
8
  //events occurring and passing on received data
9
9
  //--------------------------------------------------
10
10
 
11
- const Deffered = require("../helpers/Deffered.js");
11
+ const Deferred = require("../helpers/Deferred.js");
12
12
  const tls = require("tls");
13
13
  const CommandFactory = require("./CommandFactory.js");
14
14
 
@@ -110,7 +110,7 @@ class SmartSocket {
110
110
  });
111
111
  this.internalSocket.on("timeout", () => {
112
112
  this.adapter.log.warn("Socket timed out");
113
- setTimeout(() => {
113
+ this.adapter.setTimeout(() => {
114
114
  if (this.dataDelegate) {
115
115
  this.dataDelegate.renewSocket("Timeout");
116
116
  }
@@ -136,14 +136,14 @@ class SmartSocket {
136
136
  }
137
137
 
138
138
  startKeepAlive() {
139
- this.keepAliveHandler = setInterval(() => {
139
+ this.keepAliveHandler = this.adapter.setInterval(() => {
140
140
  this.sendJSONCommand(CommandFactory.default.createKeepAliveCmd());
141
141
  }, 5000);
142
142
  }
143
143
 
144
144
  stopKeepAlive() {
145
145
  if (this.keepAliveHandler) {
146
- clearInterval(this.keepAliveHandler);
146
+ this.adapter.clearInterval(this.keepAliveHandler);
147
147
  }
148
148
  }
149
149
 
@@ -152,7 +152,7 @@ class SmartSocket {
152
152
  //be advised, that a may occurring response is discarded and may result in an error
153
153
  sendJSONCommand(command) {
154
154
  this.adapter.log.debug(`Sending command with method: ${command.command}`);
155
- const localPromise = new Deffered.default((resolve, reject) => {
155
+ const localPromise = new Deferred.default(this.adapter, (resolve, reject) => {
156
156
  if (this.internalSocket && command) {
157
157
  this.adapter.log.debug(`Send JSON: ${command.toString()}`);
158
158
  this.internalSocket.write(command.toString());
@@ -170,7 +170,7 @@ class SmartSocket {
170
170
  //don't know if the output socket of the gateway is in-order, so maybe there needs
171
171
  //to be some checking
172
172
  sendAndRecieveCommand(command, sessionkey) {
173
- const localPromise = new Deffered.default((resolve, reject) => {
173
+ const localPromise = new Deferred.default(this.adapter, (resolve, reject) => {
174
174
  if (this.internalSocket && command) {
175
175
  this.adapter.log.debug(`Send and receive JSON: ${command.toString(sessionkey)}`);
176
176
  this.internalSocket.write(command.toString(sessionkey));
@@ -8,8 +8,8 @@
8
8
  //--------------------------------------------------
9
9
 
10
10
  class JSONCommand {
11
- constructor(methode) {
12
- this.command = methode;
11
+ constructor(method) {
12
+ this.command = method;
13
13
  }
14
14
  toString(sessionID) {
15
15
  if (sessionID) {
@@ -6,11 +6,16 @@
6
6
  //--------------------------------------------------
7
7
 
8
8
  class NewCompatibilityConfiguration {
9
- constructor(compatibilityConfigurationVersion) {
9
+ constructor(compatibilityConfigurationVersion, compatibleRadioStandards = []) {
10
10
  this.compatibilityConfigurationVersion = compatibilityConfigurationVersion;
11
+ this.compatibleRadioStandards = compatibleRadioStandards;
11
12
  }
13
+
12
14
  static fromObject(object) {
13
- return new NewCompatibilityConfiguration(object.compatibilityConfigurationVersion);
15
+ return new NewCompatibilityConfiguration(
16
+ object.compatibilityConfigurationVersion,
17
+ object.compatibleRadioStandards ?? [],
18
+ );
14
19
  }
15
20
  }
16
21
  exports.default = NewCompatibilityConfiguration;
@@ -0,0 +1,125 @@
1
+ const { SchellenbergDevice } = require("./SchellenbergDevice");
2
+ const commonDefines = require("../helpers/CommonDefines");
3
+ const commandFactory = require("../comunication/CommandFactory");
4
+
5
+ class DeviceManager {
6
+ constructor(adapter) {
7
+ this.adapter = adapter;
8
+ this.devices = new Map();
9
+ this.log = adapter.log;
10
+ this.bridge = null;
11
+ }
12
+
13
+ setBridge(bridge) {
14
+ this.bridge = bridge;
15
+ }
16
+
17
+ async createDevice(deviceInfo) {
18
+ try {
19
+ const device = new SchellenbergDevice(this.adapter);
20
+ Object.assign(device, deviceInfo);
21
+ await device.CreateAndSave(deviceInfo.masterPrefix);
22
+ this.devices.set(deviceInfo.id, device);
23
+ return device;
24
+ } catch (error) {
25
+ this.log.error(`Failed to create device ${deviceInfo.id}: ${error.message}`);
26
+ throw error;
27
+ }
28
+ }
29
+
30
+ getDevice(id) {
31
+ return this.devices.get(id);
32
+ }
33
+
34
+ getAllDevices() {
35
+ return Array.from(this.devices.values());
36
+ }
37
+
38
+ async updateDevice(id, data) {
39
+ const device = this.getDevice(id);
40
+ if (device) {
41
+ Object.assign(device, data);
42
+ await device.Update();
43
+ this.log.debug(`Device updated: ${id}`);
44
+ } else {
45
+ this.log.warn(`Device not found for update: ${id}`);
46
+ }
47
+ }
48
+
49
+ async deleteDevice(id) {
50
+ const device = this.getDevice(id);
51
+ if (device) {
52
+ await device.Delete();
53
+ this.devices.delete(id);
54
+ this.log.debug(`Device deleted: ${id}`);
55
+ }
56
+ }
57
+
58
+ async handleStateChange(id, state) {
59
+ try {
60
+ if (!state || state.ack) {
61
+ return;
62
+ }
63
+
64
+ const devicePrefix = `${this.adapter.namespace}.${commonDefines.AdapterDatapointIDs.Devices}.`;
65
+ const path = id.replace(devicePrefix, "");
66
+ const parts = path.split(".");
67
+
68
+ let childId;
69
+ if (parts.length === 1) {
70
+ // nur ein Device, kein Master
71
+ childId = parts[0];
72
+ } else if (parts.length >= 2) {
73
+ // Master + Child
74
+ childId = parts[1];
75
+ } else {
76
+ this.adapter.log.warn(`Invalid state path: ${id}`);
77
+ return;
78
+ }
79
+
80
+ const obj = await this.adapter.getObjectAsync(id);
81
+
82
+ const commandValue = typeof state.val === "number" ? state.val : obj?.native?.commandValue;
83
+
84
+ if (commandValue == null) {
85
+ this.adapter.log.warn(`No commandValue defined for ${id}`);
86
+ return;
87
+ }
88
+
89
+ this.adapter.log.debug(`Control triggered: device=${childId}, command=${commandValue} (state=${id})`);
90
+
91
+ await this.sendDeviceCommand(childId, commandValue);
92
+
93
+ await this.adapter.setStateAsync(id, false, true);
94
+ } catch (error) {
95
+ this.log.error(`Error in handleStateChange: ${error.responseMessage}`);
96
+ }
97
+ }
98
+
99
+ async sendDeviceCommand(deviceId, value) {
100
+ try {
101
+ if (!this.bridge) {
102
+ throw new Error("Bridge not initialized");
103
+ }
104
+
105
+ this.log.debug(`Sending value '${value}' to device ${deviceId}...`);
106
+
107
+ await this.bridge.sendAndReceiveCommand(commandFactory.default.createSetDeviceValueCmd(deviceId, value));
108
+ } catch (error) {
109
+ this.log.error(`Error in sendDeviceCommand: ${error.responseMessage}`);
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ updateDeviceValue(deviceValue) {
115
+ const device = this.devices?.get(deviceValue.deviceID);
116
+ if (!device) {
117
+ this.adapter.log.debug(`Received value for unknown device ${deviceValue.deviceID}, ignoring.`);
118
+ return;
119
+ }
120
+
121
+ device.updateValue(deviceValue);
122
+ }
123
+ }
124
+
125
+ module.exports = DeviceManager;
@@ -1,29 +1,31 @@
1
1
  "use strict";
2
2
 
3
- const commonDefines = require("./helpers/CommonDefines");
3
+ const commonDefines = require("../helpers/CommonDefines");
4
4
 
5
5
  class SchellenbergDevice {
6
6
  constructor(adapter) {
7
7
  this.adapter = adapter;
8
- this.platform = null;
8
+ this.definition = null;
9
9
 
10
10
  // Info
11
11
  this.id = -1;
12
12
  this.name = "";
13
13
  this.deviceType = "";
14
14
  this.designation = "";
15
-
16
- // Control
17
- this.power = false;
18
15
  }
19
16
 
20
17
  // Creates all necessery states and channels and writes the values into the DB
21
- async CreateAndSave() {
22
- const devicePrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${this.id}`;
18
+ async CreateAndSave(masterPrefix) {
19
+ let devicePrefix = masterPrefix
20
+ ? `${masterPrefix}.${this.id}`
21
+ : `${commonDefines.AdapterDatapointIDs.Devices}.${this.id}`;
22
+
23
+ devicePrefix = devicePrefix.replace(this.adapter.FORBIDDEN_CHARS, "");
24
+
23
25
  await this.adapter.setObjectNotExistsAsync(devicePrefix, {
24
26
  type: "channel",
25
27
  common: {
26
- name: `Device ${this.id} (${this.name})`,
28
+ name: this.name,
27
29
  },
28
30
  native: {},
29
31
  });
@@ -85,6 +87,7 @@ class SchellenbergDevice {
85
87
 
86
88
  //#region CONTROL
87
89
  let controlPrefix = `${devicePrefix}.${commonDefines.AdapterDatapointIDs.Control}`;
90
+
88
91
  await this.adapter.setObjectNotExistsAsync(controlPrefix, {
89
92
  type: "channel",
90
93
  common: {
@@ -95,98 +98,46 @@ class SchellenbergDevice {
95
98
 
96
99
  controlPrefix += ".";
97
100
 
98
- switch (this.deviceType) {
99
- case commonDefines.KnownDeviceTypes.AwningEngine.type:
100
- await this.adapter.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.MoveDown, {
101
- type: "state",
102
- common: {
103
- name: "Move downwards",
104
- type: "boolean",
105
- role: "button.start",
106
- read: false,
107
- write: true,
108
- def: false,
109
- desc: "Move downwards, lower sunblind",
110
- },
111
- native: {},
112
- });
101
+ // Dynamisch aus device.definition
102
+ if (this.definition?.deviceType?.switchingValues) {
103
+ for (const stateDef of this.definition.deviceType.switchingValues) {
104
+ const stateId = stateDef.name
105
+ .replace(/\${|}/g, "") // ${On} → On
106
+ .replace(this.adapter.FORBIDDEN_CHARS, "")
107
+ .toLowerCase();
113
108
 
114
- await this.adapter.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.MoveUp, {
109
+ await this.adapter.setObjectNotExistsAsync(`${controlPrefix}${stateId}`, {
115
110
  type: "state",
116
111
  common: {
117
- name: "Move upwards",
112
+ name: stateId,
118
113
  type: "boolean",
119
- role: "button.start",
114
+ role: "button",
120
115
  read: false,
121
116
  write: true,
122
117
  def: false,
123
- desc: "Move upwards, retract sunblind",
124
118
  },
125
- native: {},
126
- });
127
-
128
- await this.adapter.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.MoveStop, {
129
- type: "state",
130
- common: {
131
- name: "Stop movement",
132
- type: "boolean",
133
- role: "button.stop",
134
- read: false,
135
- write: true,
136
- def: false,
137
- desc: "Stop movement, leave sunblind at current position",
119
+ native: {
120
+ commandValue: stateDef.value,
138
121
  },
139
- native: {},
140
122
  });
141
- break;
142
- case commonDefines.KnownDeviceTypes.RollingShutter.type:
143
- await this.adapter.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.Close, {
144
- type: "state",
145
- common: {
146
- name: "Close shutter",
147
- type: "boolean",
148
- role: "button.start",
149
- read: false,
150
- write: true,
151
- def: false,
152
- desc: "Close shutter",
153
- },
154
- native: {},
155
- });
156
-
157
- await this.adapter.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.Open, {
158
- type: "state",
159
- common: {
160
- name: "Open shutter",
161
- type: "boolean",
162
- role: "button.start",
163
- read: false,
164
- write: true,
165
- def: false,
166
- desc: "Open shutter",
167
- },
168
- native: {},
169
- });
170
-
171
- await this.adapter.setObjectNotExistsAsync(controlPrefix + commonDefines.AdapterStateIDs.MoveStop, {
172
- type: "state",
173
- common: {
174
- name: "Stop movement",
175
- type: "boolean",
176
- role: "button.stop",
177
- read: false,
178
- write: true,
179
- def: false,
180
- desc: "Stop shutter movement",
181
- },
182
- native: {},
183
- });
184
- break;
185
- default:
186
- this.adapter.log.error(
187
- `No controls known for device type '${this.deviceType}' - Report this to the developer!`,
188
- );
189
- break;
123
+ }
124
+ } else if (this.definition.deviceType.kind === commonDefines.AdapterStateIDs.Position) {
125
+ await this.adapter.setObjectNotExistsAsync(`${controlPrefix}${commonDefines.AdapterStateIDs.Position}`, {
126
+ type: "state",
127
+ common: {
128
+ name: commonDefines.AdapterStateIDs.Position,
129
+ type: "number",
130
+ role: "level.blind",
131
+ read: true,
132
+ write: true,
133
+ min: this.definition.deviceType.min ?? 0,
134
+ max: this.definition.deviceType.max ?? 100,
135
+ step: this.definition.deviceType.step ?? 1,
136
+ unit: "%",
137
+ def: 0,
138
+ },
139
+ native: {},
140
+ });
190
141
  }
191
142
  //#endregion
192
143
 
@@ -213,6 +164,32 @@ class SchellenbergDevice {
213
164
 
214
165
  this.adapter.log.debug(`Updated device data for device ${this.id} (${this.name})`);
215
166
  }
167
+
168
+ async updateValue(value) {
169
+ // value: Instanz von DeviceValue
170
+ if (value.deviceID !== this.id) {
171
+ // Diese Instanz betrifft nicht dieses Device
172
+ return;
173
+ }
174
+
175
+ let controlPrefix = "";
176
+ if (value.masterDeviceID != this.id) {
177
+ // Child-Device unter einem Master-Device
178
+ controlPrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${value.masterDeviceID}.${this.id}.${commonDefines.AdapterDatapointIDs.Control}.`;
179
+ } else {
180
+ // Einzelnes Device
181
+ controlPrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${this.id}.${commonDefines.AdapterDatapointIDs.Control}.`;
182
+ }
183
+
184
+ if (this.definition?.deviceType?.switchingValues) {
185
+ // SwitchingValues ignorieren, liefern keine Updates zurück
186
+ } else if (this.definition?.deviceType?.kind === commonDefines.AdapterStateIDs.Position) {
187
+ // Für Position → direkt setzen
188
+ const stateId = `${controlPrefix}${commonDefines.AdapterStateIDs.Position}`;
189
+ await this.adapter.setStateAsync(stateId, value.value, true);
190
+ this.adapter.log.debug(`Device ${this.id}: Updated position = ${value.value}`);
191
+ }
192
+ }
216
193
  }
217
194
 
218
195
  exports.SchellenbergDevice = SchellenbergDevice;
@@ -0,0 +1,26 @@
1
+ const commonDefines = require("../helpers/CommonDefines");
2
+
3
+ class SchellenbergMasterDevice {
4
+ constructor(adapter, masterId, name, devices) {
5
+ this.adapter = adapter;
6
+ this.id = masterId;
7
+ this.name = name;
8
+ this.childDevices = devices; // Array von SchellenbergDevice
9
+ }
10
+
11
+ async createMasterFolder() {
12
+ const masterPrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${this.id.replace(this.adapter.FORBIDDEN_CHARS, "")}`;
13
+ await this.adapter.setObjectNotExistsAsync(masterPrefix, {
14
+ type: "channel",
15
+ common: { name: this.name },
16
+ native: {},
17
+ });
18
+
19
+ // Child Devices anlegen
20
+ for (const child of this.childDevices) {
21
+ await child.CreateAndSave(masterPrefix); // MasterPrefix übergeben
22
+ }
23
+ }
24
+ }
25
+
26
+ exports.SchellenbergMasterDevice = SchellenbergMasterDevice;
@@ -18,23 +18,5 @@ exports.AdapterStateIDs = Object.freeze({
18
18
  TypeClient: "typeClient",
19
19
  Designation: "designation",
20
20
  // devices.XXX.control
21
- MoveUp: "moveUp",
22
- Open: "open",
23
- MoveDown: "moveDown",
24
- Close: "close",
25
- MoveStop: "moveStop",
26
- });
27
-
28
- exports.KnownDeviceTypes = Object.freeze({
29
- AwningEngine: { name: "Markisenantrieb Plus", type: "${Awning}" },
30
- RollingShutter: { name: "Gurtantrieb", type: "${RollingShutter}" },
31
- });
32
-
33
- exports.DeviceCommands = Object.freeze({
34
- MoveDown: { name: "MoveDown", value: 1 },
35
- Open: { name: "Open", value: 1 },
36
- MoveUp: { name: "MoveUp", value: 2 },
37
- Close: { name: "Close", value: 2 },
38
- MoveStop: { name: "MoveStop", value: 0 },
39
- UNDEF: { name: "UndefinedCommand", value: -1 },
21
+ Position: "position",
40
22
  });
@@ -10,8 +10,9 @@
10
10
  //--------------------------------------------------
11
11
 
12
12
  class Deferred {
13
- constructor(executor) {
14
- this.timeout = setTimeout(() => {
13
+ constructor(adapter, executor) {
14
+ this.adapter = adapter;
15
+ this.timeout = this.adapter.setTimeout(() => {
15
16
  this.reject("timeout");
16
17
  }, 5000);
17
18
  this.promise = new Promise((resolve, reject) => {
@@ -30,11 +31,11 @@ class Deferred {
30
31
  return this.promise.finally(onfinally);
31
32
  }
32
33
  resolve(val) {
33
- clearTimeout(this.timeout);
34
+ this.adapter.clearTimeout(this.timeout);
34
35
  this._resolveSelf(val);
35
36
  }
36
37
  reject(reason) {
37
- clearTimeout(this.timeout);
38
+ this.adapter.clearTimeout(this.timeout);
38
39
  this._rejectSelf(reason);
39
40
  }
40
41
  }
package/main.js CHANGED
@@ -8,7 +8,7 @@
8
8
  const utils = require("@iobroker/adapter-core");
9
9
  const schellenbergBridge = require("./lib/SchellenbergBridge");
10
10
  const commonDefines = require("./lib/helpers/CommonDefines");
11
- const DeviceManager = require("./lib/DeviceManager");
11
+ const DeviceManager = require("./lib/devices/DeviceManager");
12
12
 
13
13
  let SchellenbergBridge = null;
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.smartfriends",
3
- "version": "1.0.1",
3
+ "version": "1.1.0-alpha.1",
4
4
  "description": "smartfriends",
5
5
  "author": {
6
6
  "name": "Black-Thunder",
@@ -23,8 +23,7 @@
23
23
  "node": ">= 20"
24
24
  },
25
25
  "dependencies": {
26
- "@iobroker/adapter-core": "^3.3.2",
27
- "base-64": "^1.0.0"
26
+ "@iobroker/adapter-core": "^3.3.2"
28
27
  },
29
28
  "devDependencies": {
30
29
  "@alcalzone/release-script": "^5.0.0",
@@ -1,121 +0,0 @@
1
- const { SchellenbergDevice } = require("./SchellenbergDevice");
2
- const commonDefines = require("./helpers/CommonDefines");
3
- const commandFactory = require("./comunication/CommandFactory");
4
-
5
- class DeviceManager {
6
- constructor(adapter) {
7
- this.adapter = adapter;
8
- this.devices = new Map();
9
- this.log = adapter.log;
10
- this.bridge = null;
11
-
12
- // Bind all methods that use 'this' context
13
- this.handleStateChange = this.handleStateChange.bind(this);
14
- this.sendDeviceCommand = this.sendDeviceCommand.bind(this);
15
- this.mapControlCommand = this.mapControlCommand.bind(this);
16
- this.createDevice = this.createDevice.bind(this);
17
- this.updateDevice = this.updateDevice.bind(this);
18
- this.deleteDevice = this.deleteDevice.bind(this);
19
- }
20
-
21
- setBridge(bridge) {
22
- this.bridge = bridge;
23
- }
24
-
25
- async createDevice(deviceInfo) {
26
- try {
27
- const device = new SchellenbergDevice(this.adapter);
28
- Object.assign(device, deviceInfo);
29
- await device.CreateAndSave();
30
- this.devices.set(deviceInfo.id, device);
31
- return device;
32
- } catch (error) {
33
- this.log.error(`Failed to create device ${deviceInfo.id}: ${error.message}`);
34
- throw error;
35
- }
36
- }
37
-
38
- getDevice(id) {
39
- return this.devices.get(id);
40
- }
41
-
42
- getAllDevices() {
43
- return Array.from(this.devices.values());
44
- }
45
-
46
- async updateDevice(id, data) {
47
- const device = this.getDevice(id);
48
- if (device) {
49
- Object.assign(device, data);
50
- await device.Update();
51
- this.log.debug(`Device updated: ${id}`);
52
- } else {
53
- this.log.warn(`Device not found for update: ${id}`);
54
- }
55
- }
56
-
57
- async deleteDevice(id) {
58
- const device = this.getDevice(id);
59
- if (device) {
60
- await device.Delete();
61
- this.devices.delete(id);
62
- this.log.debug(`Device deleted: ${id}`);
63
- }
64
- }
65
-
66
- async handleStateChange(id, state) {
67
- try {
68
- if (!state || state.ack || state.val === false) {
69
- return;
70
- }
71
-
72
- let deviceId = id.replace(`${this.adapter.namespace}.${commonDefines.AdapterDatapointIDs.Devices}.`, "");
73
- deviceId = deviceId.substring(0, deviceId.indexOf("."));
74
-
75
- const controlOption = id.substring(id.lastIndexOf(".") + 1, id.length);
76
- const controlCommand = this.mapControlCommand(controlOption);
77
-
78
- if (deviceId && controlCommand !== commonDefines.DeviceCommands.UNDEF) {
79
- await this.sendDeviceCommand(deviceId, controlCommand, id);
80
- }
81
- } catch (error) {
82
- this.log.error(`Error in handleStateChange: ${error.message}`);
83
- }
84
- }
85
-
86
- mapControlCommand(controlOption) {
87
- const commandMap = {
88
- [commonDefines.AdapterStateIDs.MoveDown]: commonDefines.DeviceCommands.MoveDown,
89
- [commonDefines.AdapterStateIDs.Close]: commonDefines.DeviceCommands.Close,
90
- [commonDefines.AdapterStateIDs.MoveUp]: commonDefines.DeviceCommands.MoveUp,
91
- [commonDefines.AdapterStateIDs.Open]: commonDefines.DeviceCommands.Open,
92
- [commonDefines.AdapterStateIDs.MoveStop]: commonDefines.DeviceCommands.MoveStop,
93
- };
94
-
95
- const command = commandMap[controlOption];
96
- if (!command) {
97
- this.log.error(`Unsupported control option: ${controlOption} - Please report this to the developer!`);
98
- return commonDefines.DeviceCommands.UNDEF;
99
- }
100
- return command;
101
- }
102
-
103
- async sendDeviceCommand(deviceId, controlCommand, stateId) {
104
- try {
105
- if (!this.bridge) {
106
- throw new Error("Bridge not initialized");
107
- }
108
-
109
- this.log.debug(`Sending command '${controlCommand.name}' to device ${deviceId}...`);
110
- await this.bridge.sendAndReceiveCommand(
111
- commandFactory.default.createSetDeviceValueCmd(deviceId, controlCommand.value),
112
- );
113
- await this.adapter.setState(stateId, false, true);
114
- } catch (error) {
115
- this.log.error(`Error in sendDeviceCommand: ${error.message}`);
116
- throw error;
117
- }
118
- }
119
- }
120
-
121
- module.exports = DeviceManager;
@@ -1,7 +0,0 @@
1
- "use strict";
2
-
3
- //--------------------------------------------------
4
- //Copyright 2020 Pascâl Hartmann
5
- //See LICENSE File
6
- //--------------------------------------------------
7
- Object.defineProperty(exports, "__esModule", { value: true });