@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,324 @@
|
|
|
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.hapChar = platform.api.hap.Characteristic
|
|
8
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
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
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
19
|
+
this.isOnline = true
|
|
20
|
+
|
|
21
|
+
// Set up custom variables for this device type
|
|
22
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
23
|
+
const showAsMotor = deviceConf.showAsMotor || platformConsts.defaultValues.showAsMotor
|
|
24
|
+
|
|
25
|
+
// Set the correct logging variables for this accessory
|
|
26
|
+
switch (deviceConf.overrideLogging) {
|
|
27
|
+
case 'standard':
|
|
28
|
+
this.enableLogging = true
|
|
29
|
+
this.enableDebugLogging = false
|
|
30
|
+
break
|
|
31
|
+
case 'debug':
|
|
32
|
+
this.enableLogging = true
|
|
33
|
+
this.enableDebugLogging = true
|
|
34
|
+
break
|
|
35
|
+
case 'disable':
|
|
36
|
+
this.enableLogging = false
|
|
37
|
+
this.enableDebugLogging = false
|
|
38
|
+
break
|
|
39
|
+
default:
|
|
40
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
41
|
+
this.enableDebugLogging = platform.config.debug
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Add the window covering service if it doesn't already exist
|
|
46
|
+
let service
|
|
47
|
+
switch (showAsMotor) {
|
|
48
|
+
case 'door':
|
|
49
|
+
service = this.hapServ.Door
|
|
50
|
+
if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
|
|
51
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
|
|
52
|
+
}
|
|
53
|
+
if (this.accessory.getService(this.hapServ.Window)) {
|
|
54
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
|
|
55
|
+
}
|
|
56
|
+
if (this.accessory.getService(this.hapServ.WindowCovering)) {
|
|
57
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
|
|
58
|
+
}
|
|
59
|
+
break
|
|
60
|
+
case 'garage':
|
|
61
|
+
service = this.hapServ.GarageDoorOpener
|
|
62
|
+
this.isGarage = true
|
|
63
|
+
if (this.accessory.getService(this.hapServ.Door)) {
|
|
64
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
|
|
65
|
+
}
|
|
66
|
+
if (this.accessory.getService(this.hapServ.Window)) {
|
|
67
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
|
|
68
|
+
}
|
|
69
|
+
if (this.accessory.getService(this.hapServ.WindowCovering)) {
|
|
70
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
|
|
71
|
+
}
|
|
72
|
+
break
|
|
73
|
+
case 'window':
|
|
74
|
+
service = this.hapServ.Window
|
|
75
|
+
if (this.accessory.getService(this.hapServ.Door)) {
|
|
76
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
|
|
77
|
+
}
|
|
78
|
+
if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
|
|
79
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
|
|
80
|
+
}
|
|
81
|
+
if (this.accessory.getService(this.hapServ.WindowCovering)) {
|
|
82
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
|
|
83
|
+
}
|
|
84
|
+
break
|
|
85
|
+
default:
|
|
86
|
+
service = this.hapServ.WindowCovering
|
|
87
|
+
if (this.accessory.getService(this.hapServ.Door)) {
|
|
88
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
|
|
89
|
+
}
|
|
90
|
+
if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
|
|
91
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
|
|
92
|
+
}
|
|
93
|
+
if (this.accessory.getService(this.hapServ.Window)) {
|
|
94
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
|
|
95
|
+
}
|
|
96
|
+
break
|
|
97
|
+
}
|
|
98
|
+
this.service = this.accessory.getService(service) || this.accessory.addService(service)
|
|
99
|
+
|
|
100
|
+
// Add the set handler to the target position characteristic
|
|
101
|
+
if (this.isGarage) {
|
|
102
|
+
this.service
|
|
103
|
+
.getCharacteristic(this.hapChar.TargetDoorState)
|
|
104
|
+
.onSet(async value => this.internalTargetUpdate(value))
|
|
105
|
+
} else {
|
|
106
|
+
this.service
|
|
107
|
+
.getCharacteristic(this.hapChar.TargetPosition)
|
|
108
|
+
.onSet(async value => this.internalPositionUpdate(value))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
112
|
+
if (!platform.config.disableNoResponse) {
|
|
113
|
+
if (this.isGarage) {
|
|
114
|
+
this.service.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
|
|
115
|
+
if (!this.isOnline) {
|
|
116
|
+
throw new this.hapErr(-70402)
|
|
117
|
+
}
|
|
118
|
+
return this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
|
|
119
|
+
})
|
|
120
|
+
this.service.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
|
|
121
|
+
if (!this.isOnline) {
|
|
122
|
+
throw new this.hapErr(-70402)
|
|
123
|
+
}
|
|
124
|
+
return this.service.getCharacteristic(this.hapChar.TargetDoorState).value
|
|
125
|
+
})
|
|
126
|
+
} else {
|
|
127
|
+
this.service.getCharacteristic(this.hapChar.CurrentPosition).onGet(() => {
|
|
128
|
+
if (!this.isOnline) {
|
|
129
|
+
throw new this.hapErr(-70402)
|
|
130
|
+
}
|
|
131
|
+
return this.service.getCharacteristic(this.hapChar.CurrentPosition).value
|
|
132
|
+
})
|
|
133
|
+
this.service.getCharacteristic(this.hapChar.TargetPosition).onGet(() => {
|
|
134
|
+
if (!this.isOnline) {
|
|
135
|
+
throw new this.hapErr(-70402)
|
|
136
|
+
}
|
|
137
|
+
return this.service.getCharacteristic(this.hapChar.TargetPosition).value
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Output the customised options to the log
|
|
143
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
144
|
+
const opts = JSON.stringify({
|
|
145
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
146
|
+
showAsMotor,
|
|
147
|
+
})
|
|
148
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
Q1
|
|
152
|
+
{"op":3} -> command to close
|
|
153
|
+
{"op":3,"per":0} -> received when closed
|
|
154
|
+
|
|
155
|
+
{"op":1,} -> command to open
|
|
156
|
+
{"op":1,"per":100} -> received when open
|
|
157
|
+
*/
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async internalPositionUpdate(value) {
|
|
161
|
+
try {
|
|
162
|
+
// This acts like a debounce function when endlessly sliding the slider
|
|
163
|
+
const updateKey = generateRandomString(5)
|
|
164
|
+
this.updateKey = updateKey
|
|
165
|
+
await sleep(500)
|
|
166
|
+
if (updateKey !== this.updateKey) {
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Create the params object to send
|
|
171
|
+
const params = {}
|
|
172
|
+
|
|
173
|
+
switch (this.accessory.context.eweUIID) {
|
|
174
|
+
case 11:
|
|
175
|
+
// If we are to fully open/close the curtain we can use the switch param
|
|
176
|
+
if ([0, 100].includes(value)) {
|
|
177
|
+
// 'on' for fully open and 'off' for fully close
|
|
178
|
+
params.switch = value === 100 ? 'on' : 'off'
|
|
179
|
+
} else {
|
|
180
|
+
// Otherwise, for a %-point we can use the 'setclose' param
|
|
181
|
+
params.setclose = Math.abs(100 - value)
|
|
182
|
+
}
|
|
183
|
+
break
|
|
184
|
+
case 67:
|
|
185
|
+
// For a %-point we can use the 'per' param int[0=CLOSED, 100=OPEN]
|
|
186
|
+
params.per = value
|
|
187
|
+
break
|
|
188
|
+
default:
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Send the device update
|
|
193
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
194
|
+
|
|
195
|
+
// Update the cache with the new position
|
|
196
|
+
this.cachePos = value
|
|
197
|
+
|
|
198
|
+
// Log the update if appropriate
|
|
199
|
+
if (this.enableLogging) {
|
|
200
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos)
|
|
201
|
+
}
|
|
202
|
+
} catch (err) {
|
|
203
|
+
// Catch any errors and let the platform display them
|
|
204
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cachePos)
|
|
207
|
+
}, 2000)
|
|
208
|
+
throw new this.hapErr(-70402)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async internalTargetUpdate(value) {
|
|
213
|
+
try {
|
|
214
|
+
// value is 0 for open and 1 for closed
|
|
215
|
+
const params = {}
|
|
216
|
+
switch (this.accessory.context.eweUIID) {
|
|
217
|
+
case 11:
|
|
218
|
+
params.switch = value === 0 ? 'on' : 'off'
|
|
219
|
+
break
|
|
220
|
+
case 67:
|
|
221
|
+
params.op = value === 0 ? 1 : 3
|
|
222
|
+
break
|
|
223
|
+
default:
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
227
|
+
} catch (err) {
|
|
228
|
+
// Catch any errors and let the platform display them
|
|
229
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
230
|
+
setTimeout(() => {
|
|
231
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, this.cachePos)
|
|
232
|
+
}, 2000)
|
|
233
|
+
throw new this.hapErr(-70402)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async externalUpdate(params) {
|
|
238
|
+
try {
|
|
239
|
+
// Don't continue if there are no useful parameters
|
|
240
|
+
if (this.isGarage) {
|
|
241
|
+
switch (this.accessory.context.eweUIID) {
|
|
242
|
+
case 11:
|
|
243
|
+
// Todo
|
|
244
|
+
break
|
|
245
|
+
case 67:
|
|
246
|
+
if (hasProperty(params, 'op') && hasProperty(params, 'per')) {
|
|
247
|
+
if (params.op === 3 && params.per === 0) {
|
|
248
|
+
// closed
|
|
249
|
+
if (this.cachePos !== 1) {
|
|
250
|
+
this.cachePos = 1
|
|
251
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
252
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
253
|
+
if (params.updateSource && this.enableLogging) {
|
|
254
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.doorClosed)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} else if (params.op === 1 && params.per === 100) {
|
|
258
|
+
// open
|
|
259
|
+
if (this.cachePos !== 0) {
|
|
260
|
+
this.cachePos = 0
|
|
261
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
262
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
263
|
+
if (params.updateSource && this.enableLogging) {
|
|
264
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.doorOpen)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
break
|
|
270
|
+
default:
|
|
271
|
+
}
|
|
272
|
+
} else if (
|
|
273
|
+
params.switch
|
|
274
|
+
|| hasProperty(params, 'setclose')
|
|
275
|
+
|| hasProperty(params, 'per')
|
|
276
|
+
) {
|
|
277
|
+
let newPos
|
|
278
|
+
switch (this.accessory.context.eweUIID) {
|
|
279
|
+
case 11:
|
|
280
|
+
// 'setclose' is 0=OPEN 100=CLOSED whereas HomeKit is 0=CLOSED 100=OPEN
|
|
281
|
+
// 'switch' is 'on' for fully open and 'off' for fully close
|
|
282
|
+
if (hasProperty(params, 'setclose')) {
|
|
283
|
+
newPos = Math.abs(100 - params.setclose)
|
|
284
|
+
} else if (params.switch) {
|
|
285
|
+
newPos = params.switch === 'on' ? 100 : 0
|
|
286
|
+
} else {
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
break
|
|
290
|
+
case 67:
|
|
291
|
+
// 'per' matches HomeKit status 0=CLOSED 100=OPEN
|
|
292
|
+
if (hasProperty(params, 'per')) {
|
|
293
|
+
newPos = params.per
|
|
294
|
+
} else {
|
|
295
|
+
return
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Update HomeKit with the provided value
|
|
303
|
+
this.service.updateCharacteristic(this.hapChar.TargetPosition, newPos)
|
|
304
|
+
this.service.updateCharacteristic(this.hapChar.CurrentPosition, newPos)
|
|
305
|
+
this.service.updateCharacteristic(this.hapChar.PositionState, 2)
|
|
306
|
+
|
|
307
|
+
// Only update the cache and log if the provided value has changed
|
|
308
|
+
if (params.updateSource && this.cachePos !== newPos) {
|
|
309
|
+
this.cachePos = newPos
|
|
310
|
+
if (this.enableLogging) {
|
|
311
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} catch (err) {
|
|
316
|
+
// Catch any errors and let the platform display them
|
|
317
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
markStatus(isOnline) {
|
|
322
|
+
this.isOnline = isOnline
|
|
323
|
+
}
|
|
324
|
+
}
|