homebridge-plejd 1.3.4 → 1.3.6
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +13 -1
- package/README.md +14 -17
- package/dist/index.d.ts +2 -3
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/model/device.d.ts +0 -1
- package/dist/model/device.js +1 -2
- package/dist/model/plejdSite.d.ts +0 -1
- package/dist/model/plejdSite.js +44 -47
- package/dist/model/plejdSite.js.map +1 -1
- package/dist/model/userInputConfig.d.ts +0 -1
- package/dist/model/userInputConfig.js +1 -2
- package/dist/plejdApi.d.ts +3 -4
- package/dist/plejdApi.js +124 -123
- package/dist/plejdApi.js.map +1 -1
- package/dist/plejdPlatform.d.ts +8 -9
- package/dist/plejdPlatform.js +190 -188
- package/dist/plejdPlatform.js.map +1 -1
- package/dist/plejdPlatformAccessory.d.ts +0 -1
- package/dist/plejdPlatformAccessory.js +46 -48
- package/dist/plejdPlatformAccessory.js.map +1 -1
- package/dist/plejdService.d.ts +2 -3
- package/dist/plejdService.js +262 -258
- package/dist/plejdService.js.map +1 -1
- package/dist/plejdUtils.d.ts +1 -2
- package/dist/plejdUtils.js +11 -17
- package/dist/plejdUtils.js.map +1 -1
- package/dist/settings.d.ts +0 -1
- package/dist/settings.js +6 -9
- package/dist/settings.js.map +1 -1
- package/package.json +19 -22
- package/dist/index.d.ts.map +0 -1
- package/dist/model/device.d.ts.map +0 -1
- package/dist/model/plejdSite.d.ts.map +0 -1
- package/dist/model/userInputConfig.d.ts.map +0 -1
- package/dist/plejdApi.d.ts.map +0 -1
- package/dist/plejdPlatform.d.ts.map +0 -1
- package/dist/plejdPlatformAccessory.d.ts.map +0 -1
- package/dist/plejdService.d.ts.map +0 -1
- package/dist/plejdUtils.d.ts.map +0 -1
- package/dist/settings.d.ts.map +0 -1
- package/my-site.json +0 -2427
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"plejdPlatformAccessory.js","sourceRoot":"","sources":["../src/plejdPlatformAccessory.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"plejdPlatformAccessory.js","sourceRoot":"","sources":["../src/plejdPlatformAccessory.ts"],"names":[],"mappings":"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"}
|
package/dist/plejdService.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { Logger } from
|
2
|
-
import { UserInputConfig } from
|
1
|
+
import { Logger } from "homebridge";
|
2
|
+
import { UserInputConfig } from "./model/userInputConfig";
|
3
3
|
export declare class PlejdService {
|
4
4
|
private readonly config;
|
5
5
|
readonly log: Logger;
|
@@ -26,4 +26,3 @@ export declare class PlejdService {
|
|
26
26
|
private gotData;
|
27
27
|
private plejdWrite;
|
28
28
|
}
|
29
|
-
//# sourceMappingURL=plejdService.d.ts.map
|
package/dist/plejdService.js
CHANGED
@@ -1,304 +1,308 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
};
|
5
|
-
|
6
|
-
exports.PlejdService = void 0;
|
7
|
-
const plejdUtils_1 = require("./plejdUtils");
|
8
|
-
const crypto_1 = require("crypto");
|
9
|
-
const noble_1 = __importDefault(require("@abandonware/noble"));
|
10
|
-
const settings_1 = require("./settings");
|
11
|
-
const NOBLE_IS_POWER_ON = 'poweredOn';
|
1
|
+
import { plejdChalResp as plejdCharResp, plejdEncodeDecode, reverseBuffer, } from "./plejdUtils";
|
2
|
+
import { randomBytes } from "crypto";
|
3
|
+
import noble from "@abandonware/noble";
|
4
|
+
import { PLEJD_WRITE_TIMEOUT } from "./settings";
|
5
|
+
const NOBLE_IS_POWER_ON = "oweredOn";
|
12
6
|
/**
|
13
7
|
* Plejd BLE UUIDs
|
14
8
|
*/
|
15
9
|
var PlejdCharacteristics;
|
16
10
|
(function (PlejdCharacteristics) {
|
17
|
-
PlejdCharacteristics["Service"] = "
|
18
|
-
PlejdCharacteristics["LightLevel"] = "
|
19
|
-
PlejdCharacteristics["Data"] = "
|
20
|
-
PlejdCharacteristics["LastData"] = "
|
21
|
-
PlejdCharacteristics["Auth"] = "
|
22
|
-
PlejdCharacteristics["Ping"] = "
|
11
|
+
PlejdCharacteristics["Service"] = "1ba000160854726be45040c957391b5";
|
12
|
+
PlejdCharacteristics["LightLevel"] = "1ba000360854726be45040c957391b5";
|
13
|
+
PlejdCharacteristics["Data"] = "1ba000460854726be45040c957391b5";
|
14
|
+
PlejdCharacteristics["LastData"] = "1ba000560854726be45040c957391b5";
|
15
|
+
PlejdCharacteristics["Auth"] = "1ba000960854726be45040c957391b5";
|
16
|
+
PlejdCharacteristics["Ping"] = "1ba000a60854726be45040c957391b5";
|
23
17
|
})(PlejdCharacteristics || (PlejdCharacteristics = {}));
|
24
18
|
var PlejdCommand;
|
25
19
|
(function (PlejdCommand) {
|
26
|
-
PlejdCommand["UpdateState"] = "
|
27
|
-
PlejdCommand["StateBrightness"] = "
|
28
|
-
PlejdCommand["Brightness"] = "
|
29
|
-
PlejdCommand["Time"] = "
|
30
|
-
PlejdCommand["Scene"] = "
|
31
|
-
PlejdCommand["RequestResponse"] = "
|
32
|
-
PlejdCommand["RequestNoResponse"] = "
|
33
|
-
PlejdCommand["RequestReadValue"] = "
|
34
|
-
PlejdCommand["ButtonClick"] = "
|
20
|
+
PlejdCommand["UpdateState"] = "097";
|
21
|
+
PlejdCommand["StateBrightness"] = "0c8";
|
22
|
+
PlejdCommand["Brightness"] = "098";
|
23
|
+
PlejdCommand["Time"] = "01b";
|
24
|
+
PlejdCommand["Scene"] = "021";
|
25
|
+
PlejdCommand["RequestResponse"] = "102";
|
26
|
+
PlejdCommand["RequestNoResponse"] = "110";
|
27
|
+
PlejdCommand["RequestReadValue"] = "103";
|
28
|
+
PlejdCommand["ButtonClick"] = "006";
|
35
29
|
})(PlejdCommand || (PlejdCommand = {}));
|
36
|
-
class PlejdService {
|
30
|
+
export class PlejdService {
|
31
|
+
config;
|
32
|
+
log;
|
33
|
+
onUpdate;
|
34
|
+
connectedPeripheral;
|
35
|
+
addressBuffer;
|
36
|
+
dataCharacteristic;
|
37
|
+
pingTimer;
|
38
|
+
queueTimer;
|
39
|
+
sendQueue;
|
37
40
|
constructor(config, log, onUpdate) {
|
38
41
|
this.config = config;
|
39
42
|
this.log = log;
|
40
43
|
this.onUpdate = onUpdate;
|
41
|
-
|
42
|
-
this.
|
43
|
-
|
44
|
-
|
44
|
+
this.addressBuffer = null;
|
45
|
+
this.dataCharacteristic = null;
|
46
|
+
this.connectedPeripheral = null;
|
47
|
+
this.sendQueue = [];
|
48
|
+
noble.on("stateChange", (state) => this.stateChange(state));
|
49
|
+
noble.on("warning", (msg) => {
|
50
|
+
this.log.debug("Noble warning: ", msg);
|
51
|
+
});
|
52
|
+
}
|
53
|
+
/// Brightness should be between 1-100
|
54
|
+
updateState = (identifier, isOn, brightness) => {
|
55
|
+
if (!this.dataCharacteristic || !this.addressBuffer) {
|
56
|
+
this.log.warn(`UpdateState | characteristic (${this.dataCharacteristic}) or address (${this.addressBuffer}) not found`);
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
const dimming = brightness !== null;
|
60
|
+
const command = isOn && dimming ? PlejdCommand.Brightness : PlejdCommand.UpdateState;
|
61
|
+
const on = isOn ? "01" : "00";
|
62
|
+
let payload = Buffer.from(identifier.toString(16).padStart(2, "0") +
|
63
|
+
PlejdCommand.RequestNoResponse +
|
64
|
+
command +
|
65
|
+
on, "hex");
|
66
|
+
if (dimming) {
|
67
|
+
const dim = Math.round(2.55 * brightness); // Convert to Plejd 0-255
|
68
|
+
this.log.debug(`Dim value sent over BLE ${dim}`);
|
69
|
+
payload = Buffer.concat([
|
70
|
+
payload,
|
71
|
+
Buffer.from(dim.toString(16).padStart(4, "0"), "hex"),
|
72
|
+
]);
|
73
|
+
}
|
74
|
+
this.log.debug("UpdateState:", this.config.cryptoKey, this.addressBuffer, payload);
|
75
|
+
const data = plejdEncodeDecode(this.config.cryptoKey, this.addressBuffer, payload);
|
76
|
+
this.sendQueue.push(data);
|
77
|
+
};
|
78
|
+
// -------------- Private -------------- \\
|
79
|
+
stateChange = (state) => {
|
80
|
+
if (state !== NOBLE_IS_POWER_ON) {
|
81
|
+
this.log.debug("stateChange | Stopped | " + state);
|
82
|
+
noble.stopScanning();
|
83
|
+
}
|
84
|
+
this.log.debug("stateChange | Started | " + state);
|
85
|
+
this.startConnection();
|
86
|
+
};
|
87
|
+
startConnection = () => {
|
88
|
+
if (this.connectedPeripheral === null || noble._state !== "poweredOn") {
|
89
|
+
noble.startScanning([PlejdCharacteristics.Service], false, (e) => {
|
90
|
+
if (e) {
|
91
|
+
this.log.error("Unable to start scanning", e);
|
92
|
+
}
|
93
|
+
});
|
94
|
+
noble.once("discover", (peripheral) => this.discover(peripheral));
|
95
|
+
}
|
96
|
+
else {
|
97
|
+
this.connectedPeripheral?.cancelConnect();
|
98
|
+
this.connectedPeripheral.connect((e) => {
|
99
|
+
this.log.error("Unable to reconnect", e);
|
100
|
+
});
|
101
|
+
}
|
102
|
+
};
|
103
|
+
discover = (peripheral) => {
|
104
|
+
noble.stopScanning();
|
105
|
+
this.log.info(`Discovered | ${peripheral.advertisement.localName} | addr: ${peripheral.address} | RSSI: ${peripheral.rssi} dB`);
|
106
|
+
peripheral.connect((error) => {
|
107
|
+
if (error) {
|
108
|
+
this.log.error(`Connecting failed | ${peripheral.advertisement.localName} | addr: ${peripheral.address}) - err: ${error}`);
|
109
|
+
this.startConnection();
|
45
110
|
return;
|
46
111
|
}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
// -------------- Private -------------- \\
|
67
|
-
this.stateChange = (state) => {
|
68
|
-
if (state !== NOBLE_IS_POWER_ON) {
|
69
|
-
this.log.debug('stateChange | Stopped | ' + state);
|
70
|
-
noble_1.default.stopScanning();
|
71
|
-
}
|
72
|
-
this.log.debug('stateChange | Started | ' + state);
|
73
|
-
this.startConnection();
|
74
|
-
};
|
75
|
-
this.startConnection = () => {
|
76
|
-
var _a;
|
77
|
-
if (this.connectedPeripheral === null || noble_1.default.state === 'disconnected') {
|
78
|
-
noble_1.default.startScanning([PlejdCharacteristics.Service], false, (e) => {
|
79
|
-
if (e) {
|
80
|
-
this.log.error('Unable to start scanning', e);
|
81
|
-
}
|
82
|
-
});
|
83
|
-
noble_1.default.once('discover', (peripheral) => this.discover(peripheral));
|
84
|
-
}
|
85
|
-
else {
|
86
|
-
(_a = this.connectedPeripheral) === null || _a === void 0 ? void 0 : _a.cancelConnect();
|
87
|
-
this.connectedPeripheral.connect((e) => {
|
88
|
-
this.log.error('Unable to reconnect', e);
|
89
|
-
});
|
112
|
+
this.connectToPeripheral(peripheral);
|
113
|
+
});
|
114
|
+
};
|
115
|
+
connectToPeripheral = (peripheral) => {
|
116
|
+
const addr = peripheral.address;
|
117
|
+
this.log.info(`Connected | ${peripheral.advertisement.localName} (addr: ${addr})`);
|
118
|
+
this.connectedPeripheral = peripheral;
|
119
|
+
this.addressBuffer = reverseBuffer(Buffer.from(String(addr).replace(/:/g, ""), "hex"));
|
120
|
+
const services = [PlejdCharacteristics.Service];
|
121
|
+
const characteristics = [
|
122
|
+
PlejdCharacteristics.Data,
|
123
|
+
PlejdCharacteristics.LastData,
|
124
|
+
PlejdCharacteristics.Auth,
|
125
|
+
PlejdCharacteristics.Ping,
|
126
|
+
];
|
127
|
+
peripheral.discoverSomeServicesAndCharacteristics(services, characteristics, (error, services, characteristics) => {
|
128
|
+
if (error) {
|
129
|
+
this.log.error(`Discover failed | ${peripheral.advertisement.localName} (${peripheral.address}) | ${error}`);
|
130
|
+
return;
|
90
131
|
}
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
this.log.info(
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
this.
|
109
|
-
|
110
|
-
|
111
|
-
PlejdCharacteristics.Data,
|
112
|
-
PlejdCharacteristics.LastData,
|
113
|
-
PlejdCharacteristics.Auth,
|
114
|
-
PlejdCharacteristics.Ping,
|
115
|
-
];
|
116
|
-
peripheral.discoverSomeServicesAndCharacteristics(services, characteristics, (error, services, characteristics) => {
|
132
|
+
this.discovered(peripheral, services, characteristics);
|
133
|
+
});
|
134
|
+
peripheral.once("disconnect", () => {
|
135
|
+
this.log.info("Peripheral disconnected");
|
136
|
+
});
|
137
|
+
};
|
138
|
+
discovered = (peripheral, services, characteristics) => {
|
139
|
+
const authChar = characteristics.find((char) => char.uuid === PlejdCharacteristics.Auth);
|
140
|
+
const lastDataChar = characteristics.find((char) => char.uuid === PlejdCharacteristics.LastData);
|
141
|
+
const pingChar = characteristics.find((char) => char.uuid === PlejdCharacteristics.Ping);
|
142
|
+
this.dataCharacteristic =
|
143
|
+
peripheral?.services[0]?.characteristics?.find((char) => char.uuid === PlejdCharacteristics.Data) ?? null;
|
144
|
+
if (!authChar || !lastDataChar || !pingChar) {
|
145
|
+
this.log.error("Unable to extract characteristic during discovery", authChar, lastDataChar, pingChar);
|
146
|
+
return;
|
147
|
+
}
|
148
|
+
this.plejdAuth(authChar, () => {
|
149
|
+
this.startPlejdPing(pingChar);
|
150
|
+
this.startPlejdQueue();
|
151
|
+
lastDataChar.subscribe((error) => {
|
117
152
|
if (error) {
|
118
|
-
this.log.error(
|
153
|
+
this.log.error("Error subscribing | " + error);
|
119
154
|
return;
|
120
155
|
}
|
121
|
-
|
156
|
+
lastDataChar.on("data", (data, isNotification) => this.gotData(data, isNotification));
|
122
157
|
});
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
const authChar = characteristics.find((char) => char.uuid === PlejdCharacteristics.Auth);
|
130
|
-
const lastDataChar = characteristics.find((char) => char.uuid === PlejdCharacteristics.LastData);
|
131
|
-
const pingChar = characteristics.find((char) => char.uuid === PlejdCharacteristics.Ping);
|
132
|
-
this.dataCharacteristic =
|
133
|
-
(_c = (_b = (_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.services[0]) === null || _a === void 0 ? void 0 : _a.characteristics) === null || _b === void 0 ? void 0 : _b.find((char) => char.uuid === PlejdCharacteristics.Data)) !== null && _c !== void 0 ? _c : null;
|
134
|
-
if (!authChar || !lastDataChar || !pingChar) {
|
135
|
-
this.log.error('Unable to extract characteristic during discovery', authChar, lastDataChar, pingChar);
|
158
|
+
});
|
159
|
+
};
|
160
|
+
plejdAuth = (authChar, callback) => {
|
161
|
+
authChar.write(Buffer.from([0x00]), false, (error) => {
|
162
|
+
if (error) {
|
163
|
+
this.log.error("Error writing auth start | " + error);
|
136
164
|
return;
|
137
165
|
}
|
138
|
-
|
139
|
-
this.startPlejdPing(pingChar);
|
140
|
-
this.startPlejdQueue();
|
141
|
-
lastDataChar.subscribe((error) => {
|
142
|
-
if (error) {
|
143
|
-
this.log.error('Error subscribing | ' + error);
|
144
|
-
return;
|
145
|
-
}
|
146
|
-
lastDataChar.on('data', (data, isNotification) => this.gotData(data, isNotification));
|
147
|
-
});
|
148
|
-
});
|
149
|
-
};
|
150
|
-
this.plejdAuth = (authChar, callback) => {
|
151
|
-
authChar.write(Buffer.from([0x00]), false, (error) => {
|
166
|
+
authChar.read((error, data) => {
|
152
167
|
if (error) {
|
153
|
-
this.log.error(
|
168
|
+
this.log.error("Error reading auth | " + error);
|
154
169
|
return;
|
155
170
|
}
|
156
|
-
authChar.
|
171
|
+
authChar.write(plejdCharResp(this.config.cryptoKey, data), false, (error) => {
|
157
172
|
if (error) {
|
158
|
-
this.log.error(
|
173
|
+
this.log.error("Error writing auth char | " + error);
|
159
174
|
return;
|
160
175
|
}
|
161
|
-
|
162
|
-
if (error) {
|
163
|
-
this.log.error('Error writing auth char | ' + error);
|
164
|
-
return;
|
165
|
-
}
|
166
|
-
callback();
|
167
|
-
});
|
176
|
+
callback();
|
168
177
|
});
|
169
178
|
});
|
170
|
-
};
|
171
|
-
|
179
|
+
});
|
180
|
+
};
|
181
|
+
startPlejdQueue = () => {
|
182
|
+
if (this.queueTimer) {
|
172
183
|
clearInterval(this.queueTimer);
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
184
|
+
}
|
185
|
+
this.queueTimer = setTimeout(() => this.writePlejdQueueItems(), PLEJD_WRITE_TIMEOUT);
|
186
|
+
};
|
187
|
+
writePlejdQueueItems = () => {
|
188
|
+
const data = this.sendQueue.pop();
|
189
|
+
if (this.dataCharacteristic && data) {
|
190
|
+
this.plejdWrite(this.dataCharacteristic, data);
|
191
|
+
this.queueTimer = setTimeout(() => this.startPlejdQueue(), PLEJD_WRITE_TIMEOUT / 2);
|
192
|
+
}
|
193
|
+
else {
|
194
|
+
this.queueTimer = setTimeout(() => this.startPlejdQueue(), PLEJD_WRITE_TIMEOUT);
|
195
|
+
}
|
196
|
+
};
|
197
|
+
startPlejdPing = (pingChar) => {
|
198
|
+
if (this.pingTimer) {
|
199
|
+
clearInterval(this.pingTimer);
|
200
|
+
}
|
201
|
+
this.pingTimer = setInterval(() => {
|
202
|
+
if (this.connectedPeripheral) {
|
203
|
+
this.plejdPing(pingChar, (pingOk) => {
|
204
|
+
if (!pingOk) {
|
205
|
+
this.disconnect(() => {
|
206
|
+
this.startConnection();
|
207
|
+
});
|
208
|
+
}
|
209
|
+
});
|
180
210
|
}
|
181
|
-
|
182
|
-
|
211
|
+
}, 1000 * 60 * 3);
|
212
|
+
};
|
213
|
+
plejdPing = (pingChar, callback) => {
|
214
|
+
const ping = randomBytes(1);
|
215
|
+
pingChar.write(ping, false, (error) => {
|
216
|
+
if (error) {
|
217
|
+
this.log.error("Error sending ping | " + error);
|
218
|
+
return callback(false);
|
183
219
|
}
|
184
|
-
|
185
|
-
this.startPlejdPing = (pingChar) => {
|
186
|
-
clearInterval(this.pingTimer);
|
187
|
-
this.pingTimer = setInterval(() => {
|
188
|
-
if (this.connectedPeripheral) {
|
189
|
-
this.plejdPing(pingChar, (pingOk) => {
|
190
|
-
if (!pingOk) {
|
191
|
-
this.disconnect(() => {
|
192
|
-
this.startConnection();
|
193
|
-
});
|
194
|
-
}
|
195
|
-
});
|
196
|
-
}
|
197
|
-
}, 1000 * 60 * 3);
|
198
|
-
};
|
199
|
-
this.plejdPing = (pingChar, callback) => {
|
200
|
-
const ping = (0, crypto_1.randomBytes)(1);
|
201
|
-
pingChar.write(ping, false, (error) => {
|
220
|
+
pingChar.read((error, pong) => {
|
202
221
|
if (error) {
|
203
|
-
this.log.error(
|
222
|
+
this.log.error("Error reading pong | " + error);
|
204
223
|
return callback(false);
|
205
224
|
}
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
}
|
215
|
-
else {
|
216
|
-
this.log.debug(`Ping success: ${ping[0]} ${pong[0]}`);
|
217
|
-
callback(true);
|
218
|
-
}
|
219
|
-
});
|
225
|
+
if (((ping[0] + 1) & 0xff) !== pong[0]) {
|
226
|
+
this.log.error(`Ping failed: ${ping[0]} ${pong[0]}`);
|
227
|
+
callback(false);
|
228
|
+
}
|
229
|
+
else {
|
230
|
+
this.log.debug(`Ping success: ${ping[0]} ${pong[0]}`);
|
231
|
+
callback(true);
|
232
|
+
}
|
220
233
|
});
|
234
|
+
});
|
235
|
+
};
|
236
|
+
disconnect = (callback) => {
|
237
|
+
if (!this.pingTimer) {
|
238
|
+
return;
|
239
|
+
}
|
240
|
+
clearInterval(this.pingTimer);
|
241
|
+
if (this.connectedPeripheral) {
|
242
|
+
this.log.info("Disconnecting peripheral");
|
243
|
+
this.connectedPeripheral.disconnect();
|
244
|
+
}
|
245
|
+
if (callback) {
|
246
|
+
callback();
|
247
|
+
}
|
248
|
+
};
|
249
|
+
gotData = (data, isNotification) => {
|
250
|
+
if (!this.addressBuffer || this.addressBuffer?.byteLength === 0) {
|
251
|
+
return;
|
252
|
+
}
|
253
|
+
this.log.debug("GotData:", this.config.cryptoKey, this.addressBuffer, data);
|
254
|
+
const decodedData = plejdEncodeDecode(this.config.cryptoKey, this.addressBuffer, data);
|
255
|
+
const id = parseInt(decodedData[0].toString(), 10);
|
256
|
+
const command = decodedData.toString("hex", 3, 5);
|
257
|
+
const isOn = parseInt(decodedData.toString("hex", 5, 6), 10) === 1;
|
258
|
+
const commandType = Object.values(PlejdCommand).find((x) => x.toString() === command) ??
|
259
|
+
"Unknown";
|
260
|
+
const d = {
|
261
|
+
id: id,
|
262
|
+
command: command,
|
263
|
+
commandType: commandType,
|
264
|
+
on: isOn,
|
265
|
+
Notification: isNotification,
|
266
|
+
payload: decodedData.toString("hex"),
|
221
267
|
};
|
222
|
-
this.
|
223
|
-
|
224
|
-
|
268
|
+
this.log.debug("GotData", d);
|
269
|
+
switch (command) {
|
270
|
+
case PlejdCommand.Time: {
|
271
|
+
const arg = parseInt(reverseBuffer(decodedData.subarray(5, 9)).toString("hex"), 16);
|
272
|
+
const date = new Date(arg * 1000);
|
273
|
+
this.log.debug("Time sync: " + date.toString());
|
274
|
+
break;
|
225
275
|
}
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
276
|
+
case PlejdCommand.Brightness:
|
277
|
+
case PlejdCommand.StateBrightness: {
|
278
|
+
const dim = parseInt(decodedData.toString("hex", 7, 8), 16);
|
279
|
+
// Convert to Homebridge 1-100
|
280
|
+
const converted = dim === 0 ? 1 : (100 / 255) * dim;
|
281
|
+
this.onUpdate(id, isOn, converted);
|
282
|
+
break;
|
230
283
|
}
|
231
|
-
|
232
|
-
|
284
|
+
case PlejdCommand.Scene:
|
285
|
+
case PlejdCommand.UpdateState:
|
286
|
+
case PlejdCommand.ButtonClick:
|
287
|
+
case PlejdCommand.RequestResponse:
|
288
|
+
case PlejdCommand.RequestNoResponse:
|
289
|
+
case PlejdCommand.RequestReadValue: {
|
290
|
+
this.onUpdate(id, isOn);
|
291
|
+
break;
|
233
292
|
}
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
if (!this.addressBuffer || ((_a = this.addressBuffer) === null || _a === void 0 ? void 0 : _a.byteLength) === 0) {
|
238
|
-
return;
|
293
|
+
default: {
|
294
|
+
this.onUpdate(id, isOn);
|
295
|
+
this.log.debug(`Unknown | command: ${command} | id: ${id} | ${decodedData.toString("hex")}`);
|
239
296
|
}
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
id: id,
|
248
|
-
command: command,
|
249
|
-
commandType: commandType,
|
250
|
-
on: isOn,
|
251
|
-
Notification: isNotification,
|
252
|
-
payload: decodedData.toString('hex'),
|
253
|
-
};
|
254
|
-
this.log.debug('GotData', d);
|
255
|
-
switch (command) {
|
256
|
-
case PlejdCommand.Time: {
|
257
|
-
const arg = parseInt((0, plejdUtils_1.reverseBuffer)(decodedData.subarray(5, 9)).toString('hex'), 16);
|
258
|
-
const date = new Date(arg * 1000);
|
259
|
-
this.log.debug('Time sync: ' + date.toString());
|
260
|
-
break;
|
261
|
-
}
|
262
|
-
case PlejdCommand.Brightness:
|
263
|
-
case PlejdCommand.StateBrightness: {
|
264
|
-
const dim = parseInt(decodedData.toString('hex', 7, 8), 16);
|
265
|
-
// Convert to Homebridge 1-100
|
266
|
-
const converted = dim === 0 ? 1 : (100 / 255) * dim;
|
267
|
-
this.onUpdate(id, isOn, converted);
|
268
|
-
break;
|
269
|
-
}
|
270
|
-
case PlejdCommand.Scene:
|
271
|
-
case PlejdCommand.UpdateState:
|
272
|
-
case PlejdCommand.ButtonClick:
|
273
|
-
case PlejdCommand.RequestResponse:
|
274
|
-
case PlejdCommand.RequestNoResponse:
|
275
|
-
case PlejdCommand.RequestReadValue: {
|
276
|
-
this.onUpdate(id, isOn);
|
277
|
-
break;
|
278
|
-
}
|
279
|
-
default: {
|
280
|
-
this.onUpdate(id, isOn);
|
281
|
-
this.log.debug(`Unknown | command: ${command} | id: ${id} | ${decodedData.toString('hex')}`);
|
282
|
-
}
|
297
|
+
}
|
298
|
+
};
|
299
|
+
plejdWrite = (dataChar, data) => {
|
300
|
+
dataChar.write(data, false, (error) => {
|
301
|
+
if (error) {
|
302
|
+
this.log.error("Error writing data | " + error);
|
303
|
+
return;
|
283
304
|
}
|
284
|
-
};
|
285
|
-
this.plejdWrite = (dataChar, data) => {
|
286
|
-
dataChar.write(data, false, (error) => {
|
287
|
-
if (error) {
|
288
|
-
this.log.error('Error writing data | ' + error);
|
289
|
-
return;
|
290
|
-
}
|
291
|
-
});
|
292
|
-
};
|
293
|
-
this.addressBuffer = null;
|
294
|
-
this.dataCharacteristic = null;
|
295
|
-
this.connectedPeripheral = null;
|
296
|
-
this.sendQueue = [];
|
297
|
-
noble_1.default.on('stateChange', (state) => this.stateChange(state));
|
298
|
-
noble_1.default.on('warning', (msg) => {
|
299
|
-
this.log.debug('Noble warning: ', msg);
|
300
305
|
});
|
301
|
-
}
|
306
|
+
};
|
302
307
|
}
|
303
|
-
exports.PlejdService = PlejdService;
|
304
308
|
//# sourceMappingURL=plejdService.js.map
|