@homebridge-plugins/homebridge-meross 10.8.0
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 +1346 -0
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/config.schema.json +2066 -0
- package/eslint.config.js +49 -0
- package/lib/connection/http.js +345 -0
- package/lib/connection/mqtt.js +174 -0
- package/lib/device/baby.js +532 -0
- package/lib/device/cooler-single.js +447 -0
- package/lib/device/diffuser.js +730 -0
- package/lib/device/fan.js +530 -0
- package/lib/device/garage-main.js +225 -0
- package/lib/device/garage-single.js +495 -0
- package/lib/device/garage-sub.js +376 -0
- package/lib/device/heater-single.js +445 -0
- package/lib/device/hub-contact.js +56 -0
- package/lib/device/hub-leak.js +86 -0
- package/lib/device/hub-main.js +403 -0
- package/lib/device/hub-sensor.js +115 -0
- package/lib/device/hub-smoke.js +40 -0
- package/lib/device/hub-valve.js +377 -0
- package/lib/device/humidifier.js +521 -0
- package/lib/device/index.js +63 -0
- package/lib/device/light-cct.js +474 -0
- package/lib/device/light-dimmer.js +312 -0
- package/lib/device/light-rgb.js +528 -0
- package/lib/device/outlet-multi.js +383 -0
- package/lib/device/outlet-single.js +405 -0
- package/lib/device/power-strip.js +282 -0
- package/lib/device/purifier-single.js +372 -0
- package/lib/device/purifier.js +403 -0
- package/lib/device/roller-location.js +317 -0
- package/lib/device/roller.js +234 -0
- package/lib/device/sensor-presence.js +201 -0
- package/lib/device/switch-multi.js +403 -0
- package/lib/device/switch-single.js +371 -0
- package/lib/device/template.js +177 -0
- package/lib/device/thermostat.js +493 -0
- package/lib/fakegato/LICENSE +21 -0
- package/lib/fakegato/fakegato-history.js +814 -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 +316 -0
- package/lib/homebridge-ui/server.js +10 -0
- package/lib/index.js +8 -0
- package/lib/platform.js +1256 -0
- package/lib/utils/colour.js +581 -0
- package/lib/utils/constants.js +377 -0
- package/lib/utils/custom-chars.js +165 -0
- package/lib/utils/eve-chars.js +130 -0
- package/lib/utils/functions.js +39 -0
- package/lib/utils/lang-en.js +114 -0
- package/package.json +70 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import PQueue from 'p-queue'
|
|
2
|
+
import { TimeoutError } from 'p-timeout'
|
|
3
|
+
|
|
4
|
+
import mqttClient from '../connection/mqtt.js'
|
|
5
|
+
import platformConsts from '../utils/constants.js'
|
|
6
|
+
import { generateRandomString, hasProperty, parseError } from '../utils/functions.js'
|
|
7
|
+
import platformLang from '../utils/lang-en.js'
|
|
8
|
+
|
|
9
|
+
export default class {
|
|
10
|
+
constructor(platform, accessory) {
|
|
11
|
+
// Set up variables from the platform
|
|
12
|
+
this.eveChar = platform.eveChar
|
|
13
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
14
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
15
|
+
this.hapServ = platform.api.hap.Service
|
|
16
|
+
this.platform = platform
|
|
17
|
+
|
|
18
|
+
// Set up variables from the accessory
|
|
19
|
+
this.accessory = accessory
|
|
20
|
+
this.operationTime = this.accessory.context.options.garageDoorOpeningTime
|
|
21
|
+
|| platformConsts.defaultValues.garageDoorOpeningTime
|
|
22
|
+
this.name = accessory.displayName
|
|
23
|
+
const cloudRefreshRate = hasProperty(platform.config, 'cloudRefreshRate')
|
|
24
|
+
? platform.config.cloudRefreshRate
|
|
25
|
+
: platformConsts.defaultValues.cloudRefreshRate
|
|
26
|
+
const localRefreshRate = hasProperty(platform.config, 'refreshRate')
|
|
27
|
+
? platform.config.refreshRate
|
|
28
|
+
: platformConsts.defaultValues.refreshRate
|
|
29
|
+
this.pollInterval = accessory.context.connection === 'local'
|
|
30
|
+
? localRefreshRate
|
|
31
|
+
: cloudRefreshRate
|
|
32
|
+
this.states = {
|
|
33
|
+
0: 'open',
|
|
34
|
+
1: 'closed',
|
|
35
|
+
2: 'opening',
|
|
36
|
+
3: 'closing',
|
|
37
|
+
4: 'stopped',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Add the garage door service if it doesn't already exist
|
|
41
|
+
this.service = this.accessory.getService(this.hapServ.GarageDoorOpener)
|
|
42
|
+
|| this.accessory.addService(this.hapServ.GarageDoorOpener)
|
|
43
|
+
|
|
44
|
+
// Add some extra Eve characteristics
|
|
45
|
+
if (!this.service.testCharacteristic(this.eveChar.LastActivation)) {
|
|
46
|
+
this.service.addCharacteristic(this.eveChar.LastActivation)
|
|
47
|
+
}
|
|
48
|
+
if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) {
|
|
49
|
+
this.service.addCharacteristic(this.eveChar.ResetTotal)
|
|
50
|
+
}
|
|
51
|
+
if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) {
|
|
52
|
+
this.service.addCharacteristic(this.eveChar.TimesOpened)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Add the set handler to the garage door target state characteristic
|
|
56
|
+
this.service
|
|
57
|
+
.getCharacteristic(this.hapChar.TargetDoorState)
|
|
58
|
+
.onSet(value => this.internalTargetUpdate(value))
|
|
59
|
+
this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value
|
|
60
|
+
this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
|
|
61
|
+
|
|
62
|
+
// Add the set handler to the garage door reset total characteristic
|
|
63
|
+
this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(() => {
|
|
64
|
+
this.service.updateCharacteristic(this.eveChar.TimesOpened, 0)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Update the obstruction detected to false on plugin load
|
|
68
|
+
this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false)
|
|
69
|
+
|
|
70
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
71
|
+
this.accessory.eveService = new platform.eveService('door', this.accessory, { log: () => {} })
|
|
72
|
+
this.accessory.eveService.addEntry({ status: this.cacheCurrent === 0 ? 0 : 1 })
|
|
73
|
+
|
|
74
|
+
// Create the queue used for sending device requests
|
|
75
|
+
this.updateInProgress = false
|
|
76
|
+
this.queue = new PQueue({
|
|
77
|
+
concurrency: 1,
|
|
78
|
+
interval: 250,
|
|
79
|
+
intervalCap: 1,
|
|
80
|
+
timeout: 10000,
|
|
81
|
+
throwOnTimeout: true,
|
|
82
|
+
})
|
|
83
|
+
this.queue.on('idle', () => {
|
|
84
|
+
this.updateInProgress = false
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Set up the mqtt client for cloud devices to send and receive device updates
|
|
88
|
+
if (accessory.context.connection !== 'local') {
|
|
89
|
+
this.accessory.mqtt = new mqttClient(platform, this.accessory)
|
|
90
|
+
this.accessory.mqtt.connect()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Always request a device update on startup, then start the interval for polling
|
|
94
|
+
setTimeout(() => this.requestUpdate(true), 2000)
|
|
95
|
+
this.accessory.refreshInterval = setInterval(
|
|
96
|
+
() => this.requestUpdate(),
|
|
97
|
+
this.pollInterval * 1000,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
// Output the customised options to the log
|
|
101
|
+
const opts = JSON.stringify({
|
|
102
|
+
connection: this.accessory.context.connection,
|
|
103
|
+
garageDoorOpeningTime: this.operationTime,
|
|
104
|
+
})
|
|
105
|
+
platform.log('[%s] %s %s.', this.name, platformLang.devInitOpts, opts)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async internalTargetUpdate(value) {
|
|
109
|
+
// Add the request to the queue so updates are sent apart
|
|
110
|
+
try {
|
|
111
|
+
await this.queue.add(async () => {
|
|
112
|
+
let action
|
|
113
|
+
let newTarget = value
|
|
114
|
+
let newCurrent
|
|
115
|
+
if (value === 1) {
|
|
116
|
+
// Request to close the garage door
|
|
117
|
+
if (this.cacheCurrent === 0) {
|
|
118
|
+
// The door is currently open
|
|
119
|
+
// ACTION: close the door
|
|
120
|
+
action = 'close'
|
|
121
|
+
|
|
122
|
+
// Mark the current door state as closing
|
|
123
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 3)
|
|
124
|
+
newCurrent = 3
|
|
125
|
+
} else if (this.cacheCurrent === 1) {
|
|
126
|
+
// The door is currently closed
|
|
127
|
+
// ACTION: none
|
|
128
|
+
// Mark the current door state as closed
|
|
129
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
130
|
+
newCurrent = 1
|
|
131
|
+
} else if (this.cacheCurrent === 2) {
|
|
132
|
+
// The door is currently opening
|
|
133
|
+
// ACTION: close the door
|
|
134
|
+
action = 'close'
|
|
135
|
+
|
|
136
|
+
// Mark the target state as close and current door state as closing
|
|
137
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
138
|
+
newTarget = 1
|
|
139
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 3)
|
|
140
|
+
newCurrent = 3
|
|
141
|
+
} else if (this.cacheCurrent === 3) {
|
|
142
|
+
// The door is currently closing
|
|
143
|
+
// ACTION: none
|
|
144
|
+
// Mark the current door state as closing
|
|
145
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 3)
|
|
146
|
+
newCurrent = 3
|
|
147
|
+
}
|
|
148
|
+
} else if (value === 0) {
|
|
149
|
+
// Request to open the door
|
|
150
|
+
if (this.cacheCurrent === 0) {
|
|
151
|
+
// The door is currently open
|
|
152
|
+
// ACTION: none
|
|
153
|
+
// Mark the current door state as open
|
|
154
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
155
|
+
newCurrent = 0
|
|
156
|
+
} else if (this.cacheCurrent === 1) {
|
|
157
|
+
// The door is currently closed
|
|
158
|
+
// ACTION: open the door
|
|
159
|
+
action = 'open'
|
|
160
|
+
|
|
161
|
+
// Mark the current door state as opening
|
|
162
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 2)
|
|
163
|
+
newCurrent = 2
|
|
164
|
+
} else if (this.cacheCurrent === 2) {
|
|
165
|
+
// The door is currently opening
|
|
166
|
+
// ACTION: none
|
|
167
|
+
|
|
168
|
+
// Mark the current door state as opening
|
|
169
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 2)
|
|
170
|
+
newCurrent = 2
|
|
171
|
+
} else if (this.cacheCurrent === 3) {
|
|
172
|
+
// The door is currently closing
|
|
173
|
+
// ACTION: open the door
|
|
174
|
+
action = 'open'
|
|
175
|
+
|
|
176
|
+
// Mark the target state as open and current state as opening
|
|
177
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
178
|
+
newTarget = 0
|
|
179
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 2)
|
|
180
|
+
newCurrent = 2
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Only send an update if we need to
|
|
185
|
+
if (action) {
|
|
186
|
+
this.ignoreIncoming = true
|
|
187
|
+
setTimeout(() => {
|
|
188
|
+
this.ignoreIncoming = false
|
|
189
|
+
}, 3000)
|
|
190
|
+
|
|
191
|
+
// Generate the payload and namespace for the correct device model
|
|
192
|
+
const namespace = 'Appliance.GarageDoor.State'
|
|
193
|
+
const payload = {
|
|
194
|
+
state: {
|
|
195
|
+
channel: 0,
|
|
196
|
+
open: action === 'open' ? 1 : 0,
|
|
197
|
+
uuid: this.accessory.context.serialNumber,
|
|
198
|
+
},
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Use the platform function to send the update to the device
|
|
202
|
+
await this.platform.sendUpdate(this.accessory, {
|
|
203
|
+
namespace,
|
|
204
|
+
payload,
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Update the cache target state if different
|
|
209
|
+
if (this.cacheTarget !== newTarget) {
|
|
210
|
+
this.cacheTarget = newTarget
|
|
211
|
+
this.accessory.log(`${platformLang.curTarg} [${this.states[this.cacheTarget]}]`)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Update the cache current state if different
|
|
215
|
+
if (this.cacheCurrent !== newCurrent) {
|
|
216
|
+
this.cacheCurrent = newCurrent
|
|
217
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/*
|
|
221
|
+
CASE: garage has been opened
|
|
222
|
+
target has been set to [open] and current has been set to [opening]
|
|
223
|
+
wait for the operation time to elapse and set the current to [open]
|
|
224
|
+
*/
|
|
225
|
+
if (action === 'open') {
|
|
226
|
+
const updateKey = generateRandomString(5)
|
|
227
|
+
this.updateKey = updateKey
|
|
228
|
+
|
|
229
|
+
// Update the Eve times opened characteristic
|
|
230
|
+
this.accessory.eveService.addEntry({ status: 0 })
|
|
231
|
+
this.service.updateCharacteristic(
|
|
232
|
+
this.eveChar.TimesOpened,
|
|
233
|
+
this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
|
|
234
|
+
)
|
|
235
|
+
const initialTime = this.accessory.eveService.getInitialTime()
|
|
236
|
+
this.service.updateCharacteristic(
|
|
237
|
+
this.eveChar.LastActivation,
|
|
238
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
239
|
+
)
|
|
240
|
+
setTimeout(() => {
|
|
241
|
+
if (updateKey !== this.updateKey) {
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
if (this.service.getCharacteristic(this.hapChar.CurrentDoorState).value !== 2) {
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
248
|
+
this.cacheCurrent = 0
|
|
249
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
250
|
+
}, this.operationTime * 1000)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
CASE: garage has been closed
|
|
255
|
+
target has been set to [close] and current has been set to [closing]
|
|
256
|
+
wait for the plugin to get a definite closed response from Meross
|
|
257
|
+
For security reasons, I don't want to rely on operation time for the garage to
|
|
258
|
+
definitely show as closed
|
|
259
|
+
Set a timer for operation time plus 15 seconds, and if the garage is still closing then
|
|
260
|
+
mark target and current state as open
|
|
261
|
+
Also setup quicker polling every 3 seconds when in local mode to get the closed status
|
|
262
|
+
*/
|
|
263
|
+
if (action === 'close') {
|
|
264
|
+
const updateKey = generateRandomString(5)
|
|
265
|
+
if (this.accessory.context.connection === 'local') {
|
|
266
|
+
this.extremePolling = setInterval(() => this.requestUpdate(), 3000)
|
|
267
|
+
}
|
|
268
|
+
this.updateKey = updateKey
|
|
269
|
+
setTimeout(() => {
|
|
270
|
+
if (updateKey !== this.updateKey) {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
if (this.service.getCharacteristic(this.hapChar.CurrentDoorState).value !== 3) {
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
277
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
278
|
+
this.cacheTarget = 0
|
|
279
|
+
this.cacheCurrent = 0
|
|
280
|
+
this.accessory.log(`${platformLang.curTarg} [${this.states[this.cacheTarget]}]`)
|
|
281
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
282
|
+
|
|
283
|
+
// Cancel any 'extreme' polling intervals from setting the garage to close
|
|
284
|
+
if (this.extremePolling) {
|
|
285
|
+
clearInterval(this.extremePolling)
|
|
286
|
+
this.extremePolling = false
|
|
287
|
+
}
|
|
288
|
+
}, (this.operationTime + 15) * 1000)
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
} catch (err) {
|
|
292
|
+
// Catch any errors whilst updating the device
|
|
293
|
+
const eText = err instanceof TimeoutError ? platformLang.timeout : parseError(err)
|
|
294
|
+
this.accessory.logWarn(`${platformLang.sendFailed} ${eText}`)
|
|
295
|
+
setTimeout(() => {
|
|
296
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, this.cacheTarget)
|
|
297
|
+
}, 2000)
|
|
298
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, new this.hapErr(-70402))
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async requestUpdate(firstRun = false) {
|
|
303
|
+
try {
|
|
304
|
+
// Don't continue if an update is currently being sent to the device
|
|
305
|
+
if (this.updateInProgress) {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Add the request to the queue so updates are sent apart
|
|
310
|
+
await this.queue.add(async () => {
|
|
311
|
+
// This flag stops the plugin from requesting updates while pending on others
|
|
312
|
+
this.updateInProgress = true
|
|
313
|
+
|
|
314
|
+
// Send the request
|
|
315
|
+
const res = await this.platform.sendUpdate(this.accessory, {
|
|
316
|
+
namespace: 'Appliance.System.All',
|
|
317
|
+
payload: {},
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
// Log the received data
|
|
321
|
+
this.accessory.logDebug(`${platformLang.incPoll}: ${JSON.stringify(res.data)}`)
|
|
322
|
+
|
|
323
|
+
// Check the response is in a useful format
|
|
324
|
+
const data = res.data.payload
|
|
325
|
+
if (data.all) {
|
|
326
|
+
if (data.all.digest && data.all.digest.garageDoor && data.all.digest.garageDoor[0]) {
|
|
327
|
+
this.applyUpdate(data.all.digest.garageDoor[0])
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// A flag to check if we need to update the accessory context
|
|
331
|
+
let needsUpdate = false
|
|
332
|
+
|
|
333
|
+
// Get the mac address and hardware version of the device
|
|
334
|
+
if (data.all.system) {
|
|
335
|
+
// Mac address and hardware don't change regularly so only get on first poll
|
|
336
|
+
if (firstRun && data.all.system.hardware) {
|
|
337
|
+
this.accessory.context.macAddress = data.all.system.hardware.macAddress.toUpperCase()
|
|
338
|
+
this.accessory.context.hardware = data.all.system.hardware.version
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Get the ip address and firmware of the device
|
|
342
|
+
if (data.all.system.firmware) {
|
|
343
|
+
// Check for an IP change each and every time the device is polled
|
|
344
|
+
if (this.accessory.context.ipAddress !== data.all.system.firmware.innerIp) {
|
|
345
|
+
this.accessory.context.ipAddress = data.all.system.firmware.innerIp
|
|
346
|
+
needsUpdate = true
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Firmware doesn't change regularly so only get on first poll
|
|
350
|
+
if (firstRun) {
|
|
351
|
+
this.accessory.context.firmware = data.all.system.firmware.version
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Get the cloud online status of the device
|
|
357
|
+
if (data.all.system.online) {
|
|
358
|
+
const isOnline = data.all.system.online.status === 1
|
|
359
|
+
if (this.accessory.context.isOnline !== isOnline) {
|
|
360
|
+
this.accessory.context.isOnline = isOnline
|
|
361
|
+
needsUpdate = true
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Update the accessory cache if anything has changed
|
|
366
|
+
if (needsUpdate || firstRun) {
|
|
367
|
+
this.platform.updateAccessory(this.accessory)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
} catch (err) {
|
|
372
|
+
const eText = err instanceof TimeoutError ? platformLang.timeout : parseError(err)
|
|
373
|
+
this.accessory.logDebugWarn(`${platformLang.reqFailed}: ${eText}`)
|
|
374
|
+
|
|
375
|
+
// Set the homebridge-ui status of the device to offline if local and error is timeout
|
|
376
|
+
if (
|
|
377
|
+
(this.accessory.context.isOnline || firstRun)
|
|
378
|
+
&& ['EHOSTUNREACH', 'timed out'].some(el => eText.includes(el))
|
|
379
|
+
) {
|
|
380
|
+
this.accessory.context.isOnline = false
|
|
381
|
+
this.platform.updateAccessory(this.accessory)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
receiveUpdate(params) {
|
|
387
|
+
try {
|
|
388
|
+
// Log the received data
|
|
389
|
+
this.accessory.logDebug(`${platformLang.incMQTT}: ${JSON.stringify(params)}`)
|
|
390
|
+
|
|
391
|
+
// Check the response is in a useful format
|
|
392
|
+
const data = params.payload
|
|
393
|
+
if (data.state && data.state[0]) {
|
|
394
|
+
this.applyUpdate(data.state[0])
|
|
395
|
+
}
|
|
396
|
+
} catch (err) {
|
|
397
|
+
this.accessory.logWarn(`${platformLang.refFailed} ${parseError(err)}`)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
applyUpdate(data) {
|
|
402
|
+
// Don't bother whilst the ignore incoming is set to true
|
|
403
|
+
if (this.ignoreIncoming) {
|
|
404
|
+
return
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// When operated externally, the plugin does not bother with 'opening' and 'closing' status
|
|
408
|
+
// Open means magnetic sensor not detected, doesn't really mean the door is open
|
|
409
|
+
if (hasProperty(data, 'open')) {
|
|
410
|
+
const isOpen = data.open === 1
|
|
411
|
+
switch (this.cacheCurrent) {
|
|
412
|
+
case 0:
|
|
413
|
+
case 2: {
|
|
414
|
+
// Homebridge has garage as open or opening
|
|
415
|
+
if (isOpen) {
|
|
416
|
+
// Meross has reported open
|
|
417
|
+
// Nothing to do
|
|
418
|
+
} else {
|
|
419
|
+
// Meross has reported closed
|
|
420
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
421
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
422
|
+
this.accessory.eveService.addEntry({ status: 1 })
|
|
423
|
+
this.cacheCurrent = 1
|
|
424
|
+
this.cacheTarget = 1
|
|
425
|
+
this.accessory.log(`${platformLang.curTarg} [${this.states[this.cacheTarget]}]`)
|
|
426
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
427
|
+
}
|
|
428
|
+
break
|
|
429
|
+
}
|
|
430
|
+
case 1: {
|
|
431
|
+
// Homebridge has garage as closed
|
|
432
|
+
if (isOpen) {
|
|
433
|
+
// Meross has reported open
|
|
434
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
435
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
436
|
+
this.accessory.eveService.addEntry({ status: 0 })
|
|
437
|
+
this.service.updateCharacteristic(
|
|
438
|
+
this.eveChar.TimesOpened,
|
|
439
|
+
this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
|
|
440
|
+
)
|
|
441
|
+
const initialTime = this.accessory.eveService.getInitialTime()
|
|
442
|
+
this.service.updateCharacteristic(
|
|
443
|
+
this.eveChar.LastActivation,
|
|
444
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
445
|
+
)
|
|
446
|
+
this.cacheCurrent = 0
|
|
447
|
+
this.cacheTarget = 0
|
|
448
|
+
this.accessory.log(`${platformLang.curTarg} [${this.states[this.cacheTarget]}]`)
|
|
449
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
450
|
+
} else {
|
|
451
|
+
// Meross has reported closed
|
|
452
|
+
// Nothing to do
|
|
453
|
+
}
|
|
454
|
+
break
|
|
455
|
+
}
|
|
456
|
+
case 3: {
|
|
457
|
+
// Homebridge has garage as closing
|
|
458
|
+
if (isOpen) {
|
|
459
|
+
// Meross has reported open
|
|
460
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 0)
|
|
461
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
462
|
+
this.accessory.eveService.addEntry({ status: 0 })
|
|
463
|
+
this.service.updateCharacteristic(
|
|
464
|
+
this.eveChar.TimesOpened,
|
|
465
|
+
this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
|
|
466
|
+
)
|
|
467
|
+
const initialTime = this.accessory.eveService.getInitialTime()
|
|
468
|
+
this.service.updateCharacteristic(
|
|
469
|
+
this.eveChar.LastActivation,
|
|
470
|
+
Math.round(new Date().valueOf() / 1000) - initialTime,
|
|
471
|
+
)
|
|
472
|
+
this.cacheCurrent = 0
|
|
473
|
+
this.cacheTarget = 0
|
|
474
|
+
this.accessory.log(`${platformLang.curTarg} [${this.states[this.cacheTarget]}]`)
|
|
475
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
476
|
+
} else {
|
|
477
|
+
// Meross has reported closed
|
|
478
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
479
|
+
this.accessory.eveService.addEntry({ status: 1 })
|
|
480
|
+
this.cacheCurrent = 1
|
|
481
|
+
this.accessory.log(`${platformLang.curState} [${this.states[this.cacheCurrent]}]`)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Cancel any 'extreme' polling intervals from setting the garage to close
|
|
485
|
+
if (this.extremePolling) {
|
|
486
|
+
clearInterval(this.extremePolling)
|
|
487
|
+
this.extremePolling = false
|
|
488
|
+
}
|
|
489
|
+
break
|
|
490
|
+
}
|
|
491
|
+
default:
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|