@mp-consulting/homebridge-unifi-access 1.0.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.
Files changed (74) hide show
  1. package/.claude/settings.local.json +91 -0
  2. package/CHANGELOG.md +13 -0
  3. package/LICENSE.md +22 -0
  4. package/README.md +159 -0
  5. package/config.schema.json +202 -0
  6. package/dist/access-controller.d.ts +41 -0
  7. package/dist/access-controller.js +342 -0
  8. package/dist/access-controller.js.map +1 -0
  9. package/dist/access-device-catalog.d.ts +43 -0
  10. package/dist/access-device-catalog.js +151 -0
  11. package/dist/access-device-catalog.js.map +1 -0
  12. package/dist/access-device.d.ts +68 -0
  13. package/dist/access-device.js +330 -0
  14. package/dist/access-device.js.map +1 -0
  15. package/dist/access-events.d.ts +27 -0
  16. package/dist/access-events.js +152 -0
  17. package/dist/access-events.js.map +1 -0
  18. package/dist/access-options.d.ts +32 -0
  19. package/dist/access-options.js +65 -0
  20. package/dist/access-options.js.map +1 -0
  21. package/dist/access-platform.d.ts +15 -0
  22. package/dist/access-platform.js +74 -0
  23. package/dist/access-platform.js.map +1 -0
  24. package/dist/access-types.d.ts +30 -0
  25. package/dist/access-types.js +42 -0
  26. package/dist/access-types.js.map +1 -0
  27. package/dist/hub/access-hub-api.d.ts +13 -0
  28. package/dist/hub/access-hub-api.js +140 -0
  29. package/dist/hub/access-hub-api.js.map +1 -0
  30. package/dist/hub/access-hub-events.d.ts +2 -0
  31. package/dist/hub/access-hub-events.js +229 -0
  32. package/dist/hub/access-hub-events.js.map +1 -0
  33. package/dist/hub/access-hub-mqtt.d.ts +2 -0
  34. package/dist/hub/access-hub-mqtt.js +137 -0
  35. package/dist/hub/access-hub-mqtt.js.map +1 -0
  36. package/dist/hub/access-hub-services.d.ts +4 -0
  37. package/dist/hub/access-hub-services.js +451 -0
  38. package/dist/hub/access-hub-services.js.map +1 -0
  39. package/dist/hub/access-hub-types.d.ts +145 -0
  40. package/dist/hub/access-hub-types.js +35 -0
  41. package/dist/hub/access-hub-types.js.map +1 -0
  42. package/dist/hub/access-hub-utils.d.ts +20 -0
  43. package/dist/hub/access-hub-utils.js +128 -0
  44. package/dist/hub/access-hub-utils.js.map +1 -0
  45. package/dist/hub/access-hub.d.ts +39 -0
  46. package/dist/hub/access-hub.js +185 -0
  47. package/dist/hub/access-hub.js.map +1 -0
  48. package/dist/hub/index.d.ts +4 -0
  49. package/dist/hub/index.js +7 -0
  50. package/dist/hub/index.js.map +1 -0
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.js +11 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/settings.d.ts +16 -0
  55. package/dist/settings.js +49 -0
  56. package/dist/settings.js.map +1 -0
  57. package/docs/FeatureOptions.md +120 -0
  58. package/docs/MQTT.md +116 -0
  59. package/docs/api_reference.pdf +0 -0
  60. package/docs/media/homebridge-unifi-access.png +0 -0
  61. package/docs/media/homebridge-unifi-access.svg +21 -0
  62. package/eslint.config.mjs +99 -0
  63. package/homebridge-ui/public/app.js +104 -0
  64. package/homebridge-ui/public/index.html +267 -0
  65. package/homebridge-ui/public/modules/constants.js +22 -0
  66. package/homebridge-ui/public/modules/controllers.js +202 -0
  67. package/homebridge-ui/public/modules/discovery.js +89 -0
  68. package/homebridge-ui/public/modules/dom-helpers.js +41 -0
  69. package/homebridge-ui/public/modules/feature-options.js +625 -0
  70. package/homebridge-ui/public/modules/state.js +26 -0
  71. package/homebridge-ui/public/styles.css +533 -0
  72. package/homebridge-ui/server.js +374 -0
  73. package/package.json +83 -0
  74. package/scripts/event-schema-monitor.ts +350 -0
