@homebridge-plugins/homebridge-ewelink 12.18.4-beta.0 → 12.19.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/CHANGELOG.md +2 -1
- package/lib/device/outlet-multi.js +16 -8
- package/lib/device/switch-multi.js +16 -8
- package/lib/utils/functions.js +25 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@homebridge-plugins/homebridge-ewelink` will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## v12.
|
|
5
|
+
## v12.19.0 (2026-10-18)
|
|
6
6
|
|
|
7
7
|
### Changed
|
|
8
8
|
|
|
9
9
|
- feat(zigbee): add the snzb-03pr2 presence sensor, with occupancy and light level
|
|
10
10
|
- feat(zigbee): add the snzb-09p indoor siren, as a switch that sounds the alarm
|
|
11
11
|
- chore(deps): dependency updates
|
|
12
|
+
- fix: match multi-channel updates by outlet, so a partial update changes the right channel (#804)
|
|
12
13
|
|
|
13
14
|
## v12.18.3 (2026-08-11)
|
|
14
15
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import platformConsts from '../utils/constants.js'
|
|
2
|
-
import { hasProperty, sleep } from '../utils/functions.js'
|
|
2
|
+
import { hasProperty, sleep, switchForChannel } from '../utils/functions.js'
|
|
3
3
|
|
|
4
4
|
export default class {
|
|
5
5
|
constructor(platform, accessory, devicesInHB) {
|
|
@@ -327,10 +327,13 @@ export default class {
|
|
|
327
327
|
if (this.devicesInHB.has(uuid)) {
|
|
328
328
|
const subAccessory = this.devicesInHB.get(uuid)
|
|
329
329
|
const service = subAccessory.getService(this.hapServ.Outlet)
|
|
330
|
-
|
|
330
|
+
// By `outlet` where the device gives it - a partial update holds only
|
|
331
|
+
// the channel that changed, at position 0 (#804)
|
|
332
|
+
const channelEntry = switchForChannel(params.switches, i - 1)
|
|
333
|
+
if (channelEntry) {
|
|
331
334
|
const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
|
|
332
335
|
if (subAccessory.context.isInched) {
|
|
333
|
-
if (
|
|
336
|
+
if (channelEntry.switch === 'on' && !subAccessory.context.ignoreUpdates) {
|
|
334
337
|
subAccessory.context.ignoreUpdates = true
|
|
335
338
|
setTimeout(() => {
|
|
336
339
|
subAccessory.context.ignoreUpdates = false
|
|
@@ -349,28 +352,33 @@ export default class {
|
|
|
349
352
|
}
|
|
350
353
|
}
|
|
351
354
|
} else {
|
|
352
|
-
if (
|
|
355
|
+
if (channelEntry.switch === 'on') {
|
|
353
356
|
primaryState = true
|
|
354
357
|
}
|
|
355
|
-
if (!params.updateSource ||
|
|
358
|
+
if (!params.updateSource || channelEntry.switch !== currentState) {
|
|
356
359
|
service.updateCharacteristic(
|
|
357
360
|
this.hapChar.On,
|
|
358
|
-
|
|
361
|
+
channelEntry.switch === 'on',
|
|
359
362
|
)
|
|
360
363
|
subAccessory.eveService.addEntry({
|
|
361
|
-
status:
|
|
364
|
+
status: channelEntry.switch === 'on' ? 1 : 0,
|
|
362
365
|
})
|
|
363
366
|
if (params.updateSource && this.enableLogging) {
|
|
364
367
|
this.log(
|
|
365
368
|
'[%s] %s [%s].',
|
|
366
369
|
subAccessory.displayName,
|
|
367
370
|
this.lang.curState,
|
|
368
|
-
|
|
371
|
+
channelEntry.switch,
|
|
369
372
|
)
|
|
370
373
|
}
|
|
371
374
|
}
|
|
372
375
|
}
|
|
373
376
|
}
|
|
377
|
+
// The master tile is on when ANY channel is on, so it has to read every
|
|
378
|
+
// channel's resulting state - a partial update names only one (#804)
|
|
379
|
+
if (service.getCharacteristic(this.hapChar.On).value) {
|
|
380
|
+
primaryState = true
|
|
381
|
+
}
|
|
374
382
|
if (this.powerReadings) {
|
|
375
383
|
let logger = false
|
|
376
384
|
let power
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import platformConsts from '../utils/constants.js'
|
|
2
|
-
import { hasProperty, sleep } from '../utils/functions.js'
|
|
2
|
+
import { hasProperty, sleep, switchForChannel } from '../utils/functions.js'
|
|
3
3
|
|
|
4
4
|
export default class {
|
|
5
5
|
constructor(platform, accessory, devicesInHB) {
|
|
@@ -322,10 +322,13 @@ export default class {
|
|
|
322
322
|
if (this.devicesInHB.has(uuid)) {
|
|
323
323
|
const subAccessory = this.devicesInHB.get(uuid)
|
|
324
324
|
const service = subAccessory.getService(this.hapServ.Switch)
|
|
325
|
-
|
|
325
|
+
// By `outlet` where the device gives it - a partial update holds only
|
|
326
|
+
// the channel that changed, at position 0 (#804)
|
|
327
|
+
const channelEntry = switchForChannel(params.switches, i - 1)
|
|
328
|
+
if (channelEntry) {
|
|
326
329
|
const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
|
|
327
330
|
if (subAccessory.context.isInched) {
|
|
328
|
-
if (
|
|
331
|
+
if (channelEntry.switch === 'on' && !subAccessory.context.ignoreUpdates) {
|
|
329
332
|
subAccessory.context.ignoreUpdates = true
|
|
330
333
|
setTimeout(() => {
|
|
331
334
|
subAccessory.context.ignoreUpdates = false
|
|
@@ -344,28 +347,33 @@ export default class {
|
|
|
344
347
|
}
|
|
345
348
|
}
|
|
346
349
|
} else {
|
|
347
|
-
if (
|
|
350
|
+
if (channelEntry.switch === 'on') {
|
|
348
351
|
primaryState = true
|
|
349
352
|
}
|
|
350
|
-
if (!params.updateSource ||
|
|
353
|
+
if (!params.updateSource || channelEntry.switch !== currentState) {
|
|
351
354
|
service.updateCharacteristic(
|
|
352
355
|
this.hapChar.On,
|
|
353
|
-
|
|
356
|
+
channelEntry.switch === 'on',
|
|
354
357
|
)
|
|
355
358
|
subAccessory.eveService.addEntry({
|
|
356
|
-
status:
|
|
359
|
+
status: channelEntry.switch === 'on' ? 1 : 0,
|
|
357
360
|
})
|
|
358
361
|
if (params.updateSource && this.enableLogging) {
|
|
359
362
|
this.log(
|
|
360
363
|
'[%s] %s [%s].',
|
|
361
364
|
subAccessory.displayName,
|
|
362
365
|
this.lang.curState,
|
|
363
|
-
|
|
366
|
+
channelEntry.switch,
|
|
364
367
|
)
|
|
365
368
|
}
|
|
366
369
|
}
|
|
367
370
|
}
|
|
368
371
|
}
|
|
372
|
+
// The master tile is on when ANY channel is on, so it has to read every
|
|
373
|
+
// channel's resulting state - a partial update names only one (#804)
|
|
374
|
+
if (service.getCharacteristic(this.hapChar.On).value) {
|
|
375
|
+
primaryState = true
|
|
376
|
+
}
|
|
369
377
|
if (this.powerReadings) {
|
|
370
378
|
let logger = false
|
|
371
379
|
let power
|
package/lib/utils/functions.js
CHANGED
|
@@ -24,6 +24,30 @@ function parseError(err, hideStack = []) {
|
|
|
24
24
|
return toReturn
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The entry for one channel in a device's `switches` array.
|
|
29
|
+
*
|
|
30
|
+
* A full report lists every channel in order, so position used to be enough.
|
|
31
|
+
* But some devices (SmartWise two-channel switches, for one) send a partial
|
|
32
|
+
* update holding only the channel that changed - always at position 0, with
|
|
33
|
+
* its real channel in `outlet`. Reading by position then applied channel 2's
|
|
34
|
+
* change to channel 1 (#804). When the entries carry `outlet`, match on it;
|
|
35
|
+
* only a list without `outlet` numbers falls back to position.
|
|
36
|
+
*
|
|
37
|
+
* @param {Array<{outlet?: number, switch: string}>} switches the reported array
|
|
38
|
+
* @param {number} index the zero-based channel wanted
|
|
39
|
+
* @returns {{outlet?: number, switch: string}|undefined} that channel's entry
|
|
40
|
+
*/
|
|
41
|
+
function switchForChannel(switches, index) {
|
|
42
|
+
if (!Array.isArray(switches)) {
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
if (switches.some(entry => typeof entry?.outlet === 'number')) {
|
|
46
|
+
return switches.find(entry => entry?.outlet === index)
|
|
47
|
+
}
|
|
48
|
+
return switches[index]
|
|
49
|
+
}
|
|
50
|
+
|
|
27
51
|
function sleep(ms) {
|
|
28
52
|
return new Promise((resolve) => {
|
|
29
53
|
setTimeout(resolve, ms)
|
|
@@ -36,4 +60,5 @@ export {
|
|
|
36
60
|
parseDeviceId,
|
|
37
61
|
parseError,
|
|
38
62
|
sleep,
|
|
63
|
+
switchForChannel,
|
|
39
64
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"displayName": "Homebridge eWeLink",
|
|
4
4
|
"alias": "eWeLink",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "12.
|
|
6
|
+
"version": "12.19.0",
|
|
7
7
|
"description": "Homebridge plugin to integrate eWeLink devices into HomeKit.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "bwp91",
|
|
@@ -69,13 +69,13 @@
|
|
|
69
69
|
"@homebridge/plugin-ui-utils": "^2.2.6",
|
|
70
70
|
"axios": "^1.20.0",
|
|
71
71
|
"node-persist": "^4.0.4",
|
|
72
|
-
"p-queue": "^
|
|
72
|
+
"p-queue": "^10.0.0",
|
|
73
73
|
"websocket-as-promised": "^3.0.1",
|
|
74
|
-
"ws": "^8.
|
|
74
|
+
"ws": "^8.22.0"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@antfu/eslint-config": "^9.
|
|
78
|
-
"@vitest/coverage-v8": "^
|
|
79
|
-
"vitest": "^
|
|
77
|
+
"@antfu/eslint-config": "^9.5.1",
|
|
78
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
79
|
+
"vitest": "^5.0.5"
|
|
80
80
|
}
|
|
81
81
|
}
|