homebridge-ratgdo 0.2.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,22 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ratgdoAccessory = void 0;
7
- const settings_js_1 = require("./settings.js");
8
- const ratgdo_options_js_1 = require("./ratgdo-options.js");
9
- const node_util_1 = __importDefault(require("node:util"));
10
- class ratgdoAccessory {
1
+ import { RATGDO_MOTION_DURATION, RATGDO_OCCUPANCY_DURATION, RATGDO_TRANSITION_DURATION } from "./settings.js";
2
+ import { RatgdoReservedNames } from "./ratgdo-types.js";
3
+ import { getOptionFloat, getOptionNumber, getOptionValue, isOptionEnabled } from "./ratgdo-options.js";
4
+ import util from "node:util";
5
+ export class RatgdoAccessory {
6
+ accessory;
7
+ api;
8
+ config;
9
+ device;
10
+ doorOccupancyTimer;
11
+ doorTimer;
12
+ hap;
13
+ hints;
14
+ log;
15
+ motionOccupancyTimer;
16
+ motionTimer;
17
+ obstructionTimer;
18
+ platform;
19
+ status;
11
20
  // The constructor initializes key variables and calls configureDevice().
12
21
  constructor(platform, accessory, device) {
13
22
  this.accessory = accessory;
@@ -20,10 +29,10 @@ class ratgdoAccessory {
20
29
  this.device = device;
21
30
  this.platform = platform;
22
31
  this.log = {
23
- debug: (message, ...parameters) => platform.debug(node_util_1.default.format(this.name + ": " + message, ...parameters)),
24
- error: (message, ...parameters) => platform.log.error(node_util_1.default.format(this.name + ": " + message, ...parameters)),
25
- info: (message, ...parameters) => platform.log.info(node_util_1.default.format(this.name + ": " + message, ...parameters)),
26
- warn: (message, ...parameters) => platform.log.warn(node_util_1.default.format(this.name + ": " + message, ...parameters))
32
+ debug: (message, ...parameters) => platform.debug(util.format(this.name + ": " + message, ...parameters)),
33
+ error: (message, ...parameters) => platform.log.error(util.format(this.name + ": " + message, ...parameters)),
34
+ info: (message, ...parameters) => platform.log.info(util.format(this.name + ": " + message, ...parameters)),
35
+ warn: (message, ...parameters) => platform.log.warn(util.format(this.name + ": " + message, ...parameters))
27
36
  };
28
37
  // Initialize our internal state.
29
38
  this.status.availability = false;
@@ -32,9 +41,10 @@ class ratgdoAccessory {
32
41
  this.status.lock = this.hap.Characteristic.LockCurrentState.UNSECURED;
33
42
  this.status.motion = false;
34
43
  this.status.obstruction = false;
44
+ this.doorOccupancyTimer = null;
45
+ this.motionOccupancyTimer = null;
35
46
  this.motionTimer = null;
36
47
  this.obstructionTimer = null;
37
- this.occupancyTimer = null;
38
48
  this.configureDevice();
39
49
  }
40
50
  // Configure a garage door accessory for HomeKit.
@@ -45,40 +55,108 @@ class ratgdoAccessory {
45
55
  this.configureHints();
46
56
  this.configureInfo();
47
57
  this.configureGarageDoor();
58
+ this.configureMqtt();
59
+ this.configureAutomationSwitch();
60
+ this.configureDoorOpenOccupancySensor();
48
61
  this.configureLight();
49
62
  this.configureMotionSensor();
50
- // this.configureSwitch();
51
- // this.configureOccupancySensor();
63
+ this.configureMotionOccupancySensor();
52
64
  }
53
65
  // Configure device-specific settings.
54
66
  configureHints() {
55
67
  this.hints.automationSwitch = this.hasFeature("Opener.Switch");
56
- this.hints.occupancySensor = this.hasFeature("Opener.OccupancySensor");
57
- // this.hints.occupancyDuration = this.getFeatureNumber("Opener.OccupancySensor.Duration") ?? RATGDO_OCCUPANCY_DURATION;
68
+ this.hints.doorOpenOccupancySensor = this.hasFeature("Opener.OccupancySensor");
69
+ this.hints.doorOpenOccupancyDuration = this.getFeatureNumber("Opener.OccupancySensor.Duration") ?? RATGDO_OCCUPANCY_DURATION;
70
+ this.hints.light = this.hasFeature("Light");
71
+ this.hints.motionOccupancySensor = this.hasFeature("Motion.OccupancySensor");
72
+ this.hints.motionOccupancyDuration = this.getFeatureNumber("Motion.OccupancySensor.Duration") ?? RATGDO_OCCUPANCY_DURATION;
73
+ this.hints.motionSensor = this.hasFeature("Motion");
58
74
  this.hints.readOnly = this.hasFeature("Opener.ReadOnly");
59
- this.hints.syncNames = this.hasFeature("Device.SyncNames");
75
+ this.hints.syncName = this.hasFeature("Device.SyncName");
76
+ if (this.hints.readOnly) {
77
+ this.log.info("Garage door opener is read-only. The opener will not respond to open and close requests from HomeKit.");
78
+ }
79
+ if (this.hints.syncName) {
80
+ this.log.info("Syncing Ratgdo device name to HomeKit.");
81
+ }
60
82
  return true;
61
83
  }
62
84
  // Configure the device information for HomeKit.
63
85
  configureInfo() {
64
- var _a, _b, _c, _d;
65
86
  // Update the manufacturer information for this device.
66
- (_a = this.accessory.getService(this.hap.Service.AccessoryInformation)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.Manufacturer, "Liftmaster");
87
+ this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.Manufacturer, "github.com/hjdhjd");
67
88
  // Update the model information for this device.
68
- (_b = this.accessory.getService(this.hap.Service.AccessoryInformation)) === null || _b === void 0 ? void 0 : _b.updateCharacteristic(this.hap.Characteristic.Model, "Ratgdo");
89
+ this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.Model, "Ratgdo");
69
90
  // Update the serial number for this device.
70
- (_c = this.accessory.getService(this.hap.Service.AccessoryInformation)) === null || _c === void 0 ? void 0 : _c.updateCharacteristic(this.hap.Characteristic.SerialNumber, this.device.mac.replace(/:/g, ""));
91
+ this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.SerialNumber, this.device.mac);
71
92
  // Update the firmware information for this device.
72
- (_d = this.accessory.getService(this.hap.Service.AccessoryInformation)) === null || _d === void 0 ? void 0 : _d.updateCharacteristic(this.hap.Characteristic.FirmwareRevision, this.device.firmwareVersion);
93
+ this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.FirmwareRevision, this.device.firmwareVersion);
94
+ return true;
95
+ }
96
+ // Configure MQTT services.
97
+ configureMqtt() {
98
+ // Return our garage door state.
99
+ this.platform.mqtt?.subscribeGet(this, "garagedoor", "Garage Door", () => {
100
+ // Return our current status using our HomeKit current state decoder ring.
101
+ return this.translateCurrentDoorState(this.status.door);
102
+ });
103
+ // Set our garage door state.
104
+ this.platform.mqtt?.subscribeSet(this, "garagedoor", "Garage Door", (value) => {
105
+ let command;
106
+ switch (value) {
107
+ case "close":
108
+ command = this.hap.Characteristic.TargetDoorState.CLOSED;
109
+ break;
110
+ case "open":
111
+ command = this.hap.Characteristic.TargetDoorState.OPEN;
112
+ break;
113
+ default:
114
+ this.log.error("Invalid command.");
115
+ return;
116
+ break;
117
+ }
118
+ // Set our door state accordingly.
119
+ this.setDoorState(command);
120
+ });
121
+ // Return our obstruction state.
122
+ this.platform.mqtt?.subscribeGet(this, "obstruction", "Obstruction", () => {
123
+ return this.status.obstruction.toString();
124
+ });
125
+ // Return our door open occupancy state if configured to do so.
126
+ if (this.hints.doorOpenOccupancySensor) {
127
+ this.platform.mqtt?.subscribeGet(this, "dooropenoccupancy", "Door Open Indicator Occupancy", () => {
128
+ return (this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_DOOR_OPEN)
129
+ ?.getCharacteristic(this.hap.Characteristic.OccupancyDetected).value ?? "false").toString();
130
+ });
131
+ }
132
+ // Return our light state if configured to do so.
133
+ if (this.hints.light) {
134
+ this.platform.mqtt?.subscribeGet(this, "light", "Light", () => {
135
+ return this.status.light.toString();
136
+ });
137
+ }
138
+ // Return our motion occupancy state if configured to do so.
139
+ if (this.hints.motionOccupancySensor) {
140
+ this.platform.mqtt?.subscribeGet(this, "occupancy", "Occupancy", () => {
141
+ return (this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_MOTION)
142
+ ?.getCharacteristic(this.hap.Characteristic.OccupancyDetected).value ?? "false").toString();
143
+ });
144
+ }
145
+ // Return our motion state if configured to do so.
146
+ if (this.hints.motionSensor) {
147
+ this.platform.mqtt?.subscribeGet(this, "motion", "Motion", () => {
148
+ return this.status.motion.toString();
149
+ });
150
+ }
73
151
  return true;
