@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,300 @@
|
|
|
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
|
+
// 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
|
+
this.sensorType = deviceConf.sensorType || 'motion'
|
|
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
|
+
// If the accessory has a switch service then remove it
|
|
46
|
+
if (this.accessory.getService(this.hapServ.Switch)) {
|
|
47
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// If the accessory has an outlet service then remove it
|
|
51
|
+
if (this.accessory.getService(this.hapServ.Outlet)) {
|
|
52
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Outlet))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// This instance is a sensor which the user can define as different types
|
|
56
|
+
let serv
|
|
57
|
+
let eveType
|
|
58
|
+
|
|
59
|
+
// Check which type this sensor is and get the correct service/characteristic
|
|
60
|
+
switch (this.sensorType) {
|
|
61
|
+
case 'water':
|
|
62
|
+
serv = this.hapServ.LeakSensor
|
|
63
|
+
this.char = this.hapChar.LeakDetected
|
|
64
|
+
eveType = 'motion'
|
|
65
|
+
break
|
|
66
|
+
case 'fire':
|
|
67
|
+
case 'smoke':
|
|
68
|
+
serv = this.hapServ.SmokeSensor
|
|
69
|
+
this.char = this.hapChar.SmokeDetected
|
|
70
|
+
eveType = 'motion'
|
|
71
|
+
break
|
|
72
|
+
case 'co':
|
|
73
|
+
serv = this.hapServ.CarbonMonoxideSensor
|
|
74
|
+
this.char = this.hapChar.CarbonMonoxideDetected
|
|
75
|
+
eveType = 'motion'
|
|
76
|
+
break
|
|
77
|
+
case 'co2':
|
|
78
|
+
serv = this.hapServ.CarbonDioxideSensor
|
|
79
|
+
this.char = this.hapChar.CarbonDioxideDetected
|
|
80
|
+
eveType = 'motion'
|
|
81
|
+
break
|
|
82
|
+
case 'contact':
|
|
83
|
+
serv = this.hapServ.ContactSensor
|
|
84
|
+
this.char = this.hapChar.ContactSensorState
|
|
85
|
+
eveType = 'door'
|
|
86
|
+
this.useLastActivation = true
|
|
87
|
+
break
|
|
88
|
+
case 'occupancy':
|
|
89
|
+
serv = this.hapServ.OccupancySensor
|
|
90
|
+
this.char = this.hapChar.OccupancyDetected
|
|
91
|
+
eveType = 'motion'
|
|
92
|
+
break
|
|
93
|
+
default:
|
|
94
|
+
serv = this.hapServ.MotionSensor
|
|
95
|
+
this.char = this.hapChar.MotionDetected
|
|
96
|
+
eveType = 'motion'
|
|
97
|
+
this.useLastActivation = true
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Add the sensor if it doesn't already exist
|
|
102
|
+
this.service = this.accessory.getService(serv)
|
|
103
|
+
if (!this.service) {
|
|
104
|
+
this.service = this.accessory.addService(serv)
|
|
105
|
+
if (this.useLastActivation) {
|
|
106
|
+
this.service.addCharacteristic(this.eveChar.LastActivation)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Set up the device type and power readings if necessary
|
|
111
|
+
if (platformConsts.devices.switchSingle.includes(this.accessory.context.eweUIID)) {
|
|
112
|
+
this.setup = 'switchSingle'
|
|
113
|
+
} else if (platformConsts.devices.switchSinglePower.includes(this.accessory.context.eweUIID)) {
|
|
114
|
+
this.setup = 'switchSingle'
|
|
115
|
+
|
|
116
|
+
// Add Eve power characteristics
|
|
117
|
+
this.powerReadings = true
|
|
118
|
+
if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
|
|
119
|
+
this.service.addCharacteristic(this.eveChar.CurrentConsumption)
|
|
120
|
+
}
|
|
121
|
+
if (this.accessory.context.eweUIID === 32) {
|
|
122
|
+
if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
|
|
123
|
+
this.service.addCharacteristic(this.eveChar.ElectricCurrent)
|
|
124
|
+
}
|
|
125
|
+
if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
|
|
126
|
+
this.service.addCharacteristic(this.eveChar.Voltage)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} else if (platformConsts.devices.switchMulti.includes(this.accessory.context.eweUIID)) {
|
|
130
|
+
this.setup = 'switchMulti'
|
|
131
|
+
if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
|
|
132
|
+
// Add Eve power characteristics
|
|
133
|
+
this.powerReadings = true
|
|
134
|
+
if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
|
|
135
|
+
this.service.addCharacteristic(this.eveChar.CurrentConsumption)
|
|
136
|
+
}
|
|
137
|
+
if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
|
|
138
|
+
this.service.addCharacteristic(this.eveChar.ElectricCurrent)
|
|
139
|
+
}
|
|
140
|
+
if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
|
|
141
|
+
this.service.addCharacteristic(this.eveChar.Voltage)
|
|
142
|
+
}
|
|
143
|
+
this.isDualR3 = true
|
|
144
|
+
}
|
|
145
|
+
} else if (platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)) {
|
|
146
|
+
this.setup = 'switchMulti'
|
|
147
|
+
} else if (platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)) {
|
|
148
|
+
// Could do power here
|
|
149
|
+
this.setup = 'switchMulti'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
153
|
+
if (!platform.config.disableNoResponse) {
|
|
154
|
+
this.service.getCharacteristic(this.char).onGet(() => {
|
|
155
|
+
if (!this.isOnline) {
|
|
156
|
+
throw new this.hapErr(-70402)
|
|
157
|
+
}
|
|
158
|
+
return this.service.getCharacteristic(this.char).value
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
163
|
+
this.accessory.eveService = new platform.eveService(eveType, this.accessory, {
|
|
164
|
+
log: () => {},
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// Set up an interval to get eWeLink to send power updates
|
|
168
|
+
if (
|
|
169
|
+
this.powerReadings
|
|
170
|
+
&& (!this.isDualR3 || (this.isDualR3 && platform.config.mode !== 'lan'))
|
|
171
|
+
) {
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
this.internalUIUpdate()
|
|
174
|
+
this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
|
|
175
|
+
}, 5000)
|
|
176
|
+
|
|
177
|
+
// Stop the intervals on Homebridge shutdown
|
|
178
|
+
platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Output the customised options to the log
|
|
182
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
183
|
+
const opts = JSON.stringify({
|
|
184
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
185
|
+
sensorType: this.sensorType,
|
|
186
|
+
showAs: 'sensor',
|
|
187
|
+
})
|
|
188
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async internalUIUpdate() {
|
|
192
|
+
try {
|
|
193
|
+
// Skip polling if device isn't online
|
|
194
|
+
if (!this.isOnline) {
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Send the params to request the updates
|
|
199
|
+
if (this.isDualR3) {
|
|
200
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
|
|
201
|
+
} else {
|
|
202
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
|
|
203
|
+
}
|
|
204
|
+
} catch (err) {
|
|
205
|
+
// Suppress errors here
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async externalUpdate(params) {
|
|
210
|
+
try {
|
|
211
|
+
if (
|
|
212
|
+
(this.setup === 'switchMulti' && params.switches)
|
|
213
|
+
|| (this.setup === 'switchSingle' && params.switch)
|
|
214
|
+
) {
|
|
215
|
+
let newState
|
|
216
|
+
if (this.setup === 'switchMulti' && params.switches) {
|
|
217
|
+
newState = params.switches[0].switch
|
|
218
|
+
} else if (this.setup === 'switchSingle' && params.switch) {
|
|
219
|
+
newState = params.switch
|
|
220
|
+
}
|
|
221
|
+
if (newState && newState !== this.cacheState) {
|
|
222
|
+
this.cacheState = newState
|
|
223
|
+
if (this.cacheState === 'on') {
|
|
224
|
+
this.service.updateCharacteristic(this.char, 1)
|
|
225
|
+
this.accessory.eveService.addEntry({ status: 1 })
|
|
226
|
+
if (this.useLastActivation) {
|
|
227
|
+
const initialTime = this.accessory.eveService.getInitialTime()
|
|
228
|
+
this.service.updateCharacteristic(
|
|
229
|
+
this.eveChar.LastActivation,
|
|
230
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
this.service.updateCharacteristic(this.char, 0)
|
|
235
|
+
this.accessory.eveService.addEntry({ status: 0 })
|
|
236
|
+
}
|
|
237
|
+
if (params.updateSource && this.enableLogging) {
|
|
238
|
+
this.log(
|
|
239
|
+
'[%s] %s [%s].',
|
|
240
|
+
this.name,
|
|
241
|
+
this.lang.curState,
|
|
242
|
+
this.cacheState === 'on' ? this.lang.sensorYes : this.lang.sensorNo,
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Get the power readings given by certain devices
|
|
249
|
+
if (!this.powerReadings) {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
let logger = false
|
|
253
|
+
let power
|
|
254
|
+
let voltage
|
|
255
|
+
let current
|
|
256
|
+
if (hasProperty(params, 'actPow_00')) {
|
|
257
|
+
power = Number.parseInt(params.actPow_00, 10) / 100
|
|
258
|
+
this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
|
|
259
|
+
logger = true
|
|
260
|
+
} else if (hasProperty(params, 'power')) {
|
|
261
|
+
power = Number.parseFloat(params.power)
|
|
262
|
+
this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
|
|
263
|
+
logger = true
|
|
264
|
+
}
|
|
265
|
+
if (hasProperty(params, 'voltage_00')) {
|
|
266
|
+
voltage = Number.parseInt(params.voltage_00, 10) / 100
|
|
267
|
+
this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
|
|
268
|
+
logger = true
|
|
269
|
+
} else if (hasProperty(params, 'voltage')) {
|
|
270
|
+
voltage = Number.parseFloat(params.voltage)
|
|
271
|
+
this.service.updateCharacteristic(this.eveChar.Voltage, voltage)
|
|
272
|
+
logger = true
|
|
273
|
+
}
|
|
274
|
+
if (hasProperty(params, 'current_00')) {
|
|
275
|
+
current = Number.parseInt(params.current_00, 10) / 100
|
|
276
|
+
this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
|
|
277
|
+
logger = true
|
|
278
|
+
} else if (hasProperty(params, 'current')) {
|
|
279
|
+
current = Number.parseFloat(params.current)
|
|
280
|
+
this.service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
|
|
281
|
+
logger = true
|
|
282
|
+
}
|
|
283
|
+
if (params.updateSource && logger && this.enableLogging) {
|
|
284
|
+
this.log(
|
|
285
|
+
'[%s] %s%s%s.',
|
|
286
|
+
this.name,
|
|
287
|
+
power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
|
|
288
|
+
voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
|
|
289
|
+
current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
|
|
290
|
+
)
|
|
291
|
+
}
|
|
292
|
+
} catch (err) {
|
|
293
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
markStatus(isOnline) {
|
|
298
|
+
this.isOnline = isOnline
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { 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.deviceConf[accessory.context.eweDeviceId] || {}
|
|
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 switch service if it doesn't already exist
|
|
46
|
+
this.sService = this.accessory.getService(this.hapServ.Switch)
|
|
47
|
+
|| this.accessory.addService(this.hapServ.Switch)
|
|
48
|
+
|
|
49
|
+
// Add the valve service if it doesn't already exist
|
|
50
|
+
this.vService = this.accessory.getService(this.hapServ.Valve)
|
|
51
|
+
if (!this.vService) {
|
|
52
|
+
this.vService = this.accessory.addService(this.hapServ.Valve)
|
|
53
|
+
this.vService.updateCharacteristic(this.hapChar.Active, 0)
|
|
54
|
+
this.vService.updateCharacteristic(this.hapChar.InUse, 0)
|
|
55
|
+
this.vService.updateCharacteristic(this.hapChar.ValveType, 1)
|
|
56
|
+
this.vService.updateCharacteristic(this.hapChar.SetDuration, 120)
|
|
57
|
+
this.vService.addCharacteristic(this.hapChar.RemainingDuration)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Certain devices give power readings
|
|
61
|
+
if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
|
|
62
|
+
// Add Eve power characteristics
|
|
63
|
+
this.powerReadings = true
|
|
64
|
+
if (!this.sService.testCharacteristic(this.eveChar.CurrentConsumption)) {
|
|
65
|
+
this.sService.addCharacteristic(this.eveChar.CurrentConsumption)
|
|
66
|
+
}
|
|
67
|
+
if (!this.vService.testCharacteristic(this.eveChar.CurrentConsumption)) {
|
|
68
|
+
this.vService.addCharacteristic(this.eveChar.CurrentConsumption)
|
|
69
|
+
}
|
|
70
|
+
if (!this.sService.testCharacteristic(this.eveChar.ElectricCurrent)) {
|
|
71
|
+
this.sService.addCharacteristic(this.eveChar.ElectricCurrent)
|
|
72
|
+
}
|
|
73
|
+
if (!this.vService.testCharacteristic(this.eveChar.ElectricCurrent)) {
|
|
74
|
+
this.vService.addCharacteristic(this.eveChar.ElectricCurrent)
|
|
75
|
+
}
|
|
76
|
+
if (!this.sService.testCharacteristic(this.eveChar.Voltage)) {
|
|
77
|
+
this.sService.addCharacteristic(this.eveChar.Voltage)
|
|
78
|
+
}
|
|
79
|
+
if (!this.vService.testCharacteristic(this.eveChar.Voltage)) {
|
|
80
|
+
this.vService.addCharacteristic(this.eveChar.Voltage)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Add the set handler to the switch on/off characteristic
|
|
85
|
+
this.sService
|
|
86
|
+
.getCharacteristic(this.hapChar.On)
|
|
87
|
+
.onSet(async value => this.internalSwitchUpdate(value))
|
|
88
|
+
|
|
89
|
+
// Add the set handler to the valve active characteristic
|
|
90
|
+
this.vService
|
|
91
|
+
.getCharacteristic(this.hapChar.Active)
|
|
92
|
+
.onSet(async value => this.internalValveUpdate(value))
|
|
93
|
+
|
|
94
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
95
|
+
if (!platform.config.disableNoResponse) {
|
|
96
|
+
this.sService.getCharacteristic(this.hapChar.On).onGet(() => {
|
|
97
|
+
if (!this.isOnline) {
|
|
98
|
+
throw new this.hapErr(-70402)
|
|
99
|
+
}
|
|
100
|
+
return this.sService.getCharacteristic(this.hapChar.On).value
|
|
101
|
+
})
|
|
102
|
+
this.vService.getCharacteristic(this.hapChar.Active).onGet(() => {
|
|
103
|
+
if (!this.isOnline) {
|
|
104
|
+
throw new this.hapErr(-70402)
|
|
105
|
+
}
|
|
106
|
+
return this.vService.getCharacteristic(this.hapChar.Active).value
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add the set handler to the valve set duration characteristic
|
|
111
|
+
this.vService.getCharacteristic(this.hapChar.SetDuration).onSet((value) => {
|
|
112
|
+
// Check if the valve is currently active
|
|
113
|
+
if (this.vService.getCharacteristic(this.hapChar.InUse).value === 1) {
|
|
114
|
+
// Update the remaining duration characteristic with the new value
|
|
115
|
+
this.vService.updateCharacteristic(this.hapChar.RemainingDuration, value)
|
|
116
|
+
|
|
117
|
+
// Clear any existing active timers
|
|
118
|
+
clearTimeout(this.timer)
|
|
119
|
+
|
|
120
|
+
// Set a new active timer with the new time amount
|
|
121
|
+
this.timer = setTimeout(
|
|
122
|
+
() => this.vService.updateCharacteristic(this.hapChar.Active, 0),
|
|
123
|
+
value * 1000,
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
129
|
+
this.accessory.eveService = new platform.eveService('switch', this.accessory, {
|
|
130
|
+
log: () => {},
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
// Set up an interval to get eWeLink to send power updates
|
|
134
|
+
if (this.powerReadings && platform.config.mode !== 'lan') {
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
this.internalUIUpdate()
|
|
137
|
+
this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
|
|
138
|
+
}, 5000)
|
|
139
|
+
|
|
140
|
+
// Stop the intervals on Homebridge shutdown
|
|
141
|
+
platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Output the customised options to the log
|
|
145
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
146
|
+
const opts = JSON.stringify({
|
|
147
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
148
|
+
showAs: 'switch_valve',
|
|
149
|
+
})
|
|
150
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async internalSwitchUpdate(value) {
|
|
154
|
+
try {
|
|
155
|
+
const params = {
|
|
156
|
+
switches: [
|
|
157
|
+
{
|
|
158
|
+
switch: value ? 'on' : 'off',
|
|
159
|
+
outlet: 0,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
}
|
|
163
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
164
|
+
this.cacheState = value ? 'on' : 'off'
|
|
165
|
+
this.accessory.eveService.addEntry({ status: value ? 1 : 0 })
|
|
166
|
+
if (this.enableLogging) {
|
|
167
|
+
this.log('[%s] [switch] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
168
|
+
}
|
|
169
|
+
} catch (err) {
|
|
170
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
this.sService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
173
|
+
}, 2000)
|
|
174
|
+
throw new this.hapErr(-70402)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async internalValveUpdate(value) {
|
|
179
|
+
try {
|
|
180
|
+
const params = {
|
|
181
|
+
switches: [
|
|
182
|
+
{
|
|
183
|
+
switch: value ? 'on' : 'off',
|
|
184
|
+
outlet: 1,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
}
|
|
188
|
+
this.vService.updateCharacteristic(this.hapChar.InUse, value)
|
|
189
|
+
switch (value) {
|
|
190
|
+
case 0:
|
|
191
|
+
this.vService.updateCharacteristic(this.hapChar.RemainingDuration, 0)
|
|
192
|
+
clearTimeout(this.timer)
|
|
193
|
+
if (this.enableLogging) {
|
|
194
|
+
this.log('[%s] [valve] %s [%s].', this.name, this.lang.curState, this.lang.valveNo)
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 1: {
|
|
198
|
+
const timer = this.vService.getCharacteristic(this.hapChar.SetDuration).value
|
|
199
|
+
this.vService.updateCharacteristic(this.hapChar.RemainingDuration, timer)
|
|
200
|
+
if (this.enableLogging) {
|
|
201
|
+
this.log('[%s] [valve] %s [%s].', this.name, this.lang.curState, this.lang.valveYes)
|
|
202
|
+
}
|
|
203
|
+
this.timer = setTimeout(() => {
|
|
204
|
+
this.vService.updateCharacteristic(this.hapChar.Active, 0)
|
|
205
|
+
}, timer * 1000)
|
|
206
|
+
break
|
|
207
|
+
}
|
|
208
|
+
default:
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
212
|
+
} catch (err) {
|
|
213
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
214
|
+
setTimeout(() => {
|
|
215
|
+
this.sService.updateCharacteristic(this.hapChar.Active, 0)
|
|
216
|
+
}, 2000)
|
|
217
|
+
throw new this.hapErr(-70402)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async internalUIUpdate() {
|
|
222
|
+
try {
|
|
223
|
+
// Skip polling if device isn't online
|
|
224
|
+
if (!this.isOnline) {
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Send the params to request the updates
|
|
229
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
|
|
230
|
+
await sleep(2000)
|
|
231
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 1, time: 120 } })
|
|
232
|
+
} catch (err) {
|
|
233
|
+
// Suppress errors here
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async externalUpdate(params) {
|
|
238
|
+
try {
|
|
239
|
+
if (params.switches) {
|
|
240
|
+
if (this.cacheState !== params.switches[0].switch) {
|
|
241
|
+
this.cacheState = params.switches[0].switch
|
|
242
|
+
this.sService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
|
|
243
|
+
this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 })
|
|
244
|
+
if (params.updateSource && this.enableLogging) {
|
|
245
|
+
this.log('[%s] [switch] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (params.switches[1].switch === 'on') {
|
|
249
|
+
if (this.vService.getCharacteristic(this.hapChar.Active).value === 0) {
|
|
250
|
+
const timer = this.vService.getCharacteristic(this.hapChar.SetDuration).value
|
|
251
|
+
this.vService.updateCharacteristic(this.hapChar.Active, 1)
|
|
252
|
+
this.vService.updateCharacteristic(this.hapChar.InUse, 1)
|
|
253
|
+
this.vService.updateCharacteristic(this.hapChar.RemainingDuration, timer)
|
|
254
|
+
if (params.updateSource && this.enableLogging) {
|
|
255
|
+
this.log('[%s] [valve] %s [%s].', this.name, this.lang.curState, this.lang.valveYes)
|
|
256
|
+
}
|
|
257
|
+
this.timer = setTimeout(() => {
|
|
258
|
+
this.vService.updateCharacteristic(this.hapChar.Active, 0)
|
|
259
|
+
}, timer * 1000)
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
this.vService.updateCharacteristic(this.hapChar.Active, 0)
|
|
263
|
+
this.vService.updateCharacteristic(this.hapChar.InUse, 0)
|
|
264
|
+
this.vService.updateCharacteristic(this.hapChar.RemainingDuration, 0)
|
|
265
|
+
clearTimeout(this.timer)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Get the power readings given by certain devices
|
|
270
|
+
if (!this.powerReadings) {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
let logger0 = false
|
|
274
|
+
let logger1 = false
|
|
275
|
+
let power0
|
|
276
|
+
let power1
|
|
277
|
+
let voltage0
|
|
278
|
+
let voltage1
|
|
279
|
+
let current0
|
|
280
|
+
let current1
|
|
281
|
+
if (hasProperty(params, 'actPow_00')) {
|
|
282
|
+
power0 = Number.parseInt(params.actPow_00, 10) / 100
|
|
283
|
+
this.sService.updateCharacteristic(this.eveChar.CurrentConsumption, power0)
|
|
284
|
+
logger0 = true
|
|
285
|
+
}
|
|
286
|
+
if (hasProperty(params, 'actPow_01')) {
|
|
287
|
+
power1 = Number.parseInt(params.actPow_01, 10) / 100
|
|
288
|
+
this.vService.updateCharacteristic(this.eveChar.CurrentConsumption, power1)
|
|
289
|
+
logger1 = true
|
|
290
|
+
}
|
|
291
|
+
if (hasProperty(params, 'voltage_00')) {
|
|
292
|
+
voltage0 = Number.parseInt(params.voltage_00, 10) / 100
|
|
293
|
+
this.sService.updateCharacteristic(this.eveChar.Voltage, voltage0)
|
|
294
|
+
logger0 = true
|
|
295
|
+
}
|
|
296
|
+
if (hasProperty(params, 'voltage_01')) {
|
|
297
|
+
voltage1 = Number.parseInt(params.voltage_01, 10) / 100
|
|
298
|
+
this.vService.updateCharacteristic(this.eveChar.Voltage, voltage1)
|
|
299
|
+
logger1 = true
|
|
300
|
+
}
|
|
301
|
+
if (hasProperty(params, 'current_00')) {
|
|
302
|
+
current0 = Number.parseInt(params.current_00, 10) / 100
|
|
303
|
+
this.sService.updateCharacteristic(this.eveChar.ElectricCurrent, current0)
|
|
304
|
+
logger0 = true
|
|
305
|
+
}
|
|
306
|
+
if (hasProperty(params, 'current_01')) {
|
|
307
|
+
current1 = Number.parseInt(params.current_01, 10) / 100
|
|
308
|
+
this.vService.updateCharacteristic(this.eveChar.ElectricCurrent, current1)
|
|
309
|
+
logger1 = true
|
|
310
|
+
}
|
|
311
|
+
if (params.updateSource && this.enableLogging) {
|
|
312
|
+
if (logger0) {
|
|
313
|
+
this.log(
|
|
314
|
+
'[%s] [switch] %s%s%s.',
|
|
315
|
+
this.name,
|
|
316
|
+
power0 !== undefined ? `${this.lang.curPower} [${power0}W]` : '',
|
|
317
|
+
voltage0 !== undefined ? ` ${this.lang.curVolt} [${voltage0}V]` : '',
|
|
318
|
+
current0 !== undefined ? ` ${this.lang.curCurr} [${current0}A]` : '',
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
if (logger1) {
|
|
322
|
+
this.log(
|
|
323
|
+
'[%s] [valve] %s%s%s.',
|
|
324
|
+
this.name,
|
|
325
|
+
power1 !== undefined ? `${this.lang.curPower} [${power1}W]` : '',
|
|
326
|
+
voltage1 !== undefined ? ` ${this.lang.curVolt} [${voltage1}V]` : '',
|
|
327
|
+
current1 !== undefined ? ` ${this.lang.curCurr} [${current1}A]` : '',
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
} catch (err) {
|
|
332
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
currentState() {
|
|
337
|
+
return {
|
|
338
|
+
services: ['switch', 'valve'],
|
|
339
|
+
switch: {
|
|
340
|
+
state: this.sService.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
|
|
341
|
+
},
|
|
342
|
+
valve: {
|
|
343
|
+
state: this.vService.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off',
|
|
344
|
+
},
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
markStatus(isOnline) {
|
|
349
|
+
this.isOnline = isOnline
|
|
350
|
+
}
|
|
351
|
+
}
|