@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.
Files changed (113) hide show
  1. package/CHANGELOG.md +1363 -0
  2. package/LICENSE +21 -0
  3. package/README.md +68 -0
  4. package/config.schema.json +1757 -0
  5. package/eslint.config.js +15 -0
  6. package/lib/connection/api.js +508 -0
  7. package/lib/connection/http.js +304 -0
  8. package/lib/connection/lan.js +318 -0
  9. package/lib/connection/ws.js +414 -0
  10. package/lib/device/curtain.js +324 -0
  11. package/lib/device/diffuser.js +473 -0
  12. package/lib/device/fan.js +349 -0
  13. package/lib/device/group.js +106 -0
  14. package/lib/device/humidifier.js +199 -0
  15. package/lib/device/index.js +61 -0
  16. package/lib/device/light-cct.js +333 -0
  17. package/lib/device/light-dimmer.js +257 -0
  18. package/lib/device/light-rgb-cct.js +809 -0
  19. package/lib/device/light-rgb.js +272 -0
  20. package/lib/device/motor.js +363 -0
  21. package/lib/device/outlet-multi.js +417 -0
  22. package/lib/device/outlet-single-inched.js +409 -0
  23. package/lib/device/outlet-single.js +384 -0
  24. package/lib/device/panel.js +382 -0
  25. package/lib/device/rf-bridge.js +321 -0
  26. package/lib/device/rf-button.js +125 -0
  27. package/lib/device/rf-sensor.js +173 -0
  28. package/lib/device/sensor-ambient.js +311 -0
  29. package/lib/device/sensor-contact.js +140 -0
  30. package/lib/device/sensor-temp-humi.js +182 -0
  31. package/lib/device/simulation/blind.js +253 -0
  32. package/lib/device/simulation/cooler.js +312 -0
  33. package/lib/device/simulation/door.js +253 -0
  34. package/lib/device/simulation/doorbell.js +190 -0
  35. package/lib/device/simulation/garage-eachen.js +235 -0
  36. package/lib/device/simulation/garage-four.js +176 -0
  37. package/lib/device/simulation/garage-od-switch.js +36 -0
  38. package/lib/device/simulation/garage-one.js +395 -0
  39. package/lib/device/simulation/garage-two.js +394 -0
  40. package/lib/device/simulation/gate-one.js +327 -0
  41. package/lib/device/simulation/heater.js +389 -0
  42. package/lib/device/simulation/index.js +75 -0
  43. package/lib/device/simulation/light-fan.js +258 -0
  44. package/lib/device/simulation/lock-eachen.js +163 -0
  45. package/lib/device/simulation/lock-one.js +366 -0
  46. package/lib/device/simulation/p-button.js +223 -0
  47. package/lib/device/simulation/purifier.js +289 -0
  48. package/lib/device/simulation/rf-blind.js +192 -0
  49. package/lib/device/simulation/rf-door.js +180 -0
  50. package/lib/device/simulation/rf-window.js +180 -0
  51. package/lib/device/simulation/sensor-hidden.js +105 -0
  52. package/lib/device/simulation/sensor-leak.js +123 -0
  53. package/lib/device/simulation/sensor-visible.js +231 -0
  54. package/lib/device/simulation/sensor.js +300 -0
  55. package/lib/device/simulation/switch-valve.js +351 -0
  56. package/lib/device/simulation/tap-one.js +283 -0
  57. package/lib/device/simulation/tap-two.js +266 -0
  58. package/lib/device/simulation/th-cooler.js +443 -0
  59. package/lib/device/simulation/th-dehumidifier.js +424 -0
  60. package/lib/device/simulation/th-heater.js +449 -0
  61. package/lib/device/simulation/th-humidifier.js +424 -0
  62. package/lib/device/simulation/th-thermostat.js +611 -0
  63. package/lib/device/simulation/tv.js +252 -0
  64. package/lib/device/simulation/valve-four.js +232 -0
  65. package/lib/device/simulation/valve-one.js +345 -0
  66. package/lib/device/simulation/valve-two.js +340 -0
  67. package/lib/device/simulation/window.js +253 -0
  68. package/lib/device/switch-man.js +106 -0
  69. package/lib/device/switch-mate.js +82 -0
  70. package/lib/device/switch-multi.js +411 -0
  71. package/lib/device/switch-single-inched.js +332 -0
  72. package/lib/device/switch-single.js +307 -0
  73. package/lib/device/template.js +43 -0
  74. package/lib/device/thermostat.js +286 -0
  75. package/lib/device/zigbee/index.js +27 -0
  76. package/lib/device/zigbee/light-cct.js +263 -0
  77. package/lib/device/zigbee/light-dimmer.js +148 -0
  78. package/lib/device/zigbee/light-rgb-cct.js +400 -0
  79. package/lib/device/zigbee/motor.js +301 -0
  80. package/lib/device/zigbee/sensor-ambient.js +177 -0
  81. package/lib/device/zigbee/sensor-contact.js +137 -0
  82. package/lib/device/zigbee/sensor-leak.js +119 -0
  83. package/lib/device/zigbee/sensor-motion.js +119 -0
  84. package/lib/device/zigbee/sensor-occupancy.js +119 -0
  85. package/lib/device/zigbee/sensor-smoke.js +96 -0
  86. package/lib/device/zigbee/switch-stateless.js +104 -0
  87. package/lib/device/zigbee/thermostat.js +323 -0
  88. package/lib/fakegato/LICENSE +21 -0
  89. package/lib/fakegato/fakegato-history.js +813 -0
  90. package/lib/fakegato/fakegato-storage.js +108 -0
  91. package/lib/fakegato/fakegato-timer.js +125 -0
  92. package/lib/fakegato/uuid.js +27 -0
  93. package/lib/homebridge-ui/public/index.html +365 -0
  94. package/lib/homebridge-ui/server.js +46 -0
  95. package/lib/index.js +7 -0
  96. package/lib/node-dns-sd/LICENSE +21 -0
  97. package/lib/node-dns-sd/README.md +613 -0
  98. package/lib/node-dns-sd/lib/dns-sd-classes.json +6 -0
  99. package/lib/node-dns-sd/lib/dns-sd-composer.js +83 -0
  100. package/lib/node-dns-sd/lib/dns-sd-parser.js +344 -0
  101. package/lib/node-dns-sd/lib/dns-sd-types.json +52 -0
  102. package/lib/node-dns-sd/lib/dns-sd.js +580 -0
  103. package/lib/platform.js +2156 -0
  104. package/lib/utils/colour.js +552 -0
  105. package/lib/utils/constants.js +589 -0
  106. package/lib/utils/custom-chars.js +33 -0
  107. package/lib/utils/eve-chars.js +130 -0
  108. package/lib/utils/functions.js +42 -0
  109. package/lib/utils/lang-en.js +160 -0
  110. package/lib/utils/lang-fr.js +163 -0
  111. package/lib/utils/lang-th.js +160 -0
  112. package/lib/utils/lang.js +5 -0
  113. package/package.json +75 -0
