Skip to content

WWSTCERT-11482 & WWSTCERT-11485: Add support to frient keypad#2927

Open
marcintyminski wants to merge 24 commits intoSmartThingsCommunity:mainfrom
marcintyminski:add-support-to-frient-keypad
Open

WWSTCERT-11482 & WWSTCERT-11485: Add support to frient keypad#2927
marcintyminski wants to merge 24 commits intoSmartThingsCommunity:mainfrom
marcintyminski:add-support-to-frient-keypad

Conversation

@marcintyminski
Copy link
Copy Markdown
Contributor

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

Summary of Completed Tests

marcintyminski and others added 21 commits February 17, 2026 14:58
Co-authored-by: Copilot <copilot@github.com>
@github-actions
Copy link
Copy Markdown

Duplicate profile check: Passed - no duplicate profiles detected.

@github-actions
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 27, 2026

Test Results

   73 files    507 suites   0s ⏱️
2 805 tests 2 805 ✅ 0 💤 0 ❌
4 693 runs  4 693 ✅ 0 💤 0 ❌

Results for commit 7074611.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 27, 2026

File Coverage
All files 76%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-keypad/src/frient-keypad/init.lua 75%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-keypad/src/frient-keypad/can_handle.lua 83%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-keypad/src/init.lua 94%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/zigbee-keypad/src/lazy_load_subdriver.lua 57%

Minimum allowed coverage is 90%

Generated by 🐒 cobertura-action against 7074611

@KKlimczukS KKlimczukS changed the title Add support to frient keypad WWSTCERT-11482 & WWSTCERT-11485: Add support to frient keypad May 5, 2026
version: 1
categories:
- name: SecurityPanel
preferences:
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.

@marcintyminski Have you considered adding a preference to enable and disable panicAlarm events? (scenario when the keypad is outside)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is added now

Copy link
Copy Markdown
Contributor

@cjswedes cjswedes left a comment

Choose a reason for hiding this comment

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

Even though this isnt explicitly a door lock, it belongs in the zigbee-lock driver. We do not want to create a new driver that will only handle a small number of devices, because it negatively impacts hub memory more than adding devices to an existing driver. Please make this a subdriver of the zigbee-lock driver.

end

local function handle_arm_command(driver, device, zb_rx)
armCommandFromKeypad = true
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.

Using a module level variable to track device state breaks down if there are more than 1 device using the driver. This should probably be a transient (persisted = false) on the device object.

There are also several early returns, where the value would not be unset, leaving the state tracking inconsistent for the device. This can result in commands being blocked indefinitely after one fails.


local function send_panel_status(device, status)
local duration = get_exit_delay_duration(device)
local panel_status = STATUS_TO_PANEL[status] or PanelStatus.PANEL_DISARMED_READY_TO_ARM
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.

This is a little confusing. STATUS_TO_PANEL is defined as

local STATUS_TO_PANEL = {
  armedAway = PanelStatus.ARMED_AWAY,
  armedStay = PanelStatus.ARMED_STAY,
  disarmed = PanelStatus.PANEL_DISARMED_READY_TO_ARM,
  exitDelay = PanelStatus.EXIT_DELAY,
}

But you call send_panel_status with both Unlocked as the status, which default to PANEL_DISARMED_READY_TO_ARM; is that intentional? There are several other possible values that could be fed into send_panel_status that do not have mappings in that constant.

Comment on lines +33 to +75
local SECURITY_STATUS_EVENTS = {
armedAway = SecuritySystem.securitySystemStatus.armedAway,
armedStay = SecuritySystem.securitySystemStatus.armedStay,
disarmed = SecuritySystem.securitySystemStatus.disarmed,
}

local MODE_STATUS_VALUES = {
Locked = "Locked",
Unlocked = "Unlocked",
}

local ARM_MODE_TO_STATUS = {
[ArmMode.DISARM] = "disarmed",
[ArmMode.ARM_DAY_HOME_ZONES_ONLY] = "armedStay",
[ArmMode.ARM_NIGHT_SLEEP_ZONES_ONLY] = "armedStay",
[ArmMode.ARM_ALL_ZONES] = "armedAway",
}

local ARM_MODE_TO_NOTIFICATION = {
[ArmMode.DISARM] = ArmNotification.ALL_ZONES_DISARMED,
[ArmMode.ARM_DAY_HOME_ZONES_ONLY] = ArmNotification.ONLY_DAY_HOME_ZONES_ARMED,
[ArmMode.ARM_NIGHT_SLEEP_ZONES_ONLY] = ArmNotification.ONLY_NIGHT_SLEEP_ZONES_ARMED,
[ArmMode.ARM_ALL_ZONES] = ArmNotification.ALL_ZONES_ARMED,
}

local STATUS_TO_PANEL = {
armedAway = PanelStatus.ARMED_AWAY,
armedStay = PanelStatus.ARMED_STAY,
disarmed = PanelStatus.PANEL_DISARMED_READY_TO_ARM,
exitDelay = PanelStatus.EXIT_DELAY,
}

local STATUS_TO_ACTIVITY = {
armedAway = "armed away",
armedStay = "armed stay",
disarmed = "disarmed",
exitDelay = "exit delay",
}

local LOCK_STATUS_TO_ACTIVITY = {
Locked = "Locked",
Unlocked = "Unlocked",
}
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.

These constants need some explanation and if possible, we should combine them. At the very least, please add a comment explaining what the mappings are used for to help anyone trying to understand all the different status, modes, activities, and notifications and what they mean for the user.

Comment on lines +627 to +628
device:send(device_management.build_bind_request(device, PowerConfiguration.ID, self.environment_info.hub_zigbee_eui))
device:send(PowerConfiguration.attributes.BatteryVoltage:configure_reporting(device, 30, 21600, 1))
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.

Suggested change
device:send(device_management.build_bind_request(device, PowerConfiguration.ID, self.environment_info.hub_zigbee_eui))
device:send(PowerConfiguration.attributes.BatteryVoltage:configure_reporting(device, 30, 21600, 1))
device:configure()

Use the default configuration path to ensure that the default attributes are configured properly and that IASZone is setup properly for this device. I do not see anything in here that will setup the IASZone status attribute reporting or the zone status notifications.

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.

Please clean up commented code in the tests.

end

local function refresh(driver, device)
device:send(PowerConfiguration.attributes.BatteryVoltage:read(device))
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.

Suggested change
device:send(PowerConfiguration.attributes.BatteryVoltage:read(device))
device:refresh()

Use default refresh behavior for the default attributes, and then do extra panel specific stuff.

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.

3 participants