iobroker.smartfriends 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +34 -0
  2. package/README.md +67 -0
  3. package/admin/i18n/de/translations.json +19 -0
  4. package/admin/i18n/en/translations.json +19 -0
  5. package/admin/i18n/es/translations.json +19 -0
  6. package/admin/i18n/fr/translations.json +19 -0
  7. package/admin/i18n/it/translations.json +19 -0
  8. package/admin/i18n/nl/translations.json +19 -0
  9. package/admin/i18n/pl/translations.json +19 -0
  10. package/admin/i18n/pt/translations.json +19 -0
  11. package/admin/i18n/ru/translations.json +19 -0
  12. package/admin/i18n/uk/translations.json +19 -0
  13. package/admin/i18n/zh-cn/translations.json +19 -0
  14. package/admin/jsonConfig.json +99 -0
  15. package/admin/smartfriends.png +0 -0
  16. package/admin/words.js +207 -0
  17. package/io-package.json +92 -0
  18. package/lib/DeviceManager.js +121 -0
  19. package/lib/SchellenbergBridge.js +315 -0
  20. package/lib/SchellenbergDevice.js +218 -0
  21. package/lib/adapter-config.d.ts +19 -0
  22. package/lib/comunication/CA.pem +22 -0
  23. package/lib/comunication/CommandFactory.js +123 -0
  24. package/lib/comunication/DataDelegateInterface.js +7 -0
  25. package/lib/comunication/HashHelper.js +41 -0
  26. package/lib/comunication/SmartSocket.js +189 -0
  27. package/lib/comunication/SmartSocketFactory.js +119 -0
  28. package/lib/comunication/comModel/JSONCommand.js +21 -0
  29. package/lib/comunication/comModel/JSONHelper.js +43 -0
  30. package/lib/comunication/comModel/JSONResponse.js +43 -0
  31. package/lib/comunication/comModel/responseBody/AllNewDeviceInfos.js +38 -0
  32. package/lib/comunication/comModel/responseBody/DeviceInfo.js +41 -0
  33. package/lib/comunication/comModel/responseBody/DeviceValue.js +24 -0
  34. package/lib/comunication/comModel/responseBody/HeloResponse.js +17 -0
  35. package/lib/comunication/comModel/responseBody/LanguageTranslation.js +17 -0
  36. package/lib/comunication/comModel/responseBody/LoginResponse.js +26 -0
  37. package/lib/comunication/comModel/responseBody/NewCompatibilityConfiguration.js +16 -0
  38. package/lib/comunication/comModel/responseBody/NewDeviceInfos.js +20 -0
  39. package/lib/comunication/comModel/responseBody/NewDeviceValues.js +20 -0
  40. package/lib/comunication/comModel/responseBody/NewLanguageTranslation.js +23 -0
  41. package/lib/helpers/CommonDefines.js +40 -0
  42. package/lib/helpers/Deffered.js +41 -0
  43. package/main.js +239 -0
  44. package/package.json +71 -0
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+
8
+ const SmartSocket = require("./SmartSocket");
9
+ const fs = require("fs");
10
+ const CommandFactory = require("./CommandFactory");
11
+ const HashHelper = require("./HashHelper");
12
+ const HeloResponse = require("./comModel/responseBody/HeloResponse");
13
+ const LoginResponse = require("./comModel/responseBody/LoginResponse");
14
+ class SmartSocketFactory {
15
+ static createSocketAndLogin(
16
+ that,
17
+ ipAddress,
18
+ port,
19
+ caFileName,
20
+ username,
21
+ password,
22
+ cSymbol,
23
+ shcVersion,
24
+ shApiVersion,
25
+ dataHandler,
26
+ startKeepAlive,
27
+ ignoreSslErrors,
28
+ ) {
29
+ const returnPromise = new Promise((resolve, reject) => {
30
+ if (dataHandler) {
31
+ this.createSocket(that, ipAddress, port, caFileName, dataHandler, ignoreSslErrors)
32
+ .catch(reason => {
33
+ reject(reason);
34
+ })
35
+ .then(socket => {
36
+ if (socket) {
37
+ socket
38
+ .sendAndRecieveCommand(CommandFactory.default.createHeloCmd(username))
39
+ .then(responseHelo => {
40
+ if (responseHelo.response) {
41
+ const parsedResponseHelo = HeloResponse.default.fromObject(
42
+ responseHelo.response,
43
+ );
44
+ if (
45
+ parsedResponseHelo &&
46
+ parsedResponseHelo.salt &&
47
+ parsedResponseHelo.sessionSalt
48
+ ) {
49
+ const digest = HashHelper.default.calculateDigest(
50
+ password,
51
+ parsedResponseHelo.salt,
52
+ parsedResponseHelo.sessionSalt,
53
+ );
54
+ socket
55
+ .sendAndRecieveCommand(
56
+ CommandFactory.default.createLoginCommand(
57
+ username,
58
+ digest,
59
+ cSymbol,
60
+ shcVersion,
61
+ shApiVersion,
62
+ ),
63
+ )
64
+ .then(responseLogin => {
65
+ if (responseLogin.response) {
66
+ const parsedResponseLogin = LoginResponse.default.fromObject(
67
+ responseLogin.response,
68
+ );
69
+ if (parsedResponseLogin && parsedResponseLogin.sessionID) {
70
+ dataHandler.handleLoginMessage(parsedResponseLogin);
71
+ if (startKeepAlive) {
72
+ socket.startKeepAlive();
73
+ }
74
+ resolve(socket);
75
+ } else {
76
+ reject("JSON Parsing Message Error 4");
77
+ }
78
+ } else {
79
+ reject("JSON Parsing Message Error 3");
80
+ }
81
+ })
82
+ .catch(reason => {
83
+ reject(reason);
84
+ });
85
+ } else {
86
+ reject("JSON Parsing Message Error 2");
87
+ }
88
+ } else {
89
+ reject("JSON Parsing Message Error 1");
90
+ }
91
+ })
92
+ .catch(reason => {
93
+ reject(reason);
94
+ });
95
+ }
96
+ });
97
+ } else {
98
+ reject("Missing dataHandler. Needed for Login.");
99
+ }
100
+ });
101
+ return returnPromise;
102
+ }
103
+ static createSocket(that, ipAddress, port, caFileName, dataHandler, ignoreSslErrors) {
104
+ const caText = fs.readFileSync(`${__dirname}/${caFileName}`, "utf8");
105
+ const socket = new SmartSocket.SmartSocket(that, ipAddress, port, caText, ignoreSslErrors);
106
+ const returnPromise = new Promise((resolve, reject) => {
107
+ socket
108
+ .setupSocket(dataHandler)
109
+ .then(() => {
110
+ resolve(socket);
111
+ })
112
+ .catch(reason => {
113
+ reject(reason);
114
+ });
115
+ });
116
+ return returnPromise;
117
+ }
118
+ }
119
+ exports.default = SmartSocketFactory;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ //Wrapper for easily gernating JSON Commands
8
+ //--------------------------------------------------
9
+
10
+ class JSONCommand {
11
+ constructor(methode) {
12
+ this.command = methode;
13
+ }
14
+ toString(sessionID) {
15
+ if (sessionID) {
16
+ this.sessionID = sessionID;
17
+ }
18
+ return JSON.stringify(this);
19
+ }
20
+ }
21
+ exports.default = JSONCommand;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ //Helper Class for JSON Encode and Decode
8
+ //--------------------------------------------------
9
+
10
+ class JSONHelper {
11
+ static stringToDate(timestamp) {
12
+ if (timestamp) {
13
+ const splitTimestamp = timestamp.toString().split(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/);
14
+ return new Date(
15
+ Number.parseInt(splitTimestamp[1]),
16
+ Number.parseInt(splitTimestamp[2]),
17
+ Number.parseInt(splitTimestamp[3]),
18
+ Number.parseInt(splitTimestamp[4]),
19
+ Number.parseInt(splitTimestamp[5]),
20
+ Number.parseInt(splitTimestamp[6]),
21
+ );
22
+ }
23
+ }
24
+ static dateToString(date) {
25
+ if (date && date.getTime() > 0) {
26
+ let returnNumber = 0;
27
+ returnNumber += date.getFullYear();
28
+ returnNumber *= 100;
29
+ returnNumber += date.getMonth();
30
+ returnNumber *= 100;
31
+ returnNumber += date.getDay();
32
+ returnNumber *= 100;
33
+ returnNumber += date.getHours();
34
+ returnNumber *= 100;
35
+ returnNumber += date.getMinutes();
36
+ returnNumber *= 100;
37
+ returnNumber += date.getSeconds();
38
+ return returnNumber.toString();
39
+ }
40
+ return "0";
41
+ }
42
+ }
43
+ exports.default = JSONHelper;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ //Wrapper for Response answers
8
+ //--------------------------------------------------
9
+ const JSONHelper = require("./JSONHelper.js");
10
+ class JSONResponse {
11
+ constructor(currentTimestamp, response, responseCode, responseMessage) {
12
+ this.currentTimestamp = currentTimestamp;
13
+ this.response = response;
14
+ this.responseCode = responseCode;
15
+ this.responseMessage = responseMessage;
16
+ }
17
+ static fromJSONString(json) {
18
+ const jsonObject = JSON.parse(json);
19
+ return this.fromObject(jsonObject);
20
+ }
21
+ static fromObject(object) {
22
+ // e.g.: { "error" : { "message" : "The TLS/SSL connection has been closed", "responseCode" : 84 } }
23
+ if (object.error != null) {
24
+ return new JSONResponse(null, object.error, object.error.responseCode, object.error.message);
25
+ }
26
+
27
+ // e.g.: { "success" : { "messageId" : "remoteHome.connected", "responseCode" : 203 } }
28
+ if (object.success != null) {
29
+ return new JSONResponse(null, object.success, object.success.responseCode, object.success.messageId);
30
+ }
31
+
32
+ // e.g.: { "currentTimestamp" : 20201210140021, "response" : { "remoteHomeActivated" : true, "remoteHomeStatus" : "notConnected" }, "responseCode" : 1, "responseMessage" : "success" }
33
+ return new JSONResponse(
34
+ JSONHelper.default.stringToDate(
35
+ object.currentTimestamp ? object.currentTimestamp : object.response.currentTimestamp,
36
+ ),
37
+ object.response,
38
+ object.responseCode,
39
+ object.responseMessage,
40
+ );
41
+ }
42
+ }
43
+ exports.default = JSONResponse;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ //Wrapper for Response answers
8
+ //--------------------------------------------------
9
+ const JSONHelper = require("../JSONHelper.js");
10
+ const NewCompatibilityConfiguration = require("./NewCompatibilityConfiguration.js");
11
+ const NewDeviceInfos = require("./NewDeviceInfos.js");
12
+ const NewDeviceValues = require("./NewDeviceValues.js");
13
+ const NewLanguageTranslation = require("./NewLanguageTranslation.js");
14
+ class AllNewDeviceInfos {
15
+ constructor(
16
+ currentTimestamp,
17
+ newCompatibilityConfiguration,
18
+ newDeviceInfos,
19
+ newDeviceValues,
20
+ newLanguageTranslation,
21
+ ) {
22
+ this.currentTimestamp = currentTimestamp;
23
+ this.newCompatibilityConfiguration = newCompatibilityConfiguration;
24
+ this.newDeviceInfos = newDeviceInfos;
25
+ this.newDeviceValues = newDeviceValues;
26
+ this.newLanguageTranslations = newLanguageTranslation;
27
+ }
28
+ static fromObject(object) {
29
+ return new AllNewDeviceInfos(
30
+ JSONHelper.default.stringToDate(object.currentTimestamp),
31
+ NewCompatibilityConfiguration.default.fromObject(object.newCompatibilityConfiguration),
32
+ NewDeviceInfos.default.fromObject(object.newDeviceInfos),
33
+ NewDeviceValues.default.fromObject(object.newDeviceValues),
34
+ NewLanguageTranslation.default.fromObject(object.newLanguageTranslation),
35
+ );
36
+ }
37
+ }
38
+ exports.default = AllNewDeviceInfos;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+
8
+ class DeviceInfo {
9
+ constructor(
10
+ deviceID,
11
+ deviceName,
12
+ masterDeviceID,
13
+ masterDeviceName,
14
+ manufacture,
15
+ deviceDesignation,
16
+ deviceTypClient,
17
+ firstLevel,
18
+ ) {
19
+ this.deviceID = deviceID;
20
+ this.deviceName = deviceName;
21
+ this.masterDeviceID = masterDeviceID;
22
+ this.masterDeviceName = masterDeviceName;
23
+ this.manufacture = manufacture;
24
+ this.deviceDesignation = deviceDesignation;
25
+ this.deviceTypClient = deviceTypClient;
26
+ this.firstLevel = firstLevel;
27
+ }
28
+ static fromObject(object) {
29
+ return new DeviceInfo(
30
+ object.deviceID,
31
+ object.deviceName,
32
+ object.masterDeviceID,
33
+ object.masterDeviceName,
34
+ object.manufacture,
35
+ object.deviceDesignation,
36
+ object.deviceTypClient,
37
+ object.firstLevel,
38
+ );
39
+ }
40
+ }
41
+ exports.default = DeviceInfo;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ const JSONHelper = require("../JSONHelper.js");
8
+ class DeviceValue {
9
+ constructor(deviceID, masterDeviceID, value, valueTimestamp) {
10
+ this.deviceID = deviceID;
11
+ this.masterDeviceID = masterDeviceID;
12
+ this.value = value;
13
+ this.valueTimestamp = valueTimestamp;
14
+ }
15
+ static fromObject(object) {
16
+ return new DeviceValue(
17
+ object.deviceID,
18
+ object.masterDeviceID,
19
+ object.value,
20
+ JSONHelper.default.stringToDate(object.valueTimestamp),
21
+ );
22
+ }
23
+ }
24
+ exports.default = DeviceValue;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+
8
+ class HeloResponse {
9
+ constructor(salt, sessionSalt) {
10
+ this.salt = salt;
11
+ this.sessionSalt = sessionSalt;
12
+ }
13
+ static fromObject(object) {
14
+ return new HeloResponse(object.salt, object.sessionSalt);
15
+ }
16
+ }
17
+ exports.default = HeloResponse;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+
8
+ class LanguageTranslation {
9
+ constructor(key, value) {
10
+ this.key = key;
11
+ this.value = value;
12
+ }
13
+ static fromObject(object) {
14
+ return new LanguageTranslation(object.key, object.value);
15
+ }
16
+ }
17
+ exports.default = LanguageTranslation;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+
8
+ class LoginResponse {
9
+ constructor(hardware, macAddress, pushNotificationUrl, sessionID, shsVersion) {
10
+ this.hardware = hardware;
11
+ this.macAddress = macAddress;
12
+ this.pushNotificationUrl = pushNotificationUrl;
13
+ this.sessionID = sessionID;
14
+ this.shsVersion = shsVersion;
15
+ }
16
+ static fromObject(object) {
17
+ return new LoginResponse(
18
+ object.hardware,
19
+ object.macAddress,
20
+ object.pushNotificationUrl,
21
+ object.sessionID,
22
+ object.shsVersion,
23
+ );
24
+ }
25
+ }
26
+ exports.default = LoginResponse;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+
8
+ class NewCompatibilityConfiguration {
9
+ constructor(compatibilityConfigurationVersion) {
10
+ this.compatibilityConfigurationVersion = compatibilityConfigurationVersion;
11
+ }
12
+ static fromObject(object) {
13
+ return new NewCompatibilityConfiguration(object.compatibilityConfigurationVersion);
14
+ }
15
+ }
16
+ exports.default = NewCompatibilityConfiguration;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ const DeviceInfo = require("./DeviceInfo");
8
+ class NewDeviceInfos {
9
+ constructor(values) {
10
+ this.values = values;
11
+ }
12
+ static fromObject(object) {
13
+ const tempValues = [];
14
+ for (const valueEntry of object) {
15
+ tempValues.push(DeviceInfo.default.fromObject(valueEntry));
16
+ }
17
+ return new NewDeviceInfos(tempValues);
18
+ }
19
+ }
20
+ exports.default = NewDeviceInfos;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ const DeviceValue = require("./DeviceValue");
8
+ class NewDeviceValues {
9
+ constructor(values) {
10
+ this.values = values;
11
+ }
12
+ static fromObject(object) {
13
+ const tempValues = [];
14
+ for (const valueEntry of object) {
15
+ tempValues.push(DeviceValue.default.fromObject(valueEntry));
16
+ }
17
+ return new NewDeviceValues(tempValues);
18
+ }
19
+ }
20
+ exports.default = NewDeviceValues;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ const LanguageTranslation = require("./LanguageTranslation");
8
+ class NewLanguageTranslation {
9
+ constructor(languageTranslationVersion, newTranslatedStrings) {
10
+ this.languageTranslationVersion = languageTranslationVersion;
11
+ this.newTranslatedStrings = newTranslatedStrings;
12
+ }
13
+ static fromObject(object) {
14
+ const tempValues = [];
15
+ if (object.newTranslatedStrings && typeof object.newTranslatedStrings[Symbol.iterator] === "function") {
16
+ for (const valueEntry of object.newTranslatedStrings) {
17
+ tempValues.push(LanguageTranslation.default.fromObject(valueEntry));
18
+ }
19
+ }
20
+ return new NewLanguageTranslation(object.languageTranslationVersion, tempValues);
21
+ }
22
+ }
23
+ exports.default = NewLanguageTranslation;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ exports.AdapterDatapointIDs = Object.freeze({
4
+ Info: "info",
5
+ Gateway: "gateway",
6
+ Devices: "devices",
7
+ Control: "control",
8
+ });
9
+
10
+ exports.AdapterStateIDs = Object.freeze({
11
+ // info
12
+ Connection: "connection",
13
+ DeviceName: "deviceName",
14
+ // gateway
15
+ HardwareName: "hardwareName",
16
+ MacAddress: "macAddress",
17
+ // devices.XXX.info
18
+ TypeClient: "typeClient",
19
+ Designation: "designation",
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 },
40
+ });
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ //--------------------------------------------------
4
+ //Copyright 2020 Pascâl Hartmann
5
+ //See LICENSE File
6
+ //--------------------------------------------------
7
+ //Helper Class for promises
8
+ //modified from
9
+ //https://codereview.stackexchange.com/questions/105754/access-resolve-function-outside-of-a-javascript-promise
10
+ //--------------------------------------------------
11
+
12
+ class Deferred {
13
+ constructor(executor) {
14
+ this.timeout = setTimeout(() => {
15
+ this.reject("timeout");
16
+ }, 5000);
17
+ this.promise = new Promise((resolve, reject) => {
18
+ this._resolveSelf = resolve;
19
+ this._rejectSelf = reject;
20
+ });
21
+ executor.call(this, this._resolveSelf, this._rejectSelf);
22
+ }
23
+ then(onfulfilled, onrejected) {
24
+ return this.promise.then(onfulfilled, onrejected);
25
+ }
26
+ catch(onrejected) {
27
+ return this.promise.then(onrejected);
28
+ }
29
+ finally(onfinally) {
30
+ return this.promise.finally(onfinally);
31
+ }
32
+ resolve(val) {
33
+ clearTimeout(this.timeout);
34
+ this._resolveSelf(val);
35
+ }
36
+ reject(reason) {
37
+ clearTimeout(this.timeout);
38
+ this._rejectSelf(reason);
39
+ }
40
+ }
41
+ exports.default = Deferred;