Skip to content

Add econet bulldog gatelock#2998

Open
Econet-Controls-Inc wants to merge 5 commits into
SmartThingsCommunity:mainfrom
Econet-Controls-Inc:add-econet-bulldog-gatelock
Open

Add econet bulldog gatelock#2998
Econet-Controls-Inc wants to merge 5 commits into
SmartThingsCommunity:mainfrom
Econet-Controls-Inc:add-econet-bulldog-gatelock

Conversation

@Econet-Controls-Inc
Copy link
Copy Markdown

Check all that apply

Type of Change

  • WWST Certification Request
    • If this is your first time contributing code:
      • I have reviewed the README.md file
      • I have reviewed the CODE_OF_CONDUCT.md file
      • I have signed the CLA
    • I plan on entering a WWST Certification Request or have entered a request through the WWST Certification console at developer.smartthings.com
  • Bug fix
  • New feature
  • Refactor

Checklist

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have verified my changes by testing with a device or have communicated a plan for testing
  • I am adding new behavior, such as adding a sub-driver, and have added and run new unit tests to cover the new behavior

Description of Change

New Matter Edge driver for the Econet Bulldog GateLock smart door lock
(Vendor ID 0x1568 / Product ID 0x000A, ma_doorlock device type).

Capabilities exposed:

  • lock — DoorLock.LockState
  • contactSensor — DoorLock.DoorState (driven by the lock's reed switch)
  • tamperAlert — GeneralDiagnostics.ActiveHardwareFaults attribute
    (primary, supports both detected and clear states) + DoorLock.DoorLockAlarm
    event (legacy fallback for older firmware builds)
  • battery — PowerSource.BatPercentRemaining
  • firmwareUpdate, refresh

Why a custom driver:
The lock exposes its physical reed switch via the standard DoorLock.DoorState
attribute, which the stock matter-lock driver does not surface as a contact
sensor. Tamper is wired through GeneralDiagnostics so the SmartThings UI
tracks both "tampered" and "clear" states from the attribute lifecycle rather
than just an event edge.

Implemented on st.matter.driver so the Matter secure session attaches per
device.

Summary of Completed Tests

Tested against an Econet Bulldog GateLock running production firmware,
paired to a SmartThings hub (V3) via Matter commissioning over BLE.

  • Pairing: device commissions successfully on first attempt; SmartThings
    app shows "Bulldog GateLock" with correct branding.
  • Lock / Unlock: both commands from the SmartThings app actuate the
    servo and the LockState attribute updates within 1 second; physical lock/
    unlock from the keypad also reflects in the app.
  • Contact sensor: opening and closing the gate (reed switch transition)
    drives the contactSensor tile open/closed in real time.
  • Tamper alert (new GeneralDiagnostics path): entering 3 wrong PINs in
    ~20 s triggers the keypad's 4-strike brute-force lockout; firmware adds
    kTamperDetected (10) to ActiveHardwareFaults; SmartThings tile transitions
    to "tampered". When the lockout expires (~10 s), firmware removes the
    fault and the tile returns to "clear".
  • Tamper alert (legacy event path): confirmed older firmware builds
    that only emit the DoorLockAlarm event still trigger "tampered" via the
    retained event handler.
  • Battery: percentage updates immediately after each lock/unlock.
  • Refresh: pull-to-refresh in the app re-subscribes and re-reads all
    attributes.

No regressions observed in 24 hours of continuous device usage.

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.
- 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
@cbaumler cbaumler requested review from ctowns and hcarter-775 May 28, 2026 14:55
Copy link
Copy Markdown
Contributor

@ctowns ctowns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the documentation, including testing results!

I think this functionality might be better suited as a sub driver within the existing matter-lock driver. Sub drivers allow us to provide device specific overrides to handlers as needed while still being able to inherit the same default behavior as all other devices.

Based on my review of this PR, it looks like the only unique handler for this device would be door_lock_alarm_handler, which has the device-specific TAMPER_CLEAR_DELAY_S for delaying clearing the tamper alert. However, the rest of the handlers look like they are similar to what already exists in our matter-lock driver.

Therefore, these change can be moved to a sub driver where only the device-specific behavior will need to be implemented, and the rest of the functions do not need to be defined since we can just use the existing definitions in the parent driver. Could you move these changes to a sub driver? You would only need to include the handler for the door lock alarm, and the rest of the functionality will be inherited from the parrent driver. So the sub driver would look something like this:

-- 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


----------------------------------------------------------------------
-- 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

----------------------------------------------------------------------
-- DRIVER TABLE  (passed as 2nd arg to MatterDriver)
----------------------------------------------------------------------

local matter_lock_driver = {
  matter_handlers = {
    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,
    },
  },

  subscribed_events = {
    [capabilities.tamperAlert.ID] = {
      DoorLock.events.DoorLockAlarm,
    },
  },
}

local matter_driver = MatterDriver("econet-gatelock", matter_lock_driver)
matter_driver:run()

Let me know if you have any questions!

deviceProfileName: matter-lock-contact-tamper
vendorId: 0x1568 # Econet Controls Inc (5480)
productId: 0x000A # 10 (Bulldog GateLock)
deviceTypes:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deviceTypes are not needed here since we are matching directly on the vendorId and productId, so they can be removed.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ctowns! One quick clarifying question before I refactor:

I noticed your example sub-driver includes
[capabilities.contactSensor.ID] = { DoorLock.attributes.DoorState }
in subscribed_attributes. The Bulldog GateLock exposes the standard
Matter DoorLock.DoorState attribute from a physical reed switch on
the gate frame, and I'd like to keep surfacing it as contactSensor
in the SmartThings app so users can see whether the gate is actually
open or closed (separate from the locked/unlocked).

To make sure I refactor correctly, can you confirm:

  1. Is the existing matter-lock parent driver expected to map
    DoorState -> contactSensor.contact automatically, or should the
    sub-driver include a small handler for that mapping?
  2. Which profile should the fingerprint reference? None of the current
    matter-lock profiles include contactSensor. Should I add a new
    profile (e.g. lock-user-pin-contact-tamper-battery) under
    matter-lock/profiles/, or is there a preferred way to ship a
    contactSensor-capable lock profile?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the existing matter-lock parent driver expected to map
DoorState -> contactSensor.contact automatically, or should the
sub-driver include a small handler for that mapping?

Good question! I hadn't realized the contactSensor handling was unique to this device and I had accidentally removed it from the example above. To answer your question, we are currently working on implementing a capability specifically for handling DoorState, and that implementation would be handled in the parent driver and would not require additional implementation in the sub driver. You can see the proposed capability here! https://developer.smartthings.com/docs/devices/capabilities/proposed#doorState

Let me get back to you on the timeline, but I believe doorState may be a better fit for your use case than the contactSensor capability. Let me know if you have any questions!

Which profile should the fingerprint reference? None of the current
matter-lock profiles include contactSensor. Should I add a new
profile (e.g. lock-user-pin-contact-tamper-battery) under
matter-lock/profiles/, or is there a preferred way to ship a
contactSensor-capable lock profile?

In using the new doorState capability, we would add support for that capability to the various lock-modular profiles, which would allow for all devices (including this one) to support that capability dynamically as needed. This support would be handled by the parent driver, so you wouldn't need to implement any changes to create a new profile for use in the sub driver once the parent driver changes have landed.

So, once the doorState capability support as been added to our parent driver, I think the scope of this sub driver would be limited to the door_lock_alarm_handler functionality above that has special handling just for this device. I believe the doorState handling would be generic enough to use a generic handler in the parent driver once that is available (I will follow up on this).

Let me know if you have any questions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants