@homebridge-plugins/homebridge-ewelink 12.3.3
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 +1363 -0
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/config.schema.json +1757 -0
- package/eslint.config.js +15 -0
- package/lib/connection/api.js +508 -0
- package/lib/connection/http.js +304 -0
- package/lib/connection/lan.js +318 -0
- package/lib/connection/ws.js +414 -0
- package/lib/device/curtain.js +324 -0
- package/lib/device/diffuser.js +473 -0
- package/lib/device/fan.js +349 -0
- package/lib/device/group.js +106 -0
- package/lib/device/humidifier.js +199 -0
- package/lib/device/index.js +61 -0
- package/lib/device/light-cct.js +333 -0
- package/lib/device/light-dimmer.js +257 -0
- package/lib/device/light-rgb-cct.js +809 -0
- package/lib/device/light-rgb.js +272 -0
- package/lib/device/motor.js +363 -0
- package/lib/device/outlet-multi.js +417 -0
- package/lib/device/outlet-single-inched.js +409 -0
- package/lib/device/outlet-single.js +384 -0
- package/lib/device/panel.js +382 -0
- package/lib/device/rf-bridge.js +321 -0
- package/lib/device/rf-button.js +125 -0
- package/lib/device/rf-sensor.js +173 -0
- package/lib/device/sensor-ambient.js +311 -0
- package/lib/device/sensor-contact.js +140 -0
- package/lib/device/sensor-temp-humi.js +182 -0
- package/lib/device/simulation/blind.js +253 -0
- package/lib/device/simulation/cooler.js +312 -0
- package/lib/device/simulation/door.js +253 -0
- package/lib/device/simulation/doorbell.js +190 -0
- package/lib/device/simulation/garage-eachen.js +235 -0
- package/lib/device/simulation/garage-four.js +176 -0
- package/lib/device/simulation/garage-od-switch.js +36 -0
- package/lib/device/simulation/garage-one.js +395 -0
- package/lib/device/simulation/garage-two.js +394 -0
- package/lib/device/simulation/gate-one.js +327 -0
- package/lib/device/simulation/heater.js +389 -0
- package/lib/device/simulation/index.js +75 -0
- package/lib/device/simulation/light-fan.js +258 -0
- package/lib/device/simulation/lock-eachen.js +163 -0
- package/lib/device/simulation/lock-one.js +366 -0
- package/lib/device/simulation/p-button.js +223 -0
- package/lib/device/simulation/purifier.js +289 -0
- package/lib/device/simulation/rf-blind.js +192 -0
- package/lib/device/simulation/rf-door.js +180 -0
- package/lib/device/simulation/rf-window.js +180 -0
- package/lib/device/simulation/sensor-hidden.js +105 -0
- package/lib/device/simulation/sensor-leak.js +123 -0
- package/lib/device/simulation/sensor-visible.js +231 -0
- package/lib/device/simulation/sensor.js +300 -0
- package/lib/device/simulation/switch-valve.js +351 -0
- package/lib/device/simulation/tap-one.js +283 -0
- package/lib/device/simulation/tap-two.js +266 -0
- package/lib/device/simulation/th-cooler.js +443 -0
- package/lib/device/simulation/th-dehumidifier.js +424 -0
- package/lib/device/simulation/th-heater.js +449 -0
- package/lib/device/simulation/th-humidifier.js +424 -0
- package/lib/device/simulation/th-thermostat.js +611 -0
- package/lib/device/simulation/tv.js +252 -0
- package/lib/device/simulation/valve-four.js +232 -0
- package/lib/device/simulation/valve-one.js +345 -0
- package/lib/device/simulation/valve-two.js +340 -0
- package/lib/device/simulation/window.js +253 -0
- package/lib/device/switch-man.js +106 -0
- package/lib/device/switch-mate.js +82 -0
- package/lib/device/switch-multi.js +411 -0
- package/lib/device/switch-single-inched.js +332 -0
- package/lib/device/switch-single.js +307 -0
- package/lib/device/template.js +43 -0
- package/lib/device/thermostat.js +286 -0
- package/lib/device/zigbee/index.js +27 -0
- package/lib/device/zigbee/light-cct.js +263 -0
- package/lib/device/zigbee/light-dimmer.js +148 -0
- package/lib/device/zigbee/light-rgb-cct.js +400 -0
- package/lib/device/zigbee/motor.js +301 -0
- package/lib/device/zigbee/sensor-ambient.js +177 -0
- package/lib/device/zigbee/sensor-contact.js +137 -0
- package/lib/device/zigbee/sensor-leak.js +119 -0
- package/lib/device/zigbee/sensor-motion.js +119 -0
- package/lib/device/zigbee/sensor-occupancy.js +119 -0
- package/lib/device/zigbee/sensor-smoke.js +96 -0
- package/lib/device/zigbee/switch-stateless.js +104 -0
- package/lib/device/zigbee/thermostat.js +323 -0
- package/lib/fakegato/LICENSE +21 -0
- package/lib/fakegato/fakegato-history.js +813 -0
- package/lib/fakegato/fakegato-storage.js +108 -0
- package/lib/fakegato/fakegato-timer.js +125 -0
- package/lib/fakegato/uuid.js +27 -0
- package/lib/homebridge-ui/public/index.html +365 -0
- package/lib/homebridge-ui/server.js +46 -0
- package/lib/index.js +7 -0
- package/lib/node-dns-sd/LICENSE +21 -0
- package/lib/node-dns-sd/README.md +613 -0
- package/lib/node-dns-sd/lib/dns-sd-classes.json +6 -0
- package/lib/node-dns-sd/lib/dns-sd-composer.js +83 -0
- package/lib/node-dns-sd/lib/dns-sd-parser.js +344 -0
- package/lib/node-dns-sd/lib/dns-sd-types.json +52 -0
- package/lib/node-dns-sd/lib/dns-sd.js +580 -0
- package/lib/platform.js +2156 -0
- package/lib/utils/colour.js +552 -0
- package/lib/utils/constants.js +589 -0
- package/lib/utils/custom-chars.js +33 -0
- package/lib/utils/eve-chars.js +130 -0
- package/lib/utils/functions.js +42 -0
- package/lib/utils/lang-en.js +160 -0
- package/lib/utils/lang-fr.js +163 -0
- package/lib/utils/lang-th.js +160 -0
- package/lib/utils/lang.js +5 -0
- package/package.json +75 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { generateRandomString, hasProperty, sleep } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.eveChar = platform.eveChar
|
|
8
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
9
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
10
|
+
this.hapServ = platform.api.hap.Service
|
|
11
|
+
this.lang = platform.lang
|
|
12
|
+
this.log = platform.log
|
|
13
|
+
this.platform = platform
|
|
14
|
+
|
|
15
|
+
// Set up variables from the accessory
|
|
16
|
+
this.name = accessory.displayName
|
|
17
|
+
this.accessory = accessory
|
|
18
|
+
|
|
19
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
20
|
+
this.isOnline = true
|
|
21
|
+
|
|
22
|
+
// Set up custom variables for this device type
|
|
23
|
+
const deviceConf = platform.rfSubdevices[accessory.context.hbDeviceId] || {}
|
|
24
|
+
this.operationTimeUp = deviceConf.operationTime || platformConsts.defaultValues.operationTime
|
|
25
|
+
this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp;
|
|
26
|
+
[this.chOpen, this.chStop, this.chClose] = Object.keys(this.accessory.context.buttons)
|
|
27
|
+
|
|
28
|
+
// Set the correct logging variables for this accessory
|
|
29
|
+
switch (deviceConf.overrideLogging) {
|
|
30
|
+
case 'standard':
|
|
31
|
+
this.enableLogging = true
|
|
32
|
+
this.enableDebugLogging = false
|
|
33
|
+
break
|
|
34
|
+
case 'debug':
|
|
35
|
+
this.enableLogging = true
|
|
36
|
+
this.enableDebugLogging = true
|
|
37
|
+
break
|
|
38
|
+
case 'disable':
|
|
39
|
+
this.enableLogging = false
|
|
40
|
+
this.enableDebugLogging = false
|
|
41
|
+
break
|
|
42
|
+
default:
|
|
43
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
44
|
+
this.enableDebugLogging = platform.config.debug
|
|
45
|
+
break
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// If the accessory has a window covering service (from an old simulation) then remove it
|
|
49
|
+
if (this.accessory.getService(this.hapServ.WindowCovering)) {
|
|
50
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// If the accessory has a door service (from an old simulation) then remove it
|
|
54
|
+
if (this.accessory.getService(this.hapServ.Door)) {
|
|
55
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Remove old switch services from before the simulation was configured
|
|
59
|
+
this.accessory.services
|
|
60
|
+
.filter(el => el.constructor.name === 'Switch')
|
|
61
|
+
.forEach(el => this.accessory.removeService(el))
|
|
62
|
+
|
|
63
|
+
// Set up the accessory with default positions when added the first time
|
|
64
|
+
if (!hasProperty(this.accessory.context, 'cacheCurrentPosition')) {
|
|
65
|
+
this.accessory.context.cacheCurrentPosition = 0
|
|
66
|
+
this.accessory.context.cachePositionState = 2
|
|
67
|
+
this.accessory.context.cacheTargetPosition = 0
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Add the window service if it doesn't already exist
|
|
71
|
+
this.service = this.accessory.getService(this.hapServ.Window)
|
|
72
|
+
if (!(this.service)) {
|
|
73
|
+
this.service = this.accessory.addService(this.hapServ.Window)
|
|
74
|
+
this.service.updateCharacteristic(this.hapChar.CurrentPosition, 0)
|
|
75
|
+
this.service.updateCharacteristic(this.hapChar.TargetPosition, 0)
|
|
76
|
+
this.service.updateCharacteristic(this.hapChar.PositionState, 2)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Add the set handler to the target position characteristic
|
|
80
|
+
this.service.getCharacteristic(this.hapChar.TargetPosition).onSet((value) => {
|
|
81
|
+
// We don't use await as we want the callback to be run straight away
|
|
82
|
+
this.internalPositionUpdate(value)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
86
|
+
if (!platform.config.disableNoResponse) {
|
|
87
|
+
this.service.getCharacteristic(this.hapChar.CurrentPosition).onGet(() => {
|
|
88
|
+
if (!this.isOnline) {
|
|
89
|
+
throw new this.hapErr(-70402)
|
|
90
|
+
}
|
|
91
|
+
return this.service.getCharacteristic(this.hapChar.CurrentPosition).value
|
|
92
|
+
})
|
|
93
|
+
this.service.getCharacteristic(this.hapChar.TargetPosition).onGet(() => {
|
|
94
|
+
if (!this.isOnline) {
|
|
95
|
+
throw new this.hapErr(-70402)
|
|
96
|
+
}
|
|
97
|
+
return this.service.getCharacteristic(this.hapChar.TargetPosition).value
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Output the customised options to the log
|
|
102
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
103
|
+
const opts = JSON.stringify({
|
|
104
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
105
|
+
operationTime: this.operationTimeUp,
|
|
106
|
+
operationTimeDown: this.operationTimeDown,
|
|
107
|
+
})
|
|
108
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async internalPositionUpdate(value) {
|
|
112
|
+
try {
|
|
113
|
+
let prevPosition = this.accessory.context.cacheCurrentPosition
|
|
114
|
+
if (value === prevPosition) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
const params = { cmd: 'transmit' }
|
|
118
|
+
const prevState = this.accessory.context.cachePositionState
|
|
119
|
+
const percentStepUpPerDS = this.operationTimeUp / 100
|
|
120
|
+
const percentStepDownPerDS = this.operationTimeDown / 100
|
|
121
|
+
const updateKey = generateRandomString(5)
|
|
122
|
+
this.updateKey = updateKey
|
|
123
|
+
if (prevState !== 2) {
|
|
124
|
+
const posPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime
|
|
125
|
+
const posPercentChangeUp = Math.floor(percentStepUpPerDS * posPercentChange)
|
|
126
|
+
const posPercentChangeDown = Math.floor(percentStepDownPerDS * posPercentChange)
|
|
127
|
+
if (prevState === 0) {
|
|
128
|
+
// Was going down
|
|
129
|
+
prevPosition -= posPercentChangeDown
|
|
130
|
+
} else {
|
|
131
|
+
// Was going up
|
|
132
|
+
prevPosition += posPercentChangeUp
|
|
133
|
+
}
|
|
134
|
+
prevPosition = Math.min(Math.max(prevPosition, 0), 100)
|
|
135
|
+
this.service.updateCharacteristic(this.hapChar.CurrentPosition, prevPosition)
|
|
136
|
+
this.accessory.context.cacheCurrentPosition = prevPosition
|
|
137
|
+
}
|
|
138
|
+
const diffPosition = value - prevPosition
|
|
139
|
+
const setToMoveUp = diffPosition > 0
|
|
140
|
+
let decisecondsToMove
|
|
141
|
+
if (setToMoveUp) {
|
|
142
|
+
decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepUpPerDS)
|
|
143
|
+
params.rfChl = Number.parseInt(this.chOpen, 10)
|
|
144
|
+
} else {
|
|
145
|
+
decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepDownPerDS)
|
|
146
|
+
params.rfChl = Number.parseInt(this.chClose, 10)
|
|
147
|
+
}
|
|
148
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
149
|
+
this.accessory.context.cacheTargetPosition = value
|
|
150
|
+
this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0
|
|
151
|
+
this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100)
|
|
152
|
+
await sleep(decisecondsToMove * 100)
|
|
153
|
+
if (this.updateKey !== updateKey) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
params.rfChl = Number.parseInt(this.chStop, 10)
|
|
157
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
158
|
+
this.service.updateCharacteristic(this.hapChar.PositionState, 2)
|
|
159
|
+
this.service.updateCharacteristic(this.hapChar.CurrentPosition, value)
|
|
160
|
+
this.accessory.context.cachePositionState = 2
|
|
161
|
+
this.accessory.context.cacheCurrentPosition = value
|
|
162
|
+
if (this.enableLogging) {
|
|
163
|
+
this.log('[%s] %s [%s%]', this.name, this.lang.curPos, value)
|
|
164
|
+
}
|
|
165
|
+
} catch (err) {
|
|
166
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
167
|
+
setTimeout(() => {
|
|
168
|
+
this.service.updateCharacteristic(
|
|
169
|
+
this.hapChar.TargetPosition,
|
|
170
|
+
this.accessory.context.cacheTargetPosition,
|
|
171
|
+
)
|
|
172
|
+
}, 2000)
|
|
173
|
+
this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402))
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
markStatus(isOnline) {
|
|
178
|
+
this.isOnline = isOnline
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { hasProperty, sleep } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory, subAccessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.eveChar = platform.eveChar
|
|
8
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
9
|
+
this.hapServ = platform.api.hap.Service
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.accessory = accessory
|
|
16
|
+
this.subAccessory = subAccessory
|
|
17
|
+
|
|
18
|
+
// Set up custom variables for this device type
|
|
19
|
+
const group = platform.deviceConf[subAccessory.context.eweDeviceId] || {}
|
|
20
|
+
this.isGarage = group.showAs === 'garage'
|
|
21
|
+
this.operationTime = group.operationTime || platformConsts.defaultValues.operationTime
|
|
22
|
+
|
|
23
|
+
// Set the correct logging variables for this accessory
|
|
24
|
+
switch (group.overrideLogging) {
|
|
25
|
+
case 'standard':
|
|
26
|
+
case 'debug':
|
|
27
|
+
this.enableLogging = true
|
|
28
|
+
break
|
|
29
|
+
case 'disable':
|
|
30
|
+
this.enableLogging = false
|
|
31
|
+
break
|
|
32
|
+
default:
|
|
33
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
34
|
+
break
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async externalUpdate(params) {
|
|
39
|
+
try {
|
|
40
|
+
if (!hasProperty(params, 'lock') && !params.switch) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
let newState
|
|
44
|
+
if (params.switch) {
|
|
45
|
+
newState = params.switch === 'on' ? 1 : 0
|
|
46
|
+
} else {
|
|
47
|
+
newState = params.lock
|
|
48
|
+
}
|
|
49
|
+
if (newState === this.cacheState) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
this.cacheState = newState
|
|
53
|
+
const subService = this.subAccessory.getService(
|
|
54
|
+
this.isGarage ? this.hapServ.GarageDoorOpener : this.hapServ.LockMechanism,
|
|
55
|
+
)
|
|
56
|
+
const name = this.subAccessory.displayName
|
|
57
|
+
switch (newState) {
|
|
58
|
+
case 0:
|
|
59
|
+
if (this.isGarage) {
|
|
60
|
+
subService.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
61
|
+
subService.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
62
|
+
this.subAccessory.eveService.addEntry({ status: 1 })
|
|
63
|
+
if (params.updateSource && this.enableLogging) {
|
|
64
|
+
this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.doorClosed)
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
subService.updateCharacteristic(this.hapChar.LockTargetState, 1)
|
|
68
|
+
subService.updateCharacteristic(this.hapChar.LockCurrentState, 1)
|
|
69
|
+
if (params.updateSource && this.enableLogging) {
|
|
70
|
+
this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.lockLocked)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
break
|
|
74
|
+
case 1: {
|
|
75
|
+
if (this.isGarage) {
|
|
76
|
+
await sleep(Math.max(this.operationTime * 100, 2000))
|
|
77
|
+
subService.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
78
|
+
subService.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
79
|
+
this.subAccessory.eveService.addEntry({ status: 0 })
|
|
80
|
+
const initialTime = this.subAccessory.eveService.getInitialTime()
|
|
81
|
+
subService.updateCharacteristic(
|
|
82
|
+
this.eveChar.LastActivation,
|
|
83
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
84
|
+
)
|
|
85
|
+
const newTO = subService.getCharacteristic(this.eveChar.TimesOpened).value + 1
|
|
86
|
+
subService.updateCharacteristic(this.eveChar.TimesOpened, newTO)
|
|
87
|
+
if (params.updateSource && this.enableLogging) {
|
|
88
|
+
this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.doorOpen)
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
subService.updateCharacteristic(this.hapChar.LockTargetState, 0)
|
|
92
|
+
subService.updateCharacteristic(this.hapChar.LockCurrentState, 0)
|
|
93
|
+
if (params.updateSource && this.enableLogging) {
|
|
94
|
+
this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.lockUnlocked)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { hasProperty } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.eveChar = platform.eveChar
|
|
8
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
9
|
+
this.hapServ = platform.api.hap.Service
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.name = accessory.displayName
|
|
16
|
+
this.accessory = accessory
|
|
17
|
+
|
|
18
|
+
// Set up custom variables for this device type
|
|
19
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
20
|
+
this.lowBattThreshold = deviceConf.lowBattThreshold
|
|
21
|
+
? Math.min(deviceConf.lowBattThreshold, 100)
|
|
22
|
+
: platformConsts.defaultValues.lowBattThreshold
|
|
23
|
+
|
|
24
|
+
// Set the correct logging variables for this accessory
|
|
25
|
+
switch (deviceConf.overrideLogging) {
|
|
26
|
+
case 'standard':
|
|
27
|
+
this.enableLogging = true
|
|
28
|
+
this.enableDebugLogging = false
|
|
29
|
+
break
|
|
30
|
+
case 'debug':
|
|
31
|
+
this.enableLogging = true
|
|
32
|
+
this.enableDebugLogging = true
|
|
33
|
+
break
|
|
34
|
+
case 'disable':
|
|
35
|
+
this.enableLogging = false
|
|
36
|
+
this.enableDebugLogging = false
|
|
37
|
+
break
|
|
38
|
+
default:
|
|
39
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
40
|
+
this.enableDebugLogging = platform.config.debug
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If the accessory has a contact sensor service then remove it
|
|
45
|
+
if (this.accessory.getService(this.hapServ.ContactSensor)) {
|
|
46
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.ContactSensor))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Add the leak sensor service if it doesn't already exist
|
|
50
|
+
this.service = this.accessory.getService(this.hapServ.LeakSensor)
|
|
51
|
+
if (!this.service) {
|
|
52
|
+
this.service = this.accessory.addService(this.hapServ.LeakSensor)
|
|
53
|
+
this.service.addCharacteristic(this.eveChar.LastActivation)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Add the battery service if it doesn't already exist
|
|
57
|
+
this.batteryService = this.accessory.getService(this.hapServ.Battery)
|
|
58
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
59
|
+
|
|
60
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
61
|
+
this.accessory.eveService = new platform.eveService('motion', this.accessory, {
|
|
62
|
+
log: () => {},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Output the customised options to the log
|
|
66
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
67
|
+
const opts = JSON.stringify({
|
|
68
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
69
|
+
lowBattThreshold: this.lowBattThreshold,
|
|
70
|
+
showAs: 'sensor_leak',
|
|
71
|
+
})
|
|
72
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async externalUpdate(params) {
|
|
76
|
+
try {
|
|
77
|
+
if (hasProperty(params, 'battery') && this.cacheBatt !== params.battery) {
|
|
78
|
+
this.cacheBatt = params.battery
|
|
79
|
+
if (this.accessory.context.eweUIID === 154) {
|
|
80
|
+
// No scaling needed for this model as provided as a %
|
|
81
|
+
this.cacheBattScaled = this.cacheBatt
|
|
82
|
+
} else {
|
|
83
|
+
// Scaling needed for UIID 102 as provided as a voltage rather than a %
|
|
84
|
+
this.cacheBattScaled = Math.min(Math.max(this.cacheBatt, 2), 3)
|
|
85
|
+
this.cacheBattScaled = Math.round((this.cacheBattScaled - 2) * 100)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.batteryService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
|
|
89
|
+
this.batteryService.updateCharacteristic(
|
|
90
|
+
this.hapChar.StatusLowBattery,
|
|
91
|
+
this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
|
|
92
|
+
)
|
|
93
|
+
if (params.updateSource && this.enableLogging) {
|
|
94
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!params.switch || params.switch === this.cacheState) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
this.cacheState = params.switch
|
|
101
|
+
const newState = params.switch === 'on' ? 0 : 1
|
|
102
|
+
this.service.updateCharacteristic(this.hapChar.LeakDetected, newState)
|
|
103
|
+
this.accessory.eveService.addEntry({ status: newState })
|
|
104
|
+
if (newState === 1) {
|
|
105
|
+
const initialTime = this.accessory.eveService.getInitialTime()
|
|
106
|
+
this.service.updateCharacteristic(
|
|
107
|
+
this.eveChar.LastActivation,
|
|
108
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
if (params.updateSource && this.enableLogging) {
|
|
112
|
+
this.log(
|
|
113
|
+
'[%s] %s [%s].',
|
|
114
|
+
this.name,
|
|
115
|
+
this.lang.curState,
|
|
116
|
+
newState === 1 ? this.lang.leakYes : this.lang.leakNo,
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
} catch (err) {
|
|
120
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { hasProperty, sleep } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory, subAccessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.eveChar = platform.eveChar
|
|
8
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
9
|
+
this.hapServ = platform.api.hap.Service
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.name = accessory.displayName
|
|
16
|
+
this.nameSub = subAccessory.displayName
|
|
17
|
+
this.accessory = accessory
|
|
18
|
+
this.subAccessory = subAccessory
|
|
19
|
+
|
|
20
|
+
// Set up custom variables for this device type
|
|
21
|
+
this.isDW2 = platformConsts.devices.sensorContact.includes(accessory.context.eweUIID)
|
|
22
|
+
this.hasBattery = platformConsts.devices.garageSensors.includes(accessory.context.eweUIID)
|
|
23
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
24
|
+
this.scaleBattery = deviceConf.scaleBattery
|
|
25
|
+
this.lowBattThreshold = deviceConf.lowBattThreshold
|
|
26
|
+
? Math.min(deviceConf.lowBattThreshold, 100)
|
|
27
|
+
: platformConsts.defaultValues.lowBattThreshold
|
|
28
|
+
const group = platform.deviceConf[subAccessory.context.eweDeviceId] || {}
|
|
29
|
+
this.isGarage = group.showAs === 'garage'
|
|
30
|
+
this.operationTime = group.operationTime || platformConsts.defaultValues.operationTime
|
|
31
|
+
|
|
32
|
+
// Set the correct logging variables for this accessory
|
|
33
|
+
switch (deviceConf.overrideLogging) {
|
|
34
|
+
case 'standard':
|
|
35
|
+
this.enableLogging = true
|
|
36
|
+
this.enableDebugLogging = false
|
|
37
|
+
break
|
|
38
|
+
case 'debug':
|
|
39
|
+
this.enableLogging = true
|
|
40
|
+
this.enableDebugLogging = true
|
|
41
|
+
break
|
|
42
|
+
case 'disable':
|
|
43
|
+
this.enableLogging = false
|
|
44
|
+
this.enableDebugLogging = false
|
|
45
|
+
break
|
|
46
|
+
default:
|
|
47
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
48
|
+
this.enableDebugLogging = platform.config.debug
|
|
49
|
+
break
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Set the correct logging variables for this sub accessory
|
|
53
|
+
switch (group.overrideLogging) {
|
|
54
|
+
case 'standard':
|
|
55
|
+
case 'debug':
|
|
56
|
+
this.enableLoggingSub = true
|
|
57
|
+
break
|
|
58
|
+
case 'disable':
|
|
59
|
+
this.enableLoggingSub = false
|
|
60
|
+
break
|
|
61
|
+
default:
|
|
62
|
+
this.enableLoggingSub = !platform.config.disableDeviceLogging
|
|
63
|
+
break
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// If the accessory has a leak sensor service then remove it
|
|
67
|
+
if (this.accessory.getService(this.hapServ.LeakSensor)) {
|
|
68
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.LeakSensor))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Add the contact sensor service if it doesn't already exist
|
|
72
|
+
this.service = this.accessory.getService(this.hapServ.ContactSensor)
|
|
73
|
+
if (!this.service) {
|
|
74
|
+
this.service = this.accessory.addService(this.hapServ.ContactSensor)
|
|
75
|
+
this.service.addCharacteristic(this.eveChar.LastActivation)
|
|
76
|
+
this.service.addCharacteristic(this.eveChar.ResetTotal)
|
|
77
|
+
this.service.addCharacteristic(this.eveChar.OpenDuration)
|
|
78
|
+
this.service.addCharacteristic(this.eveChar.ClosedDuration)
|
|
79
|
+
this.service.addCharacteristic(this.eveChar.TimesOpened)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Add the set handler to the contact sensor reset total characteristic
|
|
83
|
+
this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(() => {
|
|
84
|
+
this.service.updateCharacteristic(this.eveChar.TimesOpened, 0)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
if (this.hasBattery) {
|
|
88
|
+
// Add the battery service if it doesn't already exist
|
|
89
|
+
this.batteryService = this.accessory.getService(this.hapServ.Battery)
|
|
90
|
+
|| this.accessory.addService(this.hapServ.Battery)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
94
|
+
this.accessory.eveService = new platform.eveService('door', this.accessory, {
|
|
95
|
+
log: () => {},
|
|
96
|
+
})
|
|
97
|
+
this.accessory.eveService.addEntry({
|
|
98
|
+
status: this.service.getCharacteristic(this.hapChar.ContactSensorState).value,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// Output the customised options to the log
|
|
102
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
103
|
+
const opts = JSON.stringify({
|
|
104
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
105
|
+
lowBattThreshold: this.lowBattThreshold,
|
|
106
|
+
scaleBattery: this.scaleBattery,
|
|
107
|
+
})
|
|
108
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async externalUpdate(params) {
|
|
112
|
+
try {
|
|
113
|
+
if (
|
|
114
|
+
this.batteryService
|
|
115
|
+
&& hasProperty(params, 'battery')
|
|
116
|
+
&& params.battery !== this.cacheBatt
|
|
117
|
+
) {
|
|
118
|
+
this.cacheBatt = params.battery
|
|
119
|
+
if (this.isDW2) {
|
|
120
|
+
if (this.accessory.context.eweUIID === 154) {
|
|
121
|
+
// No scaling needed for this model as provided as a %
|
|
122
|
+
this.cacheBattScaled = this.cacheBatt
|
|
123
|
+
} else {
|
|
124
|
+
// Scaling needed for UIID 102 as provided as a voltage rather than a %
|
|
125
|
+
this.cacheBattScaled = Math.min(Math.max(this.cacheBatt, 2), 3)
|
|
126
|
+
this.cacheBattScaled = Math.round((this.cacheBattScaled - 2) * 100)
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
this.cacheBattScaled = this.scaleBattery ? this.cacheBatt * 10 : this.cacheBatt
|
|
130
|
+
}
|
|
131
|
+
this.cacheBattScaled = Math.max(Math.min(this.cacheBattScaled, 100), 0)
|
|
132
|
+
this.batteryService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
|
|
133
|
+
this.batteryService.updateCharacteristic(
|
|
134
|
+
this.hapChar.StatusLowBattery,
|
|
135
|
+
this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
|
|
136
|
+
)
|
|
137
|
+
if (params.updateSource && this.enableLogging) {
|
|
138
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!hasProperty(params, 'lock') && !params.switch) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
let newState
|
|
145
|
+
if (params.switch) {
|
|
146
|
+
newState = params.switch === 'on' ? 1 : 0
|
|
147
|
+
} else {
|
|
148
|
+
newState = params.lock
|
|
149
|
+
}
|
|
150
|
+
if (newState === this.cacheState) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
this.cacheState = newState
|
|
154
|
+
if (newState === 1) {
|
|
155
|
+
this.service.updateCharacteristic(this.hapChar.ContactSensorState, 1)
|
|
156
|
+
this.accessory.eveService.addEntry({ status: 1 })
|
|
157
|
+
const initialTime = this.accessory.eveService.getInitialTime()
|
|
158
|
+
this.service.updateCharacteristic(
|
|
159
|
+
this.eveChar.LastActivation,
|
|
160
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
161
|
+
)
|
|
162
|
+
const newTO = this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1
|
|
163
|
+
this.service.updateCharacteristic(this.eveChar.TimesOpened, newTO)
|
|
164
|
+
} else {
|
|
165
|
+
this.service.updateCharacteristic(this.hapChar.ContactSensorState, 0)
|
|
166
|
+
this.accessory.eveService.addEntry({ status: 0 })
|
|
167
|
+
}
|
|
168
|
+
if (params.updateSource && this.enableLogging) {
|
|
169
|
+
this.log(
|
|
170
|
+
'[%s] %s [%s].',
|
|
171
|
+
this.name,
|
|
172
|
+
this.lang.curState,
|
|
173
|
+
newState === 0 ? this.lang.contactYes : this.lang.contactNo,
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
const subService = this.subAccessory.getService(
|
|
177
|
+
this.isGarage ? this.hapServ.GarageDoorOpener : this.hapServ.LockMechanism,
|
|
178
|
+
)
|
|
179
|
+
switch (newState) {
|
|
180
|
+
case 0:
|
|
181
|
+
if (this.isGarage) {
|
|
182
|
+
subService.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
183
|
+
subService.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
184
|
+
this.subAccessory.eveService.addEntry({ status: 1 })
|
|
185
|
+
if (params.updateSource && this.enableLoggingSub) {
|
|
186
|
+
this.log('[%s] %s [%s].', this.nameSub, this.lang.curState, this.lang.doorClosed)
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
subService.updateCharacteristic(this.hapChar.LockTargetState, 1)
|
|
190
|
+
subService.updateCharacteristic(this.hapChar.LockCurrentState, 1)
|
|
191
|
+
this.subAccessory.context.contactDetected = true
|
|
192
|
+
if (params.updateSource && this.enableLoggingSub) {
|
|
193
|
+
this.log('[%s] %s [%s].', this.nameSub, this.lang.curState, this.lang.lockLocked)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 1: {
|
|
198
|
+
if (this.isGarage) {
|
|
199
|
+
await sleep(Math.max(this.operationTime * 100, 2000))
|
|
200
|
+
subService.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
201
|
+
subService.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
202
|
+
this.subAccessory.eveService.addEntry({ status: 0 })
|
|
203
|
+
const initialTime = this.subAccessory.eveService.getInitialTime()
|
|
204
|
+
subService.updateCharacteristic(
|
|
205
|
+
this.eveChar.LastActivation,
|
|
206
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
207
|
+
)
|
|
208
|
+
subService.updateCharacteristic(
|
|
209
|
+
this.eveChar.TimesOpened,
|
|
210
|
+
subService.getCharacteristic(this.eveChar.TimesOpened).value + 1,
|
|
211
|
+
)
|
|
212
|
+
if (params.updateSource && this.enableLoggingSub) {
|
|
213
|
+
this.log('[%s] %s [%s].', this.nameSub, this.lang.curState, this.lang.doorOpen)
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
subService.updateCharacteristic(this.hapChar.LockTargetState, 0)
|
|
217
|
+
subService.updateCharacteristic(this.hapChar.LockCurrentState, 0)
|
|
218
|
+
this.subAccessory.context.contactDetected = false
|
|
219
|
+
if (params.updateSource && this.enableLoggingSub) {
|
|
220
|
+
this.log('[%s] %s [%s].', this.nameSub, this.lang.curState, this.lang.lockUnlocked)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
break
|
|
224
|
+
}
|
|
225
|
+
default:
|
|
226
|
+
}
|
|
227
|
+
} catch (err) {
|
|
228
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|