@homebridge-plugins/homebridge-ewelink 12.3.3 → 12.4.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 +21 -0
- package/LICENSE +1 -1
- package/README.md +1 -1
- package/eslint.config.js +36 -1
- package/lib/connection/http.js +2 -0
- package/lib/connection/lan.js +2 -0
- package/lib/connection/ws.js +6 -5
- package/lib/device/diffuser.js +2 -2
- package/lib/device/fan.js +1 -1
- package/lib/device/group.js +1 -1
- package/lib/device/index.js +3 -3
- package/lib/device/light-cct.js +1 -1
- package/lib/device/light-dimmer.js +1 -1
- package/lib/device/light-rgb-cct.js +1 -1
- package/lib/device/light-rgb.js +1 -1
- package/lib/device/outlet-multi.js +2 -2
- package/lib/device/outlet-single-inched.js +1 -1
- package/lib/device/outlet-single.js +1 -1
- package/lib/device/panel.js +3 -3
- package/lib/device/rf-bridge.js +1 -0
- package/lib/device/sensor-ambient.js +3 -3
- package/lib/device/sensor-contact.js +1 -1
- package/lib/device/sensor-temp-humi.js +2 -2
- package/lib/device/simulation/cooler.js +2 -2
- package/lib/device/simulation/doorbell.js +1 -1
- package/lib/device/simulation/heater.js +2 -2
- package/lib/device/simulation/index.js +1 -1
- package/lib/device/simulation/light-fan.js +1 -1
- package/lib/device/simulation/lock-eachen.js +1 -1
- package/lib/device/simulation/lock-one.js +1 -1
- package/lib/device/simulation/p-button.js +1 -1
- package/lib/device/simulation/purifier.js +1 -1
- package/lib/device/simulation/sensor-leak.js +1 -1
- package/lib/device/simulation/sensor-visible.js +1 -1
- package/lib/device/simulation/switch-valve.js +1 -1
- package/lib/device/simulation/th-cooler.js +3 -3
- package/lib/device/simulation/th-dehumidifier.js +3 -3
- package/lib/device/simulation/th-heater.js +3 -3
- package/lib/device/simulation/th-humidifier.js +3 -3
- package/lib/device/simulation/th-thermostat.js +1 -1
- package/lib/device/simulation/tv.js +1 -1
- package/lib/device/switch-mate.js +1 -1
- package/lib/device/switch-multi.js +1 -1
- package/lib/device/switch-single-inched.js +1 -1
- package/lib/device/switch-single.js +1 -1
- package/lib/device/thermostat.js +1 -1
- package/lib/device/zigbee/index.js +2 -0
- package/lib/device/zigbee/light-cct.js +1 -1
- package/lib/device/zigbee/light-dimmer.js +1 -1
- package/lib/device/zigbee/light-rgb-cct.js +1 -1
- package/lib/device/zigbee/motor.js +1 -1
- package/lib/device/zigbee/sensor-ambient.js +3 -3
- package/lib/device/zigbee/sensor-contact.js +1 -1
- package/lib/device/zigbee/sensor-leak.js +1 -1
- package/lib/device/zigbee/sensor-motion.js +1 -1
- package/lib/device/zigbee/sensor-occupancy.js +1 -1
- package/lib/device/zigbee/sensor-smoke.js +2 -2
- package/lib/device/zigbee/switch-stateless.js +2 -2
- package/lib/device/zigbee/thermostat.js +1 -1
- package/lib/device/zigbee/zigbee-water-valve.js +195 -0
- package/lib/fakegato/fakegato-history.js +5 -4
- package/lib/homebridge-ui/public/index.html +4 -0
- package/lib/homebridge-ui/server.js +1 -0
- package/lib/index.js +1 -0
- package/lib/node-dns-sd/lib/dns-sd-composer.js +1 -1
- package/lib/node-dns-sd/lib/dns-sd-parser.js +1 -1
- package/lib/node-dns-sd/lib/dns-sd.js +2 -1
- package/lib/platform.js +31 -21
- package/lib/utils/constants.js +5 -1
- package/lib/utils/custom-chars.js +2 -2
- package/lib/utils/eve-chars.js +9 -9
- package/package.json +9 -9
|
@@ -43,7 +43,7 @@ export default class {
|
|
|
43
43
|
|
|
44
44
|
// Add the stateless switch service if it doesn't already exist
|
|
45
45
|
this.service = this.accessory.getService(this.hapServ.StatelessProgrammableSwitch)
|
|
46
|
-
|
|
46
|
+
|| this.accessory.addService(this.hapServ.StatelessProgrammableSwitch)
|
|
47
47
|
|
|
48
48
|
// Output the customised options to the log
|
|
49
49
|
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
@@ -61,7 +61,7 @@ export default class {
|
|
|
61
61
|
|
|
62
62
|
// Add the switch service if it doesn't already exist
|
|
63
63
|
this.service = this.accessory.getService(this.hapServ.Switch)
|
|
64
|
-
|
|
64
|
+
|| this.accessory.addService(this.hapServ.Switch)
|
|
65
65
|
|
|
66
66
|
if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
|
|
67
67
|
// Add Eve power characteristics
|
|
@@ -59,7 +59,7 @@ export default class {
|
|
|
59
59
|
|
|
60
60
|
// Add the switch service if it doesn't already exist
|
|
61
61
|
this.service = this.accessory.getService(this.hapServ.Switch)
|
|
62
|
-
|
|
62
|
+
|| this.accessory.addService(this.hapServ.Switch)
|
|
63
63
|
|
|
64
64
|
switch (this.accessory.context.eweUIID) {
|
|
65
65
|
case 5:
|
|
@@ -58,7 +58,7 @@ export default class {
|
|
|
58
58
|
|
|
59
59
|
// Add the switch service if it doesn't already exist
|
|
60
60
|
this.service = this.accessory.getService(this.hapServ.Switch)
|
|
61
|
-
|
|
61
|
+
|| this.accessory.addService(this.hapServ.Switch)
|
|
62
62
|
|
|
63
63
|
// Some models provide a power reading in different decimals
|
|
64
64
|
this.divisor = 1
|
package/lib/device/thermostat.js
CHANGED
|
@@ -67,7 +67,7 @@ export default class {
|
|
|
67
67
|
|
|
68
68
|
// Add the thermostat service if it doesn't already exist
|
|
69
69
|
this.service = this.accessory.getService(this.hapServ.Thermostat)
|
|
70
|
-
|
|
70
|
+
|| this.accessory.addService(this.hapServ.Thermostat)
|
|
71
71
|
|
|
72
72
|
// Set custom properties of the current temperature characteristic
|
|
73
73
|
this.service.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
|
|
@@ -10,6 +10,7 @@ import deviceSensorOccupancy from './sensor-occupancy.js'
|
|
|
10
10
|
import deviceSensorSmoke from './sensor-smoke.js'
|
|
11
11
|
import deviceSwitchStateless from './switch-stateless.js'
|
|
12
12
|
import deviceThermostat from './thermostat.js'
|
|
13
|
+
import deviceZigbeeWaterValve from './zigbee-water-valve.js'
|
|
13
14
|
|
|
14
15
|
export default {
|
|
15
16
|
deviceLightCCT,
|
|
@@ -24,4 +25,5 @@ export default {
|
|
|
24
25
|
deviceSensorSmoke,
|
|
25
26
|
deviceSwitchStateless,
|
|
26
27
|
deviceThermostat,
|
|
28
|
+
deviceZigbeeWaterValve,
|
|
27
29
|
}
|
|
@@ -48,7 +48,7 @@ export default class {
|
|
|
48
48
|
|
|
49
49
|
// Add the lightbulb service if it doesn't already exist
|
|
50
50
|
this.service = this.accessory.getService(this.hapServ.Lightbulb)
|
|
51
|
-
|
|
51
|
+
|| this.accessory.addService(this.hapServ.Lightbulb)
|
|
52
52
|
|
|
53
53
|
// If adaptive lighting has just been disabled then remove and re-add service to hide AL icon
|
|
54
54
|
if (this.alShift === -1 && this.accessory.context.adaptiveLighting) {
|
|
@@ -43,7 +43,7 @@ export default class {
|
|
|
43
43
|
|
|
44
44
|
// Add the lightbulb service if it doesn't already exist
|
|
45
45
|
this.service = this.accessory.getService(this.hapServ.Lightbulb)
|
|
46
|
-
|
|
46
|
+
|| this.accessory.addService(this.hapServ.Lightbulb)
|
|
47
47
|
|
|
48
48
|
// Add the get/set handler to the lightbulb on/off characteristic
|
|
49
49
|
this.service
|
|
@@ -48,7 +48,7 @@ export default class {
|
|
|
48
48
|
|
|
49
49
|
// Add the lightbulb service if it doesn't already exist
|
|
50
50
|
this.service = this.accessory.getService(this.hapServ.Lightbulb)
|
|
51
|
-
|
|
51
|
+
|| this.accessory.addService(this.hapServ.Lightbulb)
|
|
52
52
|
|
|
53
53
|
// If adaptive lighting has just been disabled then remove and re-add service to hide AL icon
|
|
54
54
|
if (this.alShift === -1 && this.accessory.context.adaptiveLighting) {
|
|
@@ -48,7 +48,7 @@ export default class {
|
|
|
48
48
|
|
|
49
49
|
// Add the battery service if it doesn't already exist
|
|
50
50
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
51
|
-
|
|
51
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
52
52
|
this.cacheBatt = this.battService.getCharacteristic(this.hapChar.BatteryLevel).value
|
|
53
53
|
|
|
54
54
|
// Add the window covering service if it doesn't already exist
|
|
@@ -48,7 +48,7 @@ export default class {
|
|
|
48
48
|
|
|
49
49
|
// Add the temperature sensor service if it doesn't already exist
|
|
50
50
|
this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor)
|
|
51
|
-
|
|
51
|
+
|| this.accessory.addService(this.hapServ.TemperatureSensor)
|
|
52
52
|
|
|
53
53
|
// Add options to the current temperature characteristic
|
|
54
54
|
this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
|
|
@@ -59,11 +59,11 @@ export default class {
|
|
|
59
59
|
|
|
60
60
|
// Add the humidity sensor service if it doesn't already exist
|
|
61
61
|
this.humiService = this.accessory.getService(this.hapServ.HumiditySensor)
|
|
62
|
-
|
|
62
|
+
|| this.accessory.addService(this.hapServ.HumiditySensor)
|
|
63
63
|
|
|
64
64
|
// Add the battery service if it doesn't already exist
|
|
65
65
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
66
|
-
|
|
66
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
67
67
|
|
|
68
68
|
// Pass the accessory to Fakegato to set up with Eve
|
|
69
69
|
this.accessory.eveService = new platform.eveService('weather', this.accessory, {
|
|
@@ -60,7 +60,7 @@ export default class {
|
|
|
60
60
|
|
|
61
61
|
// Add the battery service if it doesn't already exist
|
|
62
62
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
63
|
-
|
|
63
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
64
64
|
|
|
65
65
|
// Pass the accessory to Fakegato to set up with Eve
|
|
66
66
|
this.accessory.eveService = new platform.eveService('door', this.accessory, {
|
|
@@ -51,7 +51,7 @@ export default class {
|
|
|
51
51
|
|
|
52
52
|
// Add the battery service if it doesn't already exist
|
|
53
53
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
54
|
-
|
|
54
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
55
55
|
|
|
56
56
|
// Pass the accessory to Fakegato to set up with Eve
|
|
57
57
|
this.accessory.eveService = new platform.eveService('motion', this.accessory, {
|
|
@@ -51,7 +51,7 @@ export default class {
|
|
|
51
51
|
|
|
52
52
|
// Add the battery service if it doesn't already exist
|
|
53
53
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
54
|
-
|
|
54
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
55
55
|
|
|
56
56
|
// Pass the accessory to Fakegato to set up with Eve
|
|
57
57
|
this.accessory.eveService = new platform.eveService('motion', this.accessory, {
|
|
@@ -51,7 +51,7 @@ export default class {
|
|
|
51
51
|
|
|
52
52
|
// Add the battery service if it doesn't already exist
|
|
53
53
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
54
|
-
|
|
54
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
55
55
|
|
|
56
56
|
// Pass the accessory to Fakegato to set up with Eve
|
|
57
57
|
this.accessory.eveService = new platform.eveService('motion', this.accessory, {
|
|
@@ -43,11 +43,11 @@ export default class {
|
|
|
43
43
|
|
|
44
44
|
// Add the smoke sensor service if it doesn't already exist
|
|
45
45
|
this.service = this.accessory.getService(this.hapServ.SmokeSensor)
|
|
46
|
-
|
|
46
|
+
|| this.accessory.addService(this.hapServ.SmokeSensor)
|
|
47
47
|
|
|
48
48
|
// Add the battery service if it doesn't already exist
|
|
49
49
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
50
|
-
|
|
50
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
51
51
|
|
|
52
52
|
// Output the customised options to the log
|
|
53
53
|
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
@@ -44,7 +44,7 @@ export default class {
|
|
|
44
44
|
|
|
45
45
|
// Add the stateless switch service if it doesn't already exist
|
|
46
46
|
this.service = this.accessory.getService(this.hapServ.StatelessProgrammableSwitch)
|
|
47
|
-
|
|
47
|
+
|| this.accessory.addService(this.hapServ.StatelessProgrammableSwitch)
|
|
48
48
|
|
|
49
49
|
// Hide the double and long press options if the user wants
|
|
50
50
|
if (this.hideLongDouble) {
|
|
@@ -55,7 +55,7 @@ export default class {
|
|
|
55
55
|
|
|
56
56
|
// Add the battery service if it doesn't already exist
|
|
57
57
|
this.battService = this.accessory.getService(this.hapServ.Battery)
|
|
58
|
-
|
|
58
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
59
59
|
|
|
60
60
|
// Output the customised options to the log
|
|
61
61
|
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
@@ -75,7 +75,7 @@ export default class {
|
|
|
75
75
|
|
|
76
76
|
// Add the thermostat service if it doesn't already exist
|
|
77
77
|
this.service = this.accessory.getService(this.hapServ.Thermostat)
|
|
78
|
-
|
|
78
|
+
|| this.accessory.addService(this.hapServ.Thermostat)
|
|
79
79
|
|
|
80
80
|
// Set custom properties of the current temperature characteristic
|
|
81
81
|
this.service.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { hasProperty } from '../../utils/functions.js'
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
constructor(platform, accessory) {
|
|
5
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
6
|
+
this.hapServ = platform.api.hap.Service
|
|
7
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
8
|
+
this.log = platform.log
|
|
9
|
+
this.platform = platform
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.name = accessory.displayName
|
|
12
|
+
this.accessory = accessory
|
|
13
|
+
|
|
14
|
+
// Set up custom variables for this device type
|
|
15
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
16
|
+
|
|
17
|
+
// Initialize cache state
|
|
18
|
+
this.cacheState = false
|
|
19
|
+
|
|
20
|
+
// Initialize timer references
|
|
21
|
+
this.timer = null
|
|
22
|
+
this.updateInterval = null
|
|
23
|
+
|
|
24
|
+
// Set up the Valve Service for HomeKit
|
|
25
|
+
this.service = this.accessory.getService(this.hapServ.Valve)
|
|
26
|
+
if (!this.service) {
|
|
27
|
+
this.service = this.accessory.addService(this.hapServ.Valve)
|
|
28
|
+
this.service.updateCharacteristic(this.hapChar.Active, 0)
|
|
29
|
+
this.service.updateCharacteristic(this.hapChar.InUse, 0)
|
|
30
|
+
this.service.updateCharacteristic(this.hapChar.ValveType, 1) // 1 = Irrigation
|
|
31
|
+
this.service.updateCharacteristic(this.hapChar.SetDuration, 30) // Default timer duration
|
|
32
|
+
this.service.addCharacteristic(this.hapChar.RemainingDuration)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Restore timer state if it exists
|
|
36
|
+
if (this.accessory.context.timerEndTime) {
|
|
37
|
+
const now = Date.now()
|
|
38
|
+
if (now < this.accessory.context.timerEndTime) {
|
|
39
|
+
// Timer should still be running
|
|
40
|
+
const remainingTime = Math.round((this.accessory.context.timerEndTime - now) / 1000)
|
|
41
|
+
this.service.updateCharacteristic(this.hapChar.RemainingDuration, remainingTime)
|
|
42
|
+
this.startTimer(remainingTime)
|
|
43
|
+
} else {
|
|
44
|
+
// Timer has expired, clean up
|
|
45
|
+
this.service.updateCharacteristic(this.hapChar.Active, 0)
|
|
46
|
+
this.service.updateCharacteristic(this.hapChar.InUse, 0)
|
|
47
|
+
this.service.updateCharacteristic(this.hapChar.RemainingDuration, 0)
|
|
48
|
+
delete this.accessory.context.timerEndTime
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Set up event handlers for Active characteristic
|
|
53
|
+
this.service
|
|
54
|
+
.getCharacteristic(this.hapChar.Active)
|
|
55
|
+
.onSet(async (value) => {
|
|
56
|
+
try {
|
|
57
|
+
const newState = value === 1
|
|
58
|
+
if (this.enableLogging) {
|
|
59
|
+
this.log('[%s] Setting valve to [%s]', this.name, newState ? 'On' : 'Off')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Send command to the device
|
|
63
|
+
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
64
|
+
switch: newState,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Update InUse characteristic to match Active
|
|
68
|
+
this.service.updateCharacteristic(this.hapChar.InUse, value)
|
|
69
|
+
|
|
70
|
+
if (value === 1) {
|
|
71
|
+
// If turning on, start the timer
|
|
72
|
+
const duration = this.service.getCharacteristic(this.hapChar.SetDuration).value
|
|
73
|
+
this.startTimer(duration)
|
|
74
|
+
} else {
|
|
75
|
+
// If turning off, clear the timer and reset remaining duration
|
|
76
|
+
this.clearTimer()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Update cache after successful command
|
|
80
|
+
this.cacheState = newState
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// Revert the characteristic state on error
|
|
83
|
+
this.service.updateCharacteristic(this.hapChar.Active, this.cacheState)
|
|
84
|
+
this.service.updateCharacteristic(this.hapChar.InUse, this.cacheState)
|
|
85
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
86
|
+
throw new this.hapErr(-70402)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// Set up handler for SetDuration characteristic
|
|
91
|
+
this.service.getCharacteristic(this.hapChar.SetDuration)
|
|
92
|
+
.onSet((value) => {
|
|
93
|
+
if (this.service.getCharacteristic(this.hapChar.InUse).value === 1) {
|
|
94
|
+
// Update timer with new duration if valve is currently active
|
|
95
|
+
this.startTimer(value)
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
this.log('[%s] initialized as a Zigbee Smart Water Valve.', this.name)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
startTimer(duration) {
|
|
103
|
+
// Clear any existing timer
|
|
104
|
+
this.clearTimer()
|
|
105
|
+
|
|
106
|
+
// Set timer end time and store it in context
|
|
107
|
+
this.accessory.context.timerEndTime = Date.now() + (duration * 1000)
|
|
108
|
+
|
|
109
|
+
// Update remaining duration
|
|
110
|
+
this.service.updateCharacteristic(this.hapChar.RemainingDuration, duration)
|
|
111
|
+
|
|
112
|
+
// Set new timer
|
|
113
|
+
this.timer = setTimeout(async () => {
|
|
114
|
+
try {
|
|
115
|
+
// Send explicit command to turn off the valve
|
|
116
|
+
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
117
|
+
switch: false,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Update HomeKit characteristics
|
|
121
|
+
this.service.updateCharacteristic(this.hapChar.Active, 0)
|
|
122
|
+
this.service.updateCharacteristic(this.hapChar.InUse, 0)
|
|
123
|
+
this.service.updateCharacteristic(this.hapChar.RemainingDuration, 0)
|
|
124
|
+
delete this.accessory.context.timerEndTime
|
|
125
|
+
|
|
126
|
+
// Update cache state
|
|
127
|
+
this.cacheState = false
|
|
128
|
+
|
|
129
|
+
if (this.enableLogging) {
|
|
130
|
+
this.log('[%s] Timer finished - turning valve [OFF]', this.name)
|
|
131
|
+
}
|
|
132
|
+
} catch (err) {
|
|
133
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
134
|
+
}
|
|
135
|
+
}, duration * 1000)
|
|
136
|
+
|
|
137
|
+
// Start a periodic update of remaining duration
|
|
138
|
+
if (this.updateInterval) {
|
|
139
|
+
clearInterval(this.updateInterval)
|
|
140
|
+
this.updateInterval = null
|
|
141
|
+
}
|
|
142
|
+
this.updateInterval = setInterval(() => {
|
|
143
|
+
const remaining = Math.round((this.accessory.context.timerEndTime - Date.now()) / 1000)
|
|
144
|
+
if (remaining > 0) {
|
|
145
|
+
this.service.updateCharacteristic(this.hapChar.RemainingDuration, remaining)
|
|
146
|
+
} else {
|
|
147
|
+
clearInterval(this.updateInterval)
|
|
148
|
+
this.updateInterval = null
|
|
149
|
+
}
|
|
150
|
+
}, 1000)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
clearTimer() {
|
|
154
|
+
if (this.timer) {
|
|
155
|
+
clearTimeout(this.timer)
|
|
156
|
+
this.timer = null
|
|
157
|
+
}
|
|
158
|
+
if (this.updateInterval) {
|
|
159
|
+
clearInterval(this.updateInterval)
|
|
160
|
+
this.updateInterval = null
|
|
161
|
+
}
|
|
162
|
+
delete this.accessory.context.timerEndTime
|
|
163
|
+
this.service.updateCharacteristic(this.hapChar.RemainingDuration, 0)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async externalUpdate(params) {
|
|
167
|
+
try {
|
|
168
|
+
// Handle On/Off state
|
|
169
|
+
if (hasProperty(params, 'switch')) {
|
|
170
|
+
const newState = !!params.switch
|
|
171
|
+
if (newState !== this.cacheState) {
|
|
172
|
+
this.cacheState = newState
|
|
173
|
+
const value = newState ? 1 : 0
|
|
174
|
+
this.service.updateCharacteristic(this.hapChar.Active, value)
|
|
175
|
+
this.service.updateCharacteristic(this.hapChar.InUse, value)
|
|
176
|
+
|
|
177
|
+
if (!newState) {
|
|
178
|
+
// If turned off externally, clear timer
|
|
179
|
+
this.clearTimer()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (params.updateSource && this.enableLogging) {
|
|
183
|
+
this.log('[%s] Valve state updated to [%s]', this.name, newState ? 'On' : 'Off')
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
} catch (err) {
|
|
188
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
markStatus(isOnline) {
|
|
193
|
+
this.isOnline = isOnline
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer'
|
|
2
2
|
import { format as Format } from 'node:util'
|
|
3
|
+
|
|
3
4
|
import FakeGatoStorage from './fakegato-storage.js'
|
|
4
5
|
import FakeGatoTimer from './fakegato-timer.js'
|
|
5
6
|
import { toLongFormUUID, toShortFormUUID } from './uuid.js'
|
|
@@ -50,7 +51,7 @@ export default function (homebridge) {
|
|
|
50
51
|
super('S2R1', S2R1Characteristic.UUID)
|
|
51
52
|
this.setProps({
|
|
52
53
|
format: homebridge.hap.Formats.DATA,
|
|
53
|
-
perms: [homebridge.hap.Perms.
|
|
54
|
+
perms: [homebridge.hap.Perms.PAIRED_READ, homebridge.hap.Perms.NOTIFY, homebridge.hap.Perms.HIDDEN],
|
|
54
55
|
})
|
|
55
56
|
}
|
|
56
57
|
}
|
|
@@ -62,7 +63,7 @@ export default function (homebridge) {
|
|
|
62
63
|
super('S2R2', S2R2Characteristic.UUID)
|
|
63
64
|
this.setProps({
|
|
64
65
|
format: homebridge.hap.Formats.DATA,
|
|
65
|
-
perms: [homebridge.hap.Perms.
|
|
66
|
+
perms: [homebridge.hap.Perms.PAIRED_READ, homebridge.hap.Perms.NOTIFY, homebridge.hap.Perms.HIDDEN],
|
|
66
67
|
})
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -74,7 +75,7 @@ export default function (homebridge) {
|
|
|
74
75
|
super('S2W1', S2W1Characteristic.UUID)
|
|
75
76
|
this.setProps({
|
|
76
77
|
format: homebridge.hap.Formats.DATA,
|
|
77
|
-
perms: [homebridge.hap.Perms.
|
|
78
|
+
perms: [homebridge.hap.Perms.PAIRED_WRITE, homebridge.hap.Perms.HIDDEN],
|
|
78
79
|
})
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -86,7 +87,7 @@ export default function (homebridge) {
|
|
|
86
87
|
super('S2W2', S2W2Characteristic.UUID)
|
|
87
88
|
this.setProps({
|
|
88
89
|
format: homebridge.hap.Formats.DATA,
|
|
89
|
-
perms: [homebridge.hap.Perms.
|
|
90
|
+
perms: [homebridge.hap.Perms.PAIRED_WRITE, homebridge.hap.Perms.HIDDEN],
|
|
90
91
|
})
|
|
91
92
|
}
|
|
92
93
|
}
|
|
@@ -226,6 +226,7 @@
|
|
|
226
226
|
const introContinue = document.getElementById('introContinue')
|
|
227
227
|
introContinue.addEventListener('click', () => {
|
|
228
228
|
homebridge.showSpinner()
|
|
229
|
+
homebridge.disableSaveButton?.()
|
|
229
230
|
document.getElementById('pageIntro').style.display = 'none'
|
|
230
231
|
document.getElementById('menuWrapper').style.display = 'inline-flex'
|
|
231
232
|
showSettings()
|
|
@@ -235,6 +236,7 @@
|
|
|
235
236
|
}
|
|
236
237
|
showDevices = async () => {
|
|
237
238
|
homebridge.showSpinner()
|
|
239
|
+
homebridge.disableSaveButton?.()
|
|
238
240
|
homebridge.hideSchemaForm()
|
|
239
241
|
document.getElementById('menuHome').classList.remove('btn-elegant')
|
|
240
242
|
document.getElementById('menuHome').classList.add('btn-primary')
|
|
@@ -306,6 +308,7 @@
|
|
|
306
308
|
}
|
|
307
309
|
showSupport = () => {
|
|
308
310
|
homebridge.showSpinner()
|
|
311
|
+
homebridge.disableSaveButton?.()
|
|
309
312
|
homebridge.hideSchemaForm()
|
|
310
313
|
document.getElementById('menuHome').classList.add('btn-elegant')
|
|
311
314
|
document.getElementById('menuHome').classList.remove('btn-primary')
|
|
@@ -319,6 +322,7 @@
|
|
|
319
322
|
}
|
|
320
323
|
showSettings = () => {
|
|
321
324
|
homebridge.showSpinner()
|
|
325
|
+
homebridge.enableSaveButton?.()
|
|
322
326
|
document.getElementById('menuHome').classList.remove('btn-elegant')
|
|
323
327
|
document.getElementById('menuHome').classList.add('btn-primary')
|
|
324
328
|
document.getElementById('menuDevices').classList.remove('btn-elegant')
|
package/lib/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { createRequire } from 'node:module'
|
|
|
15
15
|
|
|
16
16
|
const require = createRequire(import.meta.url)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
function DnsSdComposer() {
|
|
19
19
|
this._CLASSES = require('./dns-sd-classes.json')
|
|
20
20
|
this._TYPES = require('./dns-sd-types.json')
|
|
21
21
|
}
|
|
@@ -23,7 +23,7 @@ const require = createRequire(import.meta.url)
|
|
|
23
23
|
/* ------------------------------------------------------------------
|
|
24
24
|
* Constructor: DnsSdParser()
|
|
25
25
|
* ---------------------------------------------------------------- */
|
|
26
|
-
|
|
26
|
+
function DnsSdParser() {
|
|
27
27
|
this._CLASSES = require('./dns-sd-classes.json')
|
|
28
28
|
this._CLASS_MAP = {}
|
|
29
29
|
Object.keys(this._CLASSES).forEach((k) => {
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
|
|
9
9
|
import mDgram from 'node:dgram'
|
|
10
10
|
import mOs from 'node:os'
|
|
11
|
+
|
|
11
12
|
import mDnsSdComposer from './dns-sd-composer.js'
|
|
12
13
|
import mDnsSdParser from './dns-sd-parser.js'
|
|
13
14
|
|
|
14
15
|
/* ------------------------------------------------------------------
|
|
15
16
|
* Constructor: DnsSd()
|
|
16
17
|
* ---------------------------------------------------------------- */
|
|
17
|
-
|
|
18
|
+
function DnsSd() {
|
|
18
19
|
// Public
|
|
19
20
|
this.ondata = () => { }
|
|
20
21
|
|
package/lib/platform.js
CHANGED
|
@@ -2,8 +2,10 @@ import { createServer } from 'node:http'
|
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
import process from 'node:process'
|
|
5
|
+
|
|
5
6
|
import storage from 'node-persist'
|
|
6
7
|
import PQueue from 'p-queue'
|
|
8
|
+
|
|
7
9
|
import apiClient from './connection/api.js'
|
|
8
10
|
import httpClient from './connection/http.js'
|
|
9
11
|
import lanClient from './connection/lan.js'
|
|
@@ -1479,7 +1481,7 @@ export default class {
|
|
|
1479
1481
|
|
|
1480
1482
|
// Get the sub accessory if it's new or hasn't been removed above
|
|
1481
1483
|
subAccessory = devicesInHB.get(uuidsub)
|
|
1482
|
-
|
|
1484
|
+
|| this.addAccessory(device, fullDeviceId, false, subExtraContext, 'rf_sub')
|
|
1483
1485
|
|
|
1484
1486
|
// Add context information to the sub accessory
|
|
1485
1487
|
subAccessory.context.firmware = device.params.fwVersion || plugin.version
|
|
@@ -1644,6 +1646,16 @@ export default class {
|
|
|
1644
1646
|
this.applyAccessoryLogging(accessory)
|
|
1645
1647
|
accessory.control = new deviceTypes.zb.deviceThermostat(this, accessory)
|
|
1646
1648
|
/** */
|
|
1649
|
+
} else if (platformConsts.devices.zbWaterValve.includes(uiid)) {
|
|
1650
|
+
/**
|
|
1651
|
+
*******************
|
|
1652
|
+
ZB WATER VALVE
|
|
1653
|
+
********************
|
|
1654
|
+
*/
|
|
1655
|
+
accessory = devicesInHB.get(uuid) || this.addAccessory(device, `${device.deviceid}SWX`)
|
|
1656
|
+
this.applyAccessoryLogging(accessory)
|
|
1657
|
+
accessory.control = new deviceTypes.zb.deviceZigbeeWaterValve(this, accessory)
|
|
1658
|
+
/** */
|
|
1647
1659
|
} else if (platformConsts.devices.group.includes(uiid)) {
|
|
1648
1660
|
/**
|
|
1649
1661
|
***********
|
|
@@ -1846,16 +1858,15 @@ export default class {
|
|
|
1846
1858
|
|
|
1847
1859
|
// Add helpful context values to the accessory
|
|
1848
1860
|
accessory.context = {
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
},
|
|
1861
|
+
|
|
1862
|
+
hbDeviceId,
|
|
1863
|
+
eweDeviceId: device.deviceid,
|
|
1864
|
+
eweUIID: device.extra.uiid,
|
|
1865
|
+
eweModel: device.productModel,
|
|
1866
|
+
eweApiKey: device.apikey,
|
|
1867
|
+
switchNumber,
|
|
1868
|
+
channelCount,
|
|
1869
|
+
hidden,
|
|
1859
1870
|
...extraContext,
|
|
1860
1871
|
}
|
|
1861
1872
|
|
|
@@ -1903,16 +1914,15 @@ export default class {
|
|
|
1903
1914
|
|
|
1904
1915
|
// Add helpful context values to the accessory
|
|
1905
1916
|
accessory.context = {
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
},
|
|
1917
|
+
|
|
1918
|
+
hbDeviceId,
|
|
1919
|
+
eweDeviceId: device.deviceid,
|
|
1920
|
+
eweUIID: device.extra.uiid,
|
|
1921
|
+
eweModel: device.productModel,
|
|
1922
|
+
eweApiKey: device.apikey,
|
|
1923
|
+
switchNumber: hbDeviceId.split('SW')[1].toString(),
|
|
1924
|
+
channelCount: platformConsts.supportedDevices[device.extra.uiid],
|
|
1925
|
+
hidden: false,
|
|
1916
1926
|
}
|
|
1917
1927
|
|
|
1918
1928
|
// Register the accessory
|
package/lib/utils/constants.js
CHANGED
|
@@ -284,7 +284,7 @@ export default {
|
|
|
284
284
|
211,
|
|
285
285
|
212,
|
|
286
286
|
],
|
|
287
|
-
switchSingle: [1, 6, 14, 24, 27, 1009, 1256, 7004, 7005],
|
|
287
|
+
switchSingle: [1, 6, 14, 24, 27, 226, 1009, 1256, 7004, 7005, 7010],
|
|
288
288
|
switchSCM: [77, 78, 81, 107, 112, 138, 160, 191, 209],
|
|
289
289
|
switchSCMPower: [182, 190],
|
|
290
290
|
switchSinglePower: [5, 32],
|
|
@@ -347,6 +347,7 @@ export default {
|
|
|
347
347
|
zbSensorWater: [4026],
|
|
348
348
|
zbSensorSmoke: [5026],
|
|
349
349
|
zbThermostat: [7017],
|
|
350
|
+
zbWaterValve: [7027],
|
|
350
351
|
group: [5000],
|
|
351
352
|
template: [130], // SPM sub unit
|
|
352
353
|
cannotSupport: [0, 65, 118, 119, 120, 121],
|
|
@@ -505,6 +506,7 @@ export default {
|
|
|
505
506
|
210: 2, // Sonoff Ultimate Switch T5-2C-86
|
|
506
507
|
211: 3, // Sonoff Ultimate Switch T5-3C-86
|
|
507
508
|
212: 4, // Sonoff Ultimate Switch T5-4C-86
|
|
509
|
+
226: 1, // https://github.com/homebridge-plugins/homebridge-ewelink/issues/636
|
|
508
510
|
243: 1, // Zigbee Bridge Ultra
|
|
509
511
|
1000: 1, // "zigbee_ON_OFF_SWITCH_1000" (button device)
|
|
510
512
|
1009: 1, // "" (Some sort of single switch device)
|
|
@@ -529,9 +531,11 @@ export default {
|
|
|
529
531
|
7004: 1, // Zigbee Single-Channel Switch _Support OTA
|
|
530
532
|
7005: 1, // Some switch, not entirely sure
|
|
531
533
|
7006: 1, // Zigbee Curtain_Support OTA
|
|
534
|
+
7010: 1, // Zigbee Micro https://github.com/homebridge-plugins/homebridge-ewelink/issues/630
|
|
532
535
|
7014: 1, // some sensor https://github.com/homebridge-plugins/homebridge-ewelink/issues/494
|
|
533
536
|
7016: 1, // https://sonoff.tech/product/gateway-and-sensors/snzb-06p/
|
|
534
537
|
7017: 1, // https://github.com/homebridge-plugins/homebridge-ewelink/issues/518
|
|
538
|
+
7027: 1, // Zigbee Smart Water Valve
|
|
535
539
|
},
|
|
536
540
|
|
|
537
541
|
cannotSupportDevices: {
|