@@ -0,0 +1,65 @@
1
+ /* Copyright(C) 2026, Mickael Palma. All rights reserved.
2
+ *
3
+ * access-options.ts: Feature option and type definitions for UniFi Access.
4
+ */
5
+ import { ACCESS_DEVICE_REMOVAL_DELAY_INTERVAL, ACCESS_DEVICE_UNLOCK_INTERVAL } from "./settings.js";
6
+ import { modelsDefaultGarageDoor, modelsDefaultLock, modelsDps, modelsRel, modelsRen, modelsRex, modelsSideDoor } from "./access-device-catalog.js";
7
+ // Feature option categories.
8
+ export const featureOptionCategories = [
9
+ { description: "Device feature options.", modelKey: ["all"], name: "Device" },
10
+ { description: "Controller feature options.", modelKey: ["controller"], name: "Controller" },
11
+ { description: "Hub feature options.", hasCapability: ["is_hub"], modelKey: ["all"], name: "Hub" },
12
+ { description: "Access method feature options.", hasCapability: ["is_reader"], modelKey: ["all"], name: "AccessMethod" },
13
+ { description: "Logging feature options.", modelKey: ["all"], name: "Log" }
14
+ ];
15
+ /* eslint-disable @stylistic/max-len */
16
+ // Individual feature options, broken out by category.
17
+ export const featureOptions = {
18
+ // Access method options.
19
+ "AccessMethod": [
20
+ { default: true, description: "Add a switch accessory to control the face unlock access method.", hasCapability: ["identity_face_unlock"], name: "Face" },
21
+ { default: true, description: "Add a switch accessory to control the hand wave unlock access method.", hasCapability: ["hand_wave"], name: "Hand" },
22
+ { default: true, description: "Add a switch accessory to control the mobile unlock access method.", hasCapability: ["mobile_unlock_ver2", "support_mobile_unlock"], name: "Mobile" },
23
+ { default: true, description: "Add a switch accessory to control the NFC card access method.", hasCapability: ["nfc_card_easy_provision"], name: "NFC" },
24
+ { default: true, description: "Add a switch accessory to control the PIN unlock access method.", hasCapability: ["pin_code"], name: "PIN" },
25
+ { default: true, description: "Add a switch accessory to control the QR unlock access method.", hasCapability: ["qr_code"], name: "QR" },
26
+ { default: true, description: "Add a switch accessory to control the Touch Pass access method.", hasCapability: ["support_apple_pass"], name: "TouchPass" }
27
+ ],
28
+ // Controller options.
29
+ "Controller": [
30
+ { default: true, defaultValue: ACCESS_DEVICE_REMOVAL_DELAY_INTERVAL, description: "Delay, in seconds, before removing devices that are no longer detected on the Access controller. By default, devices are added and removed in realtime.", name: "DelayDeviceRemoval" },
31
+ { default: false, description: "Publish all the realtime telemetry received from the Access controller to MQTT.", name: "Publish.Telemetry" }
32
+ ],
33
+ // Device options.
34
+ "Device": [
35
+ { default: true, description: "Make this device available in HomeKit.", name: "" },
36
+ { default: false, description: "Synchronize the UniFi Access name of this device with HomeKit. Synchronization is one-way only, syncing the device name from UniFi Access to HomeKit.", name: "SyncName" }
37
+ ],
38
+ // Hub options.
39
+ "Hub": [
40
+ { default: false, description: "Use a lock accessory instead of a garage door opener accessory for the gate.", modelKey: modelsDefaultGarageDoor, name: "Door.UseLock" },
41
+ { default: false, description: "Use a garage door opener accessory instead of a lock accessory. This is a visual preference only within HomeKit; the underlying lock behavior and feature options remain the same.", modelKey: modelsDefaultLock, name: "Door.UseGarageOpener" },
42
+ { default: false, defaultValue: ACCESS_DEVICE_UNLOCK_INTERVAL, description: "Delay, in minutes, before locking the door lock relay once it's been unlocked by HomeKit. If set to 0, it will remain unlocked indefinitely. This applies regardless of whether you use a lock or garage door opener accessory. By default, the door lock relay will lock five seconds after unlocking.", name: "LockDelayInterval" },
43
+ { default: false, description: "Add a switch accessory to control the door lock relay. This can be useful in automation scenarios where you want to work around HomeKit's security restrictions and trigger events when a lock or unlock event occurs. This works with both lock and garage door opener accessories.", name: "Lock.Trigger" },
44
+ { default: true, description: "Add a doorbell accessory to handle doorbell ring events in HomeKit.", hasCapability: ["door_bell"], name: "Doorbell" },
45
+ { default: false, description: "Add a switch accessory for automation scenarios to reflect (but not trigger) doorbell ring events on an Access doorbell.", hasCapability: ["door_bell"], name: "Doorbell.Trigger" },
46
+ { default: true, description: "Add a contact sensor accessory for the door position sensor.", modelKey: modelsDps, name: "DPS" },
47
+ { default: true, description: "Add a contact sensor accessory for the remote release.", modelKey: modelsRel, name: "REL" },
48
+ { default: true, description: "Add a contact sensor accessory for the request to enter sensor.", modelKey: modelsRen, name: "REN" },
49
+ { default: true, description: "Add a contact sensor accessory for the request to exit sensor.", modelKey: modelsRex, name: "REX" },
50
+ { default: true, description: "Add a lock accessory for the side door (pedestrian gate) on UniFi Access Gate Hub devices.", modelKey: modelsSideDoor, name: "SideDoor" },
51
+ { default: true, description: "Add a contact sensor accessory for the side door position sensor.", group: "SideDoor", modelKey: modelsSideDoor, name: "SideDoor.DPS" },
52
+ { default: false, description: "Add a switch accessory to control the side door lock. This can be useful in automation scenarios where you want to work around HomeKit's security restrictions for controlling locks.", group: "SideDoor", modelKey: modelsSideDoor, name: "SideDoor.Lock.Trigger" }
53
+ ],
54
+ // Logging options.
55
+ "Log": [
56
+ { default: true, description: "Log doorbell ring events in Homebridge.", hasCapability: ["door_bell"], name: "Doorbell" },
57
+ { default: true, description: "Log door position sensor events in Homebridge.", modelKey: modelsDps, name: "DPS" },
58
+ { default: true, description: "Log door remote release events in Homebridge.", modelKey: modelsRel, name: "REL" },
59
+ { default: true, description: "Log door request to enter events in Homebridge.", modelKey: modelsRen, name: "REN" },
60
+ { default: true, description: "Log door request to exit events in Homebridge.", modelKey: modelsRex, name: "REX" },
61
+ { default: true, description: "Log lock events in Homebridge.", hasCapability: ["is_hub"], name: "Lock" }
62
+ ]
63
+ };
64
+ /* eslint-enable @stylistic/max-len */
65
+ //# sourceMappingURL=access-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-options.js","sourceRoot":"","sources":["../src/access-options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { API, DynamicPlatformPlugin, Logging, PlatformAccessory, PlatformConfig } from "homebridge";
2
+ import { type AccessOptions } from "./access-options.js";
3
+ import { FeatureOptions } from "homebridge-plugin-utils";
4
+ export declare class AccessPlatform implements DynamicPlatformPlugin {
5
+ accessories: PlatformAccessory[];
6
+ readonly api: API;
7
+ readonly config: AccessOptions;
8
+ private readonly controllers;
9
+ readonly featureOptions: FeatureOptions;
10
+ readonly log: Logging;
11
+ constructor(log: Logging, config: PlatformConfig | undefined, api: API);
12
+ configureAccessory(accessory: PlatformAccessory): void;
13
+ private launchControllers;
14
+ debug(message: string, ...parameters: unknown[]): void;
15
+ }
@@ -0,0 +1,74 @@
1
+ import { featureOptionCategories, featureOptions } from "./access-options.js";
2
+ import { ACCESS_MQTT_TOPIC } from "./settings.js";
3
+ import { AccessController } from "./access-controller.js";
4
+ import { FeatureOptions } from "homebridge-plugin-utils";
5
+ import util from "node:util";
6
+ export class AccessPlatform {
7
+ accessories;
8
+ api;
9
+ config;
10
+ controllers;
11
+ featureOptions;
12
+ log;
13
+ constructor(log, config, api) {
14
+ this.accessories = [];
15
+ this.api = api;
16
+ this.controllers = [];
17
+ this.featureOptions = new FeatureOptions(featureOptionCategories, featureOptions, config?.options ?? []);
18
+ this.log = log;
19
+ // Plugin options into our config variables.
20
+ this.config = {
21
+ controllers: config?.controllers ?? [],
22
+ debugAll: false,
23
+ options: config?.options ?? [],
24
+ ringDelay: config?.ringDelay ?? 0
25
+ };
26
+ // We need a UniFi Access controller configured to do anything.
27
+ if (!this.config.controllers.length) {
28
+ this.log.info("No UniFi Access controllers have been configured.");
29
+ return;
30
+ }
31
+ // Debugging - most people shouldn't enable this.
32
+ this.debug("Debug logging on. Expect a lot of data.");
33
+ // Loop through each configured controller and instantiate it.
34
+ for (const controllerConfig of this.config.controllers) {
35
+ // We need an address, or there's nothing to do.
36
+ if (!controllerConfig.address) {
37
+ this.log.info("No host or IP address has been configured.");
38
+ continue;
39
+ }
40
+ // We need login credentials or we're skipping this one.
41
+ if (!controllerConfig.username || !controllerConfig.password) {
42
+ this.log.info("No UniFi Access login credentials have been configured.");
43
+ continue;
44
+ }
45
+ // MQTT topic to use.
46
+ controllerConfig.mqttTopic ||= ACCESS_MQTT_TOPIC;
47
+ this.controllers.push(new AccessController(this, controllerConfig));
48
+ }
49
+ // Avoid a prospective race condition by waiting to configure our controllers until Homebridge is done loading all the cached accessories it knows about, and calling
50
+ // configureAccessory() on each.
51
+ api.on("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */, this.launchControllers.bind(this));
52
+ }
53
+ // This gets called when homebridge restores cached accessories at startup. We intentionally avoid doing anything significant here, and save all that logic
54
+ // for device discovery.
55
+ configureAccessory(accessory) {
56
+ // Add this to the accessory array so we can track it.
57
+ this.accessories.push(accessory);
58
+ }
59
+ // Launch our configured controllers once all accessories have been loaded. Once we do, they will sustain themselves.
60
+ launchControllers() {
61
+ // Iterate through all our controllers and startup.
62
+ for (const controller of this.controllers) {
63
+ // Login to the Access controller.
64
+ void controller.login().catch((error) => this.log.error("Access controller login error: %s.", error.message));
65
+ }
66
+ }
67
+ // Utility for debug logging.
68
+ debug(message, ...parameters) {
69
+ if (this.config.debugAll) {
70
+ this.log.info(util.format(message, ...parameters));
71
+ }
72
+ }
73
+ }
74
+ //# sourceMappingURL=access-platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-platform.js","sourceRoot":"","sources":["../src/access-platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export declare enum AccessReservedNames {
2
+ CONTACT_DPS = "ContactSensor.DPS",
3
+ CONTACT_DPS_SIDE = "ContactSensor.DPS.Side",
4
+ CONTACT_REL = "ContactSensor.REL",
5
+ CONTACT_REN = "ContactSensor.REN",
6
+ CONTACT_REX = "ContactSensor.REX",
7
+ LOCK_DOOR_SIDE = "Lock.Door.Side",
8
+ SWITCH_ACCESSMETHOD_FACE = "AccessMethod.Face",
9
+ SWITCH_ACCESSMETHOD_HAND = "AccessMethod.Hand",
10
+ SWITCH_ACCESSMETHOD_MOBILE = "AccessMethod.Mobile",
11
+ SWITCH_ACCESSMETHOD_NFC = "AccessMethod.NFC",
12
+ SWITCH_ACCESSMETHOD_PIN = "AccessMethod.PIN",
13
+ SWITCH_ACCESSMETHOD_QR = "AccessMethod.QR",
14
+ SWITCH_ACCESSMETHOD_TOUCHPASS = "AccessMethod.TouchPass",
15
+ SWITCH_DOORBELL_TRIGGER = "DoorbellTrigger",
16
+ SWITCH_LOCK_DOOR_SIDE_TRIGGER = "Switch.Lock.Door.Side.Trigger",
17
+ SWITCH_LOCK_TRIGGER = "LockTrigger",
18
+ SWITCH_MOTION_SENSOR = "MotionSensorSwitch",
19
+ SWITCH_MOTION_TRIGGER = "MotionSensorTrigger"
20
+ }
21
+ export declare enum AccessEventType {
22
+ DEVICE_DELETE = "access.data.device.delete",
23
+ DEVICE_REMOTE_UNLOCK = "access.data.device.remote_unlock",
24
+ DEVICE_UPDATE = "access.data.device.update",
25
+ DEVICE_UPDATE_V2 = "access.data.v2.device.update",
26
+ DOORBELL_CANCEL = "access.remote_view.change",
27
+ DOORBELL_RING = "access.remote_view",
28
+ LOCATION_DATA_UPDATE = "access.data.location.update",
29
+ LOCATION_UPDATE = "access.data.v2.location.update"
30
+ }
@@ -0,0 +1,42 @@
1
+ /* Copyright(C) 2026, Mickael Palma. All rights reserved.
2
+ *
3
+ * access-types.ts: Interface and type definitions for UniFi Access.
4
+ */
5
+ // HBUA reserved names.
6
+ export var AccessReservedNames;
7
+ (function (AccessReservedNames) {
8
+ // Manage our contact sensor types.
9
+ AccessReservedNames["CONTACT_DPS"] = "ContactSensor.DPS";
10
+ AccessReservedNames["CONTACT_DPS_SIDE"] = "ContactSensor.DPS.Side";
11
+ AccessReservedNames["CONTACT_REL"] = "ContactSensor.REL";
12
+ AccessReservedNames["CONTACT_REN"] = "ContactSensor.REN";
13
+ AccessReservedNames["CONTACT_REX"] = "ContactSensor.REX";
14
+ // Manage our door/lock types.
15
+ AccessReservedNames["LOCK_DOOR_SIDE"] = "Lock.Door.Side";
16
+ // Manage our switch types.
17
+ AccessReservedNames["SWITCH_ACCESSMETHOD_FACE"] = "AccessMethod.Face";
18
+ AccessReservedNames["SWITCH_ACCESSMETHOD_HAND"] = "AccessMethod.Hand";
19
+ AccessReservedNames["SWITCH_ACCESSMETHOD_MOBILE"] = "AccessMethod.Mobile";
20
+ AccessReservedNames["SWITCH_ACCESSMETHOD_NFC"] = "AccessMethod.NFC";
21
+ AccessReservedNames["SWITCH_ACCESSMETHOD_PIN"] = "AccessMethod.PIN";
22
+ AccessReservedNames["SWITCH_ACCESSMETHOD_QR"] = "AccessMethod.QR";
23
+ AccessReservedNames["SWITCH_ACCESSMETHOD_TOUCHPASS"] = "AccessMethod.TouchPass";
24
+ AccessReservedNames["SWITCH_DOORBELL_TRIGGER"] = "DoorbellTrigger";
25
+ AccessReservedNames["SWITCH_LOCK_DOOR_SIDE_TRIGGER"] = "Switch.Lock.Door.Side.Trigger";
26
+ AccessReservedNames["SWITCH_LOCK_TRIGGER"] = "LockTrigger";
27
+ AccessReservedNames["SWITCH_MOTION_SENSOR"] = "MotionSensorSwitch";
28
+ AccessReservedNames["SWITCH_MOTION_TRIGGER"] = "MotionSensorTrigger";
29
+ })(AccessReservedNames || (AccessReservedNames = {}));
30
+ // UniFi Access event type strings from the Access controller API.
31
+ export var AccessEventType;
32
+ (function (AccessEventType) {
33
+ AccessEventType["DEVICE_DELETE"] = "access.data.device.delete";
34
+ AccessEventType["DEVICE_REMOTE_UNLOCK"] = "access.data.device.remote_unlock";
35
+ AccessEventType["DEVICE_UPDATE"] = "access.data.device.update";
36
+ AccessEventType["DEVICE_UPDATE_V2"] = "access.data.v2.device.update";
37
+ AccessEventType["DOORBELL_CANCEL"] = "access.remote_view.change";
38
+ AccessEventType["DOORBELL_RING"] = "access.remote_view";
39
+ AccessEventType["LOCATION_DATA_UPDATE"] = "access.data.location.update";
40
+ AccessEventType["LOCATION_UPDATE"] = "access.data.v2.location.update";
41
+ })(AccessEventType || (AccessEventType = {}));
42
+ //# sourceMappingURL=access-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-types.js","sourceRoot":"","sources":["../src/access-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uBAAuB;AACvB,MAAM,CAAN,IAAY,mBAyBX;AAzBD,WAAY,mBAAmB;IAE7B,mCAAmC;IACnC,wDAAiC,CAAA;IACjC,kEAA2C,CAAA;IAC3C,wDAAiC,CAAA;IACjC,wDAAiC,CAAA;IACjC,wDAAiC,CAAA;IAEjC,8BAA8B;IAC9B,wDAAiC,CAAA;IAEjC,2BAA2B;IAC3B,qEAA8C,CAAA;IAC9C,qEAA8C,CAAA;IAC9C,yEAAkD,CAAA;IAClD,mEAA4C,CAAA;IAC5C,mEAA4C,CAAA;IAC5C,iEAA0C,CAAA;IAC1C,+EAAwD,CAAA;IACxD,kEAA2C,CAAA;IAC3C,sFAA+D,CAAA;IAC/D,0DAAmC,CAAA;IACnC,kEAA2C,CAAA;IAC3C,oEAA6C,CAAA;AAC/C,CAAC,EAzBW,mBAAmB,KAAnB,mBAAmB,QAyB9B;AAED,kEAAkE;AAClE,MAAM,CAAN,IAAY,eAUX;AAVD,WAAY,eAAe;IAEzB,8DAA2C,CAAA;IAC3C,4EAAyD,CAAA;IACzD,8DAA2C,CAAA;IAC3C,oEAAiD,CAAA;IACjD,gEAA6C,CAAA;IAC7C,uDAAoC,CAAA;IACpC,uEAAoD,CAAA;IACpD,qEAAkD,CAAA;AACpD,CAAC,EAVW,eAAe,KAAf,eAAe,QAU1B"}
@@ -0,0 +1,13 @@
1
+ import type { AccessHub } from "./access-hub.js";
2
+ export declare function hubDoorLockCommand(hub: AccessHub, isLocking: boolean, isSideDoor?: boolean): Promise<boolean>;
3
+ export declare function discoverDoorIds(hub: AccessHub): void;
4
+ export declare function initializeDoorsFromBootstrap(hub: AccessHub, doors: {
5
+ unique_id: string;
6
+ name: string;
7
+ door_position_status?: string;
8
+ door_lock_relay_status?: string;
9
+ }[]): void;
10
+ export declare function initializeDoorState(hub: AccessHub, doorData: {
11
+ door_position_status?: string;
12
+ door_lock_relay_status?: string;
13
+ }, isSideDoor: boolean): void;
@@ -0,0 +1,140 @@
1
+ /* Copyright(C) 2026, Mickael Palma. All rights reserved.
2
+ *
3
+ * access-hub-api.ts: Hub API commands and door discovery for the UniFi Access hub.
4
+ */
5
+ import { UGT_SIDE_DOOR_TARGET_NAME } from "../access-device-catalog.js";
6
+ import { AUTO_LOCK_DELAY_MS } from "./access-hub-types.js";
7
+ import { toDpsState, toLockState } from "./access-hub-utils.js";
8
+ // Unified utility function to execute lock and unlock actions on a hub door.
9
+ export async function hubDoorLockCommand(hub, isLocking, isSideDoor = false) {
10
+ const action = isLocking ? "lock" : "unlock";
11
+ const doorName = isSideDoor ? "side door" : (hub.catalog.usesLocationApi ? "gate" : "door");
12
+ const doorId = isSideDoor ? hub.sideDoorLocationId : hub.mainDoorLocationId;
13
+ // Only allow relocking if we are able to do so. UA Gate is exempt since it's a motorized gate that needs to close. For non-UA Gate hubs, the same restriction
14
+ // applies to both Lock and GarageDoorOpener service types since GarageDoorOpener is just a visual convenience for the same underlying lock behavior.
15
+ if ((hub.lockDelayInterval === undefined) && isLocking && !hub.catalog.usesLocationApi) {
16
+ hub.log.error("Unable to manually relock the %s when the lock relay is configured to the default settings.", doorName);
17
+ return false;
18
+ }
19
+ // If we're not online, we're done.
20
+ if (!hub.isOnline) {
21
+ hub.log.error("Unable to %s the %s. Device is offline.", action, doorName);
22
+ return false;
23
+ }
24
+ // For devices using the location API, use the location-based unlock endpoint since the standard device API is not supported.
25
+ if (hub.catalog.usesLocationApi) {
26
+ if (!doorId) {
27
+ hub.log.error("Unable to %s the %s. Door not found.", action, isSideDoor ? "side door" : "gate");
28
+ return false;
29
+ }
30
+ // Execute the action using the location endpoint.
31
+ const endpoint = hub.controller.udaApi.getApiEndpoint("location") + "/" + doorId + "/unlock";
32
+ const response = await hub.controller.udaApi.retrieve(endpoint, {
33
+ body: JSON.stringify({}),
34
+ method: "PUT"
35
+ });
36
+ if (!hub.controller.udaApi.responseOk(response?.statusCode)) {
37
+ hub.log.error("Unable to %s the %s.", action, doorName);
38
+ return false;
39
+ }
40
+ // When unlocking from HomeKit, the controller doesn't send the events to the events API. Manually update the state and schedule the auto-lock.
41
+ if (!isLocking) {
42
+ hub.hkLockState = hub.hap.Characteristic.LockCurrentState.UNSECURED;
43
+ if (isSideDoor) {
44
+ hub.hkSideDoorLockState = hub.hap.Characteristic.LockCurrentState.UNSECURED;
45
+ }
46
+ setTimeout(() => {
47
+ if (isSideDoor) {
48
+ hub.hkSideDoorLockState = hub.hap.Characteristic.LockCurrentState.SECURED;
49
+ }
50
+ else {
51
+ hub.hkLockState = hub.hap.Characteristic.LockCurrentState.SECURED;
52
+ }
53
+ }, AUTO_LOCK_DELAY_MS);
54
+ }
55
+ return true;
56
+ }
57
+ // For hub types other than UA Gate, we use the standard device unlock API. GarageDoorOpener uses the same lock delay interval as Lock service since it's just a
58
+ // visual convenience for the same underlying lock behavior.
59
+ const delayInterval = hub.lockDelayInterval;
60
+ // Execute the action.
61
+ if (!(await hub.controller.udaApi.unlock(hub.uda, (delayInterval === undefined) ? undefined : (isLocking ? 0 : Infinity)))) {
62
+ hub.log.error("Unable to %s.", action);
63
+ return false;
64
+ }
65
+ return true;
66
+ }
67
+ // Discover main and side door location IDs for UA Gate hubs. This allows us to receive remote_unlock events for each door.
68
+ export function discoverDoorIds(hub) {
69
+ const doors = hub.controller.udaApi.doors ?? [];
70
+ if (doors.length === 0) {
71
+ hub.log.warn("No doors found in Access API. Door event handling may not work correctly.");
72
+ return;
73
+ }
74
+ // Get the primary door ID from device config (may be undefined).
75
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
76
+ const primaryDoorId = hub.uda.door?.unique_id;
77
+ // Strategy 1: Use the device's bound door as main door.
78
+ if (primaryDoorId) {
79
+ hub.mainDoorLocationId = primaryDoorId;
80
+ }
81
+ else if (doors.length >= 1) {
82
+ // Strategy 2: Look for a door named like "main", "gate", "portail" (but not side/pedestrian).
83
+ const mainDoor = doors.find(door => /portail|main|gate|principal|entry|front/i.test(door.name) && !/portillon|side|pedestrian|pieton|wicket|back/i.test(door.name));
84
+ // Strategy 3: Use the first door as main door.
85
+ hub.mainDoorLocationId = mainDoor?.unique_id ?? doors[0].unique_id;
86
+ }
87
+ // Find the side door (if enabled).
88
+ if (hub.hints.hasSideDoor) {
89
+ // Strategy 1: Check extensions for oper2 port setting.
90
+ const sideDoorFromExt = hub.uda.extensions?.find(ext => (ext.extension_name === "port_setting") && (ext.target_name === UGT_SIDE_DOOR_TARGET_NAME))?.target_value;
91
+ if (sideDoorFromExt) {
92
+ hub.sideDoorLocationId = sideDoorFromExt;
93
+ }
94
+ else {
95
+ // Strategy 2: Look for a door named like "side", "portillon", "pedestrian".
96
+ const sideDoor = doors.find(door => (door.unique_id !== hub.mainDoorLocationId) && /portillon|side|pedestrian|pieton|wicket|back|secondary/i.test(door.name));
97
+ if (sideDoor) {
98
+ hub.sideDoorLocationId = sideDoor.unique_id;
99
+ }
100
+ else if (doors.length === 2) {
101
+ // Strategy 3: If we have exactly 2 doors, the other one is the side door.
102
+ const otherDoor = doors.find(door => door.unique_id !== hub.mainDoorLocationId);
103
+ hub.sideDoorLocationId = otherDoor?.unique_id;
104
+ }
105
+ }
106
+ }
107
+ // Initialize door states from the already-loaded doors data.
108
+ initializeDoorsFromBootstrap(hub, doors);
109
+ }
110
+ // Initialize door states from the doors data loaded during API bootstrap. This avoids making additional API calls which may fail.
111
+ export function initializeDoorsFromBootstrap(hub, doors) {
112
+ // Find and initialize main door state.
113
+ if (hub.mainDoorLocationId) {
114
+ const mainDoor = doors.find(d => d.unique_id === hub.mainDoorLocationId);
115
+ if (mainDoor) {
116
+ initializeDoorState(hub, mainDoor, false);
117
+ }
118
+ }
119
+ // Find and initialize side door state.
120
+ if (hub.sideDoorLocationId && hub.hints.hasSideDoor) {
121
+ const sideDoor = doors.find(d => d.unique_id === hub.sideDoorLocationId);
122
+ if (sideDoor) {
123
+ initializeDoorState(hub, sideDoor, true);
124
+ }
125
+ }
126
+ }
127
+ // Initialize a single door's state from bootstrap data.
128
+ export function initializeDoorState(hub, doorData, isSideDoor) {
129
+ const newDpsState = toDpsState(hub, (doorData.door_position_status ?? "close"));
130
+ const newLockState = toLockState(hub, (doorData.door_lock_relay_status ?? "lock"));
131
+ if (isSideDoor) {
132
+ hub._hkSideDoorDpsState = newDpsState;
133
+ hub._hkSideDoorLockState = newLockState;
134
+ }
135
+ else {
136
+ hub._hkDpsState = newDpsState;
137
+ hub._hkLockState = newLockState;
138
+ }
139
+ }
140
+ //# sourceMappingURL=access-hub-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-hub-api.js","sourceRoot":"","sources":["../../src/hub/access-hub-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { AccessHub } from "./access-hub.js";
2
+ export declare function registerEventHandlers(hub: AccessHub): void;