@homebridge-plugins/homebridge-ewelink 12.18.3 → 12.18.4-beta.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.
- package/CHANGELOG.md +9 -0
- package/lib/device/outlet-multi.js +16 -8
- package/lib/device/switch-multi.js +16 -8
- package/lib/device/zigbee/index.js +2 -0
- package/lib/device/zigbee/sensor-occupancy.js +22 -9
- package/lib/device/zigbee/siren.js +132 -0
- package/lib/homebridge-ui/server.js +1 -0
- package/lib/platform.js +10 -0
- package/lib/utils/constants.js +4 -1
- package/lib/utils/functions.js +25 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@homebridge-plugins/homebridge-ewelink` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## v12.18.4 (Pending Release)
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- feat(zigbee): add the snzb-03pr2 presence sensor, with occupancy and light level
|
|
10
|
+
- feat(zigbee): add the snzb-09p indoor siren, as a switch that sounds the alarm
|
|
11
|
+
- chore(deps): dependency updates
|
|
12
|
+
- fix: match multi-channel updates by outlet, so a partial update changes the right channel (#804)
|
|
13
|
+
|
|
5
14
|
## v12.18.3 (2026-08-11)
|
|
6
15
|
|
|
7
16
|
### Changed
|
|
@@ -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
|
|
@@ -8,6 +8,7 @@ import deviceSensorLeak from './sensor-leak.js'
|
|
|
8
8
|
import deviceSensorMotion from './sensor-motion.js'
|
|
9
9
|
import deviceSensorOccupancy from './sensor-occupancy.js'
|
|
10
10
|
import deviceSensorSmoke from './sensor-smoke.js'
|
|
11
|
+
import deviceSiren from './siren.js'
|
|
11
12
|
import deviceSwitchStateless from './switch-stateless.js'
|
|
12
13
|
import deviceThermostat from './thermostat.js'
|
|
13
14
|
import deviceZigbeeWaterValve from './zigbee-water-valve.js'
|
|
@@ -23,6 +24,7 @@ export default {
|
|
|
23
24
|
deviceSensorMotion,
|
|
24
25
|
deviceSensorOccupancy,
|
|
25
26
|
deviceSensorSmoke,
|
|
27
|
+
deviceSiren,
|
|
26
28
|
deviceSwitchStateless,
|
|
27
29
|
deviceThermostat,
|
|
28
30
|
deviceZigbeeWaterValve,
|
|
@@ -53,8 +53,9 @@ export default class {
|
|
|
53
53
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
54
54
|
|| this.accessory.addService(this.hapServ.Battery)
|
|
55
55
|
|
|
56
|
-
// SNZB-06P
|
|
57
|
-
|
|
56
|
+
// SNZB-06P (uiid 7016) also reports a binary bright/dark light level, and
|
|
57
|
+
// SNZB-03PR2 (uiid 7055) a numeric illumination reading
|
|
58
|
+
if ([7016, 7055].includes(accessory.context.eweUIID)) {
|
|
58
59
|
this.lightService = this.accessory.getService(this.hapServ.LightSensor)
|
|
59
60
|
|| this.accessory.addService(this.hapServ.LightSensor)
|
|
60
61
|
} else if (this.accessory.getService(this.hapServ.LightSensor)) {
|
|
@@ -90,6 +91,18 @@ export default class {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
}
|
|
94
|
+
if (this.lightService && hasProperty(params, 'illumination')) {
|
|
95
|
+
// Some models report a numeric light reading instead of a binary one.
|
|
96
|
+
// HomeKit accepts 0.0001 to 100000 lux, so keep it inside that
|
|
97
|
+
const newLux = Math.max(Math.min(Number(params.illumination), 100000), 0.0001)
|
|
98
|
+
if (Number.isFinite(newLux) && newLux !== this.cacheLux) {
|
|
99
|
+
this.cacheLux = newLux
|
|
100
|
+
this.lightService.updateCharacteristic(this.hapChar.CurrentAmbientLightLevel, this.cacheLux)
|
|
101
|
+
if (params.updateSource && this.enableLogging) {
|
|
102
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curLightLevel, this.cacheLux)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
93
106
|
if (hasProperty(params, 'battery') && params.battery !== this.cacheBatt) {
|
|
94
107
|
this.cacheBatt = params.battery
|
|
95
108
|
this.cacheBattScaled = Math.max(Math.min(this.cacheBatt, 100), 0)
|
|
@@ -102,17 +115,17 @@ export default class {
|
|
|
102
115
|
this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
|
|
103
116
|
}
|
|
104
117
|
}
|
|
105
|
-
if (
|
|
106
|
-
hasProperty(params, 'human')
|
|
107
|
-
&& hasProperty(params, 'trigTime')
|
|
108
|
-
&& params.human !== this.cacheState
|
|
109
|
-
) {
|
|
118
|
+
if (hasProperty(params, 'human') && params.human !== this.cacheState) {
|
|
110
119
|
this.cacheState = params.human
|
|
111
|
-
|
|
120
|
+
// A report that carries a timestamp can be checked for staleness; the
|
|
121
|
+
// models that report live state without one are taken at face value
|
|
122
|
+
const isFresh = hasProperty(params, 'trigTime')
|
|
123
|
+
? (Date.now() - params.trigTime) / 1000 < this.sensorTimeDifference
|
|
124
|
+
: true
|
|
112
125
|
const occupancyDetected = !!(
|
|
113
126
|
params.updateSource
|
|
114
127
|
&& params.human === 1
|
|
115
|
-
&&
|
|
128
|
+
&& isFresh
|
|
116
129
|
)
|
|
117
130
|
this.service.updateCharacteristic(this.hapChar.OccupancyDetected, occupancyDetected)
|
|
118
131
|
if (occupancyDetected) {
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { hasProperty } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
// How long the HomeKit tile stays on after a trigger. The device runs its
|
|
5
|
+
// siren for whatever duration is configured in the eWeLink app and turns
|
|
6
|
+
// itself off without reporting that it has, so the tile resets itself rather
|
|
7
|
+
// than waiting for a state that never arrives.
|
|
8
|
+
const TILE_RESET_MS = 3000
|
|
9
|
+
|
|
10
|
+
export default class {
|
|
11
|
+
constructor(platform, accessory) {
|
|
12
|
+
// Set up variables from the platform
|
|
13
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
14
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
15
|
+
this.hapServ = platform.api.hap.Service
|
|
16
|
+
this.lang = platform.lang
|
|
17
|
+
this.log = platform.log
|
|
18
|
+
this.platform = platform
|
|
19
|
+
|
|
20
|
+
// Set up variables from the accessory
|
|
21
|
+
this.name = accessory.displayName
|
|
22
|
+
this.accessory = accessory
|
|
23
|
+
|
|
24
|
+
// Set up custom variables for this device type
|
|
25
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
26
|
+
this.lowBattThreshold = deviceConf.lowBattThreshold
|
|
27
|
+
? Math.min(deviceConf.lowBattThreshold, 100)
|
|
28
|
+
: platformConsts.defaultValues.lowBattThreshold
|
|
29
|
+
|
|
30
|
+
// Set the correct logging variables for this accessory
|
|
31
|
+
switch (deviceConf.overrideLogging) {
|
|
32
|
+
case 'standard':
|
|
33
|
+
this.enableLogging = true
|
|
34
|
+
this.enableDebugLogging = false
|
|
35
|
+
break
|
|
36
|
+
case 'debug':
|
|
37
|
+
this.enableLogging = true
|
|
38
|
+
this.enableDebugLogging = true
|
|
39
|
+
break
|
|
40
|
+
case 'disable':
|
|
41
|
+
this.enableLogging = false
|
|
42
|
+
this.enableDebugLogging = false
|
|
43
|
+
break
|
|
44
|
+
default:
|
|
45
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
46
|
+
this.enableDebugLogging = false
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Add the switch service if it doesn't already exist
|
|
51
|
+
this.service = this.accessory.getService(this.hapServ.Switch)
|
|
52
|
+
|| this.accessory.addService(this.hapServ.Switch)
|
|
53
|
+
this.service.updateCharacteristic(this.hapChar.On, false)
|
|
54
|
+
|
|
55
|
+
// Add the battery service if it doesn't already exist
|
|
56
|
+
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
57
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
58
|
+
|
|
59
|
+
// Set up the handler for the switch
|
|
60
|
+
this.service.getCharacteristic(this.hapChar.On).onSet(async (value) => {
|
|
61
|
+
try {
|
|
62
|
+
if (!value) {
|
|
63
|
+
// The device stops on its own after its configured duration and
|
|
64
|
+
// offers no early-stop command, so an off is only the tile resetting
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// The trigger rides on the device's own alarm settings, so send the
|
|
69
|
+
// last reported settings back with the trigger flag added - a bare
|
|
70
|
+
// flag could otherwise reset the volume and duration to defaults
|
|
71
|
+
const setting = { ...(this.accessory.context.cacheAlarmSetting || {}), test: true }
|
|
72
|
+
await this.platform.sendDeviceUpdate(this.accessory, { alarmSetting: setting })
|
|
73
|
+
|
|
74
|
+
if (this.enableLogging) {
|
|
75
|
+
this.log('[%s] %s [on].', this.name, this.lang.curState)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Reset the tile shortly after - see TILE_RESET_MS
|
|
79
|
+
clearTimeout(this.resetTimer)
|
|
80
|
+
this.resetTimer = setTimeout(() => {
|
|
81
|
+
this.service.updateCharacteristic(this.hapChar.On, false)
|
|
82
|
+
}, TILE_RESET_MS)
|
|
83
|
+
} catch (err) {
|
|
84
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
this.service.updateCharacteristic(this.hapChar.On, false)
|
|
87
|
+
}, 2000)
|
|
88
|
+
throw new this.hapErr(-70402)
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// Output the customised options to the log
|
|
93
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
94
|
+
const opts = JSON.stringify({
|
|
95
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
96
|
+
lowBattThreshold: this.lowBattThreshold,
|
|
97
|
+
})
|
|
98
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async externalUpdate(params) {
|
|
102
|
+
try {
|
|
103
|
+
// Keep the device's own alarm settings so a trigger can send them back
|
|
104
|
+
if (hasProperty(params, 'alarmSetting') && typeof params.alarmSetting === 'object') {
|
|
105
|
+
this.accessory.context.cacheAlarmSetting = { ...params.alarmSetting }
|
|
106
|
+
delete this.accessory.context.cacheAlarmSetting.test
|
|
107
|
+
}
|
|
108
|
+
if (hasProperty(params, 'battery') && params.battery !== this.cacheBatt) {
|
|
109
|
+
this.cacheBatt = params.battery
|
|
110
|
+
this.cacheBattScaled = Math.max(Math.min(this.cacheBatt, 100), 0)
|
|
111
|
+
this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
|
|
112
|
+
this.battService.updateCharacteristic(
|
|
113
|
+
this.hapChar.StatusLowBattery,
|
|
114
|
+
this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
|
|
115
|
+
)
|
|
116
|
+
if (params.updateSource && this.enableLogging) {
|
|
117
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
destroy() {
|
|
126
|
+
clearTimeout(this.resetTimer)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
markStatus(isOnline) {
|
|
130
|
+
this.isOnline = isOnline
|
|
131
|
+
}
|
|
132
|
+
}
|
package/lib/platform.js
CHANGED
|
@@ -1729,6 +1729,16 @@ export default class {
|
|
|
1729
1729
|
this.applyAccessoryLogging(accessory)
|
|
1730
1730
|
accessory.control = new deviceTypes.zb.deviceSensorSmoke(this, accessory)
|
|
1731
1731
|
/** */
|
|
1732
|
+
} else if (platformConsts.devices.zbSiren.includes(uiid)) {
|
|
1733
|
+
/**
|
|
1734
|
+
**************
|
|
1735
|
+
ZB SIREN
|
|
1736
|
+
***************
|
|
1737
|
+
*/
|
|
1738
|
+
accessory = devicesInHB.get(uuid) || this.addAccessory(device, `${device.deviceid}SWX`)
|
|
1739
|
+
this.applyAccessoryLogging(accessory)
|
|
1740
|
+
accessory.control = new deviceTypes.zb.deviceSiren(this, accessory)
|
|
1741
|
+
/** */
|
|
1732
1742
|
} else if (platformConsts.devices.zbThermostat.includes(uiid)) {
|
|
1733
1743
|
/**
|
|
1734
1744
|
*******************
|
package/lib/utils/constants.js
CHANGED
|
@@ -377,10 +377,11 @@ export default {
|
|
|
377
377
|
zbMotor: [1514, 7006, 7034],
|
|
378
378
|
zbSensorAmbient: [242, 1770, 1771, 7014, 7033, 7038],
|
|
379
379
|
zbSensorMotion: [2026, 7002],
|
|
380
|
-
zbSensorOccupancy: [7016],
|
|
380
|
+
zbSensorOccupancy: [7016, 7055],
|
|
381
381
|
zbSensorContact: [3026, 7003],
|
|
382
382
|
zbSensorWater: [4026, 7019],
|
|
383
383
|
zbSensorSmoke: [5026],
|
|
384
|
+
zbSiren: [7056],
|
|
384
385
|
zbThermostat: [7017],
|
|
385
386
|
zbWaterValve: [7027, 7047],
|
|
386
387
|
group: [5000],
|
|
@@ -604,6 +605,8 @@ export default {
|
|
|
604
605
|
7038: 1, // SONOFF AirGuard TH Zigbee temperature and humidity sensor (#767)
|
|
605
606
|
7040: 2, // SONOFF MINI DUO 2-gang Zigbee switch (#768)
|
|
606
607
|
7047: 1, // SONOFF Zigbee Irrigation Valve (#778)
|
|
608
|
+
7055: 1, // SNZB-03PR2 Zigbee presence sensor with light level
|
|
609
|
+
7056: 1, // SNZB-09P Zigbee indoor siren
|
|
607
610
|
20001: 1, // iHost sub-device single switch
|
|
608
611
|
20004: 4, // iHost sub-device 4-channel switch
|
|
609
612
|
20006: 1, // single-colour dimmable LED controller (#780)
|
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.18.
|
|
6
|
+
"version": "12.18.4-beta.1",
|
|
7
7
|
"description": "Homebridge plugin to integrate eWeLink devices into HomeKit.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "bwp91",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"changelog:sync": "node .github/scripts/sync-changelog.mjs"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@homebridge/plugin-ui-utils": "^2.2.
|
|
70
|
-
"axios": "^1.
|
|
69
|
+
"@homebridge/plugin-ui-utils": "^2.2.6",
|
|
70
|
+
"axios": "^1.20.0",
|
|
71
71
|
"node-persist": "^4.0.4",
|
|
72
72
|
"p-queue": "^9.3.3",
|
|
73
73
|
"websocket-as-promised": "^3.0.1",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@antfu/eslint-config": "^9.3.0",
|
|
78
|
-
"@vitest/coverage-v8": "^4.1.
|
|
79
|
-
"vitest": "^4.1.
|
|
78
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
79
|
+
"vitest": "^4.1.11"
|
|
80
80
|
}
|
|
81
81
|
}
|