74
152
  }
75
153
  // Configure the garage door service for HomeKit.
76
154
  configureGarageDoor() {
77
- var _a;
78
155
  let garageDoorService = this.accessory.getService(this.hap.Service.GarageDoorOpener);
79
156
  // Add the garage door opener service to the accessory, if needed.
80
157
  if (!garageDoorService) {
81
158
  garageDoorService = new this.hap.Service.GarageDoorOpener(this.name);
159
+ garageDoorService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
82
160
  this.accessory.addService(garageDoorService);
83
161
  }
84
162
  // Set the initial current and target door states to closed since ratgdo doesn't tell us initial state over MQTT on startup.
@@ -92,23 +170,30 @@ class ratgdoAccessory {
92
170
  garageDoorService.getCharacteristic(this.hap.Characteristic.CurrentDoorState).onGet(() => this.status.door);
93
171
  // Inform HomeKit of any obstructions.
94
172
  garageDoorService.getCharacteristic(this.hap.Characteristic.ObstructionDetected).onGet(() => this.status.obstruction === true);
95
- // Add the lock garage door lock current and target state characteristics.
96
- garageDoorService.addOptionalCharacteristic(this.hap.Characteristic.LockCurrentState);
97
- garageDoorService.addOptionalCharacteristic(this.hap.Characteristic.LockTargetState);
173
+ // Configure the lock garage door lock current and target state characteristics.
98
174
  garageDoorService.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.status.lock);
99
175
  garageDoorService.updateCharacteristic(this.hap.Characteristic.LockTargetState, this.lockTargetStateBias(this.status.lock));
100
- // Add the configured name for this device.
101
- garageDoorService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
102
- // switchService.updateCharacteristic(this.hap.Characteristic.ConfiguredName, switchName);
103
176
  // Update our configured name, if requested.
104
- if (this.hints.syncNames) {
105
- garageDoorService.updateCharacteristic(this.hap.Characteristic.ConfiguredName, this.device.name);
106
- if (this.hints.occupancySensor) {
107
- (_a = this.accessory.getService(this.hap.Service.OccupancySensor)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.ConfiguredName, this.device.name + " Open");
177
+ if (this.hints.syncName) {
178
+ this.setServiceName(garageDoorService, this.device.name);
179
+ if (this.hints.automationSwitch) {
180
+ this.setServiceName(this.accessory.getServiceById(this.hap.Service.Switch, RatgdoReservedNames.SWITCH_OPENER_AUTOMATION), this.device.name + " Automation Switch");
181
+ }
182
+ if (this.hints.doorOpenOccupancySensor) {
183
+ this.setServiceName(this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_DOOR_OPEN), this.device.name + " Open");
184
+ }
185
+ if (this.hints.light) {
186
+ this.setServiceName(this.accessory.getService(this.hap.Service.Lightbulb), this.device.name);
108
187
  }
188
+ if (this.hints.motionSensor) {
189
+ this.setServiceName(this.accessory.getService(this.hap.Service.MotionSensor), this.device.name);
190
+ }
191
+ if (this.hints.motionOccupancySensor) {
192
+ this.setServiceName(this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_MOTION), this.device.name);
193
+ }
194
+ // Finally, update the accessory name.
195
+ this.accessoryName = this.device.name;
109
196
  }
110
- // Add our status active characteristic.
111
- garageDoorService.addOptionalCharacteristic(this.hap.Characteristic.StatusActive);
112
197
  garageDoorService.getCharacteristic(this.hap.Characteristic.StatusActive).onGet(() => this.status.availability);
113
198
  garageDoorService.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
114
199
  // Let HomeKit know that this is the primary service on this accessory.
@@ -117,9 +202,16 @@ class ratgdoAccessory {
117
202
  }
118
203
  // Configure the light for HomeKit.
119
204
  configureLight() {
120
- var _a, _b;
121
205
  // Find the service, if it exists.
122
206
  let lightService = this.accessory.getService(this.hap.Service.Lightbulb);
207
+ // Have we disabled the light?
208
+ if (!this.hints.light) {
209
+ if (lightService) {
210
+ this.accessory.removeService(lightService);
211
+ this.log.info("Disabling light.");
212
+ }
213
+ return false;
214
+ }
123
215
  // Add the service to the accessory, if needed.
124
216
  if (!lightService) {
125
217
  lightService = new this.hap.Service.Lightbulb(this.name);
@@ -127,24 +219,33 @@ class ratgdoAccessory {
127
219
  this.log.error("Unable to add the light.");
128
220
  return false;
129
221
  }
222
+ lightService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
223
+ lightService.updateCharacteristic(this.hap.Characteristic.Name, this.name);
224
+ this.setServiceName(lightService, this.name);
130
225
  this.accessory.addService(lightService);
131
226
  this.log.info("Enabling light.");
132
227
  }
228
+ // Initialize the light.
229
+ lightService.updateCharacteristic(this.hap.Characteristic.On, this.status.light);
133
230
  // Turn the light on or off.
134
- (_a = lightService.getCharacteristic(this.hap.Characteristic.On)) === null || _a === void 0 ? void 0 : _a.onGet(() => this.status.light);
135
- (_b = lightService.getCharacteristic(this.hap.Characteristic.On)) === null || _b === void 0 ? void 0 : _b.onSet((value) => {
231
+ lightService.getCharacteristic(this.hap.Characteristic.On)?.onGet(() => this.status.light);
232
+ lightService.getCharacteristic(this.hap.Characteristic.On)?.onSet((value) => {
136
233
  this.command("light", value === true ? "on" : "off");
137
234
  });
138
- // Initialize the light.
139
- lightService.displayName = this.name;
140
- lightService.updateCharacteristic(this.hap.Characteristic.Name, this.name);
141
- lightService.updateCharacteristic(this.hap.Characteristic.On, this.status.light);
142
235
  return true;
143
236
  }
144
237
  // Configure the motion sensor for HomeKit.
145
238
  configureMotionSensor() {
146
239
  // Find the motion sensor service, if it exists.
147
240
  let motionService = this.accessory.getService(this.hap.Service.MotionSensor);
241
+ // Have we disabled the motion sensor?
242
+ if (!this.hints.motionSensor) {
243
+ if (motionService) {
244
+ this.accessory.removeService(motionService);
245
+ this.log.info("Disabling motion sensor.");
246
+ }
247
+ return false;
248
+ }
148
249
  // We don't have a motion sensor, let's add it to the device.
149
250
  if (!motionService) {
150
251
  // We don't have it, add the motion sensor to the device.
@@ -153,43 +254,154 @@ class ratgdoAccessory {
153
254
  this.log.error("Unable to add the motion sensor.");
154
255
  return false;
155
256
  }
257
+ motionService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
258
+ motionService.updateCharacteristic(this.hap.Characteristic.Name, this.name);
259
+ this.setServiceName(motionService, this.name);
156
260
  this.accessory.addService(motionService);
157
261
  this.log.info("Enabling motion sensor.");
158
262
  }
159
263
  // Initialize the state of the motion sensor.
160
- motionService.displayName = this.name;
161
- motionService.updateCharacteristic(this.hap.Characteristic.Name, this.name);
162
264
  motionService.updateCharacteristic(this.hap.Characteristic.MotionDetected, false);
163
265
  motionService.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
164
266
  motionService.getCharacteristic(this.hap.Characteristic.StatusActive).onGet(() => this.status.availability);
165
267
  return true;
166
268
  }
269
+ // Configure a switch to automate open and close events in HomeKit beyond what HomeKit might allow for a garage opener service that gets treated as a secure service.
270
+ configureAutomationSwitch() {
271
+ // Find the switch service, if it exists.
272
+ let switchService = this.accessory.getServiceById(this.hap.Service.Switch, RatgdoReservedNames.SWITCH_OPENER_AUTOMATION);
273
+ // The switch is disabled by default and primarily exists for automation purposes.
274
+ if (!this.hints.automationSwitch) {
275
+ if (switchService) {
276
+ this.accessory.removeService(switchService);
277
+ this.log.info("Disabling automation switch.");
278
+ }
279
+ return false;
280
+ }
281
+ // Add the switch to the opener, if needed.
282
+ if (!switchService) {
283
+ switchService = new this.hap.Service.Switch(this.name + " Automation Switch", RatgdoReservedNames.SWITCH_OPENER_AUTOMATION);
284
+ if (!switchService) {
285
+ this.log.error("Unable to add automation switch.");
286
+ return false;
287
+ }
288
+ switchService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
289
+ this.setServiceName(switchService, this.name + " Automation Switch");
290
+ this.accessory.addService(switchService);
291
+ }
292
+ // Return the current state of the opener.
293
+ switchService.getCharacteristic(this.hap.Characteristic.On)?.onGet(() => {
294
+ // We're on if we are in any state other than closed (specifically open or stopped).
295
+ return this.doorCurrentStateBias(this.status.door) !== this.hap.Characteristic.CurrentDoorState.CLOSED;
296
+ });
297
+ // Open or close the opener.
298
+ switchService.getCharacteristic(this.hap.Characteristic.On)?.onSet((value) => {
299
+ // Inform the user.
300
+ this.log.info("Automation switch: %s.", value ? "open" : "close");
301
+ // Send the command.
302
+ if (!this.setDoorState(value ? this.hap.Characteristic.TargetDoorState.OPEN : this.hap.Characteristic.TargetDoorState.CLOSED)) {
303
+ // Something went wrong. Let's make sure we revert the switch to it's prior state.
304
+ setTimeout(() => {
305
+ switchService?.updateCharacteristic(this.hap.Characteristic.On, !value);
306
+ }, 50);
307
+ }
308
+ });
309
+ // Initialize the switch.
310
+ switchService.updateCharacteristic(this.hap.Characteristic.On, this.doorCurrentStateBias(this.status.door) !== this.hap.Characteristic.CurrentDoorState.CLOSED);
311
+ this.log.info("Enabling automation switch.");
312
+ return true;
313
+ }
314
+ // Configure the door open occupancy sensor for HomeKit.
315
+ configureDoorOpenOccupancySensor() {
316
+ // Find the occupancy sensor service, if it exists.
317
+ let occupancyService = this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_DOOR_OPEN);
318
+ // The occupancy sensor is disabled by default and primarily exists for automation purposes.
319
+ if (!this.hints.doorOpenOccupancySensor) {
320
+ if (occupancyService) {
321
+ this.accessory.removeService(occupancyService);
322
+ this.log.info("Disabling door open indicator occupancy sensor.");
323
+ }
324
+ return false;
325
+ }
326
+ // We don't have an occupancy sensor, let's add it to the device.
327
+ if (!occupancyService) {
328
+ // We don't have it, add the occupancy sensor to the device.
329
+ occupancyService = new this.hap.Service.OccupancySensor(this.name + " Open", RatgdoReservedNames.OCCUPANCY_SENSOR_DOOR_OPEN);
330
+ if (!occupancyService) {
331
+ this.log.error("Unable to add door open occupancy sensor.");
332
+ return false;
333
+ }
334
+ occupancyService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
335
+ this.setServiceName(occupancyService, this.name + " Open");
336
+ this.accessory.addService(occupancyService);
337
+ }
338
+ // Initialize the state of the occupancy sensor.
339
+ occupancyService.updateCharacteristic(this.hap.Characteristic.OccupancyDetected, false);
340
+ occupancyService.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
341
+ occupancyService.getCharacteristic(this.hap.Characteristic.StatusActive).onGet(() => {
342
+ return this.status.availability;
343
+ });
344
+ this.log.info("Enabling door open indicator occupancy sensor. Occupancy will be triggered when the opener has been continuously open for more than %s seconds.", this.hints.doorOpenOccupancyDuration);
345
+ return true;
346
+ }
347
+ // Configure the motion occupancy sensor for HomeKit.
348
+ configureMotionOccupancySensor() {
349
+ // Find the occupancy sensor service, if it exists.
350
+ let occupancyService = this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_MOTION);
351
+ // The occupancy sensor is disabled by default and primarily exists for automation purposes.
352
+ if (!this.hints.motionOccupancySensor) {
353
+ if (occupancyService) {
354
+ this.accessory.removeService(occupancyService);
355
+ this.log.info("Disabling occupancy sensor.");
356
+ }
357
+ return false;
358
+ }
359
+ // We don't have an occupancy sensor, let's add it to the device.
360
+ if (!occupancyService) {
361
+ // We don't have it, add the occupancy sensor to the device.
362
+ occupancyService = new this.hap.Service.OccupancySensor(this.name, RatgdoReservedNames.OCCUPANCY_SENSOR_MOTION);
363
+ if (!occupancyService) {
364
+ this.log.error("Unable to add occupancy sensor.");
365
+ return false;
366
+ }
367
+ occupancyService.addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName);
368
+ this.setServiceName(occupancyService, this.name);
369
+ this.accessory.addService(occupancyService);
370
+ }
371
+ // Initialize the state of the occupancy sensor.
372
+ occupancyService.updateCharacteristic(this.hap.Characteristic.OccupancyDetected, false);
373
+ occupancyService.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
374
+ occupancyService.getCharacteristic(this.hap.Characteristic.StatusActive).onGet(() => {
375
+ return this.status.availability;
376
+ });
377
+ this.log.info("Enabling occupancy sensor. Occupancy event duration set to %s seconds.", this.hints.motionOccupancyDuration);
378
+ return true;
379
+ }
167
380
  // Open or close the garage door.
