From ac106e025b0e994aa1a03e552b7f097366049f6a Mon Sep 17 00:00:00 2001 From: Econet-Controls-Inc Date: Tue, 26 May 2026 11:18:30 -0400 Subject: [PATCH 1/5] Add Econet Bulldog GateLock Matter Edge driver Adds a new Matter Edge driver for the Econet Bulldog GateLock (Vendor ID 0x1568 / Product ID 0x000A). The driver subscribes to: - DoorLock.LockState -> lock capability - DoorLock.DoorState -> contactSensor capability (reed switch via Matter) - PowerSource.BatPercentRemaining -> battery capability - GeneralDiagnostics.ActiveHardwareFaults -> tamperAlert capability (fires "tampered" when kTamperDetected is present in the list, "clear" when it is removed; firmware sets this on a 4-strike keypad brute-force trip and clears it when the lockout expires) - DoorLock.DoorLockAlarm event (legacy fallback for older firmware builds that only emit the event path) Implemented on st.matter.driver so the Matter secure session is established per device. --- drivers/Econet/bulldog-gatelock/README.md | 85 ++++++++ drivers/Econet/bulldog-gatelock/config.yml | 6 + .../Econet/bulldog-gatelock/fingerprints.yml | 7 + .../profiles/gatelock-matter.yml | 18 ++ drivers/Econet/bulldog-gatelock/src/init.lua | 184 ++++++++++++++++++ 5 files changed, 300 insertions(+) create mode 100644 drivers/Econet/bulldog-gatelock/README.md create mode 100644 drivers/Econet/bulldog-gatelock/config.yml create mode 100644 drivers/Econet/bulldog-gatelock/fingerprints.yml create mode 100644 drivers/Econet/bulldog-gatelock/profiles/gatelock-matter.yml create mode 100644 drivers/Econet/bulldog-gatelock/src/init.lua diff --git a/drivers/Econet/bulldog-gatelock/README.md b/drivers/Econet/bulldog-gatelock/README.md new file mode 100644 index 0000000000..d7c7de1c46 --- /dev/null +++ b/drivers/Econet/bulldog-gatelock/README.md @@ -0,0 +1,85 @@ +# Econet GateLock — SmartThings Edge Driver (Matter) + +Custom SmartThings Edge driver for the Econet Bulldog GateLock. Built on the Matter-specific `st.matter.driver` class so the secure Matter session (`matter_channel`) is established per device. + +## Capabilities Exposed + +| SmartThings Capability | Matter Source | What it shows | +|---|---|---| +| **lock** | DoorLock cluster, LockState (attr 0x0000) | Locked / Unlocked / Not Fully Locked | +| **contactSensor** | DoorLock cluster, DoorState (attr 0x0003) | Door Open / Closed (driven by reed switch) | +| **tamperAlert** | DoorLock cluster, DoorLockAlarm event | Tampered when 4-strike PIN limit hit on the keypad | +| **battery** | PowerSource cluster, BatPercentRemaining (attr 0x000C) | 0–100% | +| **firmwareUpdate** | (infrastructure) | Required for Matter device handshake | +| **refresh** | (infrastructure) | Manual re-subscribe from the SmartThings app | + +PIN management and auto-relock configuration are not exposed by this driver. PINs are managed on the lock's keypad in admin mode; auto-relock can be set via Matter's standard cluster from any other Matter controller (or the firmware shell). + +## Reed-switch contact sensor + +The reed switch on GPIO0.28 triggers `sendDoorStateChangeAlarmEvent()` in firmware, which updates the Matter `DoorState` attribute. This driver maps it to the SmartThings **Contact Sensor** tile: +- `DoorClosed (1)` → **closed** +- Anything else → **open** + +## Tamper alert + +When the keypad's 4-strikes-in-20-seconds brute-force protection trips, the firmware: + +1. Adds `kTamperDetected (10)` to `GeneralDiagnostics.ActiveHardwareFaults` on endpoint 0 (also emits the `HardwareFaultChange` event). +2. Fires a legacy `DoorLockAlarm` event with `alarmCode = kWrongCodeEntryLimit (4)` for backwards compatibility. + +The driver subscribes to the `ActiveHardwareFaults` attribute and maps list membership directly to the **tamperAlert** capability — `tampered` while the list contains `10`, `clear` when the firmware removes it (which happens automatically when the lockout window expires). The legacy `DoorLockAlarm` event handler is retained so older firmware builds that only fire the event still surface a `tampered` state. + +## Prerequisites + +- SmartThings Hub with Matter support (v46+ firmware) +- SmartThings CLI (`@smartthings/cli`) +- Personal Access Token from https://account.smartthings.com/tokens (set as `SMARTTHINGS_TOKEN` env var) + +## Build & Deploy + +```bash +cd smartthings-edge-driver +smartthings edge:drivers:package +# Returns a driver ID + +smartthings edge:channels:assign -C +smartthings edge:drivers:install --hub -C +``` + +## Re-deploy after edits + +After every code change: + +```bash +# Package + auto-assign + install +smartthings edge:drivers:package -C --hub + +# If the hub doesn't pick up the new version (cached), force re-install: +smartthings edge:drivers:install --hub -C +``` + +## Live logs + +```bash +smartthings edge:drivers:logcat +``` + +## File structure + +``` +smartthings-edge-driver/ +├── config.yml # Driver metadata +├── fingerprints.yml # Matter vendor 5480 / product 10 match +├── profiles/ +│ └── gatelock-matter.yml # Capability list +├── src/ +│ └── init.lua # Driver code (uses st.matter.driver) +└── README.md +``` + +## Notes + +- The driver MUST use `MatterDriver = require "st.matter.driver"` and instantiate via `MatterDriver(packageKey, driverTable)`. The generic `st.driver` does not establish the Matter secure session and `device:subscribe()` will fail with `matter_channel nil`. +- `subscribed_attributes` is keyed by SmartThings capability ID, with values being arrays of cluster attribute object refs (not raw numeric IDs). +- `subscribed_events` follows the same pattern keyed by capability ID. diff --git a/drivers/Econet/bulldog-gatelock/config.yml b/drivers/Econet/bulldog-gatelock/config.yml new file mode 100644 index 0000000000..d740be2bd9 --- /dev/null +++ b/drivers/Econet/bulldog-gatelock/config.yml @@ -0,0 +1,6 @@ +name: "Econet GateLock Matter" +packageKey: "econet-gatelock-matter" +description: "SmartThings Edge driver for the Econet Bulldog GateLock (Matter). Exposes lock control, door open/close contact sensor, tamper alert, and battery." +permissions: + matter: {} +lifecycle: {} diff --git a/drivers/Econet/bulldog-gatelock/fingerprints.yml b/drivers/Econet/bulldog-gatelock/fingerprints.yml new file mode 100644 index 0000000000..10309ad610 --- /dev/null +++ b/drivers/Econet/bulldog-gatelock/fingerprints.yml @@ -0,0 +1,7 @@ +matterManufacturer: + - id: "econet-gatelock" + deviceProfileName: gatelock-matter + vendorId: 0x1568 # Econet Controls Inc (5480) + productId: 0x000A # 10 (Bulldog GateLock) + deviceTypes: + - id: 0x000A # MA-doorlock diff --git a/drivers/Econet/bulldog-gatelock/profiles/gatelock-matter.yml b/drivers/Econet/bulldog-gatelock/profiles/gatelock-matter.yml new file mode 100644 index 0000000000..e9f038b73e --- /dev/null +++ b/drivers/Econet/bulldog-gatelock/profiles/gatelock-matter.yml @@ -0,0 +1,18 @@ +name: gatelock-matter +components: + - id: main + capabilities: + - id: lock + version: 1 + - id: contactSensor + version: 1 + - id: tamperAlert + version: 1 + - id: battery + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartLock diff --git a/drivers/Econet/bulldog-gatelock/src/init.lua b/drivers/Econet/bulldog-gatelock/src/init.lua new file mode 100644 index 0000000000..e833bdf0af --- /dev/null +++ b/drivers/Econet/bulldog-gatelock/src/init.lua @@ -0,0 +1,184 @@ +-- Econet GateLock Matter Edge Driver. +-- +-- Built on st.matter.driver (NOT the generic st.driver) — this is the +-- Matter-specific driver class that actually attaches the secure +-- matter_channel session to each device. Using the generic Driver class +-- causes "matter_channel nil" because no Matter subsystem hookup happens. + +local MatterDriver = require "st.matter.driver" +local clusters = require "st.matter.clusters" +local capabilities = require "st.capabilities" + +local DoorLock = clusters.DoorLock +local PowerSource = clusters.PowerSource +local GeneralDiagnostics = clusters.GeneralDiagnostics + +local UNLATCHED_STATE = 0x3 +local HARDWARE_FAULT_TAMPER_DETECTED = 10 + +---------------------------------------------------------------------- +-- ATTRIBUTE HANDLERS +---------------------------------------------------------------------- + +local function lock_state_handler(driver, device, ib, response) + local LockState = DoorLock.attributes.LockState + local attr = capabilities.lock.lock + local map = { + [LockState.NOT_FULLY_LOCKED] = attr.not_fully_locked(), + [LockState.LOCKED] = attr.locked(), + [LockState.UNLOCKED] = attr.unlocked(), + [UNLATCHED_STATE] = attr.unlocked(), + } + if ib.data.value ~= nil and map[ib.data.value] then + device:emit_event(map[ib.data.value]) + else + device:emit_event(attr.not_fully_locked()) + end +end + +local function door_state_handler(driver, device, ib, response) + local val = ib.data.value + if val == nil then return end + if val == 1 then + device:emit_event(capabilities.contactSensor.contact.closed()) + else + device:emit_event(capabilities.contactSensor.contact.open()) + end +end + +local function battery_percent_handler(driver, device, ib, response) + if ib.data.value ~= nil then + device:emit_event(capabilities.battery.battery(math.floor(ib.data.value / 2.0 + 0.5))) + end +end + +-- GeneralDiagnostics.ActiveHardwareFaults is a list of HardwareFaultEnum values. +-- Firmware adds kTamperDetected (10) when the keypad 4-strike brute-force +-- limit trips and removes it when the lockout expires. Map list membership +-- directly to the tamperAlert capability so the SmartThings UI tracks the +-- attribute's full lifecycle (detected -> clear) instead of just the alarm +-- event edge. +local function hardware_faults_handler(driver, device, ib, response) + local list = ib.data and ib.data.elements + local tampered = false + if list ~= nil then + for _, entry in ipairs(list) do + if entry.value == HARDWARE_FAULT_TAMPER_DETECTED then + tampered = true + break + end + end + end + if tampered then + device:emit_event(capabilities.tamperAlert.tamper.detected()) + else + device:emit_event(capabilities.tamperAlert.tamper.clear()) + end +end + +---------------------------------------------------------------------- +-- EVENT HANDLERS +---------------------------------------------------------------------- + +-- Retained for compatibility with firmware that only fires the +-- DoorLockAlarm event (older builds without GeneralDiagnostics tamper +-- reporting). On builds that report both, the attribute handler above +-- supersedes this by also clearing the state. +local function door_lock_alarm_handler(driver, device, ib, response) + device:emit_event(capabilities.tamperAlert.tamper.detected()) +end + +---------------------------------------------------------------------- +-- COMMAND HANDLERS +---------------------------------------------------------------------- + +local function handle_lock(driver, device, command) + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.LockDoor(device, ep)) +end + +local function handle_unlock(driver, device, command) + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.UnlockDoor(device, ep)) +end + +local function handle_refresh(driver, device, command) + device:refresh() +end + +---------------------------------------------------------------------- +-- LIFECYCLE +---------------------------------------------------------------------- + +local function device_init(driver, device) + device:subscribe() +end + +local function device_added(driver, device) + device:emit_event(capabilities.tamperAlert.tamper.clear()) +end + +---------------------------------------------------------------------- +-- DRIVER TABLE (passed as 2nd arg to MatterDriver) +---------------------------------------------------------------------- + +local matter_lock_driver = { + lifecycle_handlers = { + init = device_init, + added = device_added, + }, + + matter_handlers = { + attr = { + [DoorLock.ID] = { + [DoorLock.attributes.LockState.ID] = lock_state_handler, + [DoorLock.attributes.DoorState.ID] = door_state_handler, + }, + [PowerSource.ID] = { + [PowerSource.attributes.BatPercentRemaining.ID] = battery_percent_handler, + }, + [GeneralDiagnostics.ID] = { + [GeneralDiagnostics.attributes.ActiveHardwareFaults.ID] = hardware_faults_handler, + }, + }, + event = { + [DoorLock.ID] = { + [DoorLock.events.DoorLockAlarm.ID] = door_lock_alarm_handler, + }, + }, + }, + + subscribed_attributes = { + [capabilities.lock.ID] = { + DoorLock.attributes.LockState, + }, + [capabilities.contactSensor.ID] = { + DoorLock.attributes.DoorState, + }, + [capabilities.battery.ID] = { + PowerSource.attributes.BatPercentRemaining, + }, + [capabilities.tamperAlert.ID] = { + GeneralDiagnostics.attributes.ActiveHardwareFaults, + }, + }, + + subscribed_events = { + [capabilities.tamperAlert.ID] = { + DoorLock.events.DoorLockAlarm, + }, + }, + + capability_handlers = { + [capabilities.lock.ID] = { + [capabilities.lock.commands.lock.NAME] = handle_lock, + [capabilities.lock.commands.unlock.NAME] = handle_unlock, + }, + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = handle_refresh, + }, + }, +} + +local matter_driver = MatterDriver("econet-gatelock-matter", matter_lock_driver) +matter_driver:run() From 08567e1b2175afc941497096eb659f6a8f342fed Mon Sep 17 00:00:00 2001 From: Econet-Controls-Inc Date: Tue, 26 May 2026 11:25:40 -0400 Subject: [PATCH 2/5] Rename driver folder to drivers/EconetControlsInc/ --- drivers/{Econet => EconetControlsInc}/bulldog-gatelock/README.md | 0 drivers/{Econet => EconetControlsInc}/bulldog-gatelock/config.yml | 0 .../bulldog-gatelock/fingerprints.yml | 0 .../bulldog-gatelock/profiles/gatelock-matter.yml | 0 .../{Econet => EconetControlsInc}/bulldog-gatelock/src/init.lua | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename drivers/{Econet => EconetControlsInc}/bulldog-gatelock/README.md (100%) rename drivers/{Econet => EconetControlsInc}/bulldog-gatelock/config.yml (100%) rename drivers/{Econet => EconetControlsInc}/bulldog-gatelock/fingerprints.yml (100%) rename drivers/{Econet => EconetControlsInc}/bulldog-gatelock/profiles/gatelock-matter.yml (100%) rename drivers/{Econet => EconetControlsInc}/bulldog-gatelock/src/init.lua (100%) diff --git a/drivers/Econet/bulldog-gatelock/README.md b/drivers/EconetControlsInc/bulldog-gatelock/README.md similarity index 100% rename from drivers/Econet/bulldog-gatelock/README.md rename to drivers/EconetControlsInc/bulldog-gatelock/README.md diff --git a/drivers/Econet/bulldog-gatelock/config.yml b/drivers/EconetControlsInc/bulldog-gatelock/config.yml similarity index 100% rename from drivers/Econet/bulldog-gatelock/config.yml rename to drivers/EconetControlsInc/bulldog-gatelock/config.yml diff --git a/drivers/Econet/bulldog-gatelock/fingerprints.yml b/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml similarity index 100% rename from drivers/Econet/bulldog-gatelock/fingerprints.yml rename to drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml diff --git a/drivers/Econet/bulldog-gatelock/profiles/gatelock-matter.yml b/drivers/EconetControlsInc/bulldog-gatelock/profiles/gatelock-matter.yml similarity index 100% rename from drivers/Econet/bulldog-gatelock/profiles/gatelock-matter.yml rename to drivers/EconetControlsInc/bulldog-gatelock/profiles/gatelock-matter.yml diff --git a/drivers/Econet/bulldog-gatelock/src/init.lua b/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua similarity index 100% rename from drivers/Econet/bulldog-gatelock/src/init.lua rename to drivers/EconetControlsInc/bulldog-gatelock/src/init.lua From 489bf0ebcbdb06bf560a2560e928923806b80c9e Mon Sep 17 00:00:00 2001 From: Econet-Controls-Inc Date: Tue, 26 May 2026 12:14:26 -0400 Subject: [PATCH 3/5] Sync driver source with working channel-published version - Revert init.lua to drop GeneralDiagnostics.ActiveHardwareFaults subscription that crashed the driver on load - Use the generic profile filename matter-lock-contact-tamper.yml (previous gatelock-matter.yml predated the rename) - Update fingerprints.yml to reference the renamed profile - Restore README tamper-alert section to the DoorLockAlarm event path --- .../bulldog-gatelock/README.md | 7 +--- .../bulldog-gatelock/fingerprints.yml | 2 +- ...ter.yml => matter-lock-contact-tamper.yml} | 2 +- .../bulldog-gatelock/src/init.lua | 42 ++----------------- 4 files changed, 6 insertions(+), 47 deletions(-) rename drivers/EconetControlsInc/bulldog-gatelock/profiles/{gatelock-matter.yml => matter-lock-contact-tamper.yml} (90%) diff --git a/drivers/EconetControlsInc/bulldog-gatelock/README.md b/drivers/EconetControlsInc/bulldog-gatelock/README.md index d7c7de1c46..4b4c81b658 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/README.md +++ b/drivers/EconetControlsInc/bulldog-gatelock/README.md @@ -23,12 +23,7 @@ The reed switch on GPIO0.28 triggers `sendDoorStateChangeAlarmEvent()` in firmwa ## Tamper alert -When the keypad's 4-strikes-in-20-seconds brute-force protection trips, the firmware: - -1. Adds `kTamperDetected (10)` to `GeneralDiagnostics.ActiveHardwareFaults` on endpoint 0 (also emits the `HardwareFaultChange` event). -2. Fires a legacy `DoorLockAlarm` event with `alarmCode = kWrongCodeEntryLimit (4)` for backwards compatibility. - -The driver subscribes to the `ActiveHardwareFaults` attribute and maps list membership directly to the **tamperAlert** capability — `tampered` while the list contains `10`, `clear` when the firmware removes it (which happens automatically when the lockout window expires). The legacy `DoorLockAlarm` event handler is retained so older firmware builds that only fire the event still surface a `tampered` state. +When the keypad's 4-strikes-in-20-seconds brute-force protection trips, the firmware fires a `DoorLockAlarm` event with `alarmCode = kWrongCodeEntryLimit (4)`. The driver maps this to the standard **tamperAlert** capability ("tampered" badge in the app). The state stays `tampered` until the driver re-initializes; on init the driver emits `clear`. ## Prerequisites diff --git a/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml b/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml index 10309ad610..59268bf4fd 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml +++ b/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml @@ -1,6 +1,6 @@ matterManufacturer: - id: "econet-gatelock" - deviceProfileName: gatelock-matter + deviceProfileName: matter-lock-contact-tamper vendorId: 0x1568 # Econet Controls Inc (5480) productId: 0x000A # 10 (Bulldog GateLock) deviceTypes: diff --git a/drivers/EconetControlsInc/bulldog-gatelock/profiles/gatelock-matter.yml b/drivers/EconetControlsInc/bulldog-gatelock/profiles/matter-lock-contact-tamper.yml similarity index 90% rename from drivers/EconetControlsInc/bulldog-gatelock/profiles/gatelock-matter.yml rename to drivers/EconetControlsInc/bulldog-gatelock/profiles/matter-lock-contact-tamper.yml index e9f038b73e..9f07f8c9f6 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/profiles/gatelock-matter.yml +++ b/drivers/EconetControlsInc/bulldog-gatelock/profiles/matter-lock-contact-tamper.yml @@ -1,4 +1,4 @@ -name: gatelock-matter +name: matter-lock-contact-tamper components: - id: main capabilities: diff --git a/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua b/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua index e833bdf0af..7be1c0bcb5 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua +++ b/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua @@ -9,12 +9,10 @@ local MatterDriver = require "st.matter.driver" local clusters = require "st.matter.clusters" local capabilities = require "st.capabilities" -local DoorLock = clusters.DoorLock -local PowerSource = clusters.PowerSource -local GeneralDiagnostics = clusters.GeneralDiagnostics +local DoorLock = clusters.DoorLock +local PowerSource = clusters.PowerSource -local UNLATCHED_STATE = 0x3 -local HARDWARE_FAULT_TAMPER_DETECTED = 10 +local UNLATCHED_STATE = 0x3 ---------------------------------------------------------------------- -- ATTRIBUTE HANDLERS @@ -52,38 +50,10 @@ local function battery_percent_handler(driver, device, ib, response) end end --- GeneralDiagnostics.ActiveHardwareFaults is a list of HardwareFaultEnum values. --- Firmware adds kTamperDetected (10) when the keypad 4-strike brute-force --- limit trips and removes it when the lockout expires. Map list membership --- directly to the tamperAlert capability so the SmartThings UI tracks the --- attribute's full lifecycle (detected -> clear) instead of just the alarm --- event edge. -local function hardware_faults_handler(driver, device, ib, response) - local list = ib.data and ib.data.elements - local tampered = false - if list ~= nil then - for _, entry in ipairs(list) do - if entry.value == HARDWARE_FAULT_TAMPER_DETECTED then - tampered = true - break - end - end - end - if tampered then - device:emit_event(capabilities.tamperAlert.tamper.detected()) - else - device:emit_event(capabilities.tamperAlert.tamper.clear()) - end -end - ---------------------------------------------------------------------- -- EVENT HANDLERS ---------------------------------------------------------------------- --- Retained for compatibility with firmware that only fires the --- DoorLockAlarm event (older builds without GeneralDiagnostics tamper --- reporting). On builds that report both, the attribute handler above --- supersedes this by also clearing the state. local function door_lock_alarm_handler(driver, device, ib, response) device:emit_event(capabilities.tamperAlert.tamper.detected()) end @@ -137,9 +107,6 @@ local matter_lock_driver = { [PowerSource.ID] = { [PowerSource.attributes.BatPercentRemaining.ID] = battery_percent_handler, }, - [GeneralDiagnostics.ID] = { - [GeneralDiagnostics.attributes.ActiveHardwareFaults.ID] = hardware_faults_handler, - }, }, event = { [DoorLock.ID] = { @@ -158,9 +125,6 @@ local matter_lock_driver = { [capabilities.battery.ID] = { PowerSource.attributes.BatPercentRemaining, }, - [capabilities.tamperAlert.ID] = { - GeneralDiagnostics.attributes.ActiveHardwareFaults, - }, }, subscribed_events = { From a143b33dba373716b395fe0ee32406ef9b2b1da6 Mon Sep 17 00:00:00 2001 From: Econet-Controls-Inc Date: Tue, 26 May 2026 12:29:10 -0400 Subject: [PATCH 4/5] driver(tamper): auto-clear tamperAlert 15 s after DoorLockAlarm event --- drivers/EconetControlsInc/bulldog-gatelock/README.md | 2 +- drivers/EconetControlsInc/bulldog-gatelock/src/init.lua | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/EconetControlsInc/bulldog-gatelock/README.md b/drivers/EconetControlsInc/bulldog-gatelock/README.md index 4b4c81b658..8a9a712024 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/README.md +++ b/drivers/EconetControlsInc/bulldog-gatelock/README.md @@ -23,7 +23,7 @@ The reed switch on GPIO0.28 triggers `sendDoorStateChangeAlarmEvent()` in firmwa ## Tamper alert -When the keypad's 4-strikes-in-20-seconds brute-force protection trips, the firmware fires a `DoorLockAlarm` event with `alarmCode = kWrongCodeEntryLimit (4)`. The driver maps this to the standard **tamperAlert** capability ("tampered" badge in the app). The state stays `tampered` until the driver re-initializes; on init the driver emits `clear`. +When the keypad's 4-strikes-in-20-seconds brute-force protection trips, the firmware fires a `DoorLockAlarm` event with `alarmCode = kWrongCodeEntryLimit (4)`. The driver maps this to the standard **tamperAlert** capability ("tampered" badge in the app) and auto-clears the state after 15 seconds, slightly longer than the firmware's ~10-second keypad lockout window. On `device_added` the driver also emits `clear` to ensure a known initial state. ## Prerequisites diff --git a/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua b/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua index 7be1c0bcb5..cb1ffaaf59 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua +++ b/drivers/EconetControlsInc/bulldog-gatelock/src/init.lua @@ -54,8 +54,16 @@ end -- EVENT HANDLERS ---------------------------------------------------------------------- +-- Firmware locks out the keypad for ~10 s on the 4-strike brute-force trip. +-- Auto-clear after 15 s (10 s lockout + 5 s buffer) so SmartThings tracks +-- a real detected->clear transition without waiting for a driver restart. +local TAMPER_CLEAR_DELAY_S = 15 + local function door_lock_alarm_handler(driver, device, ib, response) device:emit_event(capabilities.tamperAlert.tamper.detected()) + device.thread:call_with_delay(TAMPER_CLEAR_DELAY_S, function() + device:emit_event(capabilities.tamperAlert.tamper.clear()) + end) end ---------------------------------------------------------------------- From b1e5dbaa6fe0366ff3f8d0ab32c3b724d581330f Mon Sep 17 00:00:00 2001 From: Econet-Controls-Inc Date: Tue, 26 May 2026 14:10:00 -0400 Subject: [PATCH 5/5] driver(fingerprints): add required deviceLabel field --- drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml b/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml index 59268bf4fd..90a0b32a57 100644 --- a/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml +++ b/drivers/EconetControlsInc/bulldog-gatelock/fingerprints.yml @@ -1,5 +1,6 @@ matterManufacturer: - id: "econet-gatelock" + deviceLabel: Bulldog GateLock deviceProfileName: matter-lock-contact-tamper vendorId: 0x1568 # Econet Controls Inc (5480) productId: 0x000A # 10 (Bulldog GateLock)