@switchbot/homebridge-switchbot 4.0.0-beta.0 → 4.0.0-beta.2

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/src/device/bot.ts CHANGED
@@ -106,6 +106,18 @@ export class Bot extends deviceBase {
106
106
  botUpdateInProgress!: boolean
107
107
  doBotUpdate!: Subject<void>
108
108
 
109
+ /**
110
+ * Constructs a new instance of the Bot device.
111
+ *
112
+ * @param {SwitchBotPlatform} platform - The platform instance.
113
+ * @param {PlatformAccessory} accessory - The platform accessory.
114
+ * @param {device & devicesConfig} device - The device configuration.
115
+ *
116
+ * Initializes the Bot device, sets up the battery service, maps the device type to the appropriate HomeKit service,
117
+ * removes unnecessary services, retrieves initial values, registers event handlers, and starts update intervals.
118
+ *
119
+ * @constructor
120
+ */
109
121
  constructor(
110
122
  readonly platform: SwitchBotPlatform,
111
123
  accessory: PlatformAccessory,
@@ -113,7 +125,6 @@ export class Bot extends deviceBase {
113
125
  ) {
114
126
  super(platform, accessory, device)
115
127
 
116
- // default placeholders
117
128
  this.getBotConfigSettings(device)
118
129
 
119
130
  // this is subject we use to track when we need to POST changes to the SwitchBot API
@@ -132,261 +143,73 @@ export class Bot extends deviceBase {
132
143
  // Initialize Battery Characteristics
133
144
  this.Battery.Service.setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name).setCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery).setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE)
134
145
 
135
- // deviceType
136
- if (this.botDeviceType === 'switch') {
137
- // Set category
138
- accessory.category = this.hap.Categories.SWITCH
139
- // Initialize Switch Service
140
- accessory.context.Switch = accessory.context.Switch ?? {}
141
- this.Switch = {
142
- Name: accessory.displayName,
143
- Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
144
- }
145
- accessory.context.Switch = this.Switch as object
146
- this.debugLog('Displaying as Switch')
147
- // Initialize Switch Characteristics
148
- this.Switch.Service.setCharacteristic(this.hap.Characteristic.Name, this.Switch.Name).getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this))
149
- // Remove other services
150
- this.removeFanService(accessory)
151
- this.removeLockService(accessory)
152
- this.removeDoorService(accessory)
153
- this.removeFaucetService(accessory)
154
- this.removeOutletService(accessory)
155
- this.removeWindowService(accessory)
156
- this.removeGarageDoorService(accessory)
157
- this.removeWindowCoveringService(accessory)
158
- this.removeStatefulProgrammableSwitchService(accessory)
159
- } else if (this.botDeviceType === 'garagedoor') {
160
- // Set category
161
- accessory.category = this.hap.Categories.GARAGE_DOOR_OPENER
162
- // Initialize GarageDoor Service
163
- accessory.context.GarageDoor = accessory.context.GarageDoor ?? {}
164
- this.GarageDoor = {
165
- Name: accessory.displayName,
166
- Service: accessory.getService(this.hap.Service.GarageDoorOpener) ?? accessory.addService(this.hap.Service.GarageDoorOpener) as Service,
167
- }
168
- accessory.context.GarageDoor = this.GarageDoor as object
169
- this.debugLog('Displaying as Garage Door Opener')
170
- // Initialize GarageDoor Characteristics
171
- this.GarageDoor.Service.setCharacteristic(this.hap.Characteristic.Name, this.GarageDoor.Name).setCharacteristic(this.hap.Characteristic.ObstructionDetected, false).getCharacteristic(this.hap.Characteristic.TargetDoorState).setProps({
172
- validValues: [0, 100],
173
- minValue: 0,
174
- maxValue: 100,
175
- minStep: 100,
176
- }).onSet(this.OnSet.bind(this))
177
- // Remove other services
178
- this.removeFanService(accessory)
179
- this.removeLockService(accessory)
180
- this.removeDoorService(accessory)
181
- this.removeFaucetService(accessory)
182
- this.removeOutletService(accessory)
183
- this.removeSwitchService(accessory)
184
- this.removeWindowService(accessory)
185
- this.removeWindowCoveringService(accessory)
186
- this.removeStatefulProgrammableSwitchService(accessory)
187
- } else if (this.botDeviceType === 'door') {
188
- // Set category
189
- accessory.category = this.hap.Categories.DOOR
190
- // Initialize Door Service
191
- accessory.context.Door = accessory.context.Door ?? {}
192
- this.Door = {
193
- Name: accessory.displayName,
194
- Service: accessory.getService(this.hap.Service.Door) ?? accessory.addService(this.hap.Service.Door) as Service,
195
- }
196
- accessory.context.Door = this.Door as object
197
- this.debugLog('Displaying as Door')
198
- // Initialize Door Characteristics
199
- this.Door.Service.setCharacteristic(this.hap.Characteristic.Name, this.Door.Name).setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED).getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
200
- validValues: [0, 100],
201
- minValue: 0,
202
- maxValue: 100,
203
- minStep: 100,
204
- }).onSet(this.OnSet.bind(this))
205
- // Remove other services
206
- this.removeFanService(accessory)
207
- this.removeLockService(accessory)
208
- this.removeOutletService(accessory)
209
- this.removeFaucetService(accessory)
210
- this.removeSwitchService(accessory)
211
- this.removeWindowService(accessory)
212
- this.removeGarageDoorService(accessory)
213
- this.removeWindowCoveringService(accessory)
214
- this.removeStatefulProgrammableSwitchService(accessory)
215
- } else if (this.botDeviceType === 'window') {
146
+ /**
147
+ * A mapping of device types to their corresponding HomeKit categories, services, and characteristics.
148
+ *
149
+ * Each key represents a device type and maps to an object containing:
150
+ * - `category`: The HomeKit category for the device.
151
+ * - `service`: The HomeKit service associated with the device.
152
+ * - `characteristic`: The HomeKit characteristic for the device.
153
+ */
154
+ const deviceTypeMap: { [key: string]: { category: number, service: any, characteristic: any } } = {
155
+ switch: { category: this.hap.Categories.SWITCH, service: this.hap.Service.Switch, characteristic: this.hap.Characteristic.On },
156
+ garagedoor: { category: this.hap.Categories.GARAGE_DOOR_OPENER, service: this.hap.Service.GarageDoorOpener, characteristic: this.hap.Characteristic.TargetDoorState },
157
+ door: { category: this.hap.Categories.DOOR, service: this.hap.Service.Door, characteristic: this.hap.Characteristic.TargetPosition },
158
+ window: { category: this.hap.Categories.WINDOW, service: this.hap.Service.Window, characteristic: this.hap.Characteristic.TargetPosition },
159
+ windowcovering: { category: this.hap.Categories.WINDOW_COVERING, service: this.hap.Service.WindowCovering, characteristic: this.hap.Characteristic.TargetPosition },
160
+ lock: { category: this.hap.Categories.DOOR_LOCK, service: this.hap.Service.LockMechanism, characteristic: this.hap.Characteristic.LockTargetState },
161
+ faucet: { category: this.hap.Categories.FAUCET, service: this.hap.Service.Faucet, characteristic: this.hap.Characteristic.Active },
162
+ fan: { category: this.hap.Categories.FAN, service: this.hap.Service.Fanv2, characteristic: this.hap.Characteristic.Active },
163
+ stateful: { category: this.hap.Categories.PROGRAMMABLE_SWITCH, service: this.hap.Service.StatefulProgrammableSwitch, characteristic: this.hap.Characteristic.ProgrammableSwitchOutputState },
164
+ outlet: { category: this.hap.Categories.OUTLET, service: this.hap.Service.Outlet, characteristic: this.hap.Characteristic.On },
165
+ }
166
+
167
+ /**
168
+ * The type of the device, determined by mapping the botDeviceType to a value in the deviceTypeMap.
169
+ */
170
+ const deviceType = deviceTypeMap[this.botDeviceType]
171
+
172
+ if (deviceType) {
216
173
  // Set category
217
- accessory.category = this.hap.Categories.WINDOW
218
- // Initialize Window Service
219
- accessory.context.Window = accessory.context.Window ?? {}
220
- this.Window = {
174
+ accessory.category = deviceType.category
175
+ // Initialize Service
176
+ const contextKey = this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)
177
+ accessory.context[contextKey] = accessory.context[contextKey] ?? {}
178
+ this[this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)] = {
221
179
  Name: accessory.displayName,
222
- Service: accessory.getService(this.hap.Service.Window) ?? accessory.addService(this.hap.Service.Window) as Service,
180
+ Service: accessory.getService(deviceType.service) ?? accessory.addService(deviceType.service) as Service,
223
181
  }
224
- accessory.context.Window = this.Window as object
225
- this.debugLog('Displaying as Window')
226
- // Initialize Window Characteristics
227
- this.Window.Service.setCharacteristic(this.hap.Characteristic.Name, this.Window.Name).setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED).getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
228
- validValues: [0, 100],
229
- minValue: 0,
230
- maxValue: 100,
231
- minStep: 100,
232
- }).onSet(this.OnSet.bind(this))
233
- // Remove other services
234
- this.removeFanService(accessory)
235
- this.removeLockService(accessory)
236
- this.removeDoorService(accessory)
237
- this.removeOutletService(accessory)
238
- this.removeFaucetService(accessory)
239
- this.removeSwitchService(accessory)
240
- this.removeGarageDoorService(accessory)
241
- this.removeWindowCoveringService(accessory)
242
- this.removeStatefulProgrammableSwitchService(accessory)
243
- } else if (this.botDeviceType === 'windowcovering') {
244
- // Set category
245
- accessory.category = this.hap.Categories.WINDOW_COVERING
246
- // Initialize WindowCovering Service
247
- accessory.context.WindowCovering = accessory.context.WindowCovering ?? {}
248
- this.WindowCovering = {
249
- Name: accessory.displayName,
250
- Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
251
- }
252
- accessory.context.WindowCovering = this.WindowCovering as object
253
- this.debugLog('Displaying as Window Covering')
254
- // Initialize WindowCovering Characteristics
255
- this.WindowCovering.Service.setCharacteristic(this.hap.Characteristic.Name, this.WindowCovering.Name).setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED).getCharacteristic(this.hap.Characteristic.TargetPosition).setProps({
256
- validValues: [0, 100],
257
- minValue: 0,
258
- maxValue: 100,
259
- minStep: 100,
260
- }).onSet(this.OnSet.bind(this))
261
- // Remove other services
262
- this.removeFanService(accessory)
263
- this.removeLockService(accessory)
264
- this.removeDoorService(accessory)
265
- this.removeOutletService(accessory)
266
- this.removeFaucetService(accessory)
267
- this.removeSwitchService(accessory)
268
- this.removeWindowService(accessory)
269
- this.removeGarageDoorService(accessory)
270
- this.removeStatefulProgrammableSwitchService(accessory)
271
- } else if (this.botDeviceType === 'lock') {
272
- // Set category
273
- accessory.category = this.hap.Categories.DOOR_LOCK
274
- // Initialize Lock Service
275
- accessory.context.LockMechanism = accessory.context.LockMechanism ?? {}
276
- this.LockMechanism = {
277
- Name: accessory.displayName,
278
- Service: accessory.getService(this.hap.Service.LockMechanism) ?? accessory.addService(this.hap.Service.LockMechanism) as Service,
279
- }
280
- accessory.context.LockMechanism = this.LockMechanism as object
281
- this.debugLog('Displaying as Lock')
282
- // Initialize Lock Characteristics
283
- this.LockMechanism.Service.setCharacteristic(this.hap.Characteristic.Name, this.LockMechanism.Name).setCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED).getCharacteristic(this.hap.Characteristic.LockTargetState).onSet(this.OnSet.bind(this))
284
- // Remove other services
285
- this.removeFanService(accessory)
286
- this.removeDoorService(accessory)
287
- this.removeOutletService(accessory)
288
- this.removeSwitchService(accessory)
289
- this.removeFaucetService(accessory)
290
- this.removeWindowService(accessory)
291
- this.removeGarageDoorService(accessory)
292
- this.removeWindowCoveringService(accessory)
293
- this.removeStatefulProgrammableSwitchService(accessory)
294
- } else if (this.botDeviceType === 'faucet') {
295
- // Set category
296
- accessory.category = this.hap.Categories.FAUCET
297
- // Initialize Faucet Service
298
- accessory.context.Faucet = accessory.context.Faucet ?? {}
299
- this.Faucet = {
300
- Name: accessory.displayName,
301
- Service: accessory.getService(this.hap.Service.Faucet) ?? accessory.addService(this.hap.Service.Faucet) as Service,
302
- }
303
- accessory.context.Faucet = this.Faucet as object
304
- this.debugLog('Displaying as Faucet')
305
- // Initialize Faucet Characteristics
306
- this.Faucet.Service.setCharacteristic(this.hap.Characteristic.Name, this.Faucet.Name).getCharacteristic(this.hap.Characteristic.Active).onSet(this.OnSet.bind(this))
307
- // Remove other services
308
- this.removeFanService(accessory)
309
- this.removeLockService(accessory)
310
- this.removeDoorService(accessory)
311
- this.removeOutletService(accessory)
312
- this.removeSwitchService(accessory)
313
- this.removeWindowService(accessory)
314
- this.removeGarageDoorService(accessory)
315
- this.removeWindowCoveringService(accessory)
316
- this.removeStatefulProgrammableSwitchService(accessory)
317
- } else if (this.botDeviceType === 'fan') {
318
- // Set category
319
- accessory.category = this.hap.Categories.FAN
320
- // Initialize Fan Service
321
- accessory.context.Fan = accessory.context.Fan ?? {}
322
- this.Fan = {
323
- Name: accessory.displayName,
324
- Service: accessory.getService(this.hap.Service.Fanv2) ?? accessory.addService(this.hap.Service.Fanv2) as Service,
325
- }
326
- accessory.context.Fan = this.Fan as object
327
- this.debugLog('Displaying as Fan')
328
- // Initialize Fan Characteristics
329
- this.Fan.Service.setCharacteristic(this.hap.Characteristic.Name, this.Fan.Name).getCharacteristic(this.hap.Characteristic.Active).onSet(this.OnSet.bind(this))
330
- // Remove other services
331
- this.removeLockService(accessory)
332
- this.removeDoorService(accessory)
333
- this.removeFaucetService(accessory)
334
- this.removeOutletService(accessory)
335
- this.removeSwitchService(accessory)
336
- this.removeWindowService(accessory)
337
- this.removeGarageDoorService(accessory)
338
- this.removeWindowCoveringService(accessory)
339
- this.removeStatefulProgrammableSwitchService(accessory)
340
- } else if (this.botDeviceType === 'stateful') {
341
- // Set category
342
- accessory.category = this.hap.Categories.PROGRAMMABLE_SWITCH
343
- // Initialize StatefulProgrammableSwitch Service
344
- accessory.context.StatefulProgrammableSwitch = accessory.context.StatefulProgrammableSwitch ?? {}
345
- this.StatefulProgrammableSwitch = {
346
- Name: accessory.displayName,
347
- Service: accessory.getService(this.hap.Service.StatefulProgrammableSwitch) ?? accessory.addService(this.hap.Service.StatefulProgrammableSwitch) as Service,
348
- }
349
- accessory.context.StatefulProgrammableSwitch = this.StatefulProgrammableSwitch as object
350
- this.debugLog('Displaying as Stateful Programmable Switch')
351
- // Initialize StatefulProgrammableSwitch Characteristics
352
- this.StatefulProgrammableSwitch.Service.setCharacteristic(this.hap.Characteristic.Name, this.StatefulProgrammableSwitch.Name).getCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState).onSet(this.OnSet.bind(this))
353
- // Remove other services
354
- this.removeFanService(accessory)
355
- this.removeLockService(accessory)
356
- this.removeDoorService(accessory)
357
- this.removeFaucetService(accessory)
358
- this.removeOutletService(accessory)
359
- this.removeSwitchService(accessory)
360
- this.removeWindowService(accessory)
361
- this.removeGarageDoorService(accessory)
362
- this.removeWindowCoveringService(accessory)
363
- } else if (this.botDeviceType === 'outlet') {
364
- // Set category
365
- accessory.category = this.hap.Categories.OUTLET
366
- // Initialize Switch property
367
- accessory.context.Outlet = accessory.context.Outlet ?? {}
368
- this.Outlet = {
369
- Name: accessory.displayName,
370
- Service: accessory.getService(this.hap.Service.Outlet) ?? accessory.addService(this.hap.Service.Outlet) as Service,
371
- }
372
- accessory.context.Outlet = this.Outlet as object
373
- this.debugLog('Displaying as Outlet')
374
- // Initialize Outlet Characteristics
375
- this.Outlet.Service.setCharacteristic(this.hap.Characteristic.Name, this.Outlet.Name).getCharacteristic(this.hap.Characteristic.On).onSet(this.OnSet.bind(this))
376
- // Remove other services
377
- this.removeFanService(accessory)
378
- this.removeLockService(accessory)
379
- this.removeDoorService(accessory)
380
- this.removeFaucetService(accessory)
381
- this.removeSwitchService(accessory)
382
- this.removeWindowService(accessory)
383
- this.removeGarageDoorService(accessory)
384
- this.removeWindowCoveringService(accessory)
385
- this.removeStatefulProgrammableSwitchService(accessory)
182
+ accessory.context[contextKey] = this[this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)] as object
183
+ this.debugLog(`Displaying as ${contextKey}`)
184
+ // Initialize Characteristics
185
+ this[this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)].Service.setCharacteristic(this.hap.Characteristic.Name, this[this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)].Name).getCharacteristic(deviceType.characteristic).onSet(this.OnSet.bind(this))
386
186
  } else {
387
187
  this.errorLog('Device Type not set')
388
188
  }