168
381
  setDoorState(value) {
169
- const actionExisting = this.status.door === this.hap.Characteristic.CurrentDoorState.OPENING ? "opening" : "closing";
170
382
  const actionAttempt = value === this.hap.Characteristic.TargetDoorState.CLOSED ? "close" : "open";
171
383
  // If this garage door is read-only, we won't process any requests to set state.
172
384
  if (this.hints.readOnly) {
173
385
  this.log.info("Unable to %s door. The door has been configured to be read only.", actionAttempt);
174
386
  // Tell HomeKit that we haven't in fact changed our state so we don't end up in an inadvertent opening or closing state.
175
387
  setImmediate(() => {
176
- var _a;
177
- (_a = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.TargetDoorState, value === this.hap.Characteristic.TargetDoorState.CLOSED ? this.hap.Characteristic.TargetDoorState.OPEN : this.hap.Characteristic.TargetDoorState.CLOSED);
388
+ this.accessory.getService(this.hap.Service.GarageDoorOpener)?.updateCharacteristic(this.hap.Characteristic.TargetDoorState, value === this.hap.Characteristic.TargetDoorState.CLOSED ? this.hap.Characteristic.TargetDoorState.OPEN : this.hap.Characteristic.TargetDoorState.CLOSED);
178
389
  });
179
390
  return false;
180
391
  }
181
- // If we are already opening or closing the garage door, we error out. As a precaution, we ensure we complete the current action before allowing a new one. This behavior may
182
- // change in the future, but for now, we manage this edge case by eliminating the possibility of doing so.
392
+ // If we are already opening or closing the garage door, we assume the user wants to stop the garage door opener at it's current location.
183
393
  if ((this.status.door === this.hap.Characteristic.CurrentDoorState.OPENING) || (this.status.door === this.hap.Characteristic.CurrentDoorState.CLOSING)) {
184
- this.log.error("Unable to %s door while currently attempting to complete %s. The existing action must be allowed to complete before attempting a new one.", actionAttempt, actionExisting);
185
- return false;
394
+ this.log.debug("Stop requested from user while transitioning between open and close states.");
395
+ // Execute the stop command.
396
+ this.command("door", "stop");
397
+ return true;
186
398
  }
187
399
  // Close the garage door.
188
400
  if (value === this.hap.Characteristic.TargetDoorState.CLOSED) {
189
401
  // HomeKit is asking us to close the garage door, but let's make sure it's not already closed first.
190
402
  if (this.status.door !== this.hap.Characteristic.CurrentDoorState.CLOSED) {
191
403
  // Execute the command.
192
- this.command("door", "close", "closing");
404
+ this.command("door", "close");
193
405
  }
194
406
  return true;
195
407
  }
@@ -198,7 +410,7 @@ class ratgdoAccessory {
198
410
  // HomeKit is informing us to open the door, but we don't want to act if it's already open.
199
411
  if (this.status.door !== this.hap.Characteristic.CurrentDoorState.OPEN) {
200
412
  // Execute the command.
201
- this.command("door", "open", "opening");
413
+ this.command("door", "open");
202
414
  }
203
415
  return true;
204
416
  }
@@ -208,18 +420,31 @@ class ratgdoAccessory {
208
420
  }
209
421
  // Update the state of the accessory.
210
422
  updateState(event, payload) {
211
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
212
423
  const camelCase = (text) => text.charAt(0).toUpperCase() + text.slice(1);
424
+ const doorOccupancyService = this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_DOOR_OPEN);
425
+ const garageDoorService = this.accessory.getService(this.hap.Service.GarageDoorOpener);
426
+ const lightBulbService = this.accessory.getService(this.hap.Service.Lightbulb);
427
+ const motionOccupancyService = this.accessory.getServiceById(this.hap.Service.OccupancySensor, RatgdoReservedNames.OCCUPANCY_SENSOR_MOTION);
428
+ const motionService = this.accessory.getService(this.hap.Service.MotionSensor);
429
+ const switchService = this.accessory.getServiceById(this.hap.Service.Switch, RatgdoReservedNames.SWITCH_OPENER_AUTOMATION);
430
+ // We continuously rebroadcast our device information.
431
+ this.configureInfo();
213
432
  switch (event) {
214
433
  case "availability":
215
434
  this.status.availability = payload === "online";
216
435
  // Update our availability.
217
- (_a = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
218
- (_b = this.accessory.getService(this.hap.Service.MotionSensor)) === null || _b === void 0 ? void 0 : _b.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
436
+ garageDoorService?.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
437
+ doorOccupancyService?.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
438
+ motionOccupancyService?.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
439
+ motionService?.updateCharacteristic(this.hap.Characteristic.StatusActive, this.status.availability);
219
440
  // Inform the user:
220
441
  this.log.info("Device %s.", this.status.availability ? "connected" : "disconnected");
221
442
  break;
222
443
  case "door":
444
+ // If we're already in the state we're updating to, we're done.
445
+ if (this.translateCurrentDoorState(this.status.door) === payload) {
446
+ break;
447
+ }
223
448
  // Clear out our door transition timer, if we have one.
224
449
  if (this.doorTimer) {
225
450
  clearTimeout(this.doorTimer);
@@ -231,28 +456,37 @@ class ratgdoAccessory {
231
456
  break;
232
457
  case "closing":
233
458
  this.status.door = this.hap.Characteristic.CurrentDoorState.CLOSING;
234
- // As a safety measure for occasionally unreliable MQTT message delivery, let's ensure we generate a closed state after a reasonable transition period. If we receive
235
- // an actual state update before this, this safety measure won't be triggered.
459
+ // As a safety measure for occasionally unreliable MQTT message delivery, let's ensure we generate a closed state after a reasonable transition period. If we
460
+ // receive an actual state update before this, this safety measure won't be triggered.
236
461
  this.doorTimer = setTimeout(() => {
237
462
  // Mark the door as closed.
238
463
  this.log.debug("Generating a close event to complete the state transition.");
239
464
  this.updateState("door", "closed");
240
465
  this.doorTimer = null;
241
- }, settings_js_1.RATGDO_TRANSITION_DURATION * 1000);
466
+ }, RATGDO_TRANSITION_DURATION * 1000);
242
467
  break;
243
468
  case "open":
244
469
  this.status.door = this.hap.Characteristic.CurrentDoorState.OPEN;
470
+ // Trigger our occupancy timer, if configured to do so and we don't have one yet.
471
+ if (this.hints.doorOpenOccupancySensor && !this.doorOccupancyTimer) {
472
+ this.doorOccupancyTimer = setTimeout(() => {
473
+ doorOccupancyService?.updateCharacteristic(this.hap.Characteristic.OccupancyDetected, true);
474
+ this.log.info("Garage door open occupancy detected.");
475
+ // Publish to MQTT, if the user has configured it.
476
+ this.platform.mqtt?.publish(this, "dooropenoccupancy", "true");
477
+ }, this.hints.doorOpenOccupancyDuration * 1000);
478
+ }
245
479
  break;
246
480
  case "opening":
247
481
  this.status.door = this.hap.Characteristic.CurrentDoorState.OPENING;
248
- // As a safety measure for occasionally unreliable MQTT message delivery, let's ensure we generate an open state after a reasonable transition period. If we receive
249
- // an actual state update before this, this safety measure won't be triggered.
482
+ // As a safety measure for occasionally unreliable MQTT message delivery, let's ensure we generate an open state after a reasonable transition period. If we
483
+ // receive an actual state update before this, this safety measure won't be triggered.
250
484
  this.doorTimer = setTimeout(() => {
251
485
  // Mark the door as open.
252
486
  this.log.debug("Generating an open event to complete the state transition.");
253
487
  this.updateState("door", "open");
254
488
  this.doorTimer = null;
255
- }, settings_js_1.RATGDO_TRANSITION_DURATION * 1000);
489
+ }, RATGDO_TRANSITION_DURATION * 1000);
256
490
  break;
257
491
  case "stopped":
258
492
  this.status.door = this.hap.Characteristic.CurrentDoorState.STOPPED;
@@ -264,26 +498,53 @@ class ratgdoAccessory {
264
498
  // We are only going to update the target state if our current state is NOT stopped. If we are stopped, we are at the target state by definition. We also want to
265
499
  // ensure we update TargetDoorState before updating CurrentDoorState in order to work around some notification quirks HomeKit occasionally has.
266
500
  if (this.status.door !== this.hap.Characteristic.CurrentDoorState.STOPPED) {
267
- (_c = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _c === void 0 ? void 0 : _c.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.doorTargetStateBias(this.status.door));
501
+ garageDoorService?.updateCharacteristic(this.hap.Characteristic.TargetDoorState, this.doorTargetStateBias(this.status.door));
268
502
  }
269
- (_d = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _d === void 0 ? void 0 : _d.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.status.door);
503
+ garageDoorService?.updateCharacteristic(this.hap.Characteristic.CurrentDoorState, this.status.door);
504
+ // Update our automation switch, if configured.
505
+ switchService?.updateCharacteristic(this.hap.Characteristic.On, this.doorTargetStateBias(this.status.door) === this.hap.Characteristic.TargetDoorState.OPEN);
270
506
  // Inform the user:
271
507
  this.log.info("%s.", camelCase(payload));
508
+ // If we have an open occupancy sensor configured and our door state is anything other than open, clear our occupancy state.
509
+ if (this.hints.doorOpenOccupancySensor && this.doorOccupancyTimer && (payload !== "open")) {
510
+ clearTimeout(this.doorOccupancyTimer);
511
+ this.doorOccupancyTimer = null;
512
+ if (doorOccupancyService?.getCharacteristic(this.hap.Characteristic.OccupancyDetected).value) {
513
+ doorOccupancyService?.updateCharacteristic(this.hap.Characteristic.OccupancyDetected, false);
514
+ this.log.info("Garage door open occupancy no longer detected.");
515
+ // Publish to MQTT, if the user has configured it.
516
+ this.platform.mqtt?.publish(this, "dooropenoccupancy", "false");
517
+ }
518
+ }
519
+ // Publish to MQTT, if the user has configured it.
520
+ this.platform.mqtt?.publish(this, "garagedoor", payload);
272
521
  break;
273
522
  case "light":
274
- this.status.light = payload === "on";
275
- (_e = this.accessory.getService(this.hap.Service.Lightbulb)) === null || _e === void 0 ? void 0 : _e.updateCharacteristic(this.hap.Characteristic.On, this.status.light);
276
- // Inform the user:
277
- this.log.info("Light %s.", payload);
523
+ // Only act if we're not already at the state we're updating to.
524
+ if (this.status.light !== (payload === "on")) {
525
+ this.status.light = payload === "on";
526
+ lightBulbService?.updateCharacteristic(this.hap.Characteristic.On, this.status.light);
527
+ // Inform the user:
528
+ this.log.info("Light %s.", payload);
529
+ // Publish to MQTT, if the user has configured it.
530
+ this.platform.mqtt?.publish(this, "light", this.status.light.toString());
531
+ }
278
532
  break;
279
533
  case "lock":
280
- // Determine our current and target lock states.
534
+ // If we're already in the state we're updating to, we're done.
535
+ if (this.status.lock === (payload === "locked" ? this.hap.Characteristic.LockCurrentState.SECURED : this.hap.Characteristic.LockCurrentState.UNSECURED)) {
536
+ break;
537
+ }
538
+ // Determine our lock state.
281
539
  this.status.lock = payload === "locked" ? this.hap.Characteristic.LockCurrentState.SECURED : this.hap.Characteristic.LockCurrentState.UNSECURED;
282
540
  // Update our lock state.
283
- (_f = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _f === void 0 ? void 0 : _f.updateCharacteristic(this.hap.Characteristic.LockTargetState, payload === "locked" ? this.hap.Characteristic.LockTargetState.SECURED : this.hap.Characteristic.LockTargetState.UNSECURED);
284
- (_g = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _g === void 0 ? void 0 : _g.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.status.lock);
541
+ garageDoorService?.updateCharacteristic(this.hap.Characteristic.LockTargetState, payload === "locked" ?
542
+ this.hap.Characteristic.LockTargetState.SECURED : this.hap.Characteristic.LockTargetState.UNSECURED);
543
+ garageDoorService?.updateCharacteristic(this.hap.Characteristic.LockCurrentState, this.status.lock);
285
544
  // Inform the user:
286
545
  this.log.info("%s.", camelCase(payload));
546
+ // Publish to MQTT, if the user has configured it.
547
+ this.platform.mqtt?.publish(this, "lock", this.status.lock.toString());
287
548
  break;
288
549
  case "motion":
289
550
  this.status.motion = payload === "detected";
@@ -294,30 +555,92 @@ class ratgdoAccessory {
294
555
  break;
295
556
  }
296
557
  // Update the motion sensor state.
297
- (_h = this.accessory.getService(this.hap.Service.MotionSensor)) === null || _h === void 0 ? void 0 : _h.updateCharacteristic(this.hap.Characteristic.MotionDetected, this.status.motion);
298
- // If we already have an inflight motion sensor timer, clear it out since we're restarting the timer. Also, if it's our first time detecting motion for this event cycle,
299
- // let the user know.
300
- this.motionTimer ? clearTimeout(this.motionTimer) : this.log.info("Motion detected.");
558
+ motionService?.updateCharacteristic(this.hap.Characteristic.MotionDetected, this.status.motion);
559
+ // If we already have an inflight motion sensor timer, clear it out since we're restarting the timer. Also, if it's our first time detecting motion for this event
560
+ // cycle, let the user know.
561
+ if (this.motionTimer) {
562
+ clearTimeout(this.motionTimer);
563
+ }
564
+ else {
565
+ this.log.info("Motion detected.");
566
+ // Publish to MQTT, if the user has configured it.
567
+ this.platform.mqtt?.publish(this, "motion", this.status.motion.toString());
568
+ }
301
569
  // Set a timer for the motion event.
302
570
  this.motionTimer = setTimeout(() => {
303
- var _a;
304
571
  this.status.motion = false;
305
- (_a = this.accessory.getService(this.hap.Service.MotionSensor)) === null || _a === void 0 ? void 0 : _a.updateCharacteristic(this.hap.Characteristic.MotionDetected, this.status.motion);
306
- }, settings_js_1.RATGDO_MOTION_DURATION * 1000);
572
+ motionService?.updateCharacteristic(this.hap.Characteristic.MotionDetected, this.status.motion);
573
+ // Publish to MQTT, if the user has configured it.
574
+ this.platform.mqtt?.publish(this, "motion", this.status.motion.toString());
575
+ }, RATGDO_MOTION_DURATION * 1000);
576
+ // Kill any inflight occupancy sensor.
577
+ if (this.motionOccupancyTimer) {
578
+ clearTimeout(this.motionOccupancyTimer);
579
+ this.motionOccupancyTimer = null;
580
+ }
581
+ // If the motion occupancy sensor isn't already triggered, let's do so now.
582
+ if (motionOccupancyService?.getCharacteristic(this.hap.Characteristic.OccupancyDetected).value !== true) {
583
+ // Trigger the occupancy event in HomeKit.
584
+ motionOccupancyService?.updateCharacteristic(this.hap.Characteristic.OccupancyDetected, true);
585
+ // Publish to MQTT, if the user has configured it.
586
+ this.platform.mqtt?.publish(this, "occupancy", "true");
587
+ // Log the event.
588
+ this.log.info("Occupancy detected.");
589
+ }
590
+ // Reset our occupancy state after occupancyDuration.
591
+ this.motionOccupancyTimer = setTimeout(() => {
592
+ // Reset the occupancy sensor.
593
+ motionOccupancyService?.updateCharacteristic(this.hap.Characteristic.OccupancyDetected, false);
594
+ // Publish to MQTT, if the user has configured it.
595
+ this.platform.mqtt?.publish(this, "occupancy", "false");
596
+ // Log the event.
597
+ this.log.info("Occupancy no longer detected.");
598
+ // Delete the timer.
599
+ this.motionOccupancyTimer = null;
600
+ }, this.hints.motionOccupancyDuration * 1000);
307
601
  break;
308
602
  case "obstruction":
309
- this.status.obstruction = payload === "obstructed";
310
- (_j = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _j === void 0 ? void 0 : _j.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, this.status.obstruction);
311
- this.log.info("Obstruction %sdetected.", this.status.obstruction ? "" : "no longer ");
603
+ garageDoorService?.updateCharacteristic(this.hap.Characteristic.ObstructionDetected, payload === "obstructed");
604
+ // Only act if we're not already at the state we're updating to.
605
+ if (this.status.obstruction !== (payload === "obstructed")) {
606
+ this.status.obstruction = payload === "obstructed";
607
+ this.log.info("Obstruction %sdetected.", this.status.obstruction ? "" : "no longer ");
608
+ // Publish to MQTT, if the user has configured it.
609
+ this.platform.mqtt?.publish(this, "obstruction", this.status.obstruction.toString());
610
+ }
312
611
  break;
313
612
  case "default":
314
613
  break;
315
614
  }
