@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,349 @@
|
|
|
1
|
+
import { generateRandomString, sleep } from '../utils/functions.js'
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
constructor(platform, accessory) {
|
|
5
|
+
// Set up variables from the platform
|
|
6
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
7
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
8
|
+
this.hapServ = platform.api.hap.Service
|
|
9
|
+
this.lang = platform.lang
|
|
10
|
+
this.log = platform.log
|
|
11
|
+
this.platform = platform
|
|
12
|
+
|
|
13
|
+
// Set up variables from the accessory
|
|
14
|
+
this.name = accessory.displayName
|
|
15
|
+
this.accessory = accessory
|
|
16
|
+
|
|
17
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
18
|
+
this.isOnline = true
|
|
19
|
+
|
|
20
|
+
// Set up custom variables for this device type
|
|
21
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
22
|
+
this.hideLight = deviceConf.hideLight
|
|
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
|
+
// Add the fan service if it doesn't already exist
|
|
45
|
+
this.service = this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan)
|
|
46
|
+
|
|
47
|
+
// Add the set handler to the fan on/off characteristic
|
|
48
|
+
this.service
|
|
49
|
+
.getCharacteristic(this.hapChar.On)
|
|
50
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
51
|
+
|
|
52
|
+
// Add the set handler to the fan rotation speed characteristic
|
|
53
|
+
this.service
|
|
54
|
+
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
55
|
+
.setProps({
|
|
56
|
+
maxValue: 3,
|
|
57
|
+
minStep: 1,
|
|
58
|
+
minValue: 0,
|
|
59
|
+
unit: 'unitless', // This is actually from HAP for Bluetooth LE Specification, but fits
|
|
60
|
+
})
|
|
61
|
+
.onSet(async value => this.internalSpeedUpdate(value))
|
|
62
|
+
|
|
63
|
+
// Check to see if the user has hidden the light channel
|
|
64
|
+
if (this.hideLight) {
|
|
65
|
+
// The user has hidden the light channel, so remove it if it exists
|
|
66
|
+
if (this.accessory.getService(this.hapServ.Lightbulb)) {
|
|
67
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Lightbulb))
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
// The user has not hidden the light channel, so add it if it doesn't exist
|
|
71
|
+
this.lightService = this.accessory.getService(this.hapServ.Lightbulb)
|
|
72
|
+
|| this.accessory.addService(this.hapServ.Lightbulb)
|
|
73
|
+
|
|
74
|
+
// Add the set handler to the lightbulb on/off characteristic
|
|
75
|
+
this.lightService
|
|
76
|
+
.getCharacteristic(this.hapChar.On)
|
|
77
|
+
.onSet(async value => this.internalLightUpdate(value))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Set the fan service to the primary service
|
|
81
|
+
this.service.setPrimaryService()
|
|
82
|
+
|
|
83
|
+
// Conversion object eWeLink mode to text label
|
|
84
|
+
this.speed2label = {
|
|
85
|
+
1: 'low',
|
|
86
|
+
2: 'medium',
|
|
87
|
+
3: 'high',
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
91
|
+
if (!platform.config.disableNoResponse) {
|
|
92
|
+
this.service.getCharacteristic(this.hapChar.On).onGet(() => {
|
|
93
|
+
if (!this.isOnline) {
|
|
94
|
+
throw new this.hapErr(-70402)
|
|
95
|
+
}
|
|
96
|
+
return this.service.getCharacteristic(this.hapChar.On).value
|
|
97
|
+
})
|
|
98
|
+
this.service.getCharacteristic(this.hapChar.RotationSpeed).onGet(() => {
|
|
99
|
+
if (!this.isOnline) {
|
|
100
|
+
throw new this.hapErr(-70402)
|
|
101
|
+
}
|
|
102
|
+
return this.service.getCharacteristic(this.hapChar.RotationSpeed).value
|
|
103
|
+
})
|
|
104
|
+
if (this.lightService) {
|
|
105
|
+
this.lightService.getCharacteristic(this.hapChar.On).onGet(() => {
|
|
106
|
+
if (!this.isOnline) {
|
|
107
|
+
throw new this.hapErr(-70402)
|
|
108
|
+
}
|
|
109
|
+
return this.lightService.getCharacteristic(this.hapChar.On).value
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Output the customised options to the log
|
|
115
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
116
|
+
const opts = JSON.stringify({
|
|
117
|
+
hideLight: this.hideLight,
|
|
118
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
119
|
+
})
|
|
120
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async internalStateUpdate(value) {
|
|
124
|
+
try {
|
|
125
|
+
const newState = value ? 'on' : 'off'
|
|
126
|
+
if (newState === this.cacheState) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
const params = {
|
|
130
|
+
switches: [],
|
|
131
|
+
}
|
|
132
|
+
params.switches.push({
|
|
133
|
+
switch: newState,
|
|
134
|
+
outlet: 1,
|
|
135
|
+
})
|
|
136
|
+
if (newState === 'on') {
|
|
137
|
+
params.switches.push({
|
|
138
|
+
switch: this.cacheSpeed === 2 ? 'on' : 'off',
|
|
139
|
+
outlet: 2,
|
|
140
|
+
})
|
|
141
|
+
params.switches.push({
|
|
142
|
+
switch: this.cacheSpeed === 3 ? 'on' : 'off',
|
|
143
|
+
outlet: 3,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
147
|
+
this.cacheState = newState
|
|
148
|
+
if (this.enableLogging) {
|
|
149
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, newState)
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
155
|
+
}, 2000)
|
|
156
|
+
throw new this.hapErr(-70402)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async internalSpeedUpdate(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
|
+
const params = {
|
|
170
|
+
switches: [],
|
|
171
|
+
}
|
|
172
|
+
const newState = value >= 1 ? 'on' : 'off'
|
|
173
|
+
let newSpeed
|
|
174
|
+
|
|
175
|
+
if (value < 0 || value > 3) {
|
|
176
|
+
newSpeed = 0
|
|
177
|
+
} else {
|
|
178
|
+
newSpeed = value
|
|
179
|
+
}
|
|
180
|
+
if (newSpeed === this.cacheSpeed) {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
params.switches.push({
|
|
184
|
+
switch: newState === 'on' && newSpeed >= 1 ? 'on' : 'off',
|
|
185
|
+
outlet: 1,
|
|
186
|
+
})
|
|
187
|
+
params.switches.push({
|
|
188
|
+
switch: newState === 'on' && newSpeed === 2 ? 'on' : 'off',
|
|
189
|
+
outlet: 2,
|
|
190
|
+
})
|
|
191
|
+
params.switches.push({
|
|
192
|
+
switch: newState === 'on' && newSpeed === 3 ? 'on' : 'off',
|
|
193
|
+
outlet: 3,
|
|
194
|
+
})
|
|
195
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
196
|
+
if (newState !== this.cacheState) {
|
|
197
|
+
this.cacheState = newState
|
|
198
|
+
if (this.enableLogging) {
|
|
199
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (newSpeed === 0) {
|
|
203
|
+
// Update the rotation speed back to the previous value (with the fan still off)
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
206
|
+
}, 2000)
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
this.cacheSpeed = newSpeed
|
|
210
|
+
if (this.enableLogging) {
|
|
211
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curSpeed, this.speed2label[this.cacheSpeed])
|
|
212
|
+
}
|
|
213
|
+
} catch (err) {
|
|
214
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
215
|
+
setTimeout(() => {
|
|
216
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
217
|
+
}, 2000)
|
|
218
|
+
throw new this.hapErr(-70402)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async internalLightUpdate(value) {
|
|
223
|
+
try {
|
|
224
|
+
const params = {
|
|
225
|
+
switches: [],
|
|
226
|
+
}
|
|
227
|
+
const newLight = value ? 'on' : 'off'
|
|
228
|
+
if (newLight === this.cacheLight) {
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
params.switches.push({
|
|
232
|
+
switch: newLight,
|
|
233
|
+
outlet: 0,
|
|
234
|
+
})
|
|
235
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
236
|
+
this.cacheLight = newLight
|
|
237
|
+
if (this.enableLogging) {
|
|
238
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curLight, this.cacheLight)
|
|
239
|
+
}
|
|
240
|
+
} catch (err) {
|
|
241
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLight === 'on')
|
|
244
|
+
}, 2000)
|
|
245
|
+
throw new this.hapErr(-70402)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async externalUpdate(params) {
|
|
250
|
+
try {
|
|
251
|
+
if (params.light && params.fan && params.speed) {
|
|
252
|
+
// LAN update from iFan03
|
|
253
|
+
params.switches = {}
|
|
254
|
+
params.switches[0] = { switch: params.light }
|
|
255
|
+
params.switches[1] = { switch: params.fan }
|
|
256
|
+
switch (params.speed) {
|
|
257
|
+
case 1:
|
|
258
|
+
params.switches[2] = { switch: 'off' }
|
|
259
|
+
params.switches[3] = { switch: 'off' }
|
|
260
|
+
break
|
|
261
|
+
case 2:
|
|
262
|
+
params.switches[2] = { switch: 'on' }
|
|
263
|
+
params.switches[3] = { switch: 'off' }
|
|
264
|
+
break
|
|
265
|
+
case 3:
|
|
266
|
+
params.switches[2] = { switch: 'off' }
|
|
267
|
+
params.switches[3] = { switch: 'on' }
|
|
268
|
+
break
|
|
269
|
+
default:
|
|
270
|
+
return
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!params.switches) {
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
if (params.switches[1].switch !== this.cacheState) {
|
|
277
|
+
this.cacheState = params.switches[1].switch
|
|
278
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
279
|
+
if (params.updateSource && this.enableLogging) {
|
|
280
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
let speed
|
|
284
|
+
switch (params.switches[2].switch + params.switches[3].switch) {
|
|
285
|
+
case 'onoff':
|
|
286
|
+
speed = 2
|
|
287
|
+
break
|
|
288
|
+
case 'offon':
|
|
289
|
+
speed = 3
|
|
290
|
+
break
|
|
291
|
+
default:
|
|
292
|
+
speed = 1
|
|
293
|
+
break
|
|
294
|
+
}
|
|
295
|
+
if (speed !== this.cacheSpeed && this.cacheState === 'on') {
|
|
296
|
+
this.cacheSpeed = speed
|
|
297
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
298
|
+
if (params.updateSource && this.enableLogging) {
|
|
299
|
+
this.log(
|
|
300
|
+
'[%s] %s [%s].',
|
|
301
|
+
this.name,
|
|
302
|
+
this.lang.curSpeed,
|
|
303
|
+
this.speed2label[this.cacheSpeed],
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (this.lightService && params.switches[0].switch !== this.cacheLight) {
|
|
308
|
+
this.cacheLight = params.switches[0].switch
|
|
309
|
+
this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLight === 'on')
|
|
310
|
+
if (params.updateSource && this.enableLogging) {
|
|
311
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curLight, this.cacheLight)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
} catch (err) {
|
|
315
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
currentState() {
|
|
320
|
+
const toReturn = {}
|
|
321
|
+
let speedLabel
|
|
322
|
+
const speed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
|
|
323
|
+
if (speed === 0) {
|
|
324
|
+
speedLabel = 'off'
|
|
325
|
+
} else if (speed <= 1) {
|
|
326
|
+
speedLabel = 'low'
|
|
327
|
+
} else if (speed <= 2) {
|
|
328
|
+
speedLabel = 'medium'
|
|
329
|
+
} else {
|
|
330
|
+
speedLabel = 'high'
|
|
331
|
+
}
|
|
332
|
+
toReturn.services = ['fan']
|
|
333
|
+
toReturn.fan = {
|
|
334
|
+
state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
|
|
335
|
+
speed: speedLabel,
|
|
336
|
+
}
|
|
337
|
+
if (!this.hideLight) {
|
|
338
|
+
toReturn.services.push('light')
|
|
339
|
+
toReturn.light = {
|
|
340
|
+
state: this.lightService.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return toReturn
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
markStatus(isOnline) {
|
|
347
|
+
this.isOnline = isOnline
|
|
348
|
+
}
|
|
349
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import platformConsts from '../utils/constants.js'
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
constructor(platform, accessory) {
|
|
5
|
+
// Set up variables from the platform
|
|
6
|
+
this.eveChar = platform.eveChar
|
|
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
|
+
// Set the correct logging variables for this accessory
|
|
19
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
20
|
+
this.enableDebugLogging = platform.config.debug
|
|
21
|
+
|
|
22
|
+
if (platformConsts.devices.switchSCM.includes(this.accessory.context.groupUIID)) {
|
|
23
|
+
this.isSCM = true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Add the switch service if it doesn't already exist
|
|
27
|
+
this.service = this.accessory.getService(this.hapServ.Switch)
|
|
28
|
+
|| this.accessory.addService(this.hapServ.Switch)
|
|
29
|
+
|
|
30
|
+
// Add the set handler to the switch on/off characteristic
|
|
31
|
+
this.service
|
|
32
|
+
.getCharacteristic(this.hapChar.On)
|
|
33
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
34
|
+
|
|
35
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
36
|
+
this.accessory.eveService = new platform.eveService('switch', this.accessory, {
|
|
37
|
+
log: () => {},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Output the customised options to the log
|
|
41
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
42
|
+
const opts = JSON.stringify({
|
|
43
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
44
|
+
})
|
|
45
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async internalStateUpdate(value) {
|
|
49
|
+
try {
|
|
50
|
+
const newValue = value ? 'on' : 'off'
|
|
51
|
+
if (newValue === this.cacheState) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
const params = {}
|
|
55
|
+
if (this.isSCM) {
|
|
56
|
+
params.switches = [{ switch: newValue, outlet: 0 }]
|
|
57
|
+
} else {
|
|
58
|
+
params.switch = newValue
|
|
59
|
+
}
|
|
60
|
+
await this.platform.sendGroupUpdate(this.accessory, params)
|
|
61
|
+
this.cacheState = newValue
|
|
62
|
+
this.accessory.eveService.addEntry({ status: value ? 1 : 0 })
|
|
63
|
+
if (this.enableLogging) {
|
|
64
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
65
|
+
}
|
|
66
|
+
} catch (err) {
|
|
67
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
70
|
+
}, 2000)
|
|
71
|
+
throw new this.hapErr(-70402)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async externalUpdate(params) {
|
|
76
|
+
try {
|
|
77
|
+
if (!this.isSCM && params.switch && params.switch !== this.cacheState) {
|
|
78
|
+
this.cacheState = params.switch
|
|
79
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
80
|
+
this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
|
|
81
|
+
if (params.updateSource && this.enableLogging) {
|
|
82
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (this.isSCM && params.switches && params.switches[0].switch !== this.cacheState) {
|
|
86
|
+
this.cacheState = params.switches[0].switch
|
|
87
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
88
|
+
this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
|
|
89
|
+
if (params.updateSource && this.enableLogging) {
|
|
90
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async currentState() {
|
|
99
|
+
const toReturn = {}
|
|
100
|
+
toReturn.services = ['switch']
|
|
101
|
+
toReturn.switch = {
|
|
102
|
+
state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
|
|
103
|
+
}
|
|
104
|
+
return toReturn
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { generateRandomString, sleep } from '../utils/functions.js'
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
constructor(platform, accessory) {
|
|
5
|
+
// Set up variables from the platform
|
|
6
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
7
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
8
|
+
this.hapServ = platform.api.hap.Service
|
|
9
|
+
this.lang = platform.lang
|
|
10
|
+
this.log = platform.log
|
|
11
|
+
this.platform = platform
|
|
12
|
+
|
|
13
|
+
// Set up variables from the accessory
|
|
14
|
+
this.name = accessory.displayName
|
|
15
|
+
this.accessory = accessory
|
|
16
|
+
|
|
17
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
18
|
+
this.isOnline = true
|
|
19
|
+
|
|
20
|
+
// Set up custom variables for this device type
|
|
21
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
22
|
+
|
|
23
|
+
// Set the correct logging variables for this accessory
|
|
24
|
+
switch (deviceConf.overrideLogging) {
|
|
25
|
+
case 'standard':
|
|
26
|
+
this.enableLogging = true
|
|
27
|
+
this.enableDebugLogging = false
|
|
28
|
+
break
|
|
29
|
+
case 'debug':
|
|
30
|
+
this.enableLogging = true
|
|
31
|
+
this.enableDebugLogging = true
|
|
32
|
+
break
|
|
33
|
+
case 'disable':
|
|
34
|
+
this.enableLogging = false
|
|
35
|
+
this.enableDebugLogging = false
|
|
36
|
+
break
|
|
37
|
+
default:
|
|
38
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
39
|
+
this.enableDebugLogging = platform.config.debug
|
|
40
|
+
break
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
The device does not provide a current humidity reading so
|
|
45
|
+
we use a fan accessory to be able to control the on/off state
|
|
46
|
+
and the modes (1, 2, 3) using a rotation speed of (33%, 66%, 99%)
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
// Add the fan service if it doesn't already exist
|
|
50
|
+
this.service = this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan)
|
|
51
|
+
|
|
52
|
+
// Add the set handler to the fan on/off characteristic
|
|
53
|
+
this.service
|
|
54
|
+
.getCharacteristic(this.hapChar.On)
|
|
55
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
56
|
+
|
|
57
|
+
// Add the set handler to the fan rotation speed characteristic
|
|
58
|
+
this.service
|
|
59
|
+
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
60
|
+
.setProps({ minStep: 33 })
|
|
61
|
+
.onSet(async value => this.internalModeUpdate(value))
|
|
62
|
+
|
|
63
|
+
// Conversion object eWeLink mode to text label
|
|
64
|
+
this.mode2label = {
|
|
65
|
+
1: 'low',
|
|
66
|
+
2: 'medium',
|
|
67
|
+
3: 'high',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
71
|
+
if (!platform.config.disableNoResponse) {
|
|
72
|
+
this.service.getCharacteristic(this.hapChar.On).onGet(() => {
|
|
73
|
+
if (!this.isOnline) {
|
|
74
|
+
throw new this.hapErr(-70402)
|
|
75
|
+
}
|
|
76
|
+
return this.service.getCharacteristic(this.hapChar.On).value
|
|
77
|
+
})
|
|
78
|
+
this.service.getCharacteristic(this.hapChar.RotationSpeed).onGet(() => {
|
|
79
|
+
if (!this.isOnline) {
|
|
80
|
+
throw new this.hapErr(-70402)
|
|
81
|
+
}
|
|
82
|
+
return this.service.getCharacteristic(this.hapChar.RotationSpeed).value
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Output the customised options to the log
|
|
87
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
88
|
+
const opts = JSON.stringify({
|
|
89
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
90
|
+
})
|
|
91
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async internalStateUpdate(value) {
|
|
95
|
+
try {
|
|
96
|
+
const newState = value ? 'on' : 'off'
|
|
97
|
+
if (newState === this.cacheState) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
const params = { switch: newState }
|
|
101
|
+
if (newState === 'on') {
|
|
102
|
+
params.state = this.cacheMode
|
|
103
|
+
}
|
|
104
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
105
|
+
this.cacheState = newState
|
|
106
|
+
if (this.enableLogging) {
|
|
107
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, newState)
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
113
|
+
}, 2000)
|
|
114
|
+
throw new this.hapErr(-70402)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async internalModeUpdate(value) {
|
|
119
|
+
try {
|
|
120
|
+
const updateKey = generateRandomString(5)
|
|
121
|
+
this.updateKey = updateKey
|
|
122
|
+
await sleep(500)
|
|
123
|
+
if (updateKey !== this.updateKey) {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
const params = {}
|
|
127
|
+
const newState = value >= 1 ? 'on' : 'off'
|
|
128
|
+
params.switch = newState
|
|
129
|
+
let newMode
|
|
130
|
+
if (value > 0) {
|
|
131
|
+
if (value <= 33) {
|
|
132
|
+
newMode = 1
|
|
133
|
+
} else if (value <= 66) {
|
|
134
|
+
newMode = 2
|
|
135
|
+
} else {
|
|
136
|
+
newMode = 3
|
|
137
|
+
}
|
|
138
|
+
if (this.cacheMode === newMode) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
params.state = newMode
|
|
142
|
+
}
|
|
143
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
144
|
+
if (newState !== this.cacheState) {
|
|
145
|
+
this.cacheState = newState
|
|
146
|
+
if (this.enableLogging) {
|
|
147
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (value === 0) {
|
|
151
|
+
// Update the rotation speed back to the previous value (with the fan still off)
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheMode * 33)
|
|
154
|
+
}, 2000)
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
this.cacheMode = newMode
|
|
158
|
+
if (this.enableLogging) {
|
|
159
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curMode, this.mode2label[this.cacheMode])
|
|
160
|
+
}
|
|
161
|
+
} catch (err) {
|
|
162
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheMode * 33)
|
|
165
|
+
}, 2000)
|
|
166
|
+
throw new this.hapErr(-70402)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async externalUpdate(params) {
|
|
171
|
+
try {
|
|
172
|
+
if (params.switch && params.switch !== this.cacheState) {
|
|
173
|
+
this.cacheState = params.switch
|
|
174
|
+
if (params.updateSource && this.enableLogging) {
|
|
175
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
176
|
+
}
|
|
177
|
+
this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
178
|
+
if (this.cacheState !== 'on') {
|
|
179
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, 0)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (params.state && params.state !== this.cacheMode) {
|
|
183
|
+
this.cacheMode = params.state
|
|
184
|
+
if (this.cacheState === 'on') {
|
|
185
|
+
if (params.updateSource && this.enableLogging) {
|
|
186
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curMode, this.mode2label[this.cacheMode])
|
|
187
|
+
}
|
|
188
|
+
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheMode * 33)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch (err) {
|
|
192
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
markStatus(isOnline) {
|
|
197
|
+
this.isOnline = isOnline
|
|
198
|
+
}
|
|
199
|
+
}
|