@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,190 @@
|
|
|
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.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
|
+
// 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
|
+
// Add the doorbell service if it doesn't already exist
|
|
51
|
+
this.service = this.accessory.getService(this.hapServ.Doorbell)
|
|
52
|
+
|| this.accessory.addService(this.hapServ.Doorbell)
|
|
53
|
+
|
|
54
|
+
// Set up the device type and power readings if necessary
|
|
55
|
+
if (platformConsts.devices.switchSingle.includes(this.accessory.context.eweUIID)) {
|
|
56
|
+
this.setup = 'switchSingle'
|
|
57
|
+
} else if (platformConsts.devices.switchSinglePower.includes(this.accessory.context.eweUIID)) {
|
|
58
|
+
this.setup = 'switchSingle'
|
|
59
|
+
this.powerReadings = true
|
|
60
|
+
} else if (platformConsts.devices.switchMulti.includes(this.accessory.context.eweUIID)) {
|
|
61
|
+
this.setup = 'switchMulti'
|
|
62
|
+
if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
|
|
63
|
+
// Add Eve power characteristics
|
|
64
|
+
this.powerReadings = true
|
|
65
|
+
this.isDualR3 = true
|
|
66
|
+
}
|
|
67
|
+
} else if (platformConsts.devices.switchSCM.includes(this.accessory.context.eweUIID)) {
|
|
68
|
+
this.setup = 'switchMulti'
|
|
69
|
+
} else if (platformConsts.devices.switchSCMPower.includes(this.accessory.context.eweUIID)) {
|
|
70
|
+
// Could do power here
|
|
71
|
+
this.setup = 'switchMulti'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
75
|
+
if (!platform.config.disableNoResponse) {
|
|
76
|
+
this.service.getCharacteristic(this.hapChar.ProgrammableSwitchEvent).onGet(() => {
|
|
77
|
+
if (!this.isOnline) {
|
|
78
|
+
throw new this.hapErr(-70402)
|
|
79
|
+
}
|
|
80
|
+
return this.service.getCharacteristic(this.hapChar.ProgrammableSwitchEvent).value
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Set up an interval to get eWeLink to send power updates
|
|
85
|
+
if (
|
|
86
|
+
this.powerReadings
|
|
87
|
+
&& (!this.isDualR3 || (this.isDualR3 && platform.config.mode !== 'lan'))
|
|
88
|
+
) {
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
this.internalUIUpdate()
|
|
91
|
+
this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
|
|
92
|
+
}, 5000)
|
|
93
|
+
|
|
94
|
+
// Stop the intervals on Homebridge shutdown
|
|
95
|
+
platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Output the customised options to the log
|
|
99
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
100
|
+
const opts = JSON.stringify({
|
|
101
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
102
|
+
showAs: 'doorbell',
|
|
103
|
+
})
|
|
104
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async internalUIUpdate() {
|
|
108
|
+
try {
|
|
109
|
+
// Skip polling if device isn't online
|
|
110
|
+
if (!this.isOnline) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Send the params to request the updates
|
|
115
|
+
if (this.isDualR3) {
|
|
116
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
|
|
117
|
+
} else {
|
|
118
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
// Suppress errors here
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async externalUpdate(params) {
|
|
126
|
+
try {
|
|
127
|
+
if (!this.inUse) {
|
|
128
|
+
if (
|
|
129
|
+
(this.setup === 'switchMulti' && params.switches && params.switches[0].switch === 'on')
|
|
130
|
+
|| (this.setup === 'switchSingle' && params.switch && params.switch === 'on')
|
|
131
|
+
) {
|
|
132
|
+
this.inUse = true
|
|
133
|
+
setTimeout(() => {
|
|
134
|
+
this.inUse = false
|
|
135
|
+
}, 2000)
|
|
136
|
+
this.service.updateCharacteristic(this.hapChar.ProgrammableSwitchEvent, 0)
|
|
137
|
+
if (params.updateSource && this.enableLogging) {
|
|
138
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.buttonSingle)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Get the power readings given by certain devices
|
|
144
|
+
if (!this.powerReadings) {
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
let logger = false
|
|
148
|
+
let power
|
|
149
|
+
let voltage
|
|
150
|
+
let current
|
|
151
|
+
if (hasProperty(params, 'actPow_00')) {
|
|
152
|
+
power = Number.parseInt(params.actPow_00, 10) / 100
|
|
153
|
+
logger = true
|
|
154
|
+
} else if (hasProperty(params, 'power')) {
|
|
155
|
+
power = Number.parseFloat(params.power)
|
|
156
|
+
logger = true
|
|
157
|
+
}
|
|
158
|
+
if (hasProperty(params, 'voltage_00')) {
|
|
159
|
+
voltage = Number.parseInt(params.voltage_00, 10) / 100
|
|
160
|
+
logger = true
|
|
161
|
+
} else if (hasProperty(params, 'voltage')) {
|
|
162
|
+
voltage = Number.parseFloat(params.voltage)
|
|
163
|
+
logger = true
|
|
164
|
+
}
|
|
165
|
+
if (hasProperty(params, 'current_00')) {
|
|
166
|
+
current = Number.parseInt(params.current_00, 10) / 100
|
|
167
|
+
logger = true
|
|
168
|
+
} else if (hasProperty(params, 'current')) {
|
|
169
|
+
current = Number.parseFloat(params.current)
|
|
170
|
+
logger = true
|
|
171
|
+
}
|
|
172
|
+
if (params.updateSource && logger && this.enableLogging) {
|
|
173
|
+
this.log(
|
|
174
|
+
'[%s] %s%s%s.',
|
|
175
|
+
this.name,
|
|
176
|
+
power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
|
|
177
|
+
voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
|
|
178
|
+
current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
this.inUse = false
|
|
183
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
markStatus(isOnline) {
|
|
188
|
+
this.isOnline = isOnline
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { generateRandomString, 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
|
+
this.operationTime = deviceConf.operationTime || platformConsts.defaultValues.operationTime
|
|
25
|
+
|
|
26
|
+
// Set the correct logging variables for this accessory
|
|
27
|
+
switch (deviceConf.overrideLogging) {
|
|
28
|
+
case 'standard':
|
|
29
|
+
this.enableLogging = true
|
|
30
|
+
this.enableDebugLogging = false
|
|
31
|
+
break
|
|
32
|
+
case 'debug':
|
|
33
|
+
this.enableLogging = true
|
|
34
|
+
this.enableDebugLogging = true
|
|
35
|
+
break
|
|
36
|
+
case 'disable':
|
|
37
|
+
this.enableLogging = false
|
|
38
|
+
this.enableDebugLogging = false
|
|
39
|
+
break
|
|
40
|
+
default:
|
|
41
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
42
|
+
this.enableDebugLogging = platform.config.debug
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// If the accessory has a switch service then remove it
|
|
47
|
+
if (this.accessory.getService(this.hapServ.Switch)) {
|
|
48
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// If the accessory has a contact sensor service then remove it
|
|
52
|
+
if (this.accessory.getService(this.hapServ.ContactSensor)) {
|
|
53
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.ContactSensor))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// If the accessory has a lock service then remove it
|
|
57
|
+
if (this.accessory.getService(this.hapServ.LockMechanism)) {
|
|
58
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.LockMechanism))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add the garage door service if it doesn't already exist
|
|
62
|
+
this.service = this.accessory.getService(this.hapServ.GarageDoorOpener)
|
|
63
|
+
if (!this.service) {
|
|
64
|
+
this.service = this.accessory.addService(this.hapServ.GarageDoorOpener)
|
|
65
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
66
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
67
|
+
this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false)
|
|
68
|
+
this.service.addCharacteristic(this.eveChar.LastActivation)
|
|
69
|
+
this.service.addCharacteristic(this.eveChar.ResetTotal)
|
|
70
|
+
this.service.addCharacteristic(this.eveChar.TimesOpened)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Remove unneeded characteristics
|
|
74
|
+
if (this.service.testCharacteristic(this.hapChar.ContactSensorState)) {
|
|
75
|
+
this.service.removeCharacteristic(
|
|
76
|
+
this.service.getCharacteristic(this.hapChar.ContactSensorState),
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
if (this.service.testCharacteristic(this.hapChar.OpenDuration)) {
|
|
80
|
+
this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.OpenDuration))
|
|
81
|
+
}
|
|
82
|
+
if (this.service.testCharacteristic(this.hapChar.ClosedDuration)) {
|
|
83
|
+
this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.ClosedDuration))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Add the set handler to the garage door reset total characteristic
|
|
87
|
+
this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(() => {
|
|
88
|
+
this.service.updateCharacteristic(this.eveChar.TimesOpened, 0)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Add the set handler to the target position characteristic
|
|
92
|
+
this.service.getCharacteristic(this.hapChar.TargetDoorState).onSet((value) => {
|
|
93
|
+
// We don't use await as we want the callback to be run straight away
|
|
94
|
+
this.internalStateUpdate(value)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
98
|
+
if (!platform.config.disableNoResponse) {
|
|
99
|
+
this.service.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
|
|
100
|
+
if (!this.isOnline) {
|
|
101
|
+
throw new this.hapErr(-70402)
|
|
102
|
+
}
|
|
103
|
+
return this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
|
|
104
|
+
})
|
|
105
|
+
this.service.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
|
|
106
|
+
if (!this.isOnline) {
|
|
107
|
+
throw new this.hapErr(-70402)
|
|
108
|
+
}
|
|
109
|
+
return this.service.getCharacteristic(this.hapChar.TargetDoorState).value
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Update the obstruction detected to false on Homebridge restart
|
|
114
|
+
this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false)
|
|
115
|
+
|
|
116
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
117
|
+
this.accessory.eveService = new platform.eveService('door', this.accessory, {
|
|
118
|
+
log: () => {},
|
|
119
|
+
})
|
|
120
|
+
this.accessory.eveService.addEntry({
|
|
121
|
+
status: this.service.getCharacteristic(this.hapChar.CurrentDoorState).value === 0 ? 0 : 1,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// Output the customised options to the log
|
|
125
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
126
|
+
const opts = JSON.stringify({
|
|
127
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
128
|
+
operationTime: this.operationTime,
|
|
129
|
+
showAs: 'garage_eachen',
|
|
130
|
+
})
|
|
131
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async internalStateUpdate(value) {
|
|
135
|
+
try {
|
|
136
|
+
const params = { switch: value === 0 ? 'on' : 'off' }
|
|
137
|
+
const curState = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
|
|
138
|
+
if (value === curState % 2) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
this.inUse = true
|
|
142
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
143
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, value)
|
|
144
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, value + 2)
|
|
145
|
+
await sleep(3000)
|
|
146
|
+
this.inUse = false
|
|
147
|
+
if (value === 0) {
|
|
148
|
+
this.accessory.eveService.addEntry({ status: 0 })
|
|
149
|
+
this.service.updateCharacteristic(
|
|
150
|
+
this.eveChar.LastActivation,
|
|
151
|
+
Math.round(new Date().valueOf() / 1000) - this.accessory.eveService.getInitialTime(),
|
|
152
|
+
)
|
|
153
|
+
this.service.updateCharacteristic(
|
|
154
|
+
this.eveChar.TimesOpened,
|
|
155
|
+
this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
|
|
156
|
+
)
|
|
157
|
+
await sleep(Math.max((this.operationTime - 30) * 100, 0))
|
|
158
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
|
|
159
|
+
if (this.enableLogging) {
|
|
160
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.doorOpen)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch (err) {
|
|
164
|
+
this.inUse = false
|
|
165
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
this.service.updateCharacteristic(
|
|
168
|
+
this.hapChar.TargetDoorState,
|
|
169
|
+
this.accessory.context.cacheTargetDoorState,
|
|
170
|
+
)
|
|
171
|
+
}, 2000)
|
|
172
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, new this.hapErr(-70402))
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async externalUpdate(params) {
|
|
177
|
+
try {
|
|
178
|
+
if (!params.switch || this.inUse) {
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// In a period of three seconds we want to only use the 'last' update
|
|
183
|
+
const updateKey = generateRandomString(5)
|
|
184
|
+
this.updateKey = updateKey
|
|
185
|
+
await sleep(3000)
|
|
186
|
+
if (this.updateKey !== updateKey) {
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Update the characteristics
|
|
191
|
+
const newValue = params.switch === 'on' ? 0 : 1
|
|
192
|
+
if (this.service.getCharacteristic(this.hapChar.TargetDoorState).value !== newValue) {
|
|
193
|
+
this.service.updateCharacteristic(this.hapChar.TargetDoorState, newValue)
|
|
194
|
+
}
|
|
195
|
+
if (this.service.getCharacteristic(this.hapChar.CurrentDoorState).value !== newValue) {
|
|
196
|
+
this.service.updateCharacteristic(this.hapChar.CurrentDoorState, newValue)
|
|
197
|
+
}
|
|
198
|
+
this.accessory.eveService.addEntry({ status: newValue })
|
|
199
|
+
if (newValue === 0) {
|
|
200
|
+
this.service.updateCharacteristic(
|
|
201
|
+
this.eveChar.LastActivation,
|
|
202
|
+
Math.round(new Date().valueOf() / 1000) - this.accessory.eveService.getInitialTime(),
|
|
203
|
+
)
|
|
204
|
+
this.service.updateCharacteristic(
|
|
205
|
+
this.eveChar.TimesOpened,
|
|
206
|
+
this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1,
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
if (params.updateSource && this.enableLogging) {
|
|
210
|
+
this.log(
|
|
211
|
+
'[%s] %s [%s].',
|
|
212
|
+
this.name,
|
|
213
|
+
this.lang.curState,
|
|
214
|
+
params.switch === 'on' ? this.lang.doorOpen : this.lang.doorClosed,
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
} catch (err) {
|
|
218
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
currentState() {
|
|
223
|
+
return {
|
|
224
|
+
services: ['garage'],
|
|
225
|
+
garage: {
|
|
226
|
+
target: this.service.getCharacteristic(this.hapChar.TargetDoorState).value,
|
|
227
|
+
state: this.service.getCharacteristic(this.hapChar.CurrentDoorState).value,
|
|
228
|
+
},
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
markStatus(isOnline) {
|
|
233
|
+
this.isOnline = isOnline
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { generateRandomString, hasProperty, sleep } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
8
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
9
|
+
this.hapServ = platform.api.hap.Service
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.name = accessory.displayName
|
|
16
|
+
this.accessory = accessory
|
|
17
|
+
|
|
18
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
19
|
+
this.isOnline = true
|
|
20
|
+
|
|
21
|
+
// Set up custom variables for this device type
|
|
22
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
23
|
+
this.operationTimeUp = deviceConf.operationTime || platformConsts.defaultValues.operationTime
|
|
24
|
+
this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp
|
|
25
|
+
|
|
26
|
+
// Set the correct logging variables for this accessory
|
|
27
|
+
switch (deviceConf.overrideLogging) {
|
|
28
|
+
case 'standard':
|
|
29
|
+
this.enableLogging = true
|
|
30
|
+
this.enableDebugLogging = false
|
|
31
|
+
break
|
|
32
|
+
case 'debug':
|
|
33
|
+
this.enableLogging = true
|
|
34
|
+
this.enableDebugLogging = true
|
|
35
|
+
break
|
|
36
|
+
case 'disable':
|
|
37
|
+
this.enableLogging = false
|
|
38
|
+
this.enableDebugLogging = false
|
|
39
|
+
break
|
|
40
|
+
default:
|
|
41
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
42
|
+
this.enableDebugLogging = platform.config.debug
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Set up the accessory with default positions when added the first time
|
|
47
|
+
if (!hasProperty(this.accessory.context, 'cacheStates')) {
|
|
48
|
+
this.accessory.context.cacheStates = [
|
|
49
|
+
{ cacheCurrentDoorState: 1, cacheTargetDoorState: 1 },
|
|
50
|
+
{ cacheCurrentDoorState: 1, cacheTargetDoorState: 1 },
|
|
51
|
+
{ cacheCurrentDoorState: 1, cacheTargetDoorState: 1 },
|
|
52
|
+
{ cacheCurrentDoorState: 1, cacheTargetDoorState: 1 },
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// We want four garage door services for this accessory
|
|
57
|
+
['A', 'B', 'C', 'D'].forEach((v) => {
|
|
58
|
+
// Add the garage door service if it doesn't already exist
|
|
59
|
+
let gdService = this.accessory.getService(`Garage ${v}`)
|
|
60
|
+
if (!gdService) {
|
|
61
|
+
gdService = this.accessory.addService(this.hapServ.GarageDoorOpener, `Garage ${v}`, `garage${v}`)
|
|
62
|
+
gdService.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
|
|
63
|
+
gdService.updateCharacteristic(this.hapChar.TargetDoorState, 1)
|
|
64
|
+
gdService.updateCharacteristic(this.hapChar.ObstructionDetected, false)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Add the set handler to the target position characteristic
|
|
68
|
+
gdService.getCharacteristic(this.hapChar.TargetDoorState).onSet((value) => {
|
|
69
|
+
// We don't use await as we want the callback to be run straight away
|
|
70
|
+
this.internalStateUpdate(v, value)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
74
|
+
if (!platform.config.disableNoResponse) {
|
|
75
|
+
gdService.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
|
|
76
|
+
if (!this.isOnline) {
|
|
77
|
+
throw new this.hapErr(-70402)
|
|
78
|
+
}
|
|
79
|
+
return gdService.getCharacteristic(this.hapChar.CurrentDoorState).value
|
|
80
|
+
})
|
|
81
|
+
gdService.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
|
|
82
|
+
if (!this.isOnline) {
|
|
83
|
+
throw new this.hapErr(-70402)
|
|
84
|
+
}
|
|
85
|
+
return gdService.getCharacteristic(this.hapChar.TargetDoorState).value
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// Output the customised options to the log
|
|
91
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
92
|
+
const opts = JSON.stringify({
|
|
93
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
94
|
+
operationTimeDown: this.operationTimeDown,
|
|
95
|
+
operationTimeUp: this.operationTimeUp,
|
|
96
|
+
showAs: 'garage_four',
|
|
97
|
+
})
|
|
98
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async internalStateUpdate(garage, value) {
|
|
102
|
+
try {
|
|
103
|
+
let garageChannel
|
|
104
|
+
switch (garage) {
|
|
105
|
+
case 'A':
|
|
106
|
+
garageChannel = 0
|
|
107
|
+
break
|
|
108
|
+
case 'B':
|
|
109
|
+
garageChannel = 1
|
|
110
|
+
break
|
|
111
|
+
case 'C':
|
|
112
|
+
garageChannel = 2
|
|
113
|
+
break
|
|
114
|
+
case 'D':
|
|
115
|
+
garageChannel = 3
|
|
116
|
+
break
|
|
117
|
+
default:
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
const prevState = this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState
|
|
121
|
+
if (value === prevState % 2) {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
const gdService = this.accessory.getService(`Garage ${garage}`)
|
|
125
|
+
this.inUse = true
|
|
126
|
+
const updateKey = generateRandomString(5)
|
|
127
|
+
this.updateKey = updateKey
|
|
128
|
+
gdService.updateCharacteristic(this.hapChar.TargetDoorState, value)
|
|
129
|
+
gdService.updateCharacteristic(this.hapChar.CurrentDoorState, value + 2)
|
|
130
|
+
this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value
|
|
131
|
+
this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2
|
|
132
|
+
const params = {
|
|
133
|
+
switches: [
|
|
134
|
+
{
|
|
135
|
+
switch: 'on',
|
|
136
|
+
outlet: garageChannel,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
}
|
|
140
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
141
|
+
await sleep(2000)
|
|
142
|
+
this.inUse = false
|
|
143
|
+
const operationTime = value === 0 ? this.operationTimeUp : this.operationTimeDown
|
|
144
|
+
await sleep(Math.max((operationTime - 20) * 100, 0))
|
|
145
|
+
if (this.updateKey !== updateKey) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
gdService.updateCharacteristic(this.hapChar.CurrentDoorState, value)
|
|
149
|
+
this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value
|
|
150
|
+
if (this.enableLogging) {
|
|
151
|
+
this.log(
|
|
152
|
+
'[%s] %s [garage %s %s].',
|
|
153
|
+
this.name,
|
|
154
|
+
this.lang.curState,
|
|
155
|
+
garageChannel,
|
|
156
|
+
value === 0 ? this.lang.doorOpen : this.lang.doorClosed,
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
this.inUse = false
|
|
161
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
162
|
+
const gdService = this.accessory.getService(`Garage ${garage}`)
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
gdService.updateCharacteristic(
|
|
165
|
+
this.hapChar.TargetDoorState,
|
|
166
|
+
this.accessory.context.cacheTargetDoorState,
|
|
167
|
+
)
|
|
168
|
+
}, 2000)
|
|
169
|
+
gdService.updateCharacteristic(this.hapChar.TargetDoorState, new this.hapErr(-70402))
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
markStatus(isOnline) {
|
|
174
|
+
this.isOnline = isOnline
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export default class {
|
|
2
|
+
constructor(platform, accessory, devicesInHB) {
|
|
3
|
+
// Set up variables from the platform
|
|
4
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
5
|
+
this.hapServ = platform.api.hap.Service
|
|
6
|
+
this.platform = platform
|
|
7
|
+
|
|
8
|
+
// Set up variables from the accessory
|
|
9
|
+
this.accessory = accessory
|
|
10
|
+
|
|
11
|
+
// Set up custom variables for this device type
|
|
12
|
+
const garageId = platform.obstructSwitches[accessory.context.eweDeviceId]
|
|
13
|
+
|
|
14
|
+
// Check the garage door exists in Homebridge
|
|
15
|
+
const uuid = platform.api.hap.uuid.generate(`${garageId}SWX`)
|
|
16
|
+
if (!devicesInHB.has(uuid)) {
|
|
17
|
+
// Can't find garage so throw an error
|
|
18
|
+
throw new Error(platform.lang.noGarageForOD)
|
|
19
|
+
} else {
|
|
20
|
+
// Get the garage door accessory
|
|
21
|
+
this.gService = devicesInHB.get(uuid).getService(this.hapServ.GarageDoorOpener)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async externalUpdate(params) {
|
|
26
|
+
try {
|
|
27
|
+
if (!params.switch || params.switch === this.cacheState || !this.gService) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
this.gService.updateCharacteristic(this.hapChar.ObstructionDetected, params.switch === 'on')
|
|
31
|
+
this.cacheState = params.switch
|
|
32
|
+
} catch (err) {
|
|
33
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|