389
189
 
190
+ /**
191
+ * An array of service removal functions that should be executed based on the current state of the device.
192
+ * Each element in the array is a function that removes a specific service if the corresponding condition is met.
193
+ */
194
+ const servicesToRemove = [
195
+ !this.StatefulProgrammableSwitch && this.removeStatefulProgrammableSwitchService,
196
+ !this.Outlet && this.removeOutletService,
197
+ !this.Window && this.removeWindowService,
198
+ !this.GarageDoor && this.removeGarageDoorService,
199
+ this.WindowCovering && this.removeWindowCoveringService,
200
+ !this.Switch && this.removeSwitchService,
201
+ !this.Faucet && this.removeFaucetService,
202
+ !this.Door && this.removeDoorService,
203
+ !this.LockMechanism && this.removeLockService,
204
+ !this.Fan && this.removeFanService,
205
+ ].filter(Boolean)
206
+
207
+ for (const removeService of servicesToRemove) {
208
+ if (typeof removeService === 'function') {
209
+ removeService.call(this, accessory)
210
+ }
211
+ }
212
+
390
213
  // Retrieve initial values and updateHomekit
391
214
  try {
392
215
  this.debugLog('Retrieve initial values and update Homekit')
@@ -456,7 +279,7 @@ export class Bot extends deviceBase {
456
279
  // BLEmode (true if Switch Mode) | (false if Press Mode)
457
280
  this.On = this.serviceData.mode ? this.serviceData.state : false
458
281
  const mode = this.serviceData.mode ? 'Switch' : 'Press'
459
- await this.debugLog(`${mode} Mode, On: ${this.accessory.context.On}`)
282
+ await this.debugLog(`${mode} Mode, On: ${this.On}`)
460
283
  this.accessory.context.On = this.On
461
284
 
462
285
  // BatteryLevel
@@ -479,8 +302,8 @@ export class Bot extends deviceBase {
479
302
 
480
303
  // On
481
304
  this.On = this.botMode === 'press' ? false : this.deviceStatus.power === 'on'
305
+ await this.debugLog(`On: ${this.On}`)
482
306
  this.accessory.context.On = this.On
483
- await this.debugLog(`openAPI On: ${this.accessory.context.On}`)
484
307
 
485
308
  // Battery Level
486
309
  this.Battery.BatteryLevel = this.deviceStatus.battery
@@ -504,7 +327,7 @@ export class Bot extends deviceBase {
504
327
  .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
505
328
  .updateValue(deviceVersion)
506
329
  this.accessory.context.version = deviceVersion
507
- await this.debugLog(`version: ${this.accessory.context.version}`)
330
+ await this.debugLog(`version: ${deviceVersion}`)
508
331
  }
509
332
  }
510
333
 
@@ -664,7 +487,7 @@ export class Bot extends deviceBase {
664
487
 
665
488
  async BLEpushChanges(): Promise<void> {
666
489
  await this.debugLog('BLEpushChanges')
667
- if (this.On !== this.accessory.context.On || this.allowPush) {
490
+ if ((this.On !== this.accessory.context.On) || this.allowPush) {
668
491
  await this.debugLog(`BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`)
669
492
  const switchBotBLE = this.platform.switchBotBLE
670
493
  try {
@@ -742,7 +565,7 @@ export class Bot extends deviceBase {
742
565
  if (this.multiPressCount > 0) {
743
566
  await this.debugLog(`${this.multiPressCount} request(s) queued.`)
744
567
  }
745
- if (this.On !== this.accessory.context.On || this.allowPush || this.multiPressCount > 0) {
568
+ if ((this.On !== this.accessory.context.On) || this.allowPush || this.multiPressCount > 0) {
746
569
  let command = ''
747
570
  if (this.botMode === 'switch') {
748
571
  command = this.On ? 'turnOn' : 'turnOff'
@@ -762,7 +585,7 @@ export class Bot extends deviceBase {
762
585
  this.debugLog(`Sending request to SwitchBot API, body: ${JSON.stringify(bodyChange)},`)
763
586
  try {
764
587
  const { body } = await this.pushChangeRequest(bodyChange)
765
- const deviceStatus: any = await body
588
+ const deviceStatus: any = body
766
589
  await this.debugLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
767
590
  if (await this.successfulStatusCodes(deviceStatus)) {
768
591
  await this.debugSuccessLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
@@ -791,71 +614,27 @@ export class Bot extends deviceBase {
791
614
  * Handle requests to set the "On" characteristic
792
615
  */
793
616
  async OnSet(value: CharacteristicValue): Promise<void> {
794
- this.On = this.accessory.context.On ?? false
795
- this.accessory.context.On = this.On
796
- const deviceTypeActions: { [key: string]: () => Promise<void> } = {
797
- switch: async () => {
798
- if (this.Switch) {
799
- await this.debugLog(`Set On: ${value}`)
800
- this.On = value !== false
801
- }
802
- },
803
- garagedoor: async () => {
804
- if (this.GarageDoor) {
805
- await this.debugLog(`Set TargetDoorState: ${value}`)
806
- this.On = value !== this.hap.Characteristic.TargetDoorState.CLOSED
807
- }
808
- },
809
- door: async () => {
810
- if (this.Door) {
811
- await this.debugLog(`Set TargetPosition: ${value}`)
812
- this.On = value !== 0
813
- }
814
- },
815
- window: async () => {
816
- if (this.Window) {
817
- await this.debugLog(`Set TargetPosition: ${value}`)
818
- this.On = value !== 0
819
- }
820
- },
821
- windowcovering: async () => {
822
- if (this.WindowCovering) {
823
- await this.debugLog(`Set TargetPosition: ${value}`)
824
- this.On = value !== 0
825
- }
826
- },
827
- lock: async () => {
828
- if (this.LockMechanism) {
829
- await this.debugLog(`Set LockTargetState: ${value}`)
830
- this.On = value !== this.hap.Characteristic.LockTargetState.SECURED
831
- }
832
- },
833
- faucet: async () => {
834
- if (this.Faucet) {
835
- await this.debugLog(`Set Active: ${value}`)
836
- this.On = value !== this.hap.Characteristic.Active.INACTIVE
837
- }
838
- },
839
- stateful: async () => {
840
- if (this.StatefulProgrammableSwitch) {
841
- await this.debugLog(`Set ProgrammableSwitchOutputState: ${value}`)
842
- this.On = value !== 0
843
- }
844
- },
845
- default: async () => {
846
- if (this.Outlet) {
847
- await this.debugLog(`Set On: ${value}`)
848
- this.On = value !== false
849
- }
617
+ this.debugLog(`value: ${value}`)
618
+ const deviceTypeActions: { [key: string]: () => void } = {
619
+ switch: () => this.On = value !== false,
620
+ garagedoor: () => this.On = value !== this.hap.Characteristic.TargetDoorState.CLOSED,
621
+ door: () => this.On = value !== 0,
622
+ window: () => this.On = value !== 0,
623
+ windowcovering: () => this.On = value !== 0,
624
+ lock: () => this.On = value !== this.hap.Characteristic.LockTargetState.SECURED,
625
+ faucet: () => this.On = value !== this.hap.Characteristic.Active.INACTIVE,
626
+ fan: () => this.On = value !== 0,
627
+ stateful: () => this.On = value !== 0,
628
+ default: () => {
629
+ this.On = value !== false
850
630
  if ((this.device as botConfig).mode === 'multipress' && this.On) {
851
631
  this.multiPressCount++
852
- await this.debugLog(`multiPressCount: ${this.multiPressCount}`)
632
+ this.debugLog(`multiPressCount: ${this.multiPressCount}`)
853
633
  }
854
634
  },
855
635
  }
856
636
  const action = deviceTypeActions[this.botDeviceType] || deviceTypeActions.default
857
- await action()
858
- this.accessory.context.On = this.On
637
+ action()
859
638
  this.doBotUpdate.next()
860
639
  }
861
640
 
@@ -881,265 +660,119 @@ export class Bot extends deviceBase {
881
660
  await this.debugLog(`updateCharacteristic StatusLowBattery: ${this.Battery.StatusLowBattery}`)
882
661
  }
883
662
  // State
884
- if (this.botDeviceType === 'switch' && this.Switch) {
885
- if (this.On === undefined) {
886
- await this.debugLog(`On: ${this.On}`)
887
- } else {
888
- this.Switch.Service.updateCharacteristic(this.hap.Characteristic.On, this.On)
889
- await this.debugLog(`updateCharacteristic On: ${this.On}`)
890
- }
891
- } else if (this.botDeviceType === 'garagedoor' && this.GarageDoor) {
892
- if (this.On === undefined) {
893
- await this.debugLog(`On: ${this.On}`)
894
- } else {
895
- if (this.On) {
896
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.hap.Characteristic.TargetDoorState.OPEN)
897
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.hap.Characteristic.CurrentDoorState.OPEN)
898
- await this.debugLog(`updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open (${this.On})`)
899
- } else {
900
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.hap.Characteristic.TargetDoorState.CLOSED)
901
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.hap.Characteristic.CurrentDoorState.CLOSED)
902
- await this.debugLog(`updateCharacteristicc TargetDoorState: Closed, CurrentDoorState: Closed (${this.On})`)
903
- }
904
- }
905
- await this.debugLog(`Garage Door On: ${this.On}`)
906
- } else if (this.botDeviceType === 'door' && this.Door) {
907
- if (this.On === undefined) {
908
- await this.debugLog(`On: ${this.On}`)
909
- } else {
910
- if (this.On) {
911
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100)
912
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100)
913
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
914
- await this.debugLog(`updateCharacteristicc TargetPosition: 100, CurrentPosition: 100 (${this.On})`)
915
- } else {
916
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0)
917
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0)
918
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
919
- await this.debugLog(`updateCharacteristicc TargetPosition: 0, CurrentPosition: 0 (${this.On})`)
920
- }
921
- }
922
- await this.debugLog(`Door On: ${this.On}`)
923
- } else if (this.botDeviceType === 'window' && this.Window) {
924
- if (this.On === undefined) {
925
- await this.debugLog(`On: ${this.On}`)
926
- } else {
927
- if (this.On) {
928
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100)
929
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100)
930
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
931
- await this.debugLog(`updateCharacteristicc TargetPosition: 100, CurrentPosition: 100 (${this.On})`)
932
- } else {
933
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0)
934
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0)
935
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
936
- await this.debugLog(`updateCharacteristicc TargetPosition: 0, CurrentPosition: 0 (${this.On})`)
663
+ const updateCharacteristic = async (service: Service, characteristic: any, value: any, logMessage: string) => {
664
+ service.updateCharacteristic(characteristic, value)
665
+ await this.debugLog(logMessage)
666
+ }
667
+
668
+ const stateActions: { [key: string]: () => Promise<void> } = {
669
+ switch: async () => this.Switch && await updateCharacteristic(this.Switch.Service, this.hap.Characteristic.On, this.On, `updateCharacteristic On: ${this.On}`),
670
+ garagedoor: async () => {
671
+ if (this.GarageDoor) {
672
+ const targetState = this.On ? this.hap.Characteristic.TargetDoorState.OPEN : this.hap.Characteristic.TargetDoorState.CLOSED
673
+ const currentState = this.On ? this.hap.Characteristic.CurrentDoorState.OPEN : this.hap.Characteristic.CurrentDoorState.CLOSED
674
+ await updateCharacteristic(this.GarageDoor.Service, this.hap.Characteristic.TargetDoorState, targetState, `updateCharacteristic TargetDoorState: ${targetState}, CurrentDoorState: ${currentState} (${this.On})`)
675
+ await updateCharacteristic(this.GarageDoor.Service, this.hap.Characteristic.CurrentDoorState, currentState, '')
937
676
  }
938
- }
939
- await this.debugLog(`Window On: ${this.On}`)
940
- } else if (this.botDeviceType === 'windowcovering' && this.WindowCovering) {
941
- if (this.On === undefined) {
942
- await this.debugLog(`On: ${this.On}`)
943
- } else {
944
- if (this.On) {
945
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 100)
946
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 100)
947
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
948
- await this.debugLog(`updateCharacteristicc TargetPosition: 100, CurrentPosition: 100 (${this.On})`)
949
- } else {
950
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0)
951
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0)
952
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
953
- await this.debugLog(`updateCharacteristicc TargetPosition: 0, CurrentPosition: 0 (${this.On})`)
677
+ },
678
+ door: async () => {
679
+ if (this.Door) {
680
+ const position = this.On ? 100 : 0
681
+ await updateCharacteristic(this.Door.Service, this.hap.Characteristic.TargetPosition, position, `updateCharacteristic TargetPosition: ${position}, CurrentPosition: ${position} (${this.On})`)
682
+ await updateCharacteristic(this.Door.Service, this.hap.Characteristic.CurrentPosition, position, '')
683
+ await updateCharacteristic(this.Door.Service, this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED, '')
954
684
  }
955
- }
956
- await this.debugLog(`Window Covering On: ${this.On}`)
957
- } else if (this.botDeviceType === 'lock' && this.LockMechanism) {
958
- if (this.On === undefined) {
959
- await this.debugLog(`On: ${this.On}`)
960
- } else {
961
- if (this.On) {
962
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState, this.hap.Characteristic.LockTargetState.UNSECURED)
963
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.hap.Characteristic.LockCurrentState.UNSECURED)
964
- await this.debugLog(`updateCharacteristicc LockTargetState: UNSECURED, LockCurrentState: UNSECURED (${this.On})`)
965
- } else {
966
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState, this.hap.Characteristic.LockTargetState.SECURED)
967
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.hap.Characteristic.LockCurrentState.SECURED)
968
- await this.debugLog(`updateCharacteristic LockTargetState: SECURED, LockCurrentState: SECURED (${this.On})`)
685
+ },
686
+ window: async () => {
687
+ if (this.Window) {
688
+ const position = this.On ? 100 : 0
689
+ await updateCharacteristic(this.Window.Service, this.hap.Characteristic.TargetPosition, position, `updateCharacteristic TargetPosition: ${position}, CurrentPosition: ${position} (${this.On})`)
690
+ await updateCharacteristic(this.Window.Service, this.hap.Characteristic.CurrentPosition, position, '')
691
+ await updateCharacteristic(this.Window.Service, this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED, '')
969
692
  }
970
- }
971
- await this.debugLog(`Lock On: ${this.On}`)
972
- } else if (this.botDeviceType === 'faucet' && this.Faucet) {
973
- if (this.On === undefined) {
974
- await this.debugLog(`On: ${this.On}`)
975
- } else {
976
- if (this.On) {
977
- this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.ACTIVE)
978
- await this.debugLog(`updateCharacteristic Active: ${this.On}`)
979
- } else {
980
- this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.INACTIVE)
981
- await this.debugLog(`updateCharacteristic Active: ${this.On}`)
693
+ },
694
+ windowcovering: async () => {
695
+ if (this.WindowCovering) {
696
+ const position = this.On ? 100 : 0
697
+ await updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.TargetPosition, position, `updateCharacteristic TargetPosition: ${position}, CurrentPosition: ${position} (${this.On})`)
698
+ await updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.CurrentPosition, position, '')
699
+ await updateCharacteristic(this.WindowCovering.Service, this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED, '')
982
700
  }
983
- }
984
- await this.debugLog(`Faucet On: ${this.On}`)
985
- } else if (this.botDeviceType === 'fan' && this.Fan) {
986
- if (this.On === undefined) {
987
- await this.debugLog(`On: ${this.On}`)
988
- } else {
989
- if (this.On) {
990
- this.Fan.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.ACTIVE)
991
- await this.debugLog(`updateCharacteristic Active: ${this.On}`)
992
- } else {
993
- this.Fan.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.INACTIVE)
994
- await this.debugLog(`updateCharacteristic Active: ${this.On}`)
701
+ },
702
+ lock: async () => {
703
+ if (this.LockMechanism) {
704
+ const targetState = this.On ? this.hap.Characteristic.LockTargetState.UNSECURED : this.hap.Characteristic.LockTargetState.SECURED
705
+ const currentState = this.On ? this.hap.Characteristic.LockCurrentState.UNSECURED : this.hap.Characteristic.LockCurrentState.SECURED
706
+ await updateCharacteristic(this.LockMechanism.Service, this.hap.Characteristic.LockTargetState, targetState, `updateCharacteristic LockTargetState: ${targetState}, LockCurrentState: ${currentState} (${this.On})`)
707
+ await updateCharacteristic(this.LockMechanism.Service, this.hap.Characteristic.LockCurrentState, currentState, '')
995
708
  }
996
- }
997
- await this.debugLog(`Fan On: ${this.On}`)
998
- } else if (this.botDeviceType === 'stateful' && this.StatefulProgrammableSwitch) {
999
- if (this.On === undefined) {
1000
- await this.debugLog(`On: ${this.On}`)
1001
- } else {
1002
- if (this.On) {
1003
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent, this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS)
1004
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 1)
1005
- await this.debugLog(`updateCharacteristic ProgrammableSwitchEvent: ProgrammableSwitchOutputState: (${this.On})`)
1006
- } else {
1007
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent, this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS)
1008
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 0)
1009
- await this.debugLog(`updateCharacteristic ProgrammableSwitchEvent: ProgrammableSwitchOutputState: (${this.On})`)
709
+ },
710
+ faucet: async () => this.Faucet && await updateCharacteristic(this.Faucet.Service, this.hap.Characteristic.Active, this.On ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE, `updateCharacteristic Active: ${this.On}`),
711
+ fan: async () => this.Fan && await updateCharacteristic(this.Fan.Service, this.hap.Characteristic.Active, this.On ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE, `updateCharacteristic Active: ${this.On}`),
712
+ stateful: async () => {
713
+ if (this.StatefulProgrammableSwitch) {
714
+ await updateCharacteristic(this.StatefulProgrammableSwitch.Service, this.hap.Characteristic.ProgrammableSwitchEvent, this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS, `updateCharacteristic ProgrammableSwitchEvent: SINGLE_PRESS (${this.On})`)
715
+ await updateCharacteristic(this.StatefulProgrammableSwitch.Service, this.hap.Characteristic.ProgrammableSwitchOutputState, this.On ? 1 : 0, `updateCharacteristic ProgrammableSwitchOutputState: ${this.On ? 1 : 0}`)
1010
716
  }
1011
- }
1012
- await this.debugLog(`StatefulProgrammableSwitch On: ${this.On}`)
1013
- } else if (this.botDeviceType === 'outlet' && this.Outlet) {
1014
- if (this.On === undefined) {
1015
- await this.debugLog(`On: ${this.On}`)
1016
- } else {
1017
- this.Outlet.Service.updateCharacteristic(this.hap.Characteristic.On, this.On)
1018
- await this.debugLog(`updateCharacteristic On: ${this.On}`)
1019
- }
1020
- } else {
1021
- await this.errorLog(`botDeviceType: ${this.botDeviceType}, On: ${this.On}`)
717
+ },
718
+ outlet: async () => this.Outlet && await updateCharacteristic(this.Outlet.Service, this.hap.Characteristic.On, this.On, `updateCharacteristic On: ${this.On}`),
719
+ default: async () => await this.errorLog(`botDeviceType: ${this.botDeviceType}, On: ${this.On}`),
1022
720
  }
