homebridge-cync-app 0.3.4 → 0.4.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.
- package/.github/ISSUE_TEMPLATE/unsupported-or-incorrectly-detected-cync-device.md +96 -0
- package/CHANGELOG.md +32 -0
- package/dist/cync/cync-fan-accessory.d.ts +4 -0
- package/dist/cync/cync-fan-accessory.js +96 -0
- package/dist/cync/cync-fan-accessory.js.map +1 -0
- package/dist/cync/device-classifier.d.ts +16 -0
- package/dist/cync/device-classifier.js +94 -0
- package/dist/cync/device-classifier.js.map +1 -0
- package/dist/platform.js +45 -32
- package/dist/platform.js.map +1 -1
- package/package.json +1 -1
- package/src/cync/cync-fan-accessory.ts +165 -0
- package/src/cync/device-classifier.ts +130 -0
- package/src/platform.ts +76 -36
- package/.github/ISSUE_TEMPLATE/add-support-for-a-new-cync-device.md +0 -142
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Unsupported or Incorrectly Detected Cync Device
|
|
3
|
+
about: Accessory is detected, but has the wrong type or missing features
|
|
4
|
+
title: 'Cync Device Issue: [MODEL]'
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: dash16
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!--Thank you for helping expand device support in **homebridge-cync-app**.
|
|
11
|
+
|
|
12
|
+
To improve compatibility for an incorrectly identified/unidentified Cync device, I need diagnostic information from your plugin installation and the Cync app.
|
|
13
|
+
|
|
14
|
+
Please replace the placeholders below with your information.
|
|
15
|
+
You can delete these instruction comments before submitting.
|
|
16
|
+
-->
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Device Information
|
|
20
|
+
|
|
21
|
+
**1.1 Product name as shown in the Cync app**
|
|
22
|
+
|
|
23
|
+
<!--e.g., “6" Recessed Can Retrofit Fixture (Matter)”, “Indoor Smart Plug (3-in-1)”, “Indoor Smart Plug”-->
|
|
24
|
+
```
|
|
25
|
+
<insert product name>
|
|
26
|
+
```
|
|
27
|
+
**1.2 Product page URL (GE/Cync or retailer)**
|
|
28
|
+
|
|
29
|
+
<!-- Paste a GE/Cync or retailer product link, if available. -->
|
|
30
|
+
```
|
|
31
|
+
<insert URL>
|
|
32
|
+
```
|
|
33
|
+
**1.3 What kind of device is this?**
|
|
34
|
+
|
|
35
|
+
<!-- Example: plug, dimmer, tunable white light, full color light, fan, switch, sensor, other. -->
|
|
36
|
+
```
|
|
37
|
+
<insert device type>
|
|
38
|
+
```
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Discovery Logs (Required)
|
|
42
|
+
|
|
43
|
+
<!--Please enable **Homebridge Debug Mode**, restart Homebridge, and paste the startup discovery logs for the affected device.
|
|
44
|
+
|
|
45
|
+
Look for lines like:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
[Cync] CyncClient: loading Cync cloud configuration…
|
|
49
|
+
[Cync] Fetching Cync devices from https://api.gelighting.com/...
|
|
50
|
+
[Cync] Cync devices payload: top-level array length=...
|
|
51
|
+
[Cync] CyncClient: probing properties for mesh ... (id=..., product_id=...)
|
|
52
|
+
[Cync] CyncClient: mesh ... properties keys=...
|
|
53
|
+
[Cync] CyncClient: mesh ... bulbsArray length=...
|
|
54
|
+
[Cync] CyncClient: bulb #... for mesh ... → {
|
|
55
|
+
displayName: ...
|
|
56
|
+
deviceID: ...
|
|
57
|
+
deviceType: ...
|
|
58
|
+
raw: { ... }
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Please include the full bulb #... block for the affected device.
|
|
63
|
+
You may redact Wi-Fi names, MAC addresses, and tokens.
|
|
64
|
+
-->
|
|
65
|
+
```
|
|
66
|
+
<insert logs>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 3. Screenshots from the **Cync App**
|
|
72
|
+
|
|
73
|
+
<!--Please attach screenshots **from the Cync mobile app (not Apple Home)** showing:
|
|
74
|
+
|
|
75
|
+
* The **device settings page**
|
|
76
|
+
* The **main control UI** (brightness / color / mode controls)
|
|
77
|
+
* Any **advanced settings** available
|
|
78
|
+
|
|
79
|
+
These help determine which capabilities the device supports.
|
|
80
|
+
-->
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 4. Anything Else?
|
|
84
|
+
|
|
85
|
+
<!--If the device behaves in an unusual way (multiple endpoints, segmented lights, unusual controls, etc.), please describe it here.
|
|
86
|
+
-->
|
|
87
|
+
```
|
|
88
|
+
<notes>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
<!--
|
|
94
|
+
Thank You!
|
|
95
|
+
Once you submit this, I’ll analyze the device capabilities, determine the correct HomeKit service type, and add support to the plugin.
|
|
96
|
+
-->
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# v0.4.0 — Capability Classifier & Fan Support
|
|
4
|
+
|
|
5
|
+
**Release Date:** 2026-05-27
|
|
6
|
+
|
|
7
|
+
## Added
|
|
8
|
+
- Added support for Cync fan switch devices (deviceType 81) using HomeKit `Fanv2`
|
|
9
|
+
- Added dedicated `cync-fan-accessory.ts` accessory handler
|
|
10
|
+
- Added centralized `device-classifier.ts` subsystem for accessory classification
|
|
11
|
+
- Added classification debug logging showing:
|
|
12
|
+
- device name
|
|
13
|
+
- device ID
|
|
14
|
+
- resolved device type
|
|
15
|
+
- detected capabilities
|
|
16
|
+
- selected accessory type
|
|
17
|
+
- classification reason
|
|
18
|
+
- Added unsupported device fallback logging to improve future device onboarding
|
|
19
|
+
|
|
20
|
+
## Changed
|
|
21
|
+
- Refactored accessory selection to use capability-aware classification instead of relying solely on static device type lists
|
|
22
|
+
- Improved separation of concerns by moving classification logic out of `platform.ts`
|
|
23
|
+
- Expanded known Cync device catalogs using data cross-referenced from the Home Assistant Cync integration
|
|
24
|
+
|
|
25
|
+
## Fixed
|
|
26
|
+
- Fixed fan switches incorrectly appearing as Lightbulb accessories in HomeKit
|
|
27
|
+
- Restored proper handling for several light and outlet device types after classifier integration
|
|
28
|
+
- Improved accessory fallback behavior for unknown or partially supported devices
|
|
29
|
+
|
|
30
|
+
## Developer Notes
|
|
31
|
+
- Classification decisions are now centralized in `src/cync/device-classifier.ts`
|
|
32
|
+
- Future device onboarding should require significantly less modification to `platform.ts`
|
|
33
|
+
- New debug logs should make community issue reports substantially easier to triage
|
|
34
|
+
|
|
3
35
|
## 0.3.4 — Composite Switch ID Crash Fix
|
|
4
36
|
|
|
5
37
|
**Release Date:** 2026-05-22
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
2
|
+
import type { CyncDevice, CyncDeviceMesh } from './config-client.js';
|
|
3
|
+
import type { CyncAccessoryEnv } from './cync-accessory-helpers.js';
|
|
4
|
+
export declare function configureCyncFanAccessory(env: CyncAccessoryEnv, mesh: CyncDeviceMesh, device: CyncDevice, accessory: PlatformAccessory, deviceName: string, deviceId: string): void;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { applyAccessoryInformationFromCyncDevice, resolveDeviceType, } from './cync-accessory-helpers.js';
|
|
2
|
+
function clampFanSpeed(value) {
|
|
3
|
+
const speed = Math.round(Number(value));
|
|
4
|
+
if (!Number.isFinite(speed)) {
|
|
5
|
+
return 0;
|
|
6
|
+
}
|
|
7
|
+
return Math.max(0, Math.min(100, speed));
|
|
8
|
+
}
|
|
9
|
+
// Fan Accessory Configurator: Exposes Cync fan switches as HomeKit Fanv2 accessories
|
|
10
|
+
export function configureCyncFanAccessory(env, mesh, device, accessory, deviceName, deviceId) {
|
|
11
|
+
const Service = env.api.hap.Service;
|
|
12
|
+
const Characteristic = env.api.hap.Characteristic;
|
|
13
|
+
const existingLight = accessory.getService(Service.Lightbulb);
|
|
14
|
+
if (existingLight) {
|
|
15
|
+
env.log.info('Cync: removing stale Lightbulb service from %s (deviceId=%s) before configuring as Fan', deviceName, deviceId);
|
|
16
|
+
accessory.removeService(existingLight);
|
|
17
|
+
}
|
|
18
|
+
const existingSwitch = accessory.getService(Service.Switch);
|
|
19
|
+
if (existingSwitch) {
|
|
20
|
+
env.log.info('Cync: removing stale Switch service from %s (deviceId=%s) before configuring as Fan', deviceName, deviceId);
|
|
21
|
+
accessory.removeService(existingSwitch);
|
|
22
|
+
}
|
|
23
|
+
const existingOutlet = accessory.getService(Service.Outlet);
|
|
24
|
+
if (existingOutlet) {
|
|
25
|
+
env.log.info('Cync: removing stale Outlet service from %s (deviceId=%s) before configuring as Fan', deviceName, deviceId);
|
|
26
|
+
accessory.removeService(existingOutlet);
|
|
27
|
+
}
|
|
28
|
+
const service = accessory.getService(Service.Fanv2) ||
|
|
29
|
+
accessory.addService(Service.Fanv2, deviceName);
|
|
30
|
+
if (accessory.category !== 3 /* env.api.hap.Categories.FAN */) {
|
|
31
|
+
accessory.category = 3 /* env.api.hap.Categories.FAN */;
|
|
32
|
+
}
|
|
33
|
+
applyAccessoryInformationFromCyncDevice(env.api, accessory, device, deviceName, deviceId);
|
|
34
|
+
const ctx = accessory.context;
|
|
35
|
+
ctx.cync = ctx.cync ?? {
|
|
36
|
+
meshId: mesh.id,
|
|
37
|
+
deviceId,
|
|
38
|
+
productId: device.product_id,
|
|
39
|
+
on: false,
|
|
40
|
+
};
|
|
41
|
+
const resolvedDeviceType = resolveDeviceType(device);
|
|
42
|
+
if (typeof resolvedDeviceType === 'number' && Number.isFinite(resolvedDeviceType)) {
|
|
43
|
+
ctx.cync.deviceType = resolvedDeviceType;
|
|
44
|
+
}
|
|
45
|
+
env.registerAccessoryForDevice(deviceId, accessory);
|
|
46
|
+
env.markDeviceSeen(deviceId);
|
|
47
|
+
env.startPollingDevice(deviceId);
|
|
48
|
+
service
|
|
49
|
+
.getCharacteristic(Characteristic.Active)
|
|
50
|
+
.onGet(() => {
|
|
51
|
+
return ctx.cync?.on ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE;
|
|
52
|
+
})
|
|
53
|
+
.onSet(async (value) => {
|
|
54
|
+
const cyncMeta = ctx.cync;
|
|
55
|
+
if (!cyncMeta?.deviceId) {
|
|
56
|
+
env.log.warn('Cync: Fan Active.set called for %s but no cync.deviceId in context', deviceName);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const on = value === Characteristic.Active.ACTIVE;
|
|
60
|
+
cyncMeta.on = on;
|
|
61
|
+
try {
|
|
62
|
+
await env.tcpClient.setSwitchState(cyncMeta.deviceId, { on });
|
|
63
|
+
env.markDeviceSeen(cyncMeta.deviceId);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
env.log.warn('Cync: Fan Active.set failed for %s (deviceId=%s): %s', deviceName, cyncMeta.deviceId, err.message ?? String(err));
|
|
67
|
+
throw new env.api.hap.HapStatusError(-70402 /* env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
service
|
|
71
|
+
.getCharacteristic(Characteristic.RotationSpeed)
|
|
72
|
+
.onGet(() => {
|
|
73
|
+
return typeof ctx.cync?.brightness === 'number'
|
|
74
|
+
? ctx.cync.brightness
|
|
75
|
+
: ctx.cync?.on ? 100 : 0;
|
|
76
|
+
})
|
|
77
|
+
.onSet(async (value) => {
|
|
78
|
+
const cyncMeta = ctx.cync;
|
|
79
|
+
if (!cyncMeta?.deviceId) {
|
|
80
|
+
env.log.warn('Cync: Fan RotationSpeed.set called for %s but no cync.deviceId in context', deviceName);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const speed = clampFanSpeed(value);
|
|
84
|
+
cyncMeta.brightness = speed;
|
|
85
|
+
cyncMeta.on = speed > 0;
|
|
86
|
+
try {
|
|
87
|
+
await env.tcpClient.setBrightness(cyncMeta.deviceId, speed, cyncMeta.deviceType);
|
|
88
|
+
env.markDeviceSeen(cyncMeta.deviceId);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
env.log.warn('Cync: Fan RotationSpeed.set failed for %s (deviceId=%s): %s', deviceName, cyncMeta.deviceId, err.message ?? String(err));
|
|
92
|
+
throw new env.api.hap.HapStatusError(-70402 /* env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=cync-fan-accessory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cync-fan-accessory.js","sourceRoot":"","sources":["../../src/cync/cync-fan-accessory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type CyncAccessoryType = 'light' | 'fan' | 'outlet' | 'switch' | 'unsupported';
|
|
2
|
+
export interface CyncDeviceLike {
|
|
3
|
+
id?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
deviceType?: number;
|
|
6
|
+
type?: number;
|
|
7
|
+
capabilities?: string[] | Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface CyncDeviceClassification {
|
|
10
|
+
accessoryType: CyncAccessoryType;
|
|
11
|
+
deviceType?: number;
|
|
12
|
+
capabilities: string[];
|
|
13
|
+
reason: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function classifyCyncDevice(device: CyncDeviceLike, resolvedDeviceType?: number): CyncDeviceClassification;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/cync/device-classifier.ts
|
|
2
|
+
// Cync Device Classifier: Centralizes accessory type selection and classification logging context
|
|
3
|
+
const CYNC_LIGHT_DEVICE_TYPES = new Set([
|
|
4
|
+
1, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 17, 18, 19, 20, 21,
|
|
5
|
+
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
|
6
|
+
37, 46, 47, 48, 49, 55, 56, 80, 82, 83, 85, 123, 128, 129, 130,
|
|
7
|
+
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
|
|
8
|
+
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
|
|
9
|
+
155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169,
|
|
10
|
+
170, 171,
|
|
11
|
+
]);
|
|
12
|
+
const CYNC_OUTLET_DEVICE_TYPES = new Set([
|
|
13
|
+
64, 65, 66, 67, 68, 172,
|
|
14
|
+
]);
|
|
15
|
+
const CYNC_FAN_DEVICE_TYPES = new Set([
|
|
16
|
+
81,
|
|
17
|
+
]);
|
|
18
|
+
function normalizeCapabilities(capabilities) {
|
|
19
|
+
if (!capabilities) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(capabilities)) {
|
|
23
|
+
return capabilities
|
|
24
|
+
.map(capability => capability.toLowerCase())
|
|
25
|
+
.sort();
|
|
26
|
+
}
|
|
27
|
+
return Object.keys(capabilities)
|
|
28
|
+
.map(capability => capability.toLowerCase())
|
|
29
|
+
.sort();
|
|
30
|
+
}
|
|
31
|
+
function getDeviceType(device) {
|
|
32
|
+
return device.deviceType ?? device.type;
|
|
33
|
+
}
|
|
34
|
+
export function classifyCyncDevice(device, resolvedDeviceType) {
|
|
35
|
+
const deviceType = resolvedDeviceType ?? getDeviceType(device);
|
|
36
|
+
const capabilities = normalizeCapabilities(device.capabilities);
|
|
37
|
+
if (capabilities.includes('fan')) {
|
|
38
|
+
return {
|
|
39
|
+
accessoryType: 'fan',
|
|
40
|
+
deviceType,
|
|
41
|
+
capabilities,
|
|
42
|
+
reason: 'capability: fan',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (capabilities.includes('color') ||
|
|
46
|
+
capabilities.includes('colortemp') ||
|
|
47
|
+
capabilities.includes('brightness')) {
|
|
48
|
+
return {
|
|
49
|
+
accessoryType: 'light',
|
|
50
|
+
deviceType,
|
|
51
|
+
capabilities,
|
|
52
|
+
reason: 'capability: light control',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (deviceType !== undefined && CYNC_FAN_DEVICE_TYPES.has(deviceType)) {
|
|
56
|
+
return {
|
|
57
|
+
accessoryType: 'fan',
|
|
58
|
+
deviceType,
|
|
59
|
+
capabilities,
|
|
60
|
+
reason: `deviceType: ${deviceType}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (deviceType !== undefined && CYNC_LIGHT_DEVICE_TYPES.has(deviceType)) {
|
|
64
|
+
return {
|
|
65
|
+
accessoryType: 'light',
|
|
66
|
+
deviceType,
|
|
67
|
+
capabilities,
|
|
68
|
+
reason: `deviceType: ${deviceType}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (deviceType !== undefined && CYNC_OUTLET_DEVICE_TYPES.has(deviceType)) {
|
|
72
|
+
return {
|
|
73
|
+
accessoryType: 'outlet',
|
|
74
|
+
deviceType,
|
|
75
|
+
capabilities,
|
|
76
|
+
reason: `deviceType: ${deviceType}`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (capabilities.includes('onoff')) {
|
|
80
|
+
return {
|
|
81
|
+
accessoryType: 'switch',
|
|
82
|
+
deviceType,
|
|
83
|
+
capabilities,
|
|
84
|
+
reason: 'capability: onoff fallback',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
accessoryType: 'unsupported',
|
|
89
|
+
deviceType,
|
|
90
|
+
capabilities,
|
|
91
|
+
reason: 'no supported capabilities or known deviceType',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=device-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-classifier.js","sourceRoot":"","sources":["../../src/cync/device-classifier.ts"],"names":[],"mappings":"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"}
|
package/dist/platform.js
CHANGED
|
@@ -6,38 +6,16 @@ import { resolveDeviceType, rgbToHsv, } from './cync/cync-accessory-helpers.js';
|
|
|
6
6
|
import { configureCyncLightAccessory } from './cync/cync-light-accessory.js';
|
|
7
7
|
import { configureCyncSwitchAccessory } from './cync/cync-switch-accessory.js';
|
|
8
8
|
import { configureCyncOutletAccessory } from './cync/cync-outlet-accessory.js';
|
|
9
|
+
import { configureCyncFanAccessory } from './cync/cync-fan-accessory.js';
|
|
10
|
+
import { classifyCyncDevice } from './cync/device-classifier.js';
|
|
9
11
|
const toCyncLogger = (log) => ({
|
|
10
12
|
debug: log.debug.bind(log),
|
|
11
13
|
info: log.info.bind(log),
|
|
12
14
|
warn: log.warn.bind(log),
|
|
13
15
|
error: log.error.bind(log),
|
|
14
16
|
});
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
1, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 17, 18, 19, 20, 21,
|
|
18
|
-
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
|
19
|
-
37, 46, 47, 48, 49, 55, 56, 80, 81, 82, 83, 85, 123, 128, 129, 130,
|
|
20
|
-
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
|
|
21
|
-
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
|
|
22
|
-
155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169,
|
|
23
|
-
170, 171,
|
|
24
|
-
]);
|
|
25
|
-
function isCyncLightDeviceType(deviceType) {
|
|
26
|
-
return deviceType !== undefined
|
|
27
|
-
&& CYNC_LIGHT_DEVICE_TYPES.has(deviceType);
|
|
28
|
-
}
|
|
29
|
-
// Known Cync device types that should be treated as Outlet accessories
|
|
30
|
-
const CYNC_OUTLET_DEVICE_TYPES = new Set([
|
|
31
|
-
64, 65, 66, 67, 68, 172,
|
|
32
|
-
]);
|
|
33
|
-
function isCyncOutletDeviceType(deviceType) {
|
|
34
|
-
return deviceType !== undefined
|
|
35
|
-
&& CYNC_OUTLET_DEVICE_TYPES.has(deviceType);
|
|
36
|
-
}
|
|
37
|
-
function getDefaultCapabilitiesForDeviceType(deviceType) {
|
|
38
|
-
const isLight = isCyncLightDeviceType(deviceType);
|
|
39
|
-
// Conservative defaults: only claim what you can prove.
|
|
40
|
-
// We'll promote color/brightness once LAN proves it.
|
|
17
|
+
function getDefaultCapabilitiesForDeviceType() {
|
|
18
|
+
const isLight = false;
|
|
41
19
|
return {
|
|
42
20
|
isLight,
|
|
43
21
|
supportsBrightness: false,
|
|
@@ -116,18 +94,19 @@ export class CyncAppPlatform {
|
|
|
116
94
|
const Service = this.api.hap.Service;
|
|
117
95
|
const Characteristic = this.api.hap.Characteristic;
|
|
118
96
|
const lightService = accessory.getService(Service.Lightbulb);
|
|
97
|
+
const fanService = accessory.getService(Service.Fanv2);
|
|
119
98
|
const outletService = accessory.getService(Service.Outlet);
|
|
120
99
|
const switchService = accessory.getService(Service.Switch);
|
|
121
|
-
const primaryService = lightService || outletService || switchService;
|
|
100
|
+
const primaryService = lightService || fanService || outletService || switchService;
|
|
122
101
|
if (!primaryService) {
|
|
123
|
-
this.log.debug('Cync: accessory %s has no Lightbulb, Outlet, or Switch service for deviceId=%s', accessory.displayName, update.deviceId);
|
|
102
|
+
this.log.debug('Cync: accessory %s has no Lightbulb, Fan, Outlet, or Switch service for deviceId=%s', accessory.displayName, update.deviceId);
|
|
124
103
|
return;
|
|
125
104
|
}
|
|
126
105
|
// Update cached context state
|
|
127
106
|
const ctx = accessory.context;
|
|
128
107
|
ctx.cync = ctx.cync ?? { meshId: '', deviceId: update.deviceId };
|
|
129
108
|
if (!ctx.cync.capabilities) {
|
|
130
|
-
ctx.cync.capabilities = getDefaultCapabilitiesForDeviceType(
|
|
109
|
+
ctx.cync.capabilities = getDefaultCapabilitiesForDeviceType();
|
|
131
110
|
}
|
|
132
111
|
const promoted = promoteCapabilitiesFromLan(ctx.cync.capabilities, update);
|
|
133
112
|
if (promoted) {
|
|
@@ -137,10 +116,28 @@ export class CyncAppPlatform {
|
|
|
137
116
|
if (typeof update.on === 'boolean') {
|
|
138
117
|
ctx.cync.on = update.on;
|
|
139
118
|
this.log.info('Cync: LAN update -> %s is now %s (deviceId=%s)', accessory.displayName, update.on ? 'ON' : 'OFF', update.deviceId);
|
|
140
|
-
|
|
119
|
+
if (lightService || outletService || switchService) {
|
|
120
|
+
primaryService.updateCharacteristic(Characteristic.On, update.on);
|
|
121
|
+
}
|
|
141
122
|
if (outletService && outletService.testCharacteristic(Characteristic.OutletInUse)) {
|
|
142
123
|
outletService.updateCharacteristic(Characteristic.OutletInUse, update.on);
|
|
143
124
|
}
|
|
125
|
+
if (fanService && fanService.testCharacteristic(Characteristic.Active)) {
|
|
126
|
+
fanService.updateCharacteristic(Characteristic.Active, update.on ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ---- Fan Speed ----
|
|
130
|
+
if (fanService) {
|
|
131
|
+
let speedPct;
|
|
132
|
+
if (typeof update.brightnessPct === 'number' && Number.isFinite(update.brightnessPct)) {
|
|
133
|
+
speedPct = Math.max(0, Math.min(100, Math.round(update.brightnessPct)));
|
|
134
|
+
}
|
|
135
|
+
if (speedPct !== undefined) {
|
|
136
|
+
ctx.cync.brightness = speedPct;
|
|
137
|
+
if (fanService.testCharacteristic(Characteristic.RotationSpeed)) {
|
|
138
|
+
fanService.updateCharacteristic(Characteristic.RotationSpeed, speedPct);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
144
141
|
}
|
|
145
142
|
// ----- Brightness -----
|
|
146
143
|
if (lightService) {
|
|
@@ -312,15 +309,31 @@ export class CyncAppPlatform {
|
|
|
312
309
|
// Optional safety net (accessory modules also register this)
|
|
313
310
|
this.deviceIdToAccessory.set(deviceId, accessory);
|
|
314
311
|
const deviceType = resolveDeviceType(device);
|
|
312
|
+
const classification = classifyCyncDevice(device, deviceType);
|
|
313
|
+
this.log.debug('Cync device classification: ' +
|
|
314
|
+
`name="${deviceName}" ` +
|
|
315
|
+
`deviceId=${deviceId} ` +
|
|
316
|
+
`deviceType=${classification.deviceType ?? 'unknown'} ` +
|
|
317
|
+
`capabilities=${classification.capabilities.join(',') || 'none'} ` +
|
|
318
|
+
`accessoryType=${classification.accessoryType} ` +
|
|
319
|
+
`reason="${classification.reason}"`);
|
|
315
320
|
const deviceTypeStr = typeof deviceType === 'number' ? String(deviceType) : 'unknown';
|
|
316
|
-
if (
|
|
321
|
+
if (classification.accessoryType === 'fan') {
|
|
322
|
+
this.log.info('Cync: configuring %s as Fan (deviceType=%s, deviceId=%s)', deviceName, deviceTypeStr, deviceId);
|
|
323
|
+
configureCyncFanAccessory(this.accessoryEnv, mesh, device, accessory, deviceName, deviceId);
|
|
324
|
+
}
|
|
325
|
+
else if (classification.accessoryType === 'light') {
|
|
317
326
|
this.log.info('Cync: configuring %s as Lightbulb (deviceType=%s, deviceId=%s)', deviceName, deviceTypeStr, deviceId);
|
|
318
327
|
configureCyncLightAccessory(this.accessoryEnv, mesh, device, accessory, deviceName, deviceId);
|
|
319
328
|
}
|
|
320
|
-
else if (
|
|
329
|
+
else if (classification.accessoryType === 'outlet') {
|
|
321
330
|
this.log.info('Cync: configuring %s as Outlet (deviceType=%s, deviceId=%s)', deviceName, deviceTypeStr, deviceId);
|
|
322
331
|
configureCyncOutletAccessory(this.accessoryEnv, mesh, device, accessory, deviceName, deviceId);
|
|
323
332
|
}
|
|
333
|
+
else if (classification.accessoryType === 'unsupported') {
|
|
334
|
+
this.log.warn('Cync: unsupported device %s (deviceType=%s, deviceId=%s); configuring as Switch fallback', deviceName, deviceTypeStr, deviceId);
|
|
335
|
+
configureCyncSwitchAccessory(this.accessoryEnv, mesh, device, accessory, deviceName, deviceId);
|
|
336
|
+
}
|
|
324
337
|
else {
|
|
325
338
|
this.log.info('Cync: configuring %s as Switch (deviceType=%s, deviceId=%s)', deviceName, deviceTypeStr, deviceId);
|
|
326
339
|
configureCyncSwitchAccessory(this.accessoryEnv, mesh, device, accessory, deviceName, deviceId);
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "homebridge-cync-app",
|
|
3
3
|
"displayName": "Homebridge Cync App",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.0",
|
|
6
6
|
"private": false,
|
|
7
7
|
"description": "Homebridge plugin that integrates your GE Cync account (via the Cync app/API) and exposes all supported devices: plugs, lights, switches, etc",
|
|
8
8
|
"author": "Dustin Newell",
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/cync/cync-fan-accessory.ts
|
|
2
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
3
|
+
import type { CyncDevice, CyncDeviceMesh } from './config-client.js';
|
|
4
|
+
import type { CyncAccessoryContext, CyncAccessoryEnv } from './cync-accessory-helpers.js';
|
|
5
|
+
import {
|
|
6
|
+
applyAccessoryInformationFromCyncDevice,
|
|
7
|
+
resolveDeviceType,
|
|
8
|
+
} from './cync-accessory-helpers.js';
|
|
9
|
+
|
|
10
|
+
function clampFanSpeed(value: unknown): number {
|
|
11
|
+
const speed = Math.round(Number(value));
|
|
12
|
+
|
|
13
|
+
if (!Number.isFinite(speed)) {
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return Math.max(0, Math.min(100, speed));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Fan Accessory Configurator: Exposes Cync fan switches as HomeKit Fanv2 accessories
|
|
21
|
+
export function configureCyncFanAccessory(
|
|
22
|
+
env: CyncAccessoryEnv,
|
|
23
|
+
mesh: CyncDeviceMesh,
|
|
24
|
+
device: CyncDevice,
|
|
25
|
+
accessory: PlatformAccessory,
|
|
26
|
+
deviceName: string,
|
|
27
|
+
deviceId: string,
|
|
28
|
+
): void {
|
|
29
|
+
const Service = env.api.hap.Service;
|
|
30
|
+
const Characteristic = env.api.hap.Characteristic;
|
|
31
|
+
|
|
32
|
+
const existingLight = accessory.getService(Service.Lightbulb);
|
|
33
|
+
if (existingLight) {
|
|
34
|
+
env.log.info(
|
|
35
|
+
'Cync: removing stale Lightbulb service from %s (deviceId=%s) before configuring as Fan',
|
|
36
|
+
deviceName,
|
|
37
|
+
deviceId,
|
|
38
|
+
);
|
|
39
|
+
accessory.removeService(existingLight);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const existingSwitch = accessory.getService(Service.Switch);
|
|
43
|
+
if (existingSwitch) {
|
|
44
|
+
env.log.info(
|
|
45
|
+
'Cync: removing stale Switch service from %s (deviceId=%s) before configuring as Fan',
|
|
46
|
+
deviceName,
|
|
47
|
+
deviceId,
|
|
48
|
+
);
|
|
49
|
+
accessory.removeService(existingSwitch);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const existingOutlet = accessory.getService(Service.Outlet);
|
|
53
|
+
if (existingOutlet) {
|
|
54
|
+
env.log.info(
|
|
55
|
+
'Cync: removing stale Outlet service from %s (deviceId=%s) before configuring as Fan',
|
|
56
|
+
deviceName,
|
|
57
|
+
deviceId,
|
|
58
|
+
);
|
|
59
|
+
accessory.removeService(existingOutlet);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const service =
|
|
63
|
+
accessory.getService(Service.Fanv2) ||
|
|
64
|
+
accessory.addService(Service.Fanv2, deviceName);
|
|
65
|
+
|
|
66
|
+
if (accessory.category !== env.api.hap.Categories.FAN) {
|
|
67
|
+
accessory.category = env.api.hap.Categories.FAN;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
applyAccessoryInformationFromCyncDevice(env.api, accessory, device, deviceName, deviceId);
|
|
71
|
+
|
|
72
|
+
const ctx = accessory.context as CyncAccessoryContext;
|
|
73
|
+
ctx.cync = ctx.cync ?? {
|
|
74
|
+
meshId: mesh.id,
|
|
75
|
+
deviceId,
|
|
76
|
+
productId: device.product_id,
|
|
77
|
+
on: false,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const resolvedDeviceType = resolveDeviceType(device);
|
|
81
|
+
if (typeof resolvedDeviceType === 'number' && Number.isFinite(resolvedDeviceType)) {
|
|
82
|
+
ctx.cync.deviceType = resolvedDeviceType;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
env.registerAccessoryForDevice(deviceId, accessory);
|
|
86
|
+
env.markDeviceSeen(deviceId);
|
|
87
|
+
env.startPollingDevice(deviceId);
|
|
88
|
+
|
|
89
|
+
service
|
|
90
|
+
.getCharacteristic(Characteristic.Active)
|
|
91
|
+
.onGet(() => {
|
|
92
|
+
return ctx.cync?.on ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE;
|
|
93
|
+
})
|
|
94
|
+
.onSet(async (value) => {
|
|
95
|
+
const cyncMeta = ctx.cync;
|
|
96
|
+
|
|
97
|
+
if (!cyncMeta?.deviceId) {
|
|
98
|
+
env.log.warn(
|
|
99
|
+
'Cync: Fan Active.set called for %s but no cync.deviceId in context',
|
|
100
|
+
deviceName,
|
|
101
|
+
);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const on = value === Characteristic.Active.ACTIVE;
|
|
106
|
+
|
|
107
|
+
cyncMeta.on = on;
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await env.tcpClient.setSwitchState(cyncMeta.deviceId, { on });
|
|
111
|
+
env.markDeviceSeen(cyncMeta.deviceId);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
env.log.warn(
|
|
114
|
+
'Cync: Fan Active.set failed for %s (deviceId=%s): %s',
|
|
115
|
+
deviceName,
|
|
116
|
+
cyncMeta.deviceId,
|
|
117
|
+
(err as Error).message ?? String(err),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
throw new env.api.hap.HapStatusError(
|
|
121
|
+
env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
service
|
|
127
|
+
.getCharacteristic(Characteristic.RotationSpeed)
|
|
128
|
+
.onGet(() => {
|
|
129
|
+
return typeof ctx.cync?.brightness === 'number'
|
|
130
|
+
? ctx.cync.brightness
|
|
131
|
+
: ctx.cync?.on ? 100 : 0;
|
|
132
|
+
})
|
|
133
|
+
.onSet(async (value) => {
|
|
134
|
+
const cyncMeta = ctx.cync;
|
|
135
|
+
|
|
136
|
+
if (!cyncMeta?.deviceId) {
|
|
137
|
+
env.log.warn(
|
|
138
|
+
'Cync: Fan RotationSpeed.set called for %s but no cync.deviceId in context',
|
|
139
|
+
deviceName,
|
|
140
|
+
);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const speed = clampFanSpeed(value);
|
|
145
|
+
|
|
146
|
+
cyncMeta.brightness = speed;
|
|
147
|
+
cyncMeta.on = speed > 0;
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
await env.tcpClient.setBrightness(cyncMeta.deviceId, speed, cyncMeta.deviceType);
|
|
151
|
+
env.markDeviceSeen(cyncMeta.deviceId);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
env.log.warn(
|
|
154
|
+
'Cync: Fan RotationSpeed.set failed for %s (deviceId=%s): %s',
|
|
155
|
+
deviceName,
|
|
156
|
+
cyncMeta.deviceId,
|
|
157
|
+
(err as Error).message ?? String(err),
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
throw new env.api.hap.HapStatusError(
|
|
161
|
+
env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// src/cync/device-classifier.ts
|
|
2
|
+
// Cync Device Classifier: Centralizes accessory type selection and classification logging context
|
|
3
|
+
|
|
4
|
+
type CyncAccessoryType = 'light' | 'fan' | 'outlet' | 'switch' | 'unsupported';
|
|
5
|
+
|
|
6
|
+
export interface CyncDeviceLike {
|
|
7
|
+
id?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
deviceType?: number;
|
|
10
|
+
type?: number;
|
|
11
|
+
capabilities?: string[] | Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CyncDeviceClassification {
|
|
15
|
+
accessoryType: CyncAccessoryType;
|
|
16
|
+
deviceType?: number;
|
|
17
|
+
capabilities: string[];
|
|
18
|
+
reason: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const CYNC_LIGHT_DEVICE_TYPES = new Set([
|
|
22
|
+
1, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 17, 18, 19, 20, 21,
|
|
23
|
+
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
|
24
|
+
37, 46, 47, 48, 49, 55, 56, 80, 82, 83, 85, 123, 128, 129, 130,
|
|
25
|
+
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
|
|
26
|
+
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
|
|
27
|
+
155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169,
|
|
28
|
+
170, 171,
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const CYNC_OUTLET_DEVICE_TYPES = new Set([
|
|
32
|
+
64, 65, 66, 67, 68, 172,
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const CYNC_FAN_DEVICE_TYPES = new Set([
|
|
36
|
+
81,
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
function normalizeCapabilities(capabilities: CyncDeviceLike['capabilities']): string[] {
|
|
40
|
+
if (!capabilities) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(capabilities)) {
|
|
45
|
+
return capabilities
|
|
46
|
+
.map(capability => capability.toLowerCase())
|
|
47
|
+
.sort();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return Object.keys(capabilities)
|
|
51
|
+
.map(capability => capability.toLowerCase())
|
|
52
|
+
.sort();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getDeviceType(device: CyncDeviceLike): number | undefined {
|
|
56
|
+
return device.deviceType ?? device.type;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function classifyCyncDevice(
|
|
60
|
+
device: CyncDeviceLike,
|
|
61
|
+
resolvedDeviceType?: number,
|
|
62
|
+
): CyncDeviceClassification {
|
|
63
|
+
const deviceType = resolvedDeviceType ?? getDeviceType(device);
|
|
64
|
+
const capabilities = normalizeCapabilities(device.capabilities);
|
|
65
|
+
|
|
66
|
+
if (capabilities.includes('fan')) {
|
|
67
|
+
return {
|
|
68
|
+
accessoryType: 'fan',
|
|
69
|
+
deviceType,
|
|
70
|
+
capabilities,
|
|
71
|
+
reason: 'capability: fan',
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (
|
|
76
|
+
capabilities.includes('color') ||
|
|
77
|
+
capabilities.includes('colortemp') ||
|
|
78
|
+
capabilities.includes('brightness')
|
|
79
|
+
) {
|
|
80
|
+
return {
|
|
81
|
+
accessoryType: 'light',
|
|
82
|
+
deviceType,
|
|
83
|
+
capabilities,
|
|
84
|
+
reason: 'capability: light control',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (deviceType !== undefined && CYNC_FAN_DEVICE_TYPES.has(deviceType)) {
|
|
89
|
+
return {
|
|
90
|
+
accessoryType: 'fan',
|
|
91
|
+
deviceType,
|
|
92
|
+
capabilities,
|
|
93
|
+
reason: `deviceType: ${deviceType}`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (deviceType !== undefined && CYNC_LIGHT_DEVICE_TYPES.has(deviceType)) {
|
|
98
|
+
return {
|
|
99
|
+
accessoryType: 'light',
|
|
100
|
+
deviceType,
|
|
101
|
+
capabilities,
|
|
102
|
+
reason: `deviceType: ${deviceType}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (deviceType !== undefined && CYNC_OUTLET_DEVICE_TYPES.has(deviceType)) {
|
|
107
|
+
return {
|
|
108
|
+
accessoryType: 'outlet',
|
|
109
|
+
deviceType,
|
|
110
|
+
capabilities,
|
|
111
|
+
reason: `deviceType: ${deviceType}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (capabilities.includes('onoff')) {
|
|
116
|
+
return {
|
|
117
|
+
accessoryType: 'switch',
|
|
118
|
+
deviceType,
|
|
119
|
+
capabilities,
|
|
120
|
+
reason: 'capability: onoff fallback',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
accessoryType: 'unsupported',
|
|
126
|
+
deviceType,
|
|
127
|
+
capabilities,
|
|
128
|
+
reason: 'no supported capabilities or known deviceType',
|
|
129
|
+
};
|
|
130
|
+
}
|
package/src/platform.ts
CHANGED
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
import { configureCyncLightAccessory } from './cync/cync-light-accessory.js';
|
|
24
24
|
import { configureCyncSwitchAccessory } from './cync/cync-switch-accessory.js';
|
|
25
25
|
import { configureCyncOutletAccessory } from './cync/cync-outlet-accessory.js';
|
|
26
|
+
import { configureCyncFanAccessory } from './cync/cync-fan-accessory.js';
|
|
27
|
+
import { classifyCyncDevice } from './cync/device-classifier.js';
|
|
26
28
|
|
|
27
29
|
const toCyncLogger = (log: Logger): CyncLogger => ({
|
|
28
30
|
debug: log.debug.bind(log),
|
|
@@ -31,37 +33,9 @@ const toCyncLogger = (log: Logger): CyncLogger => ({
|
|
|
31
33
|
error: log.error.bind(log),
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
1, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 17, 18, 19, 20, 21,
|
|
37
|
-
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
|
38
|
-
37, 46, 47, 48, 49, 55, 56, 80, 81, 82, 83, 85, 123, 128, 129, 130,
|
|
39
|
-
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
|
|
40
|
-
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
|
|
41
|
-
155, 156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 169,
|
|
42
|
-
170, 171,
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
function isCyncLightDeviceType(deviceType: number | undefined): boolean {
|
|
46
|
-
return deviceType !== undefined
|
|
47
|
-
&& CYNC_LIGHT_DEVICE_TYPES.has(deviceType);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Known Cync device types that should be treated as Outlet accessories
|
|
51
|
-
const CYNC_OUTLET_DEVICE_TYPES = new Set([
|
|
52
|
-
64, 65, 66, 67, 68, 172,
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
function isCyncOutletDeviceType(deviceType: number | undefined): boolean {
|
|
56
|
-
return deviceType !== undefined
|
|
57
|
-
&& CYNC_OUTLET_DEVICE_TYPES.has(deviceType);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getDefaultCapabilitiesForDeviceType(deviceType: number | undefined): CyncCapabilityProfile {
|
|
61
|
-
const isLight = isCyncLightDeviceType(deviceType);
|
|
36
|
+
function getDefaultCapabilitiesForDeviceType(): CyncCapabilityProfile {
|
|
37
|
+
const isLight = false;
|
|
62
38
|
|
|
63
|
-
// Conservative defaults: only claim what you can prove.
|
|
64
|
-
// We'll promote color/brightness once LAN proves it.
|
|
65
39
|
return {
|
|
66
40
|
isLight,
|
|
67
41
|
supportsBrightness: false,
|
|
@@ -163,13 +137,14 @@ export class CyncAppPlatform implements DynamicPlatformPlugin {
|
|
|
163
137
|
const Characteristic = this.api.hap.Characteristic;
|
|
164
138
|
|
|
165
139
|
const lightService = accessory.getService(Service.Lightbulb);
|
|
140
|
+
const fanService = accessory.getService(Service.Fanv2);
|
|
166
141
|
const outletService = accessory.getService(Service.Outlet);
|
|
167
142
|
const switchService = accessory.getService(Service.Switch);
|
|
168
|
-
const primaryService = lightService || outletService || switchService;
|
|
143
|
+
const primaryService = lightService || fanService || outletService || switchService;
|
|
169
144
|
|
|
170
145
|
if (!primaryService) {
|
|
171
146
|
this.log.debug(
|
|
172
|
-
'Cync: accessory %s has no Lightbulb, Outlet, or Switch service for deviceId=%s',
|
|
147
|
+
'Cync: accessory %s has no Lightbulb, Fan, Outlet, or Switch service for deviceId=%s',
|
|
173
148
|
accessory.displayName,
|
|
174
149
|
update.deviceId,
|
|
175
150
|
);
|
|
@@ -180,7 +155,7 @@ export class CyncAppPlatform implements DynamicPlatformPlugin {
|
|
|
180
155
|
const ctx = accessory.context as CyncAccessoryContext;
|
|
181
156
|
ctx.cync = ctx.cync ?? { meshId: '', deviceId: update.deviceId };
|
|
182
157
|
if (!ctx.cync.capabilities) {
|
|
183
|
-
ctx.cync.capabilities = getDefaultCapabilitiesForDeviceType(
|
|
158
|
+
ctx.cync.capabilities = getDefaultCapabilitiesForDeviceType();
|
|
184
159
|
}
|
|
185
160
|
const promoted = promoteCapabilitiesFromLan(ctx.cync.capabilities, update);
|
|
186
161
|
if (promoted) {
|
|
@@ -203,10 +178,34 @@ export class CyncAppPlatform implements DynamicPlatformPlugin {
|
|
|
203
178
|
update.deviceId,
|
|
204
179
|
);
|
|
205
180
|
|
|
206
|
-
|
|
181
|
+
if (lightService || outletService || switchService) {
|
|
182
|
+
primaryService.updateCharacteristic(Characteristic.On, update.on);
|
|
183
|
+
}
|
|
207
184
|
if (outletService && outletService.testCharacteristic(Characteristic.OutletInUse)) {
|
|
208
185
|
outletService.updateCharacteristic(Characteristic.OutletInUse, update.on);
|
|
209
186
|
}
|
|
187
|
+
if (fanService && fanService.testCharacteristic(Characteristic.Active)) {
|
|
188
|
+
fanService.updateCharacteristic(
|
|
189
|
+
Characteristic.Active,
|
|
190
|
+
update.on ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// ---- Fan Speed ----
|
|
195
|
+
if (fanService) {
|
|
196
|
+
let speedPct: number | undefined;
|
|
197
|
+
|
|
198
|
+
if (typeof update.brightnessPct === 'number' && Number.isFinite(update.brightnessPct)) {
|
|
199
|
+
speedPct = Math.max(0, Math.min(100, Math.round(update.brightnessPct)));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (speedPct !== undefined) {
|
|
203
|
+
ctx.cync.brightness = speedPct;
|
|
204
|
+
|
|
205
|
+
if (fanService.testCharacteristic(Characteristic.RotationSpeed)) {
|
|
206
|
+
fanService.updateCharacteristic(Characteristic.RotationSpeed, speedPct);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
210
209
|
}
|
|
211
210
|
|
|
212
211
|
// ----- Brightness -----
|
|
@@ -465,10 +464,36 @@ export class CyncAppPlatform implements DynamicPlatformPlugin {
|
|
|
465
464
|
this.deviceIdToAccessory.set(deviceId, accessory);
|
|
466
465
|
|
|
467
466
|
const deviceType = resolveDeviceType(device);
|
|
467
|
+
const classification = classifyCyncDevice(device, deviceType);
|
|
468
|
+
|
|
469
|
+
this.log.debug(
|
|
470
|
+
'Cync device classification: ' +
|
|
471
|
+
`name="${deviceName}" ` +
|
|
472
|
+
`deviceId=${deviceId} ` +
|
|
473
|
+
`deviceType=${classification.deviceType ?? 'unknown'} ` +
|
|
474
|
+
`capabilities=${classification.capabilities.join(',') || 'none'} ` +
|
|
475
|
+
`accessoryType=${classification.accessoryType} ` +
|
|
476
|
+
`reason="${classification.reason}"`,
|
|
477
|
+
);
|
|
468
478
|
const deviceTypeStr =
|
|
469
479
|
typeof deviceType === 'number' ? String(deviceType) : 'unknown';
|
|
470
480
|
|
|
471
|
-
if (
|
|
481
|
+
if (classification.accessoryType === 'fan') {
|
|
482
|
+
this.log.info(
|
|
483
|
+
'Cync: configuring %s as Fan (deviceType=%s, deviceId=%s)',
|
|
484
|
+
deviceName,
|
|
485
|
+
deviceTypeStr,
|
|
486
|
+
deviceId,
|
|
487
|
+
);
|
|
488
|
+
configureCyncFanAccessory(
|
|
489
|
+
this.accessoryEnv,
|
|
490
|
+
mesh,
|
|
491
|
+
device,
|
|
492
|
+
accessory,
|
|
493
|
+
deviceName,
|
|
494
|
+
deviceId,
|
|
495
|
+
);
|
|
496
|
+
} else if (classification.accessoryType === 'light') {
|
|
472
497
|
this.log.info(
|
|
473
498
|
'Cync: configuring %s as Lightbulb (deviceType=%s, deviceId=%s)',
|
|
474
499
|
deviceName,
|
|
@@ -483,7 +508,7 @@ export class CyncAppPlatform implements DynamicPlatformPlugin {
|
|
|
483
508
|
deviceName,
|
|
484
509
|
deviceId,
|
|
485
510
|
);
|
|
486
|
-
} else if (
|
|
511
|
+
} else if (classification.accessoryType === 'outlet') {
|
|
487
512
|
this.log.info(
|
|
488
513
|
'Cync: configuring %s as Outlet (deviceType=%s, deviceId=%s)',
|
|
489
514
|
deviceName,
|
|
@@ -498,6 +523,21 @@ export class CyncAppPlatform implements DynamicPlatformPlugin {
|
|
|
498
523
|
deviceName,
|
|
499
524
|
deviceId,
|
|
500
525
|
);
|
|
526
|
+
} else if (classification.accessoryType === 'unsupported') {
|
|
527
|
+
this.log.warn(
|
|
528
|
+
'Cync: unsupported device %s (deviceType=%s, deviceId=%s); configuring as Switch fallback',
|
|
529
|
+
deviceName,
|
|
530
|
+
deviceTypeStr,
|
|
531
|
+
deviceId,
|
|
532
|
+
);
|
|
533
|
+
configureCyncSwitchAccessory(
|
|
534
|
+
this.accessoryEnv,
|
|
535
|
+
mesh,
|
|
536
|
+
device,
|
|
537
|
+
accessory,
|
|
538
|
+
deviceName,
|
|
539
|
+
deviceId,
|
|
540
|
+
);
|
|
501
541
|
} else {
|
|
502
542
|
this.log.info(
|
|
503
543
|
'Cync: configuring %s as Switch (deviceType=%s, deviceId=%s)',
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Add Support for a New Cync Device
|
|
3
|
-
about: Request adding support for a Cync device
|
|
4
|
-
title: Add Cync Device [MODEL]
|
|
5
|
-
labels: enhancement
|
|
6
|
-
assignees: dash16
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
Thank you for helping expand device support in **homebridge-cync-app**.
|
|
11
|
-
|
|
12
|
-
To add support for a new device model, I need diagnostic information from your plugin installation and the Cync app.
|
|
13
|
-
|
|
14
|
-
Please fill out all sections below.
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 1. Device Information
|
|
19
|
-
|
|
20
|
-
**1.1 Product name as shown in the Cync app**
|
|
21
|
-
|
|
22
|
-
(e.g., “6" Recessed Can Retrofit Fixture (Matter)”, “Indoor Smart Plug (3-in-1)”, “Indoor Smart Plug”)
|
|
23
|
-
|
|
24
|
-
**1.2 Product page URL (GE/Cync or retailer)**
|
|
25
|
-
|
|
26
|
-
Link to the product page if available.
|
|
27
|
-
|
|
28
|
-
Example:
|
|
29
|
-
https://www.gelighting.com/smart-home/led-bulbs/soft-white
|
|
30
|
-
|
|
31
|
-
**1.3 What kind of device is this?**
|
|
32
|
-
|
|
33
|
-
* Plug (on/off only)
|
|
34
|
-
* Dimmer
|
|
35
|
-
* Tunable white
|
|
36
|
-
* Full color light
|
|
37
|
-
* Multi-zone light
|
|
38
|
-
* Switch
|
|
39
|
-
* Downlight
|
|
40
|
-
* Other (describe)
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## 2. Discovery Logs (Required)
|
|
45
|
-
|
|
46
|
-
Please enable **Homebridge Debug Mode** (`-D` or toggle in the UI), restart Homebridge, and paste the **full debug block for this device**.
|
|
47
|
-
|
|
48
|
-
Look for log lines like:
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
[Cync App] Fetched device: {
|
|
53
|
-
deviceId: …,
|
|
54
|
-
productId: …,
|
|
55
|
-
model: …,
|
|
56
|
-
capabilities: …,
|
|
57
|
-
raw: …
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Paste them here (you may redact serial numbers if desired):
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
<insert logs>
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## 3. Cloud `/property` Responses
|
|
72
|
-
|
|
73
|
-
To understand how the device reports state, please:
|
|
74
|
-
|
|
75
|
-
1. Turn the device **on**
|
|
76
|
-
2. Turn it **off**
|
|
77
|
-
3. Adjust **brightness** or **color** in the **Cync app**
|
|
78
|
-
|
|
79
|
-
Then copy any log lines showing cloud property responses such as:
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
[Cync App] [cloud] GET /product/.../device/.../property → …
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Paste them here:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
<insert logs>
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 4. LAN / TCP Logs (If Available)
|
|
94
|
-
|
|
95
|
-
Some Cync devices support **LAN/TCP communication** for faster updates.
|
|
96
|
-
|
|
97
|
-
If you see logs like `[Cync TCP] Connecting…`, please include examples such as:
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
[Cync TCP][recv] …
|
|
101
|
-
[Cync TCP][send] …
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Paste them here:
|
|
105
|
-
|
|
106
|
-
```
|
|
107
|
-
<insert logs>
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
If your device does **not** show TCP logs, say so:
|
|
111
|
-
|
|
112
|
-
```
|
|
113
|
-
No TCP messages observed.
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## 5. Screenshots from the **Cync App**
|
|
119
|
-
|
|
120
|
-
Please attach screenshots **from the Cync mobile app (not Apple Home)** showing:
|
|
121
|
-
|
|
122
|
-
* The **device settings page**
|
|
123
|
-
* The **main control UI** (brightness / color / mode controls)
|
|
124
|
-
* Any **advanced settings** available
|
|
125
|
-
|
|
126
|
-
These help determine which capabilities the device supports.
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## 6. Anything Else?
|
|
131
|
-
|
|
132
|
-
If the device behaves in an unusual way (multiple endpoints, segmented lights, unusual controls, etc.), please describe it here.
|
|
133
|
-
|
|
134
|
-
```
|
|
135
|
-
<notes>
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## Thank You
|
|
141
|
-
|
|
142
|
-
Once you submit this, I’ll analyze the device capabilities, determine the correct HomeKit service type, and add support to the plugin.
|