homebridge-cync-app 0.4.5 → 0.4.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.4.6
4
+ **Release Date:** 2026-06-13
5
+
6
+ ### Added
7
+ - Added brightness control support for supported Cync switch devices.
8
+ - Added cached brightness restore behavior for Cync paddle dimmer switches.
9
+
10
+ ### Fixed
11
+ - Fixed Cync paddle dimmer switches returning to 100% brightness after being turned off and back on from HomeKit.
12
+
13
+ ## v0.4.5
14
+
15
+ **Release Date:** 2026-06-10
16
+
17
+ ### Added
18
+ - Added device classification support for Cync Gen 1 Paddle Dimmer switches (device type 125).
19
+ - Introduced native switch accessory handling for supported Cync switch devices.
20
+
21
+ ### Changed
22
+ - Unsupported device types are now skipped instead of being automatically exposed as HomeKit switches.
23
+ - Improved device classification accuracy by requiring explicit switch classification before creating switch accessories.
24
+
25
+ ### Fixed
26
+ - Prevented unknown or unsupported Cync devices from appearing as incorrect HomeKit switch accessories.
27
+
3
28
  ## v0.4.4
4
29
 
5
30
  **Release Date:** 2026-06-08
@@ -1,14 +1,21 @@
1
1
  import { applyAccessoryInformationFromCyncDevice } from './cync-accessory-helpers.js';