@@ -0,0 +1,301 @@
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
+ // Set up custom variables for this device type
19
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
20
+ this.lowBattThreshold = deviceConf.lowBattThreshold
21
+ ? Math.min(deviceConf.lowBattThreshold, 100)
22
+ : platformConsts.defaultValues.lowBattThreshold
23
+ const showAsMotor = deviceConf.showAsMotor || platformConsts.defaultValues.showAsMotor
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
+ // Temp override for debugging
46
+ this.enableLogging = true
47
+ this.enableDebugLogging = true
48
+
49
+ // Add the battery service if it doesn't already exist
50
+ this.battService = this.accessory.getService(this.hapServ.Battery)
51
+ || this.accessory.addService(this.hapServ.Battery)
52
+ this.cacheBatt = this.battService.getCharacteristic(this.hapChar.BatteryLevel).value
53
+
54
+ // Add the window covering service if it doesn't already exist
55
+ let service
56
+ switch (showAsMotor) {
57
+ case 'door':
58
+ service = this.hapServ.Door
59
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
60
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
61
+ }
62
+ if (this.accessory.getService(this.hapServ.Window)) {
63
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
64
+ }
65
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
66
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
67
+ }
68
+ break
69
+ case 'garage':
70
+ service = this.hapServ.GarageDoorOpener
71
+ this.isGarage = true
72
+ if (this.accessory.getService(this.hapServ.Door)) {
73
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
74
+ }
75
+ if (this.accessory.getService(this.hapServ.Window)) {
76
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
77
+ }
78
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
79
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
80
+ }
81
+ break
82
+ case 'window':
83
+ service = this.hapServ.Window
84
+ if (this.accessory.getService(this.hapServ.Door)) {
85
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
86
+ }
87
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
88
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
89
+ }
90
+ if (this.accessory.getService(this.hapServ.WindowCovering)) {
91
+ this.accessory.removeService(this.accessory.getService(this.hapServ.WindowCovering))
92
+ }
93
+ break
94
+ default:
95
+ service = this.hapServ.WindowCovering
96
+ if (this.accessory.getService(this.hapServ.Door)) {
97
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Door))
98
+ }
99
+ if (this.accessory.getService(this.hapServ.GarageDoorOpener)) {
100
+ this.accessory.removeService(this.accessory.getService(this.hapServ.GarageDoorOpener))
101
+ }
102
+ if (this.accessory.getService(this.hapServ.Window)) {
103
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Window))
104
+ }
105
+ break
106
+ }
107
+ this.service = this.accessory.getService(service) || this.accessory.addService(service)
108
+
109
+ // Add the set handler to the target position characteristic
110
+ if (this.isGarage) {
111
+ this.service
112
+ .getCharacteristic(this.hapChar.TargetDoorState)
113
+ .onSet(async value => this.internalTargetUpdate(value))
114
+ } else {
115
+ this.service
116
+ .getCharacteristic(this.hapChar.TargetPosition)
117
+ .onSet(async value => this.internalPositionUpdate(value))
118
+ }
119
+
120
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
121
+ if (!platform.config.disableNoResponse) {
122
+ if (this.isGarage) {
123
+ this.service.getCharacteristic(this.hapChar.CurrentDoorState).onGet(() => {
124
+ if (!this.isOnline) {
125
+ throw new this.hapErr(-70402)
126
+ }
127
+ return this.service.getCharacteristic(this.hapChar.CurrentDoorState).value
128
+ })
129
+ this.service.getCharacteristic(this.hapChar.TargetDoorState).onGet(() => {
130
+ if (!this.isOnline) {
131
+ throw new this.hapErr(-70402)
132
+ }
133
+ return this.service.getCharacteristic(this.hapChar.TargetDoorState).value
134
+ })
135
+ } else {
136
+ this.service.getCharacteristic(this.hapChar.CurrentPosition).onGet(() => {
137
+ if (!this.isOnline) {
138
+ throw new this.hapErr(-70402)
139
+ }
140
+ return this.service.getCharacteristic(this.hapChar.CurrentPosition).value
141
+ })
142
+ this.service.getCharacteristic(this.hapChar.TargetPosition).onGet(() => {
143
+ if (!this.isOnline) {
144
+ throw new this.hapErr(-70402)
145
+ }
146
+ return this.service.getCharacteristic(this.hapChar.TargetPosition).value
147
+ })
148
+ }
149
+ }
150
+
151
+ // Output the customised options to the log
152
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
153
+ const opts = JSON.stringify({
154
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
155
+ lowBattThreshold: this.lowBattThreshold,
156
+ showAsMotor,
157
+ })
158
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
159
+ }
160
+
161
+ async internalPositionUpdate(value) {
162
+ try {
163
+ if (this.cachePos === value) {
164
+ return
165
+ }
166
+ const updateKey = generateRandomString(5)
167
+ this.updateKey = updateKey
168
+ await sleep(500)
169
+ if (updateKey !== this.updateKey) {
170
+ return
171
+ }
172
+ const params = { openPercent: value }
173
+ await this.platform.sendDeviceUpdate(this.accessory, params)
174
+ this.cacheTarg = value
175
+ if (this.enableLogging) {
176
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, this.cacheTarg)
177
+ }
178
+ } catch (err) {
179
+ // Catch any errors and let the platform display them
180
+ this.platform.deviceUpdateError(this.accessory, err, true)
181
+ setTimeout(() => {
182
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cacheTarg)
183
+ }, 2000)
184
+ throw new this.hapErr(-70402)
185
+ }
186
+ }
187
+
188
+ async internalTargetUpdate(value) {
189
+ try {
190
+ // 0 for open, 1 for closed
191
+ // this.cachePos is 0 for closed and >0 for open
192
+
193
+ const params = { openPercent: value === 1 ? 0 : 100 }
194
+ await this.platform.sendDeviceUpdate(this.accessory, params)
195
+ this.cacheTarg = value === 1 ? 0 : 100
196
+ if (this.enableLogging) {
197
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, this.cacheTarg)
198
+ }
199
+ } catch (err) {
200
+ // Catch any errors and let the platform display them
201
+ this.platform.deviceUpdateError(this.accessory, err, true)
202
+ setTimeout(() => {
203
+ this.service.updateCharacteristic(this.hapChar.TargetDoorState, this.cacheTarg)
204
+ }, 2000)
205
+ throw new this.hapErr(-70402)
206
+ }
207
+ }
208
+
209
+ async externalUpdate(params) {
210
+ try {
211
+ if (hasProperty(params, 'battery') && params.battery !== this.cacheBatt) {
212
+ this.cacheBatt = params.battery
213
+ this.cacheBattScaled = Math.max(Math.min(this.cacheBatt, 100), 0)
214
+ this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
215
+ this.battService.updateCharacteristic(
216
+ this.hapChar.StatusLowBattery,
217
+ this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
218
+ )
219
+ if (params.updateSource && this.enableLogging) {
220
+ this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
221
+ }
222
+ }
223
+
224
+ // currLocation is the current position of the motor
225
+ if (hasProperty(params, 'curPercen')) {
226
+ if (params.curPercen !== this.cachePos) {
227
+ this.cachePos = params.curPercen
228
+ if (!this.isGarage) {
229
+ this.service.updateCharacteristic(this.hapChar.CurrentPosition, this.cachePos)
230
+ }
231
+ if (params.updateSource && this.enableLogging) {
232
+ this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos)
233
+ }
234
+ }
235
+ }
236
+
237
+ // location is the target position of the motor
238
+ if (hasProperty(params, 'openPercent')) {
239
+ if (params.openPercent !== this.cacheTarg) {
240
+ this.cacheTarg = params.openPercent
241
+ if (!this.isGarage) {
242
+ this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cacheTarg)
243
+ }
244
+ if (params.updateSource && this.enableLogging) {
245
+ this.log('[%s] %s [%s%].', this.name, this.lang.curTarg, this.cacheTarg)
246
+ }
247
+ }
248
+ }
249
+
250
+ // Get the target door state characteristic for use later
251
+ let targetChar
252
+ if (this.isGarage) {
253
+ targetChar = this.service.getCharacteristic(this.TargetDoorState)
254
+ }
255
+
256
+ // If the two are equal then the motor must have stopped at this position
257
+ if (this.cacheTarg === this.cachePos) {
258
+ if (this.isGarage) {
259
+ if (this.cachePos === 0) {
260
+ // CLOSED
261
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 1)
262
+ if (targetChar.value !== 1) {
263
+ targetChar.updateValue(1)
264
+ }
265
+ } else {
266
+ // OPEN
267
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 0)
268
+ if (targetChar.value !== 0) {
269
+ targetChar.updateValue(0)
270
+ }
271
+ }
272
+ } else {
273
+ // PositionState 2 === STOPPED
274
+ this.service.updateCharacteristic(this.hapChar.PositionState, 2)
275
+ }
276
+ } else if (this.cacheTarg > this.cachePos) {
277
+ if (this.isGarage) {
278
+ // OPENING
279
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 2)
280
+ if (targetChar.value !== 0) {
281
+ targetChar.updateValue(0)
282
+ }
283
+ } else {
284
+ // PositionState 1 === INCREASING
285
+ this.service.updateCharacteristic(this.hapChar.PositionState, 1)
286
+ }
287
+ } else if (this.isGarage) {
288
+ // CLOSING
289
+ this.service.updateCharacteristic(this.hapChar.CurrentDoorState, 3)
290
+ if (targetChar.value !== 1) {
291
+ targetChar.updateValue(1)
292
+ }
293
+ } else {
294
+ // PositionState 0 === DECREASING
295
+ this.service.updateCharacteristic(this.hapChar.PositionState, 0)
296
+ }
297
+ } catch (err) {
298
+ this.platform.deviceUpdateError(this.accessory, err, false)
299
+ }
300
+ }
301
+ }
@@ -0,0 +1,177 @@
1
+ import platformConsts from '../../utils/constants.js'
2
+ import { hasProperty, parseError } 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.hapServ = platform.api.hap.Service
9
+ this.lang = platform.lang
10
+ this.log = platform.log
11
+ this.platform = platform
12
+
13
+ // Set up variables from the accessory
14
+ this.name = accessory.displayName
15
+ this.accessory = accessory
16
+
17
+ // Set up custom variables for this device type
18
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
19
+ this.lowBattThreshold = deviceConf.lowBattThreshold
20
+ ? Math.min(deviceConf.lowBattThreshold, 100)
21
+ : platformConsts.defaultValues.lowBattThreshold
22
+ this.tempOffset = deviceConf.offset || platformConsts.defaultValues.offset
23
+ this.tempOffsetFactor = deviceConf.offsetFactor
24
+ this.humiOffset = deviceConf.humidityOffset
25
+ ? Number.parseInt(deviceConf.humidityOffset, 10)
26
+ : platformConsts.defaultValues.humidityOffset
27
+ this.humiOffsetFactor = deviceConf.humidityOffsetFactor
28
+
29
+ // Set the correct logging variables for this accessory
30
+ switch (deviceConf.overrideLogging) {
31
+ case 'standard':
32
+ this.enableLogging = true
33
+ this.enableDebugLogging = false
34
+ break
35
+ case 'debug':
36
+ this.enableLogging = true
37
+ this.enableDebugLogging = true
38
+ break
39
+ case 'disable':
40
+ this.enableLogging = false
41
+ this.enableDebugLogging = false
42
+ break
43
+ default:
44
+ this.enableLogging = !platform.config.disableDeviceLogging
45
+ this.enableDebugLogging = platform.config.debug
46
+ break
47
+ }
48
+
49
+ // Add the temperature sensor service if it doesn't already exist
50
+ this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor)
51
+ || this.accessory.addService(this.hapServ.TemperatureSensor)
52
+
53
+ // Add options to the current temperature characteristic
54
+ this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
55
+ minStep: 0.1,
56
+ })
57
+ this.cacheTemp = this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value
58
+ this.updateCache()
59
+
60
+ // Add the humidity sensor service if it doesn't already exist
61
+ this.humiService = this.accessory.getService(this.hapServ.HumiditySensor)
62
+ || this.accessory.addService(this.hapServ.HumiditySensor)
63
+
64
+ // Add the battery service if it doesn't already exist
65
+ this.battService = this.accessory.getService(this.hapServ.Battery)
66
+ || this.accessory.addService(this.hapServ.Battery)
67
+
68
+ // Pass the accessory to Fakegato to set up with Eve
69
+ this.accessory.eveService = new platform.eveService('weather', this.accessory, {
70
+ log: () => {},
71
+ })
72
+
73
+ // Output the customised options to the log
74
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
75
+ const opts = JSON.stringify({
76
+ humidityOffset: this.humiOffset,
77
+ humidityOffsetFactor: this.humiOffsetFactor,
78
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
79
+ lowBattThreshold: this.lowBattThreshold,
80
+ offset: this.tempOffset,
81
+ offsetFactor: this.tempOffsetFactor,
82
+ })
83
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
84
+ }
85
+
86
+ async externalUpdate(params) {
87
+ try {
88
+ if (hasProperty(params, 'battery') && params.battery !== this.cacheBatt) {
89
+ this.cacheBatt = params.battery
90
+ this.cacheBattScaled = Math.max(Math.min(this.cacheBatt, 100), 0)
91
+ this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
92
+ this.battService.updateCharacteristic(
93
+ this.hapChar.StatusLowBattery,
94
+ this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
95
+ )
96
+ if (params.updateSource && this.enableLogging) {
97
+ this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
98
+ }
99
+ }
100
+ if (hasProperty(params, 'temperature')) {
101
+ let newTemp = Number.parseInt(params.temperature, 10) / 100
102
+ if (this.tempOffsetFactor) {
103
+ newTemp *= this.tempOffset
104
+ } else {
105
+ newTemp += this.tempOffset
106
+ }
107
+ if (newTemp !== this.cacheTemp) {
108
+ this.cacheTemp = newTemp
109
+ this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
110
+ this.accessory.eveService.addEntry({ temp: this.cacheTemp })
111
+ if (params.updateSource && this.enableLogging) {
112
+ this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
113
+ }
114
+
115
+ // Update the cache file with the new temperature
116
+ this.updateCache()
117
+ }
118
+ }
119
+ if (hasProperty(params, 'humidity')) {
120
+ let newHumi = Number.parseInt(params.humidity, 10) / 100
121
+ if (this.humiOffsetFactor) {
122
+ newHumi *= this.humiOffset
123
+ } else {
124
+ newHumi += this.humiOffset
125
+ }
126
+ newHumi = Math.max(Math.min(Number.parseInt(newHumi, 10), 100), 0)
127
+ if (newHumi !== this.cacheHumi) {
128
+ this.cacheHumi = newHumi
129
+ this.humiService.updateCharacteristic(
130
+ this.hapChar.CurrentRelativeHumidity,
131
+ this.cacheHumi,
132
+ )
133
+ this.accessory.eveService.addEntry({ humidity: this.cacheHumi })
134
+ if (params.updateSource && this.enableLogging) {
135
+ this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, this.cacheHumi)
136
+ }
137
+ }
138
+ }
139
+ } catch (err) {
140
+ this.platform.deviceUpdateError(this.accessory, err, false)
141
+ }
142
+ }
143
+
144
+ async updateCache() {
145
+ // Don't continue if the storage client hasn't initialised properly
146
+ if (!this.platform.storageClientData) {
147
+ return
148
+ }
149
+
150
+ // Attempt to save the new temperature to the cache
151
+ try {
152
+ await this.platform.storageData.setItem(
153
+ `${this.accessory.context.eweDeviceId}_temp`,
154
+ this.cacheTemp,
155
+ )
156
+ } catch (err) {
157
+ if (this.enableLogging) {
158
+ this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
159
+ }
160
+ }
161
+ }
162
+
163
+ currentState() {
164
+ const toReturn = {}
165
+ toReturn.services = ['temperature', 'humidity', 'battery']
166
+ toReturn.temperature = {
167
+ current: this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value,
168
+ }
169
+ toReturn.humidity = {
170
+ current: this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value,
171
+ }
172
+ toReturn.battery = {
173
+ current: this.battService.getCharacteristic(this.hapChar.BatteryLevel).value,
174
+ }
175
+ return toReturn
176
+ }
177
+ }
@@ -0,0 +1,137 @@
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
+ // Set up custom variables for this device type
19
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
20
+ this.scaleBattery = deviceConf.scaleBattery
21
+ this.lowBattThreshold = deviceConf.lowBattThreshold
22
+ ? Math.min(deviceConf.lowBattThreshold, 100)
23
+ : platformConsts.defaultValues.lowBattThreshold
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 contact sensor service if it doesn't already exist
46
+ this.service = this.accessory.getService(this.hapServ.ContactSensor)
47
+ if (!this.service) {
48
+ this.service = this.accessory.addService(this.hapServ.ContactSensor)
49
+ this.service.addCharacteristic(this.eveChar.LastActivation)
50
+ this.service.addCharacteristic(this.eveChar.ResetTotal)
51
+ this.service.addCharacteristic(this.eveChar.OpenDuration)
52
+ this.service.addCharacteristic(this.eveChar.ClosedDuration)
53
+ this.service.addCharacteristic(this.eveChar.TimesOpened)
54
+ }
55
+
56
+ // Add the set handler to the contact sensor reset total characteristic
57
+ this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(() => {
58
+ this.service.updateCharacteristic(this.eveChar.TimesOpened, 0)
59
+ })
60
+
61
+ // Add the battery service if it doesn't already exist
62
+ this.battService = this.accessory.getService(this.hapServ.Battery)
63
+ || this.accessory.addService(this.hapServ.Battery)
64
+
65
+ // Pass the accessory to Fakegato to set up with Eve
66
+ this.accessory.eveService = new platform.eveService('door', this.accessory, {
67
+ log: () => {},
68
+ })
69
+
70
+ // Output the customised options to the log
71
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
72
+ const opts = JSON.stringify({
73
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
74
+ lowBattThreshold: this.lowBattThreshold,
75
+ scaleBattery: this.scaleBattery,
76
+ })
77
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
78
+ }
79
+
80
+ async externalUpdate(params) {
81
+ try {
82
+ if (hasProperty(params, 'battery') && params.battery !== this.cacheBatt) {
83
+ this.cacheBatt = params.battery
84
+ this.cacheBattScaled = this.scaleBattery ? this.cacheBatt * 10 : this.cacheBatt
85
+ this.cacheBattScaled = Math.max(Math.min(this.cacheBattScaled, 100), 0)
86
+ this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBattScaled)
87
+ this.battService.updateCharacteristic(
88
+ this.hapChar.StatusLowBattery,
89
+ this.cacheBattScaled < this.lowBattThreshold ? 1 : 0,
90
+ )
91
+ if (params.updateSource && this.enableLogging) {
92
+ this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBattScaled)
93
+ }
94
+ }
95
+ if (
96
+ hasProperty(params, 'lock')
97
+ && [0, 1].includes(params.lock)
98
+ && params.lock !== this.cacheState
99
+ ) {
100
+ this.cacheState = params.lock
101
+ if (params.lock === 1) {
102
+ this.service.updateCharacteristic(this.hapChar.ContactSensorState, 1)
103
+ this.accessory.eveService.addEntry({ status: 1 })
104
+ const initialTime = this.accessory.eveService.getInitialTime()
105
+ this.service.updateCharacteristic(
106
+ this.eveChar.LastActivation,
107
+ Math.round(new Date().valueOf() / 1000) - initialTime,
108
+ )
109
+ const newTO = this.service.getCharacteristic(this.eveChar.TimesOpened).value + 1
110
+ this.service.updateCharacteristic(this.eveChar.TimesOpened, newTO)
111
+ } else {
112
+ this.service.updateCharacteristic(this.hapChar.ContactSensorState, 0)
113
+ this.accessory.eveService.addEntry({ status: 0 })
114
+ }
115
+ if (params.updateSource && this.enableLogging) {
116
+ this.log(
117
+ '[%s] %s [%s].',
118
+ this.name,
119
+ this.lang.curState,
120
+ params.lock === 0 ? this.lang.contactYes : this.lang.contactNo,
121
+ )
122
+ }
123
+ }
124
+ } catch (err) {
125
+ this.platform.deviceUpdateError(this.accessory, err, false)
126
+ }
127
+ }
128
+
129
+ currentState() {
130
+ return {
131
+ services: ['contact'],
132
+ contact: {
133
+ state: this.service.getCharacteristic(this.hapChar.ContactSensorState).value,
134
+ },
135
+ }
136
+ }
137
+ }