721
+
722
+ const action = stateActions[this.botDeviceType] || stateActions.default
723
+ await action()
1023
724
  }
1024
725
 
1025
- async removeOutletService(accessory: PlatformAccessory): Promise<void> {
1026
- // If outletService still present, then remove first
1027
- accessory.context.Outlet = accessory.context.Outlet ?? {}
1028
- this.Outlet = {
1029
- Name: accessory.context.Outlet.Name ?? accessory.displayName,
1030
- Service: accessory.getService(this.hap.Service.Outlet) as Service,
726
+ async removeService(accessory: PlatformAccessory, serviceType: string, serviceName: string): Promise<void> {
727
+ const contextKey = serviceName.charAt(0).toUpperCase() + serviceName.slice(1)
728
+ accessory.context[contextKey] = accessory.context[contextKey] ?? {}
729
+ this[contextKey] = {
730
+ Name: accessory.context[contextKey].Name ?? accessory.displayName,
731
+ Service: accessory.getService(this.hap.Service[serviceType]) as Service,
1031
732
  }
1032
- accessory.context.Outlet = this.Outlet as object
1033
- await this.debugWarnLog('Removing any leftover Outlet Service')
1034
- accessory.removeService(this.Outlet.Service)
733
+ accessory.context[contextKey] = this[contextKey] as object
734
+ await this.debugWarnLog(`Removing any leftover ${contextKey} Service`)
735
+ accessory.removeService(this[contextKey].Service)
736
+ }
737
+
738
+ async removeOutletService(accessory: PlatformAccessory): Promise<void> {
739
+ await this.removeService(accessory, 'Outlet', 'outlet')
1035
740
  }
1036
741
 
1037
742
  async removeGarageDoorService(accessory: PlatformAccessory): Promise<void> {
1038
- // If garageDoorService still present, then remove first
1039
- accessory.context.GarageDoor = accessory.context.GarageDoor ?? {}
1040
- this.GarageDoor = {
1041
- Name: accessory.context.GarageDoor.Name ?? accessory.displayName,
1042
- Service: accessory.getService(this.hap.Service.GarageDoorOpener) as Service,
1043
- }
1044
- accessory.context.GarageDoor = this.GarageDoor as object
1045
- await this.debugWarnLog('Removing any leftover Garage Door Service')
1046
- accessory.removeService(this.GarageDoor.Service)
743
+ await this.removeService(accessory, 'GarageDoorOpener', 'garageDoor')
1047
744
  }
1048
745
 
1049
746
  async removeDoorService(accessory: PlatformAccessory): Promise<void> {
1050
- // If doorService still present, then remove first
1051
- accessory.context.Door = accessory.context.Door ?? {}
1052
- this.Door = {
1053
- Name: accessory.context.Door.Name ?? accessory.displayName,
1054
- Service: accessory.getService(this.hap.Service.Door) as Service,
1055
- }
1056
- accessory.context.Door = this.Door as object
1057
- await this.debugWarnLog('Removing any leftover Door Service')
1058
- accessory.removeService(this.Door.Service)
747
+ await this.removeService(accessory, 'Door', 'door')
1059
748
  }
1060
749
 
1061
750
  async removeLockService(accessory: PlatformAccessory): Promise<void> {
1062
- // If lockService still present, then remove first
1063
- accessory.context.LockMechanism = accessory.context.LockMechanism ?? {}
1064
- this.LockMechanism = {
1065
- Name: accessory.context.LockMechanism.Name ?? accessory.displayName,
1066
- Service: accessory.getService(this.hap.Service.LockMechanism) as Service,
1067
- }
1068
- accessory.context.LockMechanism = this.LockMechanism as object
1069
- await this.debugWarnLog('Removing any leftover Lock Service')
1070
- accessory.removeService(this.LockMechanism.Service)
751
+ await this.removeService(accessory, 'LockMechanism', 'lockMechanism')
1071
752
  }
1072
753
 
1073
754
  async removeFaucetService(accessory: PlatformAccessory): Promise<void> {
1074
- // If faucetService still present, then remove first
1075
- accessory.context.Faucet = accessory.context.Faucet ?? {}
1076
- this.Faucet = {
1077
- Name: accessory.context.Faucet.Name ?? accessory.displayName,
1078
- Service: accessory.getService(this.hap.Service.Valve) as Service,
1079
- }
1080
- accessory.context.Faucet = this.Faucet as object
1081
- await this.debugWarnLog('Removing any leftover Faucet Service')
1082
- accessory.removeService(this.Faucet.Service)
755
+ await this.removeService(accessory, 'Valve', 'faucet')
1083
756
  }
1084
757
 
1085
758
  async removeFanService(accessory: PlatformAccessory): Promise<void> {
1086
- // If fanService still present, then remove first
1087
- accessory.context.Fan = accessory.context.Fan ?? {}
1088
- this.Fan = {
1089
- Name: accessory.context.Fan.Name ?? accessory.displayName,
1090
- Service: accessory.getService(this.hap.Service.Fan) as Service,
1091
- }
1092
- accessory.context.Fan = this.Fan as object
1093
- await this.debugWarnLog('Removing any leftover Fan Service')
1094
- accessory.removeService(this.Fan.Service)
759
+ await this.removeService(accessory, 'Fan', 'fan')
1095
760
  }
1096
761
 
1097
762
  async removeWindowService(accessory: PlatformAccessory): Promise<void> {
1098
- // If windowService still present, then remove first
1099
- accessory.context.Window = accessory.context.Window ?? {}
1100
- this.Window = {
1101
- Name: accessory.context.Window.Name ?? accessory.displayName,
1102
- Service: accessory.getService(this.hap.Service.Window) as Service,
1103
- }
1104
- accessory.context.Window = this.Window as object
1105
- await this.debugWarnLog('Removing any leftover Window Service')
1106
- accessory.removeService(this.Window.Service)
763
+ await this.removeService(accessory, 'Window', 'window')
1107
764
  }
1108
765
 
1109
766
  async removeWindowCoveringService(accessory: PlatformAccessory): Promise<void> {
1110
- // If windowCoveringService still present, then remove first
1111
- accessory.context.WindowCovering = accessory.context.WindowCovering ?? {}
1112
- this.WindowCovering = {
1113
- Name: accessory.context.WindowCovering.Name ?? accessory.displayName,
1114
- Service: accessory.getService(this.hap.Service.WindowCovering) as Service,
1115
- }
1116
- accessory.context.WindowCovering = this.WindowCovering as object
1117
- await this.debugWarnLog('Removing any leftover Window Covering Service')
1118
- accessory.removeService(this.WindowCovering.Service)
767
+ await this.removeService(accessory, 'WindowCovering', 'windowCovering')
1119
768
  }
1120
769
 
1121
770
  async removeStatefulProgrammableSwitchService(accessory: PlatformAccessory): Promise<void> {
1122
- // If statefulProgrammableSwitchService still present, then remove first
1123
- accessory.context.StatefulProgrammableSwitch = accessory.context.StatefulProgrammableSwitch ?? {}
1124
- this.StatefulProgrammableSwitch = {
1125
- Name: accessory.context.StatefulProgrammableSwitch.Name ?? accessory.displayName,
1126
- Service: accessory.getService(this.hap.Service.StatefulProgrammableSwitch) as Service,
1127
- }
1128
- accessory.context.StatefulProgrammableSwitch = this.StatefulProgrammableSwitch as object
1129
- await this.debugWarnLog('Removing any leftover Stateful Programmable Switch Service')
1130
- accessory.removeService(this.StatefulProgrammableSwitch.Service)
771
+ await this.removeService(accessory, 'StatefulProgrammableSwitch', 'statefulProgrammableSwitch')
1131
772
  }
1132
773
 
1133
774
  async removeSwitchService(accessory: PlatformAccessory): Promise<void> {
1134
- // If switchService still present, then remove first
1135
- accessory.context.Switch = accessory.context.Switch ?? {}
1136
- this.Switch = {
1137
- Name: accessory.context.Switch.Name ?? accessory.displayName,
1138
- Service: accessory.getService(this.hap.Service.Switch) as Service,
1139
- }
1140
- accessory.context.Switch = this.Switch as object
1141
- await this.debugWarnLog('Removing any leftover Switch Service')
1142
- accessory.removeService(this.Switch.Service)
775
+ await this.removeService(accessory, 'Switch', 'switch')
1143
776
  }
1144
777
 
1145
778
  async getBotConfigSettings(device: device & devicesConfig) {
@@ -1169,21 +802,18 @@ export class Bot extends deviceBase {
1169
802
  ? `Using Double Press: ${this.doublePress}`
1170
803
  : `No Double Press Set, Using default Double Press: ${this.doublePress}`
1171
804
  await this.debugWarnLog(doublePress)
1172
- this.accessory.context.doublePress = this.doublePress
1173
805
  // Bot Press PushRate
1174
806
  this.pushRatePress = (device as botConfig).pushRatePress ?? 15
1175
807
  const pushRatePress = (device as botConfig).pushRatePress
1176
808
  ? `Using Bot Push Rate Press: ${this.pushRatePress}`
1177
809
  : `No Push Rate Press Set, Using default Push Rate Press: ${this.pushRatePress}`
1178
810
  await this.debugWarnLog(pushRatePress)
1179
- this.accessory.context.pushRatePress = this.pushRatePress
1180
811
  // Bot Allow Push
1181
812
  this.allowPush = (device as botConfig).allowPush ?? false
1182
813
  const allowPush = (device as botConfig).allowPush
1183
814
  ? `Using Allow Push: ${this.allowPush}`
1184
815
  : `No Allow Push Set, Using default Allow Push: ${this.allowPush}`
1185
816
  await this.debugWarnLog(allowPush)
1186
- this.accessory.context.allowPush = this.allowPush
1187
817
  // Bot Multi Press Count
1188
818
  this.multiPressCount = 0
1189
819
  await this.debugWarnLog(`Multi Press Count: ${this.multiPressCount}`)
@@ -1206,113 +836,58 @@ export class Bot extends deviceBase {
1206
836
 
1207
837
  async offlineOff(): Promise<void> {
1208
838
  if (this.device.offline) {
1209
- if (this.botDeviceType === 'garagedoor') {
1210
- if (this.GarageDoor) {
1211
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.hap.Characteristic.TargetDoorState.CLOSED)
1212
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.hap.Characteristic.CurrentDoorState.CLOSED)
1213
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, false)
1214
- }
1215
- } else if (this.botDeviceType === 'door') {
1216
- if (this.Door) {
1217
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0)
1218
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0)
1219
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
1220
- }
1221
- } else if (this.botDeviceType === 'window') {
1222
- if (this.Window) {
1223
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0)
1224
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0)
1225
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
1226
- }
1227
- } else if (this.botDeviceType === 'windowcovering') {
1228
- if (this.WindowCovering) {
1229
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, 0)
1230
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, 0)
1231
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, this.hap.Characteristic.PositionState.STOPPED)
1232
- }
1233
- } else if (this.botDeviceType === 'lock') {
1234
- if (this.LockMechanism) {
1235
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState, this.hap.Characteristic.LockTargetState.SECURED)
1236
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.hap.Characteristic.LockCurrentState.SECURED)
1237
- }
1238
- } else if (this.botDeviceType === 'faucet') {
1239
- if (this.Faucet) {
1240
- this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, this.hap.Characteristic.Active.INACTIVE)
1241
- }
1242
- } else if (this.botDeviceType === 'fan') {
1243
- if (this.Fan) {
1244
- this.Fan.Service.updateCharacteristic(this.hap.Characteristic.On, false)
1245
- }
1246
- } else if (this.botDeviceType === 'stateful') {
1247
- if (this.StatefulProgrammableSwitch) {
1248
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent, this.hap.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS)
1249
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, 0)
1250
- }
1251
- } else if (this.botDeviceType === 'switch') {
1252
- if (this.Switch) {
1253
- this.Switch.Service.updateCharacteristic(this.hap.Characteristic.On, false)
1254
- }
1255
- } else {
1256
- if (this.Outlet) {
1257
- this.Outlet.Service.updateCharacteristic(this.hap.Characteristic.On, false)
839
+ const updateCharacteristics = (service: Service, characteristics: { [key: string]: any }) => {
840
+ for (const [characteristic, value] of Object.entries(characteristics)) {
841
+ service.updateCharacteristic(this.hap.Characteristic[characteristic], value)
1258
842
  }
1259
843
  }
844
+
845
+ const characteristicsMap: { [key: string]: { [key: string]: any } } = {
846
+ garagedoor: { TargetDoorState: 'CLOSED', CurrentDoorState: 'CLOSED', ObstructionDetected: false },
847
+ door: { TargetPosition: 0, CurrentPosition: 0, PositionState: 'STOPPED' },
848
+ window: { TargetPosition: 0, CurrentPosition: 0, PositionState: 'STOPPED' },
849
+ windowcovering: { TargetPosition: 0, CurrentPosition: 0, PositionState: 'STOPPED' },
850
+ lock: { LockTargetState: 'SECURED', LockCurrentState: 'SECURED' },
851
+ faucet: { Active: 'INACTIVE' },
852
+ fan: { On: false },
853
+ stateful: { ProgrammableSwitchEvent: 'SINGLE_PRESS', ProgrammableSwitchOutputState: 0 },
854
+ switch: { On: false },
855
+ outlet: { On: false },
856
+ }
857
+
858
+ const service = this[this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)]?.Service
859
+ if (service) {
860
+ updateCharacteristics(service, characteristicsMap[this.botDeviceType])
861
+ }
1260
862
  }