2
2
  export function configureCyncSwitchAccessory(env, mesh, device, accessory, deviceName, deviceId) {
3
- const service = accessory.getService(env.api.hap.Service.Switch) ||
4
- accessory.addService(env.api.hap.Service.Switch, deviceName);
5
- const existingLight = accessory.getService(env.api.hap.Service.Lightbulb);
3
+ const { Characteristic, Service } = env.api.hap;
4
+ const service = accessory.getService(Service.Switch) ||
5
+ accessory.addService(Service.Switch, deviceName);
6
+ const existingLight = accessory.getService(Service.Lightbulb);
6
7
  if (existingLight) {
7
8
  env.log.info('Cync: removing stale Lightbulb service from %s (deviceId=%s) before configuring as Switch', deviceName, deviceId);
8
9
  accessory.removeService(existingLight);
9
10
  }
11
+ const deviceRecord = device;
12
+ const deviceType = typeof deviceRecord.deviceType === 'number'
13
+ ? deviceRecord.deviceType
14
+ : typeof deviceRecord.type === 'number'
15
+ ? deviceRecord.type
16
+ : undefined;
17
+ const supportsBrightness = deviceType === 125;
10
18
  applyAccessoryInformationFromCyncDevice(env.api, accessory, device, deviceName, deviceId);
11
- // Ensure context is initialized
12
19
  const ctx = accessory.context;
13
20
  ctx.cync = ctx.cync ?? {
14
21
  meshId: mesh.id,
@@ -16,19 +23,19 @@ export function configureCyncSwitchAccessory(env, mesh, device, accessory, devic
16
23
  productId: device.product_id,
17
24
  on: false,
18
25
  };
19
- // Remember mapping for LAN updates
26
+ ctx.cync.deviceType = deviceType;
20
27
  env.registerAccessoryForDevice(deviceId, accessory);
21
28
  env.markDeviceSeen(deviceId);
22
29
  env.startPollingDevice(deviceId);
23
30
  service
24
- .getCharacteristic(env.api.hap.Characteristic.On)
31
+ .getCharacteristic(Characteristic.On)
25
32
  .onGet(() => {
26
33
  const currentOn = !!ctx.cync?.on;
27
34
  if (env.isDeviceProbablyOffline(deviceId)) {
28
35
  env.log.debug('Cync: Switch On.get offline-heuristic hit; returning cached=%s for %s (deviceId=%s)', String(currentOn), deviceName, deviceId);
29
36
  return currentOn;
30
37
  }
31
- env.log.info('Cync: On.get -> %s for %s (deviceId=%s)', String(currentOn), deviceName, deviceId);
38
+ env.log.info('Cync: Switch On.get -> %s for %s (deviceId=%s)', String(currentOn), deviceName, deviceId);
32
39
  return currentOn;
33
40
  })
34
41
  .onSet(async (value) => {
@@ -39,7 +46,6 @@ export function configureCyncSwitchAccessory(env, mesh, device, accessory, devic
39
46
  }
40
47
  const on = value === true || value === 1;
41
48
  env.log.info('Cync: Switch On.set -> %s for %s (deviceId=%s)', String(on), deviceName, cyncMeta.deviceId);
42
- // Optimistic cache
43
49
  cyncMeta.on = on;
44
50
  try {
45
51
  if (!on) {
@@ -47,11 +53,13 @@ export function configureCyncSwitchAccessory(env, mesh, device, accessory, devic
47
53
  env.markDeviceSeen(cyncMeta.deviceId);
48
54
  return;
49
55
  }
50
- if (cyncMeta.colorActive && cyncMeta.rgb && typeof cyncMeta.brightness === 'number') {
51
- await env.tcpClient.setColor(cyncMeta.deviceId, cyncMeta.rgb, cyncMeta.brightness);
52
- }
53
- else {
54
- await env.tcpClient.setSwitchState(cyncMeta.deviceId, { on: true });
56
+ await env.tcpClient.setSwitchState(cyncMeta.deviceId, { on: true });
57
+ if (supportsBrightness &&
58
+ typeof cyncMeta.brightness === 'number' &&
59
+ cyncMeta.brightness > 0 &&
60
+ cyncMeta.brightness < 100) {
61
+ env.log.debug('Cync: Switch On.set restoring brightness=%d for %s (deviceId=%s)', cyncMeta.brightness, deviceName, cyncMeta.deviceId);
62
+ await env.tcpClient.setBrightness(cyncMeta.deviceId, cyncMeta.brightness, cyncMeta.deviceType);
55
63
  }
56
64
  env.markDeviceSeen(cyncMeta.deviceId);
57
65
  }
@@ -60,5 +68,42 @@ export function configureCyncSwitchAccessory(env, mesh, device, accessory, devic
60
68
  throw new env.api.hap.HapStatusError(-70402 /* env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
61
69
  }
62
70
  });
71
+ if (supportsBrightness) {
72
+ service
73
+ .getCharacteristic(Characteristic.Brightness)
74
+ .onGet(() => {
75
+ const current = ctx.cync?.brightness;
76
+ const cachedBrightness = typeof current === 'number'
77
+ ? current
78
+ : (ctx.cync?.on ?? false) ? 100 : 0;
79
+ if (env.isDeviceProbablyOffline(deviceId)) {
80
+ env.log.debug('Cync: Switch Brightness.get offline-heuristic hit; returning cached=%d for %s (deviceId=%s)', cachedBrightness, deviceName, deviceId);
81
+ }
82
+ return cachedBrightness;
83
+ })
84
+ .onSet(async (value) => {
85
+ const cyncMeta = ctx.cync;
86
+ if (!cyncMeta?.deviceId) {
87
+ env.log.warn('Cync: Switch Brightness.set called for %s but no cync.deviceId in context', deviceName);
88
+ return;
89
+ }
90
+ const brightness = Math.max(0, Math.min(100, Number(value)));
91
+ if (!Number.isFinite(brightness)) {
92
+ env.log.warn('Cync: Switch Brightness.set received invalid value=%o for %s (deviceId=%s)', value, deviceName, cyncMeta.deviceId);
93
+ return;
94
+ }
95
+ cyncMeta.brightness = brightness;
96
+ cyncMeta.on = brightness > 0;
97
+ env.log.info('Cync: Switch Brightness.set -> %d for %s (deviceId=%s)', brightness, deviceName, cyncMeta.deviceId);
98
+ try {
99
+ await env.tcpClient.setBrightness(cyncMeta.deviceId, brightness, cyncMeta.deviceType);
100
+ env.markDeviceSeen(cyncMeta.deviceId);
101
+ }
102
+ catch (err) {
103
+ env.log.warn('Cync: Switch Brightness.set failed for %s (deviceId=%s): %s', deviceName, cyncMeta.deviceId, err.message ?? String(err));
104
+ throw new env.api.hap.HapStatusError(-70402 /* env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
105
+ }
106
+ });
107
+ }
63
108
  }
64
109
  //# sourceMappingURL=cync-switch-accessory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cync-switch-accessory.js","sourceRoot":"","sources":["../../src/cync/cync-switch-accessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cync-switch-accessory.js","sourceRoot":"","sources":["../../src/cync/cync-switch-accessory.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,9 @@ const CYNC_FAN_DEVICE_TYPES = new Set([
18
18
  const CYNC_SWITCH_DEVICE_TYPES = new Set([
19
19
  125,
20
20
  ]);
21
+ const CYNC_DIMMABLE_SWITCH_DEVICE_TYPES = new Set([
22
+ 125,
23
+ ]);
21
24
  const CYNC_IGNORED_DEVICE_TYPES = new Set([
22
25
  115,
23
26
  ]);
@@ -82,17 +85,19 @@ export function classifyCyncDevice(device, resolvedDeviceType) {
82
85
  reason: `deviceType: ${deviceType}`,
83
86
  };
84
87
  }
85
- if (deviceType !== undefined && CYNC_OUTLET_DEVICE_TYPES.has(deviceType)) {
88
+ if (deviceType !== undefined && CYNC_SWITCH_DEVICE_TYPES.has(deviceType)) {
86
89
  return {
87
- accessoryType: 'outlet',
90
+ accessoryType: 'switch',
88
91
  deviceType,
89
- capabilities,
92
+ capabilities: CYNC_DIMMABLE_SWITCH_DEVICE_TYPES.has(deviceType)
93
+ ? [...capabilities, 'brightness']
94
+ : capabilities,
90
95
  reason: `deviceType: ${deviceType}`,
91
96
  };
92
97
  }
93
- if (deviceType !== undefined && CYNC_SWITCH_DEVICE_TYPES.has(deviceType)) {
98
+ if (deviceType !== undefined && CYNC_OUTLET_DEVICE_TYPES.has(deviceType)) {
94
99
  return {
95
- accessoryType: 'switch',
100
+ accessoryType: 'outlet',
96
101
  deviceType,
97
102
  capabilities,
98
103
  reason: `deviceType: ${deviceType}`,
@@ -1 +1 @@
1
- {"version":3,"file":"device-classifier.js","sourceRoot":"","sources":["../../src/cync/device-classifier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"device-classifier.js","sourceRoot":"","sources":["../../src/cync/device-classifier.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.4.5",
5
+ "version": "0.4.6",
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",
@@ -12,11 +12,13 @@ export function configureCyncSwitchAccessory(
12
12
  deviceName: string,
13
13
  deviceId: string,
14
14
  ): void {
15
+ const { Characteristic, Service } = env.api.hap;
16
+
15
17
  const service =
16
- accessory.getService(env.api.hap.Service.Switch) ||
17
- accessory.addService(env.api.hap.Service.Switch, deviceName);
18
+ accessory.getService(Service.Switch) ||
19
+ accessory.addService(Service.Switch, deviceName);
18
20
 
19
- const existingLight = accessory.getService(env.api.hap.Service.Lightbulb);
21
+ const existingLight = accessory.getService(Service.Lightbulb);
20
22
  if (existingLight) {
21
23
  env.log.info(
22
24
  'Cync: removing stale Lightbulb service from %s (deviceId=%s) before configuring as Switch',
@@ -26,9 +28,19 @@ export function configureCyncSwitchAccessory(
26
28
  accessory.removeService(existingLight);
27
29
  }
28
30
 
31
+ const deviceRecord = device as unknown as Record<string, unknown>;
32
+
33
+ const deviceType =
34
+ typeof deviceRecord.deviceType === 'number'
35
+ ? deviceRecord.deviceType
36
+ : typeof deviceRecord.type === 'number'
37
+ ? deviceRecord.type
38
+ : undefined;
39
+
40
+ const supportsBrightness = deviceType === 125;
41
+
29
42
  applyAccessoryInformationFromCyncDevice(env.api, accessory, device, deviceName, deviceId);
30
43
 
31
- // Ensure context is initialized
32
44
  const ctx = accessory.context as CyncAccessoryContext;
33
45
  ctx.cync = ctx.cync ?? {
34
46
  meshId: mesh.id,
@@ -37,13 +49,14 @@ export function configureCyncSwitchAccessory(
37
49
  on: false,
38
50
  };
39
51
 
40
- // Remember mapping for LAN updates
52
+ ctx.cync.deviceType = deviceType;
53
+
41
54
  env.registerAccessoryForDevice(deviceId, accessory);
42
55
  env.markDeviceSeen(deviceId);
43
56
  env.startPollingDevice(deviceId);
44
57
 
45
58
  service
46
- .getCharacteristic(env.api.hap.Characteristic.On)
59
+ .getCharacteristic(Characteristic.On)
47
60
  .onGet(() => {
48
61
  const currentOn = !!ctx.cync?.on;
49
62
 
@@ -58,7 +71,7 @@ export function configureCyncSwitchAccessory(
58
71
  }
59
72
 
60
73
  env.log.info(
61
- 'Cync: On.get -> %s for %s (deviceId=%s)',
74
+ 'Cync: Switch On.get -> %s for %s (deviceId=%s)',
62
75
  String(currentOn),
63
76
  deviceName,
64
77
  deviceId,
@@ -86,7 +99,6 @@ export function configureCyncSwitchAccessory(
86
99
  cyncMeta.deviceId,
87
100
  );
88
101
 
89
- // Optimistic cache
90
102
  cyncMeta.on = on;
91
103
 
92
104
  try {
@@ -96,10 +108,26 @@ export function configureCyncSwitchAccessory(
96
108
  return;
97
109
  }
98
110
 
99
- if (cyncMeta.colorActive && cyncMeta.rgb && typeof cyncMeta.brightness === 'number') {
100
- await env.tcpClient.setColor(cyncMeta.deviceId, cyncMeta.rgb, cyncMeta.brightness);
101
- } else {
102
- await env.tcpClient.setSwitchState(cyncMeta.deviceId, { on: true });
111
+ await env.tcpClient.setSwitchState(cyncMeta.deviceId, { on: true });
112
+
113
+ if (
114
+ supportsBrightness &&
115
+ typeof cyncMeta.brightness === 'number' &&
116
+ cyncMeta.brightness > 0 &&
117
+ cyncMeta.brightness < 100
118
+ ) {
119
+ env.log.debug(
120
+ 'Cync: Switch On.set restoring brightness=%d for %s (deviceId=%s)',
121
+ cyncMeta.brightness,
122
+ deviceName,
123
+ cyncMeta.deviceId,
124
+ );
125
+
126
+ await env.tcpClient.setBrightness(
127
+ cyncMeta.deviceId,
128
+ cyncMeta.brightness,
129
+ cyncMeta.deviceType,
130
+ );
103
131
  }
104
132
 
105
133
  env.markDeviceSeen(cyncMeta.deviceId);
@@ -116,4 +144,82 @@ export function configureCyncSwitchAccessory(
116
144
  );
117
145
  }
118
146
  });
147
+
148
+ if (supportsBrightness) {
149
+ service
150
+ .getCharacteristic(Characteristic.Brightness)
151
+ .onGet(() => {
152
+ const current = ctx.cync?.brightness;
153
+
154
+ const cachedBrightness =
155
+ typeof current === 'number'
156
+ ? current
157
+ : (ctx.cync?.on ?? false) ? 100 : 0;
158
+
159
+ if (env.isDeviceProbablyOffline(deviceId)) {
160
+ env.log.debug(
161
+ 'Cync: Switch Brightness.get offline-heuristic hit; returning cached=%d for %s (deviceId=%s)',
162
+ cachedBrightness,
163
+ deviceName,
164
+ deviceId,
165
+ );
166
+ }
167
+
168
+ return cachedBrightness;
169
+ })
170
+ .onSet(async (value) => {
171
+ const cyncMeta = ctx.cync;
172
+
173
+ if (!cyncMeta?.deviceId) {
174
+ env.log.warn(
175
+ 'Cync: Switch Brightness.set called for %s but no cync.deviceId in context',
176
+ deviceName,
177
+ );
178
+ return;
179
+ }
180
+
181
+ const brightness = Math.max(0, Math.min(100, Number(value)));
182
+
183
+ if (!Number.isFinite(brightness)) {
184
+ env.log.warn(
185
+ 'Cync: Switch Brightness.set received invalid value=%o for %s (deviceId=%s)',
186
+ value,
187
+ deviceName,
188
+ cyncMeta.deviceId,
189
+ );
190
+ return;
191
+ }
192
+
193
+ cyncMeta.brightness = brightness;
194
+ cyncMeta.on = brightness > 0;
195
+
196
+ env.log.info(
197
+ 'Cync: Switch Brightness.set -> %d for %s (deviceId=%s)',
198
+ brightness,
199
+ deviceName,
200
+ cyncMeta.deviceId,
201
+ );
202
+
203
+ try {
204
+ await env.tcpClient.setBrightness(
205
+ cyncMeta.deviceId,
206
+ brightness,
207
+ cyncMeta.deviceType,
208
+ );
209
+
210
+ env.markDeviceSeen(cyncMeta.deviceId);
211
+ } catch (err) {
212
+ env.log.warn(
213
+ 'Cync: Switch Brightness.set failed for %s (deviceId=%s): %s',
214
+ deviceName,
215
+ cyncMeta.deviceId,
216
+ (err as Error).message ?? String(err),
217
+ );
218
+
219
+ throw new env.api.hap.HapStatusError(
220
+ env.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
221
+ );
222
+ }
223
+ });
224
+ }
119
225
  }
@@ -40,6 +40,10 @@ const CYNC_SWITCH_DEVICE_TYPES = new Set([
40
40
  125,
41
41
  ]);
42
42
 
43
+ const CYNC_DIMMABLE_SWITCH_DEVICE_TYPES = new Set([
44
+ 125,
45
+ ]);
46
+
43
47
  const CYNC_IGNORED_DEVICE_TYPES = new Set([
44
48
  115,
45
49
  ]);
@@ -120,18 +124,20 @@ export function classifyCyncDevice(
120
124
  };
121
125
  }
122
126
 
123
- if (deviceType !== undefined && CYNC_OUTLET_DEVICE_TYPES.has(deviceType)) {
127
+ if (deviceType !== undefined && CYNC_SWITCH_DEVICE_TYPES.has(deviceType)) {
124
128
  return {
125
- accessoryType: 'outlet',
129
+ accessoryType: 'switch',
126
130
  deviceType,
127
- capabilities,
131
+ capabilities: CYNC_DIMMABLE_SWITCH_DEVICE_TYPES.has(deviceType)
132
+ ? [...capabilities, 'brightness']
133
+ : capabilities,
128
134
  reason: `deviceType: ${deviceType}`,
129
135
  };
130
136
  }
131
137
 
132
- if (deviceType !== undefined && CYNC_SWITCH_DEVICE_TYPES.has(deviceType)) {
138
+ if (deviceType !== undefined && CYNC_OUTLET_DEVICE_TYPES.has(deviceType)) {
133
139
  return {
134
- accessoryType: 'switch',
140
+ accessoryType: 'outlet',
135
141
  deviceType,
136
142
  capabilities,
137
143
  reason: `deviceType: ${deviceType}`,