homebridge-cync-app 0.0.2 → 0.1.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.
@@ -1,7 +1,6 @@
1
1
  // src/cync/tcp-client.ts
2
- // Thin TCP client stub for talking to Cync WiFi devices.
3
- // The binary protocol is non-trivial; for now this class only logs calls so
4
- // that higher layers can be wired up and tested without crashing.
2
+ import net from 'net';
3
+ import tls from 'tls';
5
4
  const defaultLogger = {
6
5
  debug: (...args) => console.debug('[cync-tcp]', ...args),
7
6
  info: (...args) => console.info('[cync-tcp]', ...args),
@@ -9,30 +8,254 @@ const defaultLogger = {
9
8
  error: (...args) => console.error('[cync-tcp]', ...args),
10
9
  };
11
10
  export class TcpClient {
11
+ registerSwitchMapping(controllerId, deviceId) {
12
+ if (!Number.isFinite(controllerId)) {
13
+ return;
14
+ }
15
+ this.controllerToDevice.set(controllerId, deviceId);
16
+ }
17
+ homeDevices = {};
18
+ switchIdToHomeId = new Map();
12
19
  log;
20
+ loginCode = null;
21
+ config = null;
22
+ meshSockets = new Map();
13
23
  deviceUpdateCb = null;
14
24
  roomUpdateCb = null;
15
25
  motionUpdateCb = null;
16
26
  ambientUpdateCb = null;
27
+ socket = null;
28
+ seq = 0;
29
+ readBuffer = Buffer.alloc(0);
30
+ heartbeatTimer = null;
31
+ rawFrameListeners = [];
32
+ controllerToDevice = new Map();
33
+ parseSwitchStateFrame(frame) {
34
+ if (frame.length < 16) {
35
+ return null;
36
+ }
37
+ // First 4 bytes are the controller ID (big-endian)
38
+ const controllerId = frame.readUInt32BE(0);
39
+ // Look for the marker sequence db 11 02 01
40
+ const marker = Buffer.from('db110201', 'hex');
41
+ const idx = frame.indexOf(marker);
42
+ if (idx === -1) {
43
+ return null;
44
+ }
45
+ // We need at least two bytes following the marker: onFlag + level
46
+ const onIndex = idx + marker.length;
47
+ const levelIndex = onIndex + 1;
48
+ if (levelIndex >= frame.length) {
49
+ return null;
50
+ }
51
+ const onFlag = frame[onIndex];
52
+ const level = frame[levelIndex];
53
+ const on = onFlag === 0x01 && level > 0;
54
+ return { controllerId, on, level };
55
+ }
56
+ parseLanSwitchUpdate(frame) {
57
+ // Need at least enough bytes for the HA layout:
58
+ // switch_id(4) ... type(1) ... deviceIndex(1) ... state(1) ... brightness(1)
59
+ if (frame.length < 29) {
60
+ return null;
61
+ }
62
+ const controllerId = frame.readUInt32BE(0);
63
+ const homeId = this.switchIdToHomeId.get(controllerId);
64
+ if (!homeId) {
65
+ return null;
66
+ }
67
+ const devices = this.homeDevices[homeId];
68
+ if (!devices || devices.length === 0) {
69
+ return null;
70
+ }
71
+ // HA checks: packet_length >= 33 and packet[13] == 219 (0xdb)
72
+ const typeByte = frame[13];
73
+ if (typeByte !== 0xdb) {
74
+ return null;
75
+ }
76
+ const deviceIndex = frame[21];
77
+ const stateByte = frame[27];
78
+ const levelByte = frame[28];
79
+ const on = stateByte > 0;
80
+ const level = on ? levelByte : 0;
81
+ const deviceId = deviceIndex < devices.length ? devices[deviceIndex] : undefined;
82
+ return {
83
+ controllerId,
84
+ deviceId,
85
+ on,
86
+ level,
87
+ };
88
+ }
17
89
  constructor(logger) {
18
90
  this.log = logger ?? defaultLogger;
19
91
  }
20
92
  /**
21
93
  * Establish a TCP session to one or more Cync devices.
22
94
  *
23
- * In the full implementation, loginCode will be the authentication blob used
24
- * by the LAN devices, and config will contain the mesh/network information
25
- * needed to discover and connect to the correct hosts.
26
- *
27
- * For now this is a no-op that simply logs the request.
95
+ * For Homebridge:
96
+ * - We cache loginCode + config here.
97
+ * - Actual socket creation happens in ensureConnected()/establishSocket().
28
98
  */
29
99
  async connect(loginCode, config) {
30
- this.log.info('TcpClient.connect() stub called with loginCode length=%d meshes=%d', loginCode.length, config.meshes.length);
100
+ this.loginCode = loginCode;
101
+ this.config = config;
102
+ if (!loginCode.length) {
103
+ this.log.warn('[Cync TCP] connect() called with empty loginCode; LAN control will remain disabled.');
104
+ return;
105
+ }
106
+ // Optional eager connect at startup; failures are logged and we rely
107
+ // on ensureConnected() to reconnect on demand later.
108
+ await this.ensureConnected();
109
+ }
110
+ applyLanTopology(topology) {
111
+ this.homeDevices = topology.homeDevices ?? {};
112
+ this.switchIdToHomeId = new Map();
113
+ for (const [key, homeId] of Object.entries(topology.switchIdToHomeId ?? {})) {
114
+ const num = Number(key);
115
+ if (Number.isFinite(num)) {
116
+ this.switchIdToHomeId.set(num, homeId);
117
+ }
118
+ }
119
+ this.log.info('[Cync TCP] LAN topology applied: homes=%d controllers=%d', Object.keys(this.homeDevices).length, this.switchIdToHomeId.size);
120
+ }
121
+ /**
122
+ * Ensure we have an open, logged-in socket.
123
+ * If the socket is closed or missing, attempt to reconnect.
124
+ */
125
+ async ensureConnected() {
126
+ if (this.socket && !this.socket.destroyed) {
127
+ return true;
128
+ }
129
+ if (!this.loginCode || !this.loginCode.length || !this.config) {
130
+ this.log.warn('[Cync TCP] ensureConnected() called without loginCode/config; cannot open socket.');
131
+ return false;
132
+ }
133
+ await this.establishSocket();
134
+ return !!(this.socket && !this.socket.destroyed);
135
+ }
136
+ /**
137
+ * Open a new socket to cm.gelighting.com and send the loginCode,
138
+ * mirroring the HA integration’s behavior.
139
+ */
140
+ async establishSocket() {
141
+ const host = 'cm.gelighting.com';
142
+ const portTLS = 23779;
143
+ const portTCP = 23778;
144
+ this.log.info('[Cync TCP] Connecting to %s…', host);
145
+ let socket = null;
146
+ try {
147
+ // 1. Try strict TLS
148
+ try {
149
+ socket = await this.openTlsSocket(host, portTLS, true);
150
+ }
151
+ catch (e1) {
152
+ this.log.warn('[Cync TCP] TLS strict failed, trying relaxed TLS…');
153
+ try {
154
+ socket = await this.openTlsSocket(host, portTLS, false);
155
+ }
156
+ catch (e2) {
157
+ this.log.warn('[Cync TCP] TLS relaxed failed, falling back to plain TCP…');
158
+ socket = await this.openTcpSocket(host, portTCP);
159
+ }
160
+ }
161
+ }
162
+ catch (err) {
163
+ this.log.error('[Cync TCP] Failed to connect to %s: %s', host, String(err));
164
+ this.socket = null;
165
+ return;
166
+ }
167
+ if (!socket) {
168
+ this.log.error('[Cync TCP] Socket is null after connect attempts.');
169
+ this.socket = null;
170
+ return;
171
+ }
172
+ this.socket = socket;
173
+ this.attachSocketListeners(this.socket);
174
+ // Send loginCode immediately, as HA does.
175
+ if (this.loginCode && this.loginCode.length > 0) {
176
+ this.socket.write(Buffer.from(this.loginCode));
177
+ this.log.info('[Cync TCP] Login code sent (%d bytes).', this.loginCode.length);
178
+ }
179
+ else {
180
+ this.log.warn('[Cync TCP] establishSocket() reached with no loginCode; skipping auth write.');
181
+ }
182
+ // Start heartbeat: every 180 seconds send d3 00 00 00 00
183
+ this.startHeartbeat();
184
+ }
185
+ openTlsSocket(host, port, strict) {
186
+ return new Promise((resolve, reject) => {
187
+ const sock = tls.connect({
188
+ host,
189
+ port,
190
+ rejectUnauthorized: strict,
191
+ }, () => resolve(sock));
192
+ sock.once('error', reject);
193
+ });
194
+ }
195
+ openTcpSocket(host, port) {
196
+ return new Promise((resolve, reject) => {
197
+ const sock = net.createConnection({ host, port }, () => resolve(sock));
198
+ sock.once('error', reject);
199
+ });
200
+ }
201
+ startHeartbeat() {
202
+ if (this.heartbeatTimer) {
203
+ clearInterval(this.heartbeatTimer);
204
+ }
205
+ this.heartbeatTimer = setInterval(() => {
206
+ if (!this.socket || this.socket.destroyed) {
207
+ return;
208
+ }
209
+ this.socket.write(Buffer.from('d300000000', 'hex'));
210
+ }, 180_000);
211
+ }
212
+ nextSeq() {
213
+ if (this.seq === 65535) {
214
+ this.seq = 1;
215
+ }
216
+ else {
217
+ this.seq++;
218
+ }
219
+ return this.seq;
220
+ }
221
+ buildPowerPacket(controllerId, meshId, on, seq) {
222
+ const header = Buffer.from('730000001f', 'hex');
223
+ const switchBytes = Buffer.alloc(4);
224
+ switchBytes.writeUInt32BE(controllerId, 0);
225
+ const seqBytes = Buffer.alloc(2);
226
+ seqBytes.writeUInt16BE(seq, 0);
227
+ const middle = Buffer.from('007e00000000f8d00d000000000000', 'hex');
228
+ const meshBytes = Buffer.alloc(2);
229
+ meshBytes.writeUInt16LE(meshId, 0);
230
+ const tail = Buffer.from(on ? 'd00000010000' : 'd00000000000', 'hex');
231
+ const checksumSeed = on ? 430 : 429;
232
+ const checksumByte = (checksumSeed + meshBytes[0] + meshBytes[1]) & 0xff;
233
+ const checksum = Buffer.from([checksumByte]);
234
+ const end = Buffer.from('7e', 'hex');
235
+ return Buffer.concat([
236
+ header,
237
+ switchBytes,
238
+ seqBytes,
239
+ middle,
240
+ meshBytes,
241
+ tail,
242
+ checksum,
243
+ end,
244
+ ]);
31
245
  }
32
246
  async disconnect() {
33
- this.log.info('TcpClient.disconnect() stub called.');
247
+ this.log.info('[Cync TCP] disconnect() called.');
248
+ if (this.heartbeatTimer) {
249
+ clearInterval(this.heartbeatTimer);
250
+ this.heartbeatTimer = null;
251
+ }
252
+ if (this.socket) {
253
+ this.socket.destroy();
254
+ this.socket = null;
255
+ }
34
256
  }
35
257
  onDeviceUpdate(cb) {
258
+ this.log.info('[Cync TCP] device update subscriber registered.');
36
259
  this.deviceUpdateCb = cb;
37
260
  }
38
261
  onRoomUpdate(cb) {
@@ -44,16 +267,135 @@ export class TcpClient {
44
267
  onAmbientUpdate(cb) {
45
268
  this.ambientUpdateCb = cb;
46
269
  }
270
+ onRawFrame(listener) {
271
+ this.rawFrameListeners.push(listener);
272
+ }
47
273
  /**
48
- * High-level API to change switch state. The actual encoding and TCP send
49
- * will be filled in once the LAN protocol is implemented.
274
+ * High-level API to change switch state.
275
+ * Ensures we have a live socket before sending.
50
276
  */
51
277
  async setSwitchState(deviceId, params) {
52
- this.log.info('TcpClient.setSwitchState() stub: deviceId=%s params=%o', deviceId, params);
53
- // In a future implementation, this is where we would:
54
- // 1. Look up the device in the current CyncCloudConfig.
55
- // 2. Construct the appropriate binary payload.
56
- // 3. Send via a net.Socket and handle the response.
278
+ if (!this.config) {
279
+ this.log.warn('[Cync TCP] No config available.');
280
+ return;
281
+ }
282
+ const connected = await this.ensureConnected();
283
+ if (!connected || !this.socket || this.socket.destroyed) {
284
+ this.log.warn('[Cync TCP] Cannot send, socket not ready even after reconnect attempt.');
285
+ return;
286
+ }
287
+ const device = this.findDevice(deviceId);
288
+ if (!device) {
289
+ this.log.warn('[Cync TCP] Unknown deviceId=%s', deviceId);
290
+ return;
291
+ }
292
+ const controllerId = Number(device.switch_controller);
293
+ const meshIndex = Number(device.mesh_id);
294
+ if (!Number.isFinite(controllerId) || !Number.isFinite(meshIndex)) {
295
+ this.log.warn('[Cync TCP] Device %s is missing LAN fields (switch_controller=%o mesh_id=%o)', deviceId, device.switch_controller, device.mesh_id);
296
+ return;
297
+ }
298
+ const seq = this.nextSeq();
299
+ const packet = this.buildPowerPacket(controllerId, meshIndex, params.on, seq);
300
+ this.socket.write(packet);
301
+ this.log.info('[Cync TCP] Sent power packet: device=%s on=%s seq=%d', deviceId, String(params.on), seq);
302
+ }
303
+ findDevice(deviceId) {
304
+ for (const mesh of this.config?.meshes ?? []) {
305
+ for (const dev of mesh.devices ?? []) {
306
+ const record = dev;
307
+ const devDeviceId = record.device_id !== undefined && record.device_id !== null
308
+ ? String(record.device_id)
309
+ : undefined;
310
+ const devId = record.id !== undefined && record.id !== null
311
+ ? String(record.id)
312
+ : undefined;
313
+ if (devDeviceId === deviceId || devId === deviceId) {
314
+ return dev;
315
+ }
316
+ }
317
+ }
318
+ return null;
319
+ }
320
+ attachSocketListeners(socket) {
321
+ socket.on('data', (chunk) => {
322
+ this.log.debug('[Cync TCP] received %d bytes from server', chunk.byteLength);
323
+ this.readBuffer = Buffer.concat([this.readBuffer, chunk]);
324
+ this.processIncoming();
325
+ });
326
+ socket.on('close', () => {
327
+ this.log.warn('[Cync TCP] Socket closed.');
328
+ this.socket = null;
329
+ });
330
+ socket.on('error', (err) => {
331
+ this.log.error('[Cync TCP] Socket error:', String(err));
332
+ });
333
+ }
334
+ processIncoming() {
335
+ while (this.readBuffer.length >= 5) {
336
+ const type = this.readBuffer.readUInt8(0);
337
+ const len = this.readBuffer.readUInt32BE(1);
338
+ const total = 5 + len;
339
+ if (this.readBuffer.length < total) {
340
+ return;
341
+ }
342
+ const body = this.readBuffer.subarray(5, total);
343
+ // Debug log with full hex dump so we can reverse-engineer the protocol
344
+ this.log.debug('[Cync TCP] frame type=0x%s len=%d body=%s', type.toString(16).padStart(2, '0'), len, body.toString('hex'));
345
+ if (type === 0x7b && body.length >= 6) {
346
+ const seq = body.readUInt16BE(4);
347
+ this.log.debug('[Cync TCP] ACK for seq=%d', seq);
348
+ }
349
+ else {
350
+ this.handleIncomingFrame(body, type);
351
+ }
352
+ this.readBuffer = this.readBuffer.subarray(total);
353
+ }
354
+ }
355
+ async sendRawCommand(deviceId, command, params) {
356
+ if (!this.config || !this.loginCode) {
357
+ this.log.warn('TcpClient.sendRawCommand() called before connect(); deviceId=%s command=%s params=%o', deviceId, command, params);
358
+ return;
359
+ }
360
+ this.log.info('TcpClient.sendRawCommand() stub: deviceId=%s command=%s params=%o', deviceId, command, params);
361
+ }
362
+ // ### 🧩 Incoming Frame Handler: routes LAN messages to raw + parsed callbacks
363
+ handleIncomingFrame(frame, type) {
364
+ // Fan out raw frame to higher layers (CyncClient) for debugging
365
+ for (const listener of this.rawFrameListeners) {
366
+ try {
367
+ listener(frame);
368
+ }
369
+ catch (err) {
370
+ this.log.error('[Cync TCP] raw frame listener threw: %s', String(err));
371
+ }
372
+ }
373
+ // Default payload is the raw frame
374
+ let payload = frame;
375
+ if (type === 0x83) {
376
+ // Preferred path: HA-style per-device parsing using homeDevices + switchIdToHomeId
377
+ const lanParsed = this.parseLanSwitchUpdate(frame);
378
+ if (lanParsed) {
379
+ payload = lanParsed;
380
+ }
381
+ else {
382
+ // Fallback to legacy controller-level parsing
383
+ const parsed = this.parseSwitchStateFrame(frame);
384
+ if (parsed) {
385
+ const deviceId = this.controllerToDevice.get(parsed.controllerId);
386
+ payload = {
387
+ ...parsed,
388
+ deviceId,
389
+ };
390
+ }
391
+ }
392
+ }
393
+ if (this.deviceUpdateCb) {
394
+ this.deviceUpdateCb(payload);
395
+ }
396
+ else {
397
+ this.log.debug('[Cync TCP] Dropping device update frame (no subscriber).');
398
+ }
57
399
  }
58
400
  }
59
401
  //# sourceMappingURL=tcp-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tcp-client.js","sourceRoot":"","sources":["../../src/cync/tcp-client.ts"],"names":[],"mappings":"AAAA,yBAAyB;AACzB,yDAAyD;AACzD,4EAA4E;AAC5E,kEAAkE;AAIlE,MAAM,aAAa,GAAe;IACjC,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC;IACnE,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC;IACjE,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC;IACjE,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC;CACnE,CAAC;AAIF,MAAM,OAAO,SAAS;IACJ,GAAG,CAAa;IAEzB,cAAc,GAAgC,IAAI,CAAC;IACnD,YAAY,GAAgC,IAAI,CAAC;IACjD,cAAc,GAAgC,IAAI,CAAC;IACnD,eAAe,GAAgC,IAAI,CAAC;IAE5D,YAAY,MAAmB;QAC9B,IAAI,CAAC,GAAG,GAAG,MAAM,IAAI,aAAa,CAAC;IACpC,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,OAAO,CACnB,SAAqB,EACrB,MAAuB;QAEvB,IAAI,CAAC,GAAG,CAAC,IAAI,CACZ,oEAAoE,EACpE,SAAS,CAAC,MAAM,EAChB,MAAM,CAAC,MAAM,CAAC,MAAM,CACpB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;IACtD,CAAC;IAEM,cAAc,CAAC,EAAwB;QAC7C,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;IAC1B,CAAC;IAEM,YAAY,CAAC,EAAwB;QAC3C,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;IACxB,CAAC;IAEM,cAAc,CAAC,EAAwB;QAC7C,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;IAC1B,CAAC;IAEM,eAAe,CAAC,EAAwB;QAC9C,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,cAAc,CAC1B,QAAgB,EAChB,MAA+C;QAE/C,IAAI,CAAC,GAAG,CAAC,IAAI,CACZ,wDAAwD,EACxD,QAAQ,EACR,MAAM,CACN,CAAC;QAEF,sDAAsD;QACtD,wDAAwD;QACxD,+CAA+C;QAC/C,oDAAoD;IACrD,CAAC;CACD"}
1
+ {"version":3,"file":"tcp-client.js","sourceRoot":"","sources":["../../src/cync/tcp-client.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,8 @@ export interface CyncTokenData {
3
3
  accessToken: string;
4
4
  refreshToken?: string;
5
5
  expiresAt?: number;
6
+ authorize?: string;
7
+ lanLoginCode?: string;
6
8
  }
7
9
  /**
8
10
  * Simple JSON token store under the Homebridge storage path.
@@ -1 +1 @@
1
- {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/cync/token-store.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AASlC;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,QAAQ,CAAS;IAElC,YAAmB,WAAmB;QACrC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAC5D,CAAC;IAEM,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACrD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;YAE9C,wDAAwD;YACxD,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;gBACpD,OAAO,IAAI,CAAC;YACb,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,IAAmB;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAEM,KAAK,CAAC,KAAK;QACjB,IAAI,CAAC;YACJ,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACR,oBAAoB;QACrB,CAAC;IACF,CAAC;CACD"}
1
+ {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/cync/token-store.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAWlC;;GAEG;AACH,MAAM,OAAO,cAAc;IACT,QAAQ,CAAS;IAElC,YAAmB,WAAmB;QACrC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAC5D,CAAC;IAEM,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACrD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;YAE9C,wDAAwD;YACxD,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;gBACpD,OAAO,IAAI,CAAC;YACb,CAAC;YAED,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,IAAmB;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAEM,KAAK,CAAC,KAAK;QACjB,IAAI,CAAC;YACJ,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACR,oBAAoB;QACrB,CAAC;IACF,CAAC;CACD"}
@@ -13,7 +13,11 @@ export declare class CyncAppPlatform implements DynamicPlatformPlugin {
13
13
  private readonly api;
14
14
  private readonly config;
15
15
  private readonly client;
16
+ private readonly tcpClient;
16
17
  private cloudConfig;
18
+ private readonly deviceIdToAccessory;
19
+ private handleLanUpdate;
20
+ private configureCyncSwitchAccessory;
17
21
  constructor(log: Logger, config: PlatformConfig, api: API);
18
22
  /**
19
23
  * Called when cached accessories are restored from disk.
@@ -22,8 +26,7 @@ export declare class CyncAppPlatform implements DynamicPlatformPlugin {
22
26
  private loadCync;
23
27
  /**
24
28
  * Discover devices from the Cync cloud config and register them as
25
- * Homebridge accessories. For now, each device is exposed as a simple
26
- * dummy Switch that logs state changes.
29
+ * Homebridge accessories.
27
30
  */
28
31
  private discoverDevices;
29
32
  }