@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,414 @@
|
|
|
1
|
+
import events from 'node:events'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
import wsp from 'websocket-as-promised'
|
|
4
|
+
import ws from 'ws'
|
|
5
|
+
import platformConsts from '../utils/constants.js'
|
|
6
|
+
import { hasProperty, parseError, sleep } from '../utils/functions.js'
|
|
7
|
+
|
|
8
|
+
const emitter = new events()
|
|
9
|
+
|
|
10
|
+
export default class {
|
|
11
|
+
constructor(platform, authData) {
|
|
12
|
+
// Set up variables from the platform
|
|
13
|
+
this.appId = platform.config.appId || platformConsts.appId
|
|
14
|
+
this.appSecret = platform.config.appSecret || platformConsts.appSecret
|
|
15
|
+
this.debug = platform.config.debug
|
|
16
|
+
this.lang = platform.lang
|
|
17
|
+
this.log = platform.log
|
|
18
|
+
|
|
19
|
+
// Set up variables from the authData (from HTTP)
|
|
20
|
+
this.httpHost = authData.httpHost
|
|
21
|
+
this.aToken = authData.aToken
|
|
22
|
+
this.apiKey = authData.apiKey
|
|
23
|
+
|
|
24
|
+
// Flag used to determine ws connection status
|
|
25
|
+
this.wsIsConnected = false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async getHost() {
|
|
29
|
+
// Used to get the web socket host
|
|
30
|
+
try {
|
|
31
|
+
// Send the HTTP request to get the web socket host
|
|
32
|
+
const res = await axios({
|
|
33
|
+
method: 'post',
|
|
34
|
+
url: `https://${this.httpHost.replace('-api', '-disp')}/dispatch/app`,
|
|
35
|
+
headers: {
|
|
36
|
+
'Authorization': `Bearer ${this.aToken}`,
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
},
|
|
39
|
+
data: {
|
|
40
|
+
appid: this.appId,
|
|
41
|
+
nonce: Math.random()
|
|
42
|
+
.toString(36)
|
|
43
|
+
.substr(2, 8),
|
|
44
|
+
ts: Math.floor(new Date().getTime() / 1000),
|
|
45
|
+
version: 8,
|
|
46
|
+
},
|
|
47
|
+
timeout: 6000,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Parse the response
|
|
51
|
+
const body = res.data
|
|
52
|
+
|
|
53
|
+
// Check for any reason a host wasn't received
|
|
54
|
+
if (!body.domain) {
|
|
55
|
+
throw new Error(this.lang.noWSHost)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Log the received host if appropriate
|
|
59
|
+
if (this.debug) {
|
|
60
|
+
this.log('%s [%s].', this.lang.wsHostRec, body.domain)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Return the received web socket host
|
|
64
|
+
return body.domain
|
|
65
|
+
} catch (err) {
|
|
66
|
+
// Check to see if it's a eWeLink server problem, and we can retry
|
|
67
|
+
if (err.code && platformConsts.httpRetryCodes.includes(err.code)) {
|
|
68
|
+
// Retry if another attempt could be successful
|
|
69
|
+
this.log.warn('%s [getHost() - %s].', this.lang.httpRetry, err.code)
|
|
70
|
+
await sleep(30000)
|
|
71
|
+
return this.getHost()
|
|
72
|
+
}
|
|
73
|
+
// It's not a eWeLink problem so report the error back
|
|
74
|
+
this.log.warn('%s.', this.lang.errGetHost)
|
|
75
|
+
throw err
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async login() {
|
|
80
|
+
// Used to create the web socket connection and authenticate
|
|
81
|
+
try {
|
|
82
|
+
// This may be called onClose and onError, we just want it to run once
|
|
83
|
+
if (this.debounce) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
this.debounce = true
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
this.debounce = false
|
|
89
|
+
}, 4000)
|
|
90
|
+
|
|
91
|
+
// Close any existing web socket connection
|
|
92
|
+
await this.closeConnection()
|
|
93
|
+
|
|
94
|
+
// Refresh the web socket host
|
|
95
|
+
const wsHost = await this.getHost()
|
|
96
|
+
|
|
97
|
+
// Create the web socket client
|
|
98
|
+
this.wsClient = new wsp(`wss://${wsHost}:8080/api/ws`, {
|
|
99
|
+
createWebSocket: url => new ws(url),
|
|
100
|
+
extractMessageData: event => event,
|
|
101
|
+
attachRequestId: (data, requestId) => ({ sequence: requestId, ...data }),
|
|
102
|
+
extractRequestId: data => data && data.sequence,
|
|
103
|
+
packMessage: data => JSON.stringify(data),
|
|
104
|
+
unpackMessage: (data) => {
|
|
105
|
+
data = data.toString()
|
|
106
|
+
return data === 'pong' ? data : JSON.parse(data)
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// Add a listener to authenticate when a web socket connection is opened
|
|
111
|
+
this.wsClient.onOpen.addListener(async () => {
|
|
112
|
+
const sequence = Math.floor(new Date()).toString()
|
|
113
|
+
|
|
114
|
+
// Generate the login payload for the web socket
|
|
115
|
+
const payload = {
|
|
116
|
+
action: 'userOnline',
|
|
117
|
+
apikey: this.apiKey,
|
|
118
|
+
appid: this.appId,
|
|
119
|
+
at: this.aToken,
|
|
120
|
+
nonce: Math.random()
|
|
121
|
+
.toString(36)
|
|
122
|
+
.substr(2, 8),
|
|
123
|
+
sequence,
|
|
124
|
+
ts: Math.floor(new Date() / 1000),
|
|
125
|
+
userAgent: 'app',
|
|
126
|
+
version: 8,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Log the web socket login if appropriate
|
|
130
|
+
if (this.debug) {
|
|
131
|
+
this.log('%s.', this.lang.wsLogin)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Attempt to authenticate the web socket connection
|
|
135
|
+
try {
|
|
136
|
+
// Send the request
|
|
137
|
+
const res = await this.wsClient.sendRequest(payload, {
|
|
138
|
+
requestId: sequence,
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// Parse the response
|
|
142
|
+
if (res.config && res.config.hb && res.config.hbInterval) {
|
|
143
|
+
// Update the flags
|
|
144
|
+
this.wsIsConnected = true
|
|
145
|
+
|
|
146
|
+
// Create a new ping interval
|
|
147
|
+
this.hbInterval = setInterval(() => {
|
|
148
|
+
try {
|
|
149
|
+
// Send the ping
|
|
150
|
+
this.wsClient.send('ping')
|
|
151
|
+
} catch (err) {
|
|
152
|
+
// Catch errors sending ping and show in debug mode
|
|
153
|
+
if (this.debug) {
|
|
154
|
+
this.log.warn('%s %s.', this.lang.wsPingError, parseError(err))
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}, (res.config.hbInterval + 7) * 1000)
|
|
158
|
+
|
|
159
|
+
// Login was successful and log if appropriate
|
|
160
|
+
if (this.debug) {
|
|
161
|
+
this.log('%s.', this.lang.wsLoginSuccess)
|
|
162
|
+
}
|
|
163
|
+
} else if (res.error === 406) {
|
|
164
|
+
// There was a problem with the authentication response
|
|
165
|
+
this.log.warn(this.lang.wsLogin406)
|
|
166
|
+
} else {
|
|
167
|
+
// There was a problem with the authentication response
|
|
168
|
+
const str = JSON.stringify(res, null, 2)
|
|
169
|
+
throw new Error(`${this.lang.wsLoginErr}\n${str}`)
|
|
170
|
+
}
|
|
171
|
+
} catch (err) {
|
|
172
|
+
// Catch any errors authenticating the WS connection
|
|
173
|
+
this.log.warn('%s %s.', this.lang.wsLoginError, parseError(err))
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// Add a listener for when we receive a WS message
|
|
178
|
+
this.wsClient.onUnpackedMessage.addListener((msg) => {
|
|
179
|
+
// Don't continue if it's a simple pong
|
|
180
|
+
if (msg === 'pong') {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Set a device online flag now which we can change later
|
|
185
|
+
let onlineStatus = true
|
|
186
|
+
|
|
187
|
+
// Set up a params object if one didn't already come within the message
|
|
188
|
+
if (!msg.params) {
|
|
189
|
+
msg.params = {}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// We received a device on/offline or error notification
|
|
193
|
+
if (msg.deviceid && hasProperty(msg, 'error')) {
|
|
194
|
+
msg.action = 'update'
|
|
195
|
+
// Set the online status of the device
|
|
196
|
+
onlineStatus = msg.error === 0
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Normally the WS messages comes with an action
|
|
200
|
+
if (msg.action) {
|
|
201
|
+
// Check which action the WS message includes
|
|
202
|
+
switch (msg.action) {
|
|
203
|
+
case 'update':
|
|
204
|
+
case 'sysmsg': {
|
|
205
|
+
if (msg.action === 'sysmsg' && hasProperty(msg.params, 'online')) {
|
|
206
|
+
// Update the online/offline status provided in the message
|
|
207
|
+
onlineStatus = msg.params.online
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Loop through the device parameters received
|
|
211
|
+
Object.keys(msg.params).forEach((param) => {
|
|
212
|
+
// Remove any params that the plugin doesn't need
|
|
213
|
+
if (!platformConsts.paramsToKeep.includes(param.replace(/\d/g, ''))) {
|
|
214
|
+
delete msg.params[param]
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
if (Object.keys(msg.params).length > 0) {
|
|
219
|
+
// Add more params to report back to the plugin
|
|
220
|
+
msg.params.online = onlineStatus
|
|
221
|
+
msg.params.updateSource = 'WS'
|
|
222
|
+
|
|
223
|
+
// Generate the object to return to the plugin
|
|
224
|
+
const returnTemplate = {
|
|
225
|
+
deviceid: msg.deviceid,
|
|
226
|
+
params: msg.params,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Report the new device params object back to the plugin to deal with
|
|
230
|
+
emitter.emit('update', returnTemplate)
|
|
231
|
+
}
|
|
232
|
+
break
|
|
233
|
+
}
|
|
234
|
+
case 'reportSubDevice':
|
|
235
|
+
case 'subDevice':
|
|
236
|
+
// We don't need to do anything with this action
|
|
237
|
+
return
|
|
238
|
+
default: {
|
|
239
|
+
this.log.warn(
|
|
240
|
+
'[%s] %s.\n%s',
|
|
241
|
+
msg.deviceid,
|
|
242
|
+
this.lang.wsUnkAct,
|
|
243
|
+
JSON.stringify(msg, null, 2),
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} else if (hasProperty(msg, 'error') && msg.error === 0) {
|
|
248
|
+
// Safe to ignore these messages
|
|
249
|
+
} else {
|
|
250
|
+
// WS message received has an unknown action
|
|
251
|
+
this.log.warn('%s.\n%s', this.lang.wsUnkCmd, JSON.stringify(msg, null, 2))
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
// Add a listener for when the web socket closes for any reason
|
|
256
|
+
this.wsClient.onClose.addListener(async (e) => {
|
|
257
|
+
// Don't continue further with logging/reconnection if it's a wanted closure
|
|
258
|
+
if (e === 1005) {
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Log that the web socket has closed if appropriate
|
|
263
|
+
if (this.debug) {
|
|
264
|
+
this.log.warn('%s [%s].', this.lang.wsReconnectError, e)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Wait for 4 seconds and try to re-establish the web socket connection
|
|
268
|
+
await sleep(4000)
|
|
269
|
+
await this.login()
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
// Add a listener for when the web socket throws an error
|
|
273
|
+
this.wsClient.onError.addListener(async (e) => {
|
|
274
|
+
// Log that the web socket has closed if appropriate
|
|
275
|
+
if (this.debug) {
|
|
276
|
+
this.log.warn('%s [%s].', this.lang.wsReconnectClose, e)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Wait for 6 seconds and try to re-establish the web socket connection
|
|
280
|
+
await sleep(6000)
|
|
281
|
+
await this.login()
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
// Open the web socket connection
|
|
285
|
+
await this.wsClient.open()
|
|
286
|
+
} catch (err) {
|
|
287
|
+
const errToShow = parseError(err)
|
|
288
|
+
|
|
289
|
+
// Log the error if appropriate (debug on)
|
|
290
|
+
if (this.debug) {
|
|
291
|
+
this.log('%s: %s.', this.lang.wsLoginErrRecon, errToShow)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Wait for 5 seconds and try to re-establish the web socket connection
|
|
295
|
+
await sleep(5000)
|
|
296
|
+
await this.login()
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
async sendUpdate(json) {
|
|
301
|
+
// Generate the payload to send
|
|
302
|
+
const toSend = {
|
|
303
|
+
...json,
|
|
304
|
+
...{
|
|
305
|
+
action: 'update',
|
|
306
|
+
ts: 0,
|
|
307
|
+
userAgent: 'app',
|
|
308
|
+
},
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Check the web socket is open
|
|
312
|
+
if (this.wsClient && this.wsIsConnected) {
|
|
313
|
+
try {
|
|
314
|
+
// Generate the sequence that will be attached to the message
|
|
315
|
+
const sequence = Math.floor(new Date()).toString()
|
|
316
|
+
|
|
317
|
+
// Send the request to eWeLink
|
|
318
|
+
const res = await this.wsClient.sendRequest(toSend, {
|
|
319
|
+
requestId: sequence,
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
// Parse the response and see if any error has been reported back
|
|
323
|
+
res.error = hasProperty(res, 'error') ? res.error : -1
|
|
324
|
+
|
|
325
|
+
// Check if and which error has been reported back
|
|
326
|
+
switch (res.error) {
|
|
327
|
+
case 0:
|
|
328
|
+
// No error is always what is wanted
|
|
329
|
+
if (res.config && res.config.hundredDaysKwhData) {
|
|
330
|
+
return res.config.hundredDaysKwhData
|
|
331
|
+
}
|
|
332
|
+
return true
|
|
333
|
+
case 504:
|
|
334
|
+
throw new Error(`${this.lang.wsReqTimeout} [504]`)
|
|
335
|
+
default:
|
|
336
|
+
// An error has occurred
|
|
337
|
+
throw new Error(`${this.lang.wsUnkRes} [${res.error}]`)
|
|
338
|
+
}
|
|
339
|
+
} catch (err) {
|
|
340
|
+
// Catch any errors sending the device update
|
|
341
|
+
throw new Error(parseError(err))
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
// The web socket isn't currently open so log this
|
|
345
|
+
throw new Error(this.lang.wsResend)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
receiveUpdate(f) {
|
|
350
|
+
emitter.addListener('update', f)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async requestUpdate(accessory) {
|
|
354
|
+
// Don't continue if disabled for any eWeLink UIID
|
|
355
|
+
if (platformConsts.devices.skipUpdateRequest.includes(accessory.context.eweUIID)) {
|
|
356
|
+
return
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Log the action if appropriate
|
|
360
|
+
if (accessory.control.enableDebugLogging) {
|
|
361
|
+
this.log('[%s] %s.', accessory.displayName, this.lang.updReq)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Generate the payload to send
|
|
365
|
+
const json = {
|
|
366
|
+
action: 'query',
|
|
367
|
+
apikey: accessory.context.eweApiKey,
|
|
368
|
+
deviceid: accessory.context.eweDeviceId,
|
|
369
|
+
params: [],
|
|
370
|
+
sequence: Math.floor(new Date()).toString(),
|
|
371
|
+
ts: 0,
|
|
372
|
+
userAgent: 'app',
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Check the web socket is open
|
|
376
|
+
if (this.wsClient && this.wsIsConnected) {
|
|
377
|
+
// Send the request
|
|
378
|
+
this.wsClient.send(JSON.stringify(json))
|
|
379
|
+
} else {
|
|
380
|
+
// The web socket isn't currently open so log this
|
|
381
|
+
throw new Error(this.lang.wsResend)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async closeConnection() {
|
|
386
|
+
// This is called when refreshing connection or if Homebridge shuts down
|
|
387
|
+
|
|
388
|
+
// Clear any existing ping interval
|
|
389
|
+
if (this.hbInterval) {
|
|
390
|
+
clearInterval(this.hbInterval)
|
|
391
|
+
this.hbInterval = null
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Check the ws client is set up
|
|
395
|
+
if (this.wsClient) {
|
|
396
|
+
// Remove any existing listeners
|
|
397
|
+
this.wsClient.removeAllListeners()
|
|
398
|
+
|
|
399
|
+
// Close the web socket connection
|
|
400
|
+
if (this.wsIsConnected) {
|
|
401
|
+
// Set the connection flag to false
|
|
402
|
+
this.wsIsConnected = false
|
|
403
|
+
|
|
404
|
+
// Close the connection
|
|
405
|
+
await this.wsClient.close()
|
|
406
|
+
|
|
407
|
+
// Log if appropriate
|
|
408
|
+
if (this.debug) {
|
|
409
|
+
this.log('%s.', this.lang.stoppedWS)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|