316
615
  }
616
+ // Utility function to translate HomeKit's current door state values into human-readable form.
617
+ translateCurrentDoorState(value) {
618
+ // HomeKit state decoder ring.
619
+ switch (value) {
620
+ case this.hap.Characteristic.CurrentDoorState.CLOSED:
621
+ return "closed";
622
+ break;
623
+ case this.hap.Characteristic.CurrentDoorState.CLOSING:
624
+ return "closing";
625
+ break;
626
+ case this.hap.Characteristic.CurrentDoorState.OPEN:
627
+ return "open";
628
+ break;
629
+ case this.hap.Characteristic.CurrentDoorState.OPENING:
630
+ return "opening";
631
+ break;
632
+ case this.hap.Characteristic.CurrentDoorState.STOPPED:
633
+ return "stopped";
634
+ break;
635
+ default:
636
+ break;
637
+ }
638
+ return "unknown";
639
+ }
317
640
  // Utility function to return our bias for what the current door state should be. This is primarily used for our initial bias on startup.
318
641
  doorCurrentStateBias(state) {
319
- // Our current door state reflects our opinion on what open or closed means in HomeKit terms. For the obvious states, this is easy. For some of the edge cases, it can be
320
- // less so. Our north star is that if we are in an obstructed state, we are open.
642
+ // Our current door state reflects our opinion on what open or closed means in HomeKit terms. For the obvious states, this is easy. For some of the edge cases, it can
643
+ // be less so. Our north star is that if we are in an obstructed state, we are open.
321
644
  if (this.status.obstruction) {
322
645
  return this.hap.Characteristic.CurrentDoorState.OPEN;
323
646
  }
@@ -338,9 +661,9 @@ class ratgdoAccessory {
338
661
  }
339
662
  // Utility function to return our bias for what the target door state should be.
340
663
  doorTargetStateBias(state) {
341
- // We need to be careful with respect to the target state and we need to make some reasonable assumptions about where we intend to end up. If we are opening or closing, our
342
- // target state needs to be the completion of those actions. If we're stopped or obstructed, we're going to assume the desired target state is to be open, since that is the
343
- // typical opener behavior, and it's impossible for us to know with reasonable certainty what the original intention of the action was.
664
+ // We need to be careful with respect to the target state and we need to make some reasonable assumptions about where we intend to end up. If we are opening or
665
+ // closing, our target state needs to be the completion of those actions. If we're stopped or obstructed, we're going to assume the desired target state is to be
666
+ // open, since that is the typical opener behavior, and it's impossible for us to know with reasonable certainty what the original intention of the action was.
344
667
  if (this.status.obstruction) {
345
668
  return this.hap.Characteristic.TargetDoorState.OPEN;
346
669
  }
@@ -372,31 +695,52 @@ class ratgdoAccessory {
372
695
  }
373
696
  }
374
697
  // Utility function to transmit a command to Ratgdo.
375
- command(topic, payload, updatePayload) {
376
- this.platform.broker.publish({ cmd: "publish", dup: false, payload: payload, qos: 2, retain: false, topic: this.device.name + "/command/" + topic }, () => { });
377
- // Update our internal state as well.
378
- if (updatePayload) {
379
- this.updateState(topic, updatePayload);
380
- }
698
+ command(topic, payload) {
699
+ this.platform.broker.publish({ cmd: "publish", dup: false, payload: payload, qos: 2, retain: false, topic: this.device.name + "/command/" + topic }, (error) => {
700
+ if (error) {
701
+ this.log.error("Publish error:");
702
+ this.log.error(util.inspect(error), { colors: true, depth: null, sorted: true });
703
+ }
704
+ });
381
705
  }
382
706
  // Utility function to return a floating point configuration parameter on a device.
383
707
  getFeatureFloat(option) {
384
- return (0, ratgdo_options_js_1.getOptionFloat)((0, ratgdo_options_js_1.getOptionValue)(this.platform.configOptions, this.device, option));
708
+ return getOptionFloat(getOptionValue(this.platform.configOptions, this.device, option));
385
709
  }
386
710
  // Utility function to return an integer configuration parameter on a device.
387
711
  getFeatureNumber(option) {
388
- return (0, ratgdo_options_js_1.getOptionNumber)((0, ratgdo_options_js_1.getOptionValue)(this.platform.configOptions, this.device, option));
712
+ return getOptionNumber(getOptionValue(this.platform.configOptions, this.device, option));
389
713
  }
390
714
  // Utility for checking feature options on a device.
391
715
  hasFeature(option) {
392
- return (0, ratgdo_options_js_1.isOptionEnabled)(this.platform.configOptions, this.device, option, this.platform.featureOptionDefault(option));
716
+ return isOptionEnabled(this.platform.configOptions, this.device, option, this.platform.featureOptionDefault(option));
717
+ }
718
+ // Utility function to set the name of a service.
719
+ setServiceName(service, name) {
720
+ if (!service) {
721
+ return;
722
+ }
723
+ service.displayName = name;
724
+ service.updateCharacteristic(this.hap.Characteristic.ConfiguredName, name);
393
725
  }
394
- // Name utility function.
726
+ // Utility function to return the name of this device.
395
727
  get name() {
396
- var _a;
397
- const configuredName = (_a = this.accessory.getService(this.hap.Service.GarageDoorOpener)) === null || _a === void 0 ? void 0 : _a.getCharacteristic(this.hap.Characteristic.ConfiguredName).value;
398
- return (configuredName === null || configuredName === void 0 ? void 0 : configuredName.length) ? configuredName : this.device.name;
728
+ // We use the garage door service as the natural proxy for the name.
729
+ const configuredName = this.accessory.getService(this.hap.Service.GarageDoorOpener)?.getCharacteristic(this.hap.Characteristic.ConfiguredName).value;
730
+ // If we don't have a name for the garage door service, return the device name from Ratgdo.
731
+ return configuredName?.length ? configuredName : this.device.name;
732
+ }
733
+ // Utility function to return the current accessory name of this device.
734
+ get accessoryName() {
735
+ return this.accessory.getService(this.hap.Service.AccessoryInformation)?.getCharacteristic(this.hap.Characteristic.Name).value ?? this.device.name;
736
+ }
737
+ // Utility function to set the current accessory name of this device.
738
+ set accessoryName(name) {
739
+ // Set all the internally managed names within Homebridge to the new accessory name.
740
+ this.accessory.displayName = name;
741
+ this.accessory._associatedHAPAccessory.displayName = name;
742
+ // Set all the HomeKit-visible names.
743
+ this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.Name, name);
399
744
  }
400
745
  }
401
- exports.ratgdoAccessory = ratgdoAccessory;
402
746
  //# sourceMappingURL=ratgdo-device.js.map