homebridge-smartsystem 7.1.22 → 7.1.23
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/accessories/accessory.js +2 -2
- package/accessories/dimmer.js +2 -1
- package/accessories/temperature.js +2 -1
- package/duotecno/types.js +1 -0
- package/package.json +2 -2
- package/server/proxy.js +51 -3
package/accessories/accessory.js
CHANGED
|
@@ -49,7 +49,7 @@ class Accessory {
|
|
|
49
49
|
getState(next) {
|
|
50
50
|
if (this.unit) {
|
|
51
51
|
(0, logger_1.log)("accessory", "getState was called for " + this.unit.node.getName() + " - " + this.unit.getName() + " -> " + this.unit.status);
|
|
52
|
-
next(null, this.unit.status);
|
|
52
|
+
next(null, !!this.unit.status);
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
55
|
next(new Error("accessory - getState needs to be overridden if no unit is provided."));
|
|
@@ -81,7 +81,7 @@ class Accessory {
|
|
|
81
81
|
next(new Error("accessory - setState needs to be overridden if no unit is provided."));
|
|
82
82
|
}
|
|
83
83
|
updateState() {
|
|
84
|
-
this.me.getCharacteristic(this.homebridge.Characteristic.On).updateValue(this.unit.status);
|
|
84
|
+
this.me.getCharacteristic(this.homebridge.Characteristic.On).updateValue(!!this.unit.status);
|
|
85
85
|
(0, logger_1.log)("accessory", "Received status change -> update accessory -> " + this.unit.getName() + " -> on = " + this.unit.status);
|
|
86
86
|
}
|
|
87
87
|
}
|
package/accessories/dimmer.js
CHANGED
|
@@ -28,9 +28,10 @@ class Dimmer extends accessory_1.Accessory {
|
|
|
28
28
|
return [lightbulbService];
|
|
29
29
|
}
|
|
30
30
|
getBrightness(next) {
|
|
31
|
+
var _a;
|
|
31
32
|
if (this.unit) {
|
|
32
33
|
(0, logger_1.log)("accessory", "getBrightness was called for " + this.unit.node.getName() + " - " + this.unit.getName() + " -> " + this.unit.value);
|
|
33
|
-
next(null, this.unit.value);
|
|
34
|
+
next(null, (_a = this.unit.value) !== null && _a !== void 0 ? _a : 0);
|
|
34
35
|
}
|
|
35
36
|
else {
|
|
36
37
|
next(new Error("accessory - getBrightness needs to be overridden if no unit is provided."));
|
|
@@ -21,9 +21,10 @@ class Temperature extends accessory_1.Accessory {
|
|
|
21
21
|
return [temperatureService];
|
|
22
22
|
}
|
|
23
23
|
getTemperature(next) {
|
|
24
|
+
var _a;
|
|
24
25
|
if (this.unit) {
|
|
25
26
|
(0, logger_1.log)("accessory", "getTemperature was called for " + this.unit.node.getName() + " - " + this.unit.getName() + " -> " + this.unit.value);
|
|
26
|
-
const limited = Math.max(-100, Math.min(100, this.unit.value / 10.0));
|
|
27
|
+
const limited = Math.max(-100, Math.min(100, ((_a = this.unit.value) !== null && _a !== void 0 ? _a : 0) / 10.0));
|
|
27
28
|
next(null, limited);
|
|
28
29
|
}
|
|
29
30
|
else {
|
package/duotecno/types.js
CHANGED
|
@@ -428,6 +428,7 @@ exports.Sanitizers = {
|
|
|
428
428
|
c.installationId = (config === null || config === void 0 ? void 0 : config.installationId) || proxy_1.kEmptyProxy.installationId;
|
|
429
429
|
c.nodeNumber = (typeof (config === null || config === void 0 ? void 0 : config.nodeNumber) === "number") ? config.nodeNumber : proxy_1.kEmptyProxy.nodeNumber;
|
|
430
430
|
c.httpEnabled = !!(config === null || config === void 0 ? void 0 : config.httpEnabled);
|
|
431
|
+
c.gatewayPhysicalId = (config === null || config === void 0 ? void 0 : config.gatewayPhysicalId) || proxy_1.kEmptyProxy.gatewayPhysicalId;
|
|
431
432
|
c.kind = "gw";
|
|
432
433
|
return c;
|
|
433
434
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-smartsystem",
|
|
3
3
|
"displayname": "Duotecno Bridge",
|
|
4
|
-
"version": "7.1.
|
|
4
|
+
"version": "7.1.23",
|
|
5
5
|
"description": "SmartServer (Proxy TCP sockets to the cloud, Smappee MQTT, Duotecno IP Nodes, Homekit interface)",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"author": "Johan Coppieters",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
],
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/Duotecno-developer/smartsocket.git"
|
|
39
|
+
"url": "git+https://github.com/Duotecno-developer/smartsocket.git"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"bonjour-service": "^1.3.0",
|
package/server/proxy.js
CHANGED
|
@@ -11,8 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.Context = exports.cleanStart = exports.makeNewCloudConnection = exports.gCloudConnections = exports.setProxyConfig = exports.setWebApp = exports.kEmptyProxy = exports.gatewayHttpPort = exports.makeDeviceId = exports.kMasterNodeNumber = void 0;
|
|
13
13
|
const net = require("net");
|
|
14
|
+
const os = require("os");
|
|
14
15
|
const child_process_1 = require("child_process");
|
|
15
16
|
const process_1 = require("process");
|
|
17
|
+
const config_1 = require("../duotecno/config");
|
|
16
18
|
// Fixed, non-configurable logical node number every Duotecno master identifies itself with
|
|
17
19
|
// on the bus -- used for both of the master's own registrations (raw protocol + Config API).
|
|
18
20
|
exports.kMasterNodeNumber = 0xfc;
|
|
@@ -31,6 +33,47 @@ function gatewayHttpPort() {
|
|
|
31
33
|
return port || 80;
|
|
32
34
|
}
|
|
33
35
|
exports.gatewayHttpPort = gatewayHttpPort;
|
|
36
|
+
// The cloud server can tell apart two different physical devices that were accidentally
|
|
37
|
+
// registered under the same unique id (instead of assuming a reconnect and evicting the
|
|
38
|
+
// other one), given a "physical address" -- 1-8 hex digits, formatted "0x..." -- alongside
|
|
39
|
+
// the unique id at registration. Masters have a real one: the Duotecno bus physical address
|
|
40
|
+
// of their own logical node (kMasterNodeNumber). Returns '' if not known yet (e.g. the master
|
|
41
|
+
// hasn't finished its initial discovery), in which case no physical address is sent for this
|
|
42
|
+
// registration, same as old firmware.
|
|
43
|
+
function masterPhysicalAddress() {
|
|
44
|
+
const system = gWebApp === null || gWebApp === void 0 ? void 0 : gWebApp.system;
|
|
45
|
+
const master = (system === null || system === void 0 ? void 0 : system.findMaster) ? system.findMaster(config.masterAddress, config.masterPort) : null;
|
|
46
|
+
const node = (master === null || master === void 0 ? void 0 : master.findNode) ? master.findNode(exports.kMasterNodeNumber) : null;
|
|
47
|
+
const phys = node === null || node === void 0 ? void 0 : node.physicalAddress;
|
|
48
|
+
return (typeof phys === "number" && phys > 0) ? "0x" + phys.toString(16) : '';
|
|
49
|
+
}
|
|
50
|
+
// The gateway itself has no Duotecno bus address of its own. Prefer the last two groups of a
|
|
51
|
+
// non-internal IPv6 address (8 hex digits total, e.g. "2afa:23fa:b95:9ebf" -> last two groups
|
|
52
|
+
// "b95:9ebf" -> "0x0b959ebf") if one is available on this machine; otherwise fall back to a
|
|
53
|
+
// random id generated once and persisted in config.json, so it stays stable across restarts
|
|
54
|
+
// and lets the cloud tell two different physical gateways apart even if they were accidentally
|
|
55
|
+
// given the same installation id.
|
|
56
|
+
function gatewayPhysicalAddress() {
|
|
57
|
+
const interfaces = os.networkInterfaces();
|
|
58
|
+
for (const name in interfaces) {
|
|
59
|
+
for (const iface of interfaces[name] || []) {
|
|
60
|
+
if ((iface.family === "IPv6" || iface.family === 6) && !iface.internal) {
|
|
61
|
+
const groups = iface.address.split(":").filter(g => g.length > 0);
|
|
62
|
+
if (groups.length >= 2) {
|
|
63
|
+
const last2 = groups.slice(-2).map(g => g.padStart(4, '0')).join('');
|
|
64
|
+
return "0x" + last2;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!config.gatewayPhysicalId) {
|
|
70
|
+
config.gatewayPhysicalId = "0x" + Math.floor(Math.random() * 0x100000000).toString(16).padStart(8, '0');
|
|
71
|
+
(0, config_1.setSubConfig)("proxy", config);
|
|
72
|
+
(0, config_1.setAPIConfig)();
|
|
73
|
+
log(`[PROXY] No IPv6 address available, generated and stored a random physical id for this gateway: ${config.gatewayPhysicalId}`);
|
|
74
|
+
}
|
|
75
|
+
return config.gatewayPhysicalId;
|
|
76
|
+
}
|
|
34
77
|
exports.kEmptyProxy = {
|
|
35
78
|
cloudServer: "masters.duotecno.eu",
|
|
36
79
|
cloudPort: 5097,
|
|
@@ -40,6 +83,7 @@ exports.kEmptyProxy = {
|
|
|
40
83
|
installationId: "",
|
|
41
84
|
nodeNumber: 0xff,
|
|
42
85
|
httpEnabled: false,
|
|
86
|
+
gatewayPhysicalId: "",
|
|
43
87
|
debug: false,
|
|
44
88
|
kind: "gw" // default running under the gateway or other process manager -> don't restart yourself
|
|
45
89
|
};
|
|
@@ -61,6 +105,7 @@ function setProxyConfig(c) {
|
|
|
61
105
|
config.installationId = c.installationId || exports.kEmptyProxy.installationId;
|
|
62
106
|
config.nodeNumber = (typeof c.nodeNumber === "number") ? c.nodeNumber : exports.kEmptyProxy.nodeNumber;
|
|
63
107
|
config.httpEnabled = !!c.httpEnabled;
|
|
108
|
+
config.gatewayPhysicalId = c.gatewayPhysicalId || exports.kEmptyProxy.gatewayPhysicalId;
|
|
64
109
|
config.debug = !!c.debug;
|
|
65
110
|
config.kind = c.kind || exports.kEmptyProxy.kind;
|
|
66
111
|
}
|
|
@@ -114,6 +159,9 @@ function makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId
|
|
|
114
159
|
// we check every 16 seconds for a free connection, if none found -> restart
|
|
115
160
|
}
|
|
116
161
|
}
|
|
162
|
+
// lets the cloud tell two genuinely different physical devices apart if they were ever
|
|
163
|
+
// accidentally configured with the same unique id, instead of assuming a reconnect
|
|
164
|
+
const physicalAddress = isGateway ? gatewayPhysicalAddress() : masterPhysicalAddress();
|
|
117
165
|
const cloudSocket = new net.Socket();
|
|
118
166
|
cloudSocket.once('error', reconnect);
|
|
119
167
|
// net.Socket.connect() has no default timeout: if the TCP handshake to the cloud gets
|
|
@@ -130,9 +178,9 @@ function makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId
|
|
|
130
178
|
log(`[PROXY] → [CLOUD] Connected to Cloud at ${server}:${serverPort}`);
|
|
131
179
|
cloudSocket.setTimeout(0); // connected -- no longer subject to the connect-attempt timeout
|
|
132
180
|
cloudSocket.removeListener('error', reconnect);
|
|
133
|
-
// Send unique ID as the first message to identify this proxy/device
|
|
134
|
-
cloudSocket.write(`[${uniqueId}]`);
|
|
135
|
-
debug(`[PROXY] → [CLOUD] Sent unique ID: ${uniqueId}`);
|
|
181
|
+
// Send unique ID (and physical address, if known) as the first message to identify this proxy/device
|
|
182
|
+
cloudSocket.write(physicalAddress ? `[${uniqueId}][${physicalAddress}]` : `[${uniqueId}]`);
|
|
183
|
+
debug(`[PROXY] → [CLOUD] Sent unique ID: ${uniqueId}` + (physicalAddress ? ` physical address: ${physicalAddress}` : ''));
|
|
136
184
|
const context = new Context(cloudSocket, master, masterPort, server, serverPort, uniqueId, isGateway);
|
|
137
185
|
exports.gCloudConnections.push(context);
|
|
138
186
|
log(`[PROXY] → [CLOUD] New free connection #${exports.gCloudConnections.length} to the Cloud at ${server}:${serverPort}`);
|