iobroker.smartfriends 1.1.0-alpha.0 → 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 +2 -1
- package/io-package.json +139 -116
- package/lib/SchellenbergBridge.js +33 -16
- package/lib/comunication/CommandFactory.js +15 -50
- package/lib/comunication/HashHelper.js +10 -21
- package/lib/comunication/SmartSocket.js +6 -6
- package/lib/comunication/comModel/JSONCommand.js +2 -2
- package/lib/devices/SchellenbergDevice.js +8 -2
- package/lib/devices/SchellenbergMasterDevice.js +1 -1
- package/lib/helpers/{Deffered.js → Deferred.js} +5 -4
- package/package.json +2 -3
- package/lib/comunication/DataDelegateInterface.js +0 -7
package/README.md
CHANGED
|
@@ -33,9 +33,10 @@ 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.
|
|
36
|
+
### 1.1.0-alpha.1 (2025-12-28)
|
|
37
37
|
|
|
38
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
|
|
39
40
|
|
|
40
41
|
### 1.0.1 (2025-12-20)
|
|
41
42
|
|
package/io-package.json
CHANGED
|
@@ -1,118 +1,141 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
2
|
+
"common": {
|
|
3
|
+
"name": "smartfriends",
|
|
4
|
+
"version": "1.1.0-alpha.1",
|
|
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
|
+
},
|
|
32
|
+
"1.0.1": {
|
|
33
|
+
"en": "Increased robustness when communicating with the gateway\nAdded new option to ignore certificate errors",
|
|
34
|
+
"de": "Erhöhte Robustheit bei der Kommunikation mit dem Gateway\nNeue Option hinzugefügt, um Zertifikatsfehler zu ignorieren",
|
|
35
|
+
"ru": "Повышенная надежность при общении с шлюзом\nДобавлена новая возможность игнорировать ошибки сертификата",
|
|
36
|
+
"pt": "Maior robustez ao se comunicar com o gateway\nAdicionada nova opção para ignorar erros de certificado",
|
|
37
|
+
"nl": "Verhoogde robuustheid bij het communiceren met de gateway\nNieuwe optie toegevoegd om certificaatfouten te negeren",
|
|
38
|
+
"fr": "Une robustesse accrue lors de la communication avec la passerelle\nAjout d'une nouvelle option pour ignorer les erreurs de certificat",
|
|
39
|
+
"it": "Maggiore robustezza quando si comunica con il gateway\nAggiunta nuova opzione per ignorare gli errori del certificato",
|
|
40
|
+
"es": "Mayor robustez al comunicarse con la puerta de entrada\nNueva opción para ignorar errores de certificado",
|
|
41
|
+
"pl": "Większa odporność podczas komunikacji z bramą\nDodano nową opcję do ignorowania błędów certyfikatu",
|
|
42
|
+
"uk": "Підвищена надійність при спілкуванні з шлюзом\nДодано новий варіант ігнорувати помилки сертифіката",
|
|
43
|
+
"zh-cn": "与网关沟通时的强度提高\n添加新选项以忽略证书错误"
|
|
44
|
+
},
|
|
45
|
+
"1.0.0": {
|
|
46
|
+
"en": "initial release",
|
|
47
|
+
"de": "Erstveröffentlichung",
|
|
48
|
+
"ru": "Начальная версия",
|
|
49
|
+
"pt": "lançamento inicial",
|
|
50
|
+
"nl": "Eerste uitgave",
|
|
51
|
+
"fr": "Première version",
|
|
52
|
+
"it": "Versione iniziale",
|
|
53
|
+
"es": "Versión inicial",
|
|
54
|
+
"pl": "Pierwsze wydanie",
|
|
55
|
+
"zh-cn": "首次出版",
|
|
56
|
+
"uk": "початковий випуск"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"titleLang": {
|
|
60
|
+
"en": "SmartFriends",
|
|
61
|
+
"de": "SmartFriends",
|
|
62
|
+
"ru": "SmartFriends",
|
|
63
|
+
"pt": "SmartFriends",
|
|
64
|
+
"nl": "SmartFriends",
|
|
65
|
+
"fr": "SmartFriends",
|
|
66
|
+
"it": "SmartFriends",
|
|
67
|
+
"es": "SmartFriends",
|
|
68
|
+
"pl": "SmartFriends",
|
|
69
|
+
"zh-cn": "SmartFriends",
|
|
70
|
+
"uk": "SmartFriends"
|
|
71
|
+
},
|
|
72
|
+
"desc": {
|
|
73
|
+
"en": "Local control of SmartFriends gateways and connected devices without cloud access.",
|
|
74
|
+
"de": "Lokale Steuerung von SmartFriends-Gateways und angeschlossenen Geräten ohne Cloud-Anbindung.",
|
|
75
|
+
"ru": "Локальное управление шлюзами SmartFriends и подключёнными устройствами без облака.",
|
|
76
|
+
"pt": "Controle local de gateways SmartFriends e dispositivos conectados sem uso de nuvem.",
|
|
77
|
+
"nl": "Lokale aansturing van SmartFriends-gateways en aangesloten apparaten zonder cloud.",
|
|
78
|
+
"fr": "Contrôle local des passerelles SmartFriends et des appareils connectés sans cloud.",
|
|
79
|
+
"it": "Controllo locale dei gateway SmartFriends e dei dispositivi collegati senza cloud.",
|
|
80
|
+
"es": "Control local de gateways SmartFriends y dispositivos conectados sin nube.",
|
|
81
|
+
"pl": "Lokalne sterowanie bramkami SmartFriends i podłączonymi urządzeniami bez chmury.",
|
|
82
|
+
"zh-cn": "无需云服务即可本地控制 SmartFriends 网关及其连接的设备。",
|
|
83
|
+
"uk": "Локальне керування шлюзами SmartFriends і підключеними пристроями без хмари."
|
|
84
|
+
},
|
|
85
|
+
"authors": [
|
|
86
|
+
"Black-Thunder <glwars@aol.de>"
|
|
87
|
+
],
|
|
88
|
+
"keywords": [
|
|
89
|
+
"home automation",
|
|
90
|
+
"smartfriends",
|
|
91
|
+
"schellenberg"
|
|
92
|
+
],
|
|
93
|
+
"licenseInformation": {
|
|
94
|
+
"license": "MIT",
|
|
95
|
+
"type": "free"
|
|
96
|
+
},
|
|
97
|
+
"platform": "Javascript/Node.js",
|
|
98
|
+
"icon": "smartfriends.png",
|
|
99
|
+
"enabled": false,
|
|
100
|
+
"extIcon": "https://raw.githubusercontent.com/Black-Thunder/ioBroker.smartfriends/master/admin/smartfriends.png",
|
|
101
|
+
"readme": "https://github.com/Black-Thunder/ioBroker.smartfriends/blob/master/README.md",
|
|
102
|
+
"loglevel": "info",
|
|
103
|
+
"mode": "daemon",
|
|
104
|
+
"type": "iot-systems",
|
|
105
|
+
"compact": true,
|
|
106
|
+
"connectionType": "local",
|
|
107
|
+
"dataSource": "poll",
|
|
108
|
+
"adminUI": {
|
|
109
|
+
"config": "json"
|
|
110
|
+
},
|
|
111
|
+
"dependencies": [
|
|
112
|
+
{
|
|
113
|
+
"js-controller": ">=6.0.11"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"globalDependencies": [
|
|
117
|
+
{
|
|
118
|
+
"admin": ">=7.6.17"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"tier": 2
|
|
122
|
+
},
|
|
123
|
+
"encryptedNative": [
|
|
124
|
+
"smartFriendsPassword"
|
|
125
|
+
],
|
|
126
|
+
"protectedNative": [
|
|
127
|
+
"smartFriendsPassword"
|
|
128
|
+
],
|
|
129
|
+
"native": {
|
|
130
|
+
"smartFriendsPort": 4300,
|
|
131
|
+
"smartFriendsIP": "",
|
|
132
|
+
"smartFriendsUsername": "",
|
|
133
|
+
"smartFriendsPassword": "",
|
|
134
|
+
"smartFriendsCSymbol": "D19033i",
|
|
135
|
+
"smartFriendsShcVersion": "3.7.4",
|
|
136
|
+
"smartFriendsShApiVersion": "3.4",
|
|
137
|
+
"ignoreSslErrors": false
|
|
138
|
+
},
|
|
139
|
+
"objects": [],
|
|
140
|
+
"instanceObjects": []
|
|
118
141
|
}
|
|
@@ -74,8 +74,18 @@ class SchellenbergBridge {
|
|
|
74
74
|
await this.processAllNewDeviceInfos(allNewDeviceInfosParsed);
|
|
75
75
|
this.processInitialDeviceValues(allNewDeviceInfosParsed);
|
|
76
76
|
} catch (err) {
|
|
77
|
-
|
|
78
|
-
this.
|
|
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
|
+
}
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
|
|
@@ -124,6 +134,16 @@ class SchellenbergBridge {
|
|
|
124
134
|
this.deviceManager.updateDeviceValue(deviceValue);
|
|
125
135
|
}
|
|
126
136
|
|
|
137
|
+
handleDeviceInfo(deviceInfo) {
|
|
138
|
+
if (!deviceInfo || deviceInfo.deviceName || !deviceInfo.deviceDesignation) {
|
|
139
|
+
this.adapter.log.debug("Invalid device info received, ignoring.");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.adapter.log.debug(`New device info received for deviceID=${deviceInfo.deviceID}`);
|
|
144
|
+
// TODO: implement updates of device info if needed
|
|
145
|
+
}
|
|
146
|
+
|
|
127
147
|
async processAllNewDeviceInfos(response) {
|
|
128
148
|
try {
|
|
129
149
|
const deviceInfos = response.newDeviceInfos?.values ?? [];
|
|
@@ -253,6 +273,7 @@ class SchellenbergBridge {
|
|
|
253
273
|
[1]: r => {
|
|
254
274
|
this.retryCounter = 0;
|
|
255
275
|
this.resolveNextPromise(r);
|
|
276
|
+
this.updateTimestamp(r);
|
|
256
277
|
},
|
|
257
278
|
[2]: r => this.handleUpdate(r),
|
|
258
279
|
[5]: r => this.handleSpecificResponseCode(r, 5),
|
|
@@ -312,12 +333,12 @@ class SchellenbergBridge {
|
|
|
312
333
|
if (this.retryCounter < maxRetries) {
|
|
313
334
|
this.retryCounter++;
|
|
314
335
|
this.adapter.log.warn(`Reconnecting (try ${this.retryCounter} of ${maxRetries})...`);
|
|
315
|
-
setTimeout(() => this.Connect(), reconnectInterval);
|
|
336
|
+
this.adapter.setTimeout(() => this.Connect(), reconnectInterval);
|
|
316
337
|
} else {
|
|
317
338
|
this.adapter.log.warn(
|
|
318
339
|
`Connection to gateway lost, connection temporarily disabled! Trying again in ${retryInterval / (60 * 1000)} minutes.`,
|
|
319
340
|
);
|
|
320
|
-
setTimeout(() => this.Connect(), retryInterval);
|
|
341
|
+
this.adapter.setTimeout(() => this.Connect(), retryInterval);
|
|
321
342
|
}
|
|
322
343
|
}
|
|
323
344
|
|
|
@@ -382,17 +403,13 @@ class SchellenbergBridge {
|
|
|
382
403
|
}
|
|
383
404
|
|
|
384
405
|
handleUpdate(response) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
this.
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
// new device infos (optional, für später)
|
|
393
|
-
if (response.newDeviceInfos?.values?.length) {
|
|
394
|
-
for (const device of response.newDeviceInfos.values) {
|
|
395
|
-
this.adapter.log.debug(`New device info received for deviceID=${device.deviceID}`);
|
|
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);
|
|
396
413
|
}
|
|
397
414
|
}
|
|
398
415
|
}
|
|
@@ -403,7 +420,7 @@ class SchellenbergBridge {
|
|
|
403
420
|
}
|
|
404
421
|
|
|
405
422
|
this.adapter.log.warn(`Socket renewal was requested with reason: ${reason}`);
|
|
406
|
-
setTimeout(() => {
|
|
423
|
+
this.adapter.setTimeout(() => {
|
|
407
424
|
this.Connect();
|
|
408
425
|
}, 1000);
|
|
409
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
static
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
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
|
|
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
|
|
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));
|
|
@@ -16,10 +16,12 @@ class SchellenbergDevice {
|
|
|
16
16
|
|
|
17
17
|
// Creates all necessery states and channels and writes the values into the DB
|
|
18
18
|
async CreateAndSave(masterPrefix) {
|
|
19
|
-
|
|
19
|
+
let devicePrefix = masterPrefix
|
|
20
20
|
? `${masterPrefix}.${this.id}`
|
|
21
21
|
: `${commonDefines.AdapterDatapointIDs.Devices}.${this.id}`;
|
|
22
22
|
|
|
23
|
+
devicePrefix = devicePrefix.replace(this.adapter.FORBIDDEN_CHARS, "");
|
|
24
|
+
|
|
23
25
|
await this.adapter.setObjectNotExistsAsync(devicePrefix, {
|
|
24
26
|
type: "channel",
|
|
25
27
|
common: {
|
|
@@ -99,7 +101,11 @@ class SchellenbergDevice {
|
|
|
99
101
|
// Dynamisch aus device.definition
|
|
100
102
|
if (this.definition?.deviceType?.switchingValues) {
|
|
101
103
|
for (const stateDef of this.definition.deviceType.switchingValues) {
|
|
102
|
-
const stateId = stateDef.name
|
|
104
|
+
const stateId = stateDef.name
|
|
105
|
+
.replace(/\${|}/g, "") // ${On} → On
|
|
106
|
+
.replace(this.adapter.FORBIDDEN_CHARS, "")
|
|
107
|
+
.toLowerCase();
|
|
108
|
+
|
|
103
109
|
await this.adapter.setObjectNotExistsAsync(`${controlPrefix}${stateId}`, {
|
|
104
110
|
type: "state",
|
|
105
111
|
common: {
|
|
@@ -9,7 +9,7 @@ class SchellenbergMasterDevice {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
async createMasterFolder() {
|
|
12
|
-
const masterPrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${this.id}`;
|
|
12
|
+
const masterPrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${this.id.replace(this.adapter.FORBIDDEN_CHARS, "")}`;
|
|
13
13
|
await this.adapter.setObjectNotExistsAsync(masterPrefix, {
|
|
14
14
|
type: "channel",
|
|
15
15
|
common: { name: this.name },
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
//--------------------------------------------------
|
|
11
11
|
|
|
12
12
|
class Deferred {
|
|
13
|
-
constructor(executor) {
|
|
14
|
-
this.
|
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.smartfriends",
|
|
3
|
-
"version": "1.1.0-alpha.
|
|
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",
|