diff --git a/packages/homebridge-ring/README.md b/packages/homebridge-ring/README.md index ac8973ba..3c427fae 100644 --- a/packages/homebridge-ring/README.md +++ b/packages/homebridge-ring/README.md @@ -59,6 +59,7 @@ Only include an optional parameter if you actually need it. Default behavior wit { "alarmOnEntryDelay": true, "beamDurationSeconds": 60, + "blockDisarm": true, "hideDeviceIds": [ "477e4800-fcde-4493-969b-d1a06f683102", "5aaed7a7-06df-4f18-b3af-291c89854d60" @@ -102,6 +103,7 @@ Only include an optional parameter if you actually need it. Default behavior wit | `ffmpegPath` | Uses `ffmpeg-for-homebridge` | A custom path to the `ffmpeg` executable. By default, the static binaries built in [ffmpeg-for-homebridge](https://github.com/oznu/ffmpeg-for-homebridge) will be used. If you prefer to use your own version of ffmpeg, you can pass a complete path, or simply `"ffmpeg"` to use ffmpeg from your `PATH`. | | `debug` | false | Turns on additional logging. In particular, ffmpeg logging. | | `disableLogs` | false | Turns off all logging | +| `blockDisarm` | `false` | If `true`, prevents disarming your Ring Alarm from HomeKit for added security. | ### Cameras diff --git a/packages/homebridge-ring/config.schema.json b/packages/homebridge-ring/config.schema.json index b697724e..0411c6ec 100644 --- a/packages/homebridge-ring/config.schema.json +++ b/packages/homebridge-ring/config.schema.json @@ -21,6 +21,12 @@ "type": "boolean", "description": "If enabled, HomeKit will register a delayed entry event as a triggered alarm. Useful if you want to know as soon as someone opens a door with the alarm armed" }, + "blockDisarm": { + "title": "Block Disarm from HomeKit", + "type": "boolean", + "default": false, + "description": "If enabled, HomeKit disarm requests are ignored and the accessory snaps back without an error." + }, "hideLightGroups": { "title": "Hide Light Groups", "type": "boolean", @@ -153,6 +159,7 @@ "expandable": true, "items": [ "alarmOnEntryDelay", + "blockDisarm", "hideLightGroups", "hideDoorbellSwitch", "hideCameraLight", diff --git a/packages/homebridge-ring/config.ts b/packages/homebridge-ring/config.ts index 4109f42f..670dff7f 100644 --- a/packages/homebridge-ring/config.ts +++ b/packages/homebridge-ring/config.ts @@ -23,6 +23,7 @@ export interface RingPlatformConfig extends RingApiOptions { onlyDeviceTypes?: string[] showPanicButtons?: boolean disableLogs?: boolean + blockDisarm?: boolean // If true, disarming is disabled } export function updateHomebridgeConfig( diff --git a/packages/homebridge-ring/security-panel.ts b/packages/homebridge-ring/security-panel.ts index a19a85db..300b7d86 100644 --- a/packages/homebridge-ring/security-panel.ts +++ b/packages/homebridge-ring/security-panel.ts @@ -133,7 +133,7 @@ export class SecurityPanel extends BaseDeviceAccessory { Characteristic: { SecuritySystemTargetState: State }, } = hap, { location } = this.device, - { nightModeBypassFor } = this.config + { nightModeBypassFor, blockDisarm } = this.config let bypass = false this.targetingNightMode = state === State.NIGHT_ARM @@ -151,6 +151,35 @@ export class SecurityPanel extends BaseDeviceAccessory { } } + // Prevent disarming if blockDisarm is false + if (state === State.DISARM && blockDisarm === true) { + logInfo( + `[Ring Alarm] Disarm attempt from HomeKit blocked (blockDisarm=true) for ${this.device.name}` + ) + const svc = this.getService(hap.Service.SecuritySystem) + const { SecuritySystemTargetState, SecuritySystemCurrentState } = hap.Characteristic + + // Use the *actual* current state for both chars so Home sees no transition pending + const cur = this.getCurrentState(this.device.data) + + const setBoth = (val: any) => { + svc.getCharacteristic(SecuritySystemTargetState).updateValue(val) + svc.getCharacteristic(SecuritySystemCurrentState).updateValue(val) + } + + // 1) immediate snap-back + setBoth(cur) + + // 2) nudge after the set-tx completes on Home’s side + setTimeout(() => setBoth(cur), 200) + + // 3) one last nudge in case the previous gets coalesced by the Home app + setTimeout(() => setBoth(cur), 1000) + + this.targetingNightMode = false + return + } + const bypassContactSensors = bypass ? (await location.getDevices()).filter((device) => { return (