@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,417 @@
1
+ import platformConsts from '../utils/constants.js'
2
+ import { hasProperty, sleep } from '../utils/functions.js'
3
+
4
+ export default class {
5
+ constructor(platform, accessory, devicesInHB) {
6
+ // Set up variables from the platform
7
+ this.cusChar = platform.cusChar
8
+ this.devicesInHB = devicesInHB
9
+ this.eveChar = platform.eveChar
10
+ this.hapChar = platform.api.hap.Characteristic
11
+ this.hapErr = platform.api.hap.HapStatusError
12
+ this.hapServ = platform.api.hap.Service
13
+ this.hapUUIDGen = platform.api.hap.uuid.generate
14
+ this.lang = platform.lang
15
+ this.log = platform.log
16
+ this.platform = platform
17
+
18
+ // Set up variables from the accessory
19
+ this.name = accessory.displayName
20
+ this.accessory = accessory
21
+
22
+ // Initially set the online flag as true (to be then updated as false if necessary)
23
+ this.isOnline = true
24
+
25
+ /*
26
+ UIID 2/3/4/7/8/9/29/30/31/41/82/83/84/113/114: multi switch, no power readings
27
+ UIID 126: multi switch, with wattage, voltage and amp readings (DUALR3)
28
+ */
29
+
30
+ // Set up custom variables for this device type
31
+ const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
32
+ this.hideChannels = deviceConf.hideChannels
33
+ this.inchChannels = deviceConf.inchChannels || ''
34
+ this.inUsePowerThreshold = deviceConf.inUsePowerThreshold || platformConsts.defaultValues.inUsePowerThreshold
35
+ accessory.context.isInched = accessory.context.switchNumber !== '0'
36
+ && this.inchChannels.includes(accessory.context.switchNumber)
37
+
38
+ // Set the correct logging variables for this accessory
39
+ switch (deviceConf.overrideLogging) {
40
+ case 'standard':
41
+ this.enableLogging = true
42
+ this.enableDebugLogging = false
43
+ break
44
+ case 'debug':
45
+ this.enableLogging = true
46
+ this.enableDebugLogging = true
47
+ break
48
+ case 'disable':
49
+ this.enableLogging = false
50
+ this.enableDebugLogging = false
51
+ break
52
+ default:
53
+ this.enableLogging = !platform.config.disableDeviceLogging
54
+ this.enableDebugLogging = platform.config.debug
55
+ break
56
+ }
57
+
58
+ // If the accessory has a switch service then remove it
59
+ if (this.accessory.getService(this.hapServ.Switch)) {
60
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
61
+ }
62
+
63
+ // Add the outlet service if it doesn't already exist
64
+ this.service = this.accessory.getService(this.hapServ.Outlet)
65
+ || this.accessory.addService(this.hapServ.Outlet)
66
+
67
+ if (platformConsts.devices.switchMultiPower.includes(this.accessory.context.eweUIID)) {
68
+ // Add Eve power characteristics
69
+ this.powerReadings = true
70
+ this.isDual = true
71
+ if (accessory.context.switchNumber !== '0') {
72
+ if (!this.service.testCharacteristic(this.hapChar.OutletInUse)) {
73
+ this.service.addCharacteristic(this.hapChar.OutletInUse)
74
+ }
75
+ if (!this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
76
+ this.service.addCharacteristic(this.eveChar.CurrentConsumption)
77
+ }
78
+ if (!this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
79
+ this.service.addCharacteristic(this.eveChar.ElectricCurrent)
80
+ }
81
+ if (!this.service.testCharacteristic(this.eveChar.Voltage)) {
82
+ this.service.addCharacteristic(this.eveChar.Voltage)
83
+ }
84
+ }
85
+ } else {
86
+ // Remove unused Eve characteristics
87
+ if (this.service.testCharacteristic(this.hapChar.OutletInUse)) {
88
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.OutletInUse))
89
+ }
90
+ if (this.service.testCharacteristic(this.eveChar.CurrentConsumption)) {
91
+ this.service.removeCharacteristic(
92
+ this.service.getCharacteristic(this.eveChar.CurrentConsumption),
93
+ )
94
+ }
95
+ if (this.service.testCharacteristic(this.eveChar.ElectricCurrent)) {
96
+ this.service.removeCharacteristic(
97
+ this.service.getCharacteristic(this.eveChar.ElectricCurrent),
98
+ )
99
+ }
100
+ if (this.service.testCharacteristic(this.eveChar.Voltage)) {
101
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage))
102
+ }
103
+ }
104
+
105
+ // Add the set handler to the outlet on/off characteristic
106
+ this.service
107
+ .getCharacteristic(this.hapChar.On)
108
+ .onSet(async value => this.internalStateUpdate(value))
109
+
110
+ // Add a custom characteristic for inverting the switch if inching setting is enabled
111
+ if (this.accessory.context.isInched) {
112
+ if (!this.service.testCharacteristic(this.cusChar.InvertSwitch)) {
113
+ this.service.addCharacteristic(this.cusChar.InvertSwitch)
114
+ }
115
+ this.service.updateCharacteristic(
116
+ this.cusChar.InvertSwitch,
117
+ this.service.getCharacteristic(this.hapChar.On).value,
118
+ )
119
+
120
+ // Add the set handler to invert the switch
121
+ this.service.getCharacteristic(this.cusChar.InvertSwitch).onSet((value) => {
122
+ this.service.updateCharacteristic(this.hapChar.On, value)
123
+ this.log('[%s] %s [%s].', this.name, this.lang.curState, value ? 'on' : 'off')
124
+ })
125
+ }
126
+
127
+ // Add the get handlers only if the user hasn't disabled the disableNoResponse setting
128
+ if (!platform.config.disableNoResponse) {
129
+ this.service.getCharacteristic(this.hapChar.On).onGet(() => {
130
+ if (!this.isOnline) {
131
+ throw new this.hapErr(-70402)
132
+ }
133
+ return this.service.getCharacteristic(this.hapChar.On).value
134
+ })
135
+ }
136
+
137
+ // Pass the accessory to Fakegato to set up with Eve
138
+ this.accessory.eveService = new platform.eveService('energy', this.accessory, {
139
+ log: () => {},
140
+ })
141
+
142
+ // Set up extra features for outlets that provide power readings
143
+ if (
144
+ this.powerReadings
145
+ && accessory.context.switchNumber === '0'
146
+ && platform.config.mode !== 'lan'
147
+ ) {
148
+ // Set up an interval to get eWeLink to send power updates
149
+ setTimeout(() => {
150
+ this.internalUIUpdate()
151
+ this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
152
+ }, 5000)
153
+
154
+ // Stop the intervals on Homebridge shutdown
155
+ platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
156
+ }
157
+
158
+ // Output the customised options to the log
159
+ if (accessory.context.switchNumber === '0') {
160
+ const normalLogging = this.enableLogging ? 'standard' : 'disable'
161
+ const opts = JSON.stringify({
162
+ hideChannels: this.hideChannels,
163
+ inchChannels: this.inchChannels,
164
+ inUsePowerThreshold: this.inUsePowerThreshold,
165
+ logging: this.enableDebugLogging ? 'debug' : normalLogging,
166
+ showAs: 'outlet',
167
+ })
168
+ this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
169
+ }
170
+ }
171
+
172
+ async internalStateUpdate(value) {
173
+ try {
174
+ let primaryState = false
175
+ if (this.accessory.context.isInched) {
176
+ value = !this.service.getCharacteristic(this.hapChar.On).value
177
+ }
178
+ const params = {
179
+ switches: [],
180
+ }
181
+ const { switchNumber } = this.accessory.context
182
+ switch (switchNumber) {
183
+ case '0':
184
+ params.switches.push({ switch: value ? 'on' : 'off', outlet: 0 })
185
+ params.switches.push({ switch: value ? 'on' : 'off', outlet: 1 })
186
+ if (!this.isDual) {
187
+ params.switches.push({ switch: value ? 'on' : 'off', outlet: 2 })
188
+ params.switches.push({ switch: value ? 'on' : 'off', outlet: 3 })
189
+ }
190
+ break
191
+ case '1':
192
+ case '2':
193
+ case '3':
194
+ case '4':
195
+ params.switches.push({
196
+ switch: value || this.accessory.context.isInched ? 'on' : 'off',
197
+ outlet: switchNumber - 1,
198
+ })
199
+ break
200
+ default:
201
+ return
202
+ }
203
+ if (this.accessory.context.isInched) {
204
+ this.accessory.context.ignoreUpdates = true
205
+ setTimeout(() => {
206
+ this.accessory.context.ignoreUpdates = false
207
+ }, 1500)
208
+ }
209
+ await this.platform.sendDeviceUpdate(this.accessory, params)
210
+ if (this.accessory.context.isInched) {
211
+ this.service.updateCharacteristic(this.cusChar.InvertSwitch, value)
212
+ }
213
+ switch (switchNumber) {
214
+ case '0':
215
+ for (let i = 0; i <= this.accessory.context.channelCount; i += 1) {
216
+ const idToCheck = `${this.accessory.context.eweDeviceId}SW${i}`
217
+ const uuid = this.hapUUIDGen(idToCheck)
218
+ if (this.devicesInHB.has(uuid)) {
219
+ const subAccessory = this.devicesInHB.get(uuid)
220
+ const service = subAccessory.getService(this.hapServ.Outlet)
221
+ service.updateCharacteristic(this.hapChar.On, value)
222
+ subAccessory.eveService.addEntry({ status: value ? 1 : 0 })
223
+ if (i > 0) {
224
+ if (this.enableLogging) {
225
+ this.log(
226
+ '[%s] %s [%s].',
227
+ subAccessory.displayName,
228
+ this.lang.curState,
229
+ value ? 'on' : 'off',
230
+ )
231
+ }
232
+ }
233
+ }
234
+ }
235
+ break
236
+ case '1':
237
+ case '2':
238
+ case '3':
239
+ case '4':
240
+ for (let i = 1; i <= this.accessory.context.channelCount; i += 1) {
241
+ const idToCheck = `${this.accessory.context.eweDeviceId}SW${i}`
242
+ const uuid = this.hapUUIDGen(idToCheck)
243
+ if (this.devicesInHB.has(uuid)) {
244
+ const subAccessory = this.devicesInHB.get(uuid)
245
+ const service = subAccessory.getService(this.hapServ.Outlet)
246
+ if (i === Number.parseInt(switchNumber, 10)) {
247
+ if (value) {
248
+ primaryState = true
249
+ }
250
+ subAccessory.eveService.addEntry({ status: value ? 1 : 0 })
251
+ if (i > 0) {
252
+ if (this.enableLogging) {
253
+ this.log(
254
+ '[%s] %s [%s].',
255
+ subAccessory.displayName,
256
+ this.lang.curState,
257
+ value ? 'on' : 'off',
258
+ )
259
+ }
260
+ }
261
+ } else if (service.getCharacteristic(this.hapChar.On).value) {
262
+ primaryState = true
263
+ }
264
+ }
265
+ }
266
+ if (!this.platform.hideMasters.includes(this.accessory.context.eweDeviceId)) {
267
+ const idToCheck = `${this.accessory.context.eweDeviceId}SW0`
268
+ const uuid = this.hapUUIDGen(idToCheck)
269
+ const priAccessory = this.devicesInHB.get(uuid)
270
+ priAccessory
271
+ .getService(this.hapServ.Outlet)
272
+ .updateCharacteristic(this.hapChar.On, primaryState)
273
+ priAccessory.eveService.addEntry({ status: primaryState ? 1 : 0 })
274
+ }
275
+ break
276
+ default:
277
+ }
278
+ } catch (err) {
279
+ this.platform.deviceUpdateError(this.accessory, err, true)
280
+ setTimeout(() => {
281
+ this.service.updateCharacteristic(this.hapChar.On, !value)
282
+ }, 2000)
283
+ throw new this.hapErr(-70402)
284
+ }
285
+ }
286
+
287
+ async internalUIUpdate() {
288
+ try {
289
+ // Skip polling if device isn't online
290
+ if (!this.isOnline) {
291
+ return
292
+ }
293
+
294
+ // Send the params to request the updates
295
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 0, time: 120 } })
296
+ await sleep(2000)
297
+ await this.platform.sendDeviceUpdate(this.accessory, { uiActive: { outlet: 1, time: 120 } })
298
+ } catch (err) {
299
+ // Suppress errors here
300
+ }
301
+ }
302
+
303
+ async externalUpdate(params) {
304
+ try {
305
+ const idToCheck = `${this.accessory.context.eweDeviceId}SW`
306
+ let primaryState = false
307
+ for (let i = 1; i <= this.accessory.context.channelCount; i += 1) {
308
+ const uuid = this.hapUUIDGen(idToCheck + i)
309
+ if (this.devicesInHB.has(uuid)) {
310
+ const subAccessory = this.devicesInHB.get(uuid)
311
+ const service = subAccessory.getService(this.hapServ.Outlet)
312
+ if (params.switches) {
313
+ const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
314
+ if (subAccessory.context.isInched) {
315
+ if (params.switches[i - 1].switch === 'on' && !subAccessory.context.ignoreUpdates) {
316
+ subAccessory.context.ignoreUpdates = true
317
+ setTimeout(() => {
318
+ subAccessory.context.ignoreUpdates = false
319
+ }, 1500)
320
+ const newState = currentState === 'on' ? 'off' : 'on'
321
+ if (newState === 'on') {
322
+ primaryState = true
323
+ }
324
+ service.updateCharacteristic(this.hapChar.On, newState === 'on')
325
+ service.updateCharacteristic(this.cusChar.InvertSwitch, newState === 'on')
326
+ subAccessory.eveService.addEntry({
327
+ status: newState === 'on' ? 1 : 0,
328
+ })
329
+ if (params.updateSource && this.enableLogging) {
330
+ this.log('[%s] %s [%s].', subAccessory.displayName, this.lang.curState, newState)
331
+ }
332
+ }
333
+ } else {
334
+ if (params.switches[i - 1].switch === 'on') {
335
+ primaryState = true
336
+ }
337
+ if (!params.updateSource || params.switches[i - 1].switch !== currentState) {
338
+ service.updateCharacteristic(
339
+ this.hapChar.On,
340
+ params.switches[i - 1].switch === 'on',
341
+ )
342
+ subAccessory.eveService.addEntry({
343
+ status: params.switches[i - 1].switch === 'on' ? 1 : 0,
344
+ })
345
+ if (params.updateSource && this.enableLogging) {
346
+ this.log(
347
+ '[%s] %s [%s].',
348
+ subAccessory.displayName,
349
+ this.lang.curState,
350
+ params.switches[i - 1].switch,
351
+ )
352
+ }
353
+ }
354
+ }
355
+ }
356
+ if (this.powerReadings) {
357
+ let logger = false
358
+ let power
359
+ let voltage
360
+ let current
361
+ if (hasProperty(params, `actPow_0${i - 1}`)) {
362
+ power = Number.parseInt(params[`actPow_0${i - 1}`], 10) / 100
363
+ service.updateCharacteristic(
364
+ this.hapChar.OutletInUse,
365
+ service.getCharacteristic(this.hapChar.On).value && power > this.inUsePowerThreshold,
366
+ )
367
+ service.updateCharacteristic(this.eveChar.CurrentConsumption, power)
368
+ subAccessory.eveService.addEntry({ power })
369
+ logger = true
370
+ }
371
+ if (hasProperty(params, `voltage_0${i - 1}`)) {
372
+ voltage = Number.parseInt(params[`voltage_0${i - 1}`], 10) / 100
373
+ service.updateCharacteristic(this.eveChar.Voltage, voltage)
374
+ logger = true
375
+ }
376
+ if (hasProperty(params, `current_0${i - 1}`)) {
377
+ current = Number.parseInt(params[`current_0${i - 1}`], 10) / 100
378
+ service.updateCharacteristic(this.eveChar.ElectricCurrent, current)
379
+ logger = true
380
+ }
381
+ if (params.updateSource && logger && this.enableLogging) {
382
+ this.log(
383
+ '[%s] %s%s%s.',
384
+ subAccessory.displayName,
385
+ power !== undefined ? `${this.lang.curPower} [${power}W]` : '',
386
+ voltage !== undefined ? ` ${this.lang.curVolt} [${voltage}V]` : '',
387
+ current !== undefined ? ` ${this.lang.curCurr} [${current}A]` : '',
388
+ )
389
+ }
390
+ }
391
+ }
392
+ }
393
+ if (
394
+ !this.platform.hideMasters.includes(this.accessory.context.eweDeviceId)
395
+ && params.switches
396
+ ) {
397
+ this.service.updateCharacteristic(this.hapChar.On, primaryState)
398
+ this.accessory.eveService.addEntry({ status: primaryState ? 1 : 0 })
399
+ }
400
+ } catch (err) {
401
+ this.platform.deviceUpdateError(this.accessory, err, false)
402
+ }
403
+ }
404
+
405
+ markStatus(isOnline) {
406
+ this.isOnline = isOnline
407
+ }
408
+
409
+ currentState() {
410
+ const toReturn = {}
411
+ toReturn.services = ['outlet']
412
+ toReturn.outlet = {
413
+ state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off',
414
+ }
415
+ return toReturn
416
+ }
417
+ }