1261
863
  }
1262
864
 
1263
865
  async apiError(e: any): Promise<void> {
866
+ const updateCharacteristics = (service: Service, characteristics: { [key: string]: any }) => {
867
+ for (const [characteristic] of Object.entries(characteristics)) {
868
+ service.updateCharacteristic(this.hap.Characteristic[characteristic], e)
869
+ }
870
+ }
871
+
872
+ const characteristicsMap: { [key: string]: { [key: string]: any } } = {
873
+ garagedoor: { TargetDoorState: e, CurrentDoorState: e, ObstructionDetected: e },
874
+ door: { TargetPosition: e, CurrentPosition: e, PositionState: e },
875
+ window: { TargetPosition: e, CurrentPosition: e, PositionState: e },
876
+ windowcovering: { TargetPosition: e, CurrentPosition: e, PositionState: e },
877
+ lock: { LockTargetState: e, LockCurrentState: e },
878
+ faucet: { Active: e },
879
+ fan: { On: e },
880
+ stateful: { ProgrammableSwitchEvent: e, ProgrammableSwitchOutputState: e },
881
+ switch: { On: e },
882
+ outlet: { On: e },
883
+ }
884
+
1264
885
  this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e)
1265
886
  this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e)
1266
- if (this.botDeviceType === 'garagedoor') {
1267
- if (this.GarageDoor) {
1268
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.TargetDoorState, e)
1269
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, e)
1270
- this.GarageDoor.Service.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, e)
1271
- }
1272
- } else if (this.botDeviceType === 'door') {
1273
- if (this.Door) {
1274
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e)
1275
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e)
1276
- this.Door.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e)
1277
- }
1278
- } else if (this.botDeviceType === 'window') {
1279
- if (this.Window) {
1280
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e)
1281
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e)
1282
- this.Window.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e)
1283
- }
1284
- } else if (this.botDeviceType === 'windowcovering') {
1285
- if (this.WindowCovering) {
1286
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.TargetPosition, e)
1287
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, e)
1288
- this.WindowCovering.Service.updateCharacteristic(this.hap.Characteristic.PositionState, e)
1289
- }
1290
- } else if (this.botDeviceType === 'lock') {
1291
- if (this.LockMechanism) {
1292
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockTargetState, e)
1293
- this.LockMechanism.Service.updateCharacteristic(this.hap.Characteristic.LockCurrentState, e)
1294
- }
1295
- } else if (this.botDeviceType === 'faucet') {
1296
- if (this.Faucet) {
1297
- this.Faucet.Service.updateCharacteristic(this.hap.Characteristic.Active, e)
1298
- }
1299
- } else if (this.botDeviceType === 'fan') {
1300
- if (this.Fan) {
1301
- this.Fan.Service.updateCharacteristic(this.hap.Characteristic.On, e)
1302
- }
1303
- } else if (this.botDeviceType === 'stateful') {
1304
- if (this.StatefulProgrammableSwitch) {
1305
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchEvent, e)
1306
- this.StatefulProgrammableSwitch.Service.updateCharacteristic(this.hap.Characteristic.ProgrammableSwitchOutputState, e)
1307
- }
1308
- } else if (this.botDeviceType === 'switch') {
1309
- if (this.Switch) {
1310
- this.Switch.Service.updateCharacteristic(this.hap.Characteristic.On, e)
1311
- }
1312
- } else {
1313
- if (this.Outlet) {
1314
- this.Outlet.Service.updateCharacteristic(this.hap.Characteristic.On, e)
1315
- }
887
+
888
+ const service = this[this.botDeviceType.charAt(0).toUpperCase() + this.botDeviceType.slice(1)]?.Service
889
+ if (service) {
890
+ updateCharacteristics(service, characteristicsMap[this.botDeviceType])
1316
891
  }
1317
892
  }
1318
893
  }