From b6c9c65b74997d6b61aaee2cb785aa0e4d4594ff Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Tue, 10 Sep 2024 00:17:37 +0900 Subject: [PATCH 01/20] Add new-matter-lock driver Signed-off-by: Hunsup Jung --- .../profiles/lock-user-pin-schedule.yml | 27 + .../matter-lock/profiles/lock-user-pin.yml | 25 + .../profiles/lock-user-schedule.yml | 25 + .../matter-lock/profiles/lock-user.yml | 23 + .../matter-lock/src/aqara-lock/init.lua | 146 -- drivers/SmartThings/matter-lock/src/init.lua | 17 +- .../matter-lock/src/lock_utils.lua | 8 +- .../matter-lock/src/new-matter-lock/init.lua | 1801 +++++++++++++++++ 8 files changed, 1910 insertions(+), 162 deletions(-) create mode 100644 drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml create mode 100644 drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml create mode 100644 drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml create mode 100644 drivers/SmartThings/matter-lock/profiles/lock-user.yml delete mode 100644 drivers/SmartThings/matter-lock/src/aqara-lock/init.lua create mode 100644 drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml b/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml new file mode 100644 index 0000000000..911476d6a6 --- /dev/null +++ b/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml @@ -0,0 +1,27 @@ +name: lock-user-pin-schedule +components: +- id: main + capabilities: + - id: lock + version: 1 + config: + values: + - key: "lock.value" + enabledValues: + - locked + - unlocked + - not fully locked + - id: lockAlarm + version: 1 + - id: remoteControlStatus + version: 1 + - id: lockUsers + version: 1 + - id: lockCredentials + version: 1 + - id: lockSchedules + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartLock diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml b/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml new file mode 100644 index 0000000000..eb8036c1cd --- /dev/null +++ b/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml @@ -0,0 +1,25 @@ +name: lock-user-pin +components: +- id: main + capabilities: + - id: lock + version: 1 + config: + values: + - key: "lock.value" + enabledValues: + - locked + - unlocked + - not fully locked + - id: lockAlarm + version: 1 + - id: remoteControlStatus + version: 1 + - id: lockUsers + version: 1 + - id: lockCredentials + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartLock diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml b/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml new file mode 100644 index 0000000000..39e51a2523 --- /dev/null +++ b/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml @@ -0,0 +1,25 @@ +name: lock-user-schedule +components: +- id: main + capabilities: + - id: lock + version: 1 + config: + values: + - key: "lock.value" + enabledValues: + - locked + - unlocked + - not fully locked + - id: lockAlarm + version: 1 + - id: remoteControlStatus + version: 1 + - id: lockUsers + version: 1 + - id: lockSchedules + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartLock diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user.yml b/drivers/SmartThings/matter-lock/profiles/lock-user.yml new file mode 100644 index 0000000000..614524266f --- /dev/null +++ b/drivers/SmartThings/matter-lock/profiles/lock-user.yml @@ -0,0 +1,23 @@ +name: lock-user +components: +- id: main + capabilities: + - id: lock + version: 1 + config: + values: + - key: "lock.value" + enabledValues: + - locked + - unlocked + - not fully locked + - id: lockAlarm + version: 1 + - id: remoteControlStatus + version: 1 + - id: lockUsers + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartLock diff --git a/drivers/SmartThings/matter-lock/src/aqara-lock/init.lua b/drivers/SmartThings/matter-lock/src/aqara-lock/init.lua deleted file mode 100644 index 835b41de1a..0000000000 --- a/drivers/SmartThings/matter-lock/src/aqara-lock/init.lua +++ /dev/null @@ -1,146 +0,0 @@ --- Copyright 2024 SmartThings --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. - -local capabilities = require "st.capabilities" -local clusters = require "st.matter.clusters" -local device_lib = require "st.device" - -local DoorLock = clusters.DoorLock -local AQARA_MANUFACTURER_ID = 0x115f - -local function is_aqara_products(opts, driver, device) - if device.network_type == device_lib.NETWORK_TYPE_MATTER and - device.manufacturer_info.vendor_id == AQARA_MANUFACTURER_ID then - return true - end - return false -end - -local function find_default_endpoint(device, cluster) - local res = device.MATTER_DEFAULT_ENDPOINT - local eps = device:get_endpoints(cluster) - table.sort(eps) - for _, v in ipairs(eps) do - if v ~= 0 then --0 is the matter RootNode endpoint - return v - end - end - device.log.warn(string.format("Did not find default endpoint, will use endpoint %d instead", device.MATTER_DEFAULT_ENDPOINT)) - return res -end - -local function component_to_endpoint(device, component_name) - return find_default_endpoint(device, clusters.DoorLock.ID) -end - -local function device_init(driver, device) - device:set_component_to_endpoint_fn(component_to_endpoint) - device:subscribe() - end - -local function device_added(driver, device) - device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) -end - -local function lock_state_handler(driver, device, ib, response) - local LockState = DoorLock.attributes.LockState - local attr = capabilities.lock.lock - local LOCK_STATE = { - [LockState.NOT_FULLY_LOCKED] = attr.not_fully_locked(), - [LockState.LOCKED] = attr.locked(), - [LockState.UNLOCKED] = attr.unlocked(), - } - - if ib.data.value ~= nil then - device:emit_event(LOCK_STATE[ib.data.value]) - else - device:emit_event(LOCK_STATE[LockState.NOT_FULLY_LOCKED]) - end -end - -local function alarm_event_handler(driver, device, ib, response) - local DlAlarmCode = DoorLock.types.DlAlarmCode - local alarm_code = ib.data.elements.alarm_code - if alarm_code.value == DlAlarmCode.LOCK_JAMMED then - device:emit_event(capabilities.lockAlarm.alarm.unableToLockTheDoor({state_change = true})) - elseif alarm_code.value == DlAlarmCode.LOCK_FACTORY_RESET then - device:emit_event(capabilities.lockAlarm.alarm.lockFactoryReset({state_change = true})) - elseif alarm_code.value == DlAlarmCode.WRONG_CODE_ENTRY_LIMIT then - device:emit_event(capabilities.lockAlarm.alarm.attemptsExceeded({state_change = true})) - elseif alarm_code.value == DlAlarmCode.FRONT_ESCEUTCHEON_REMOVED then - device:emit_event(capabilities.lockAlarm.alarm.damaged({state_change = true})) - elseif alarm_code.value == DlAlarmCode.DOOR_FORCED_OPEN then - device:emit_event(capabilities.lockAlarm.alarm.forcedOpeningAttempt({state_change = true})) - end -end - -local function handle_refresh(driver, device, command) - local req = DoorLock.attributes.LockState:read(device) - device:send(req) -end - -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 aqara_lock_handler = { - NAME = "Aqara Lock Handler", - lifecycle_handlers = { - init = device_init, - added = device_added, - }, - matter_handlers = { - attr = { - [DoorLock.ID] = { - [DoorLock.attributes.LockState.ID] = lock_state_handler - }, - }, - event = { - [DoorLock.ID] = { - [DoorLock.events.DoorLockAlarm.ID] = alarm_event_handler - }, - }, - }, - subscribed_attributes = { - [capabilities.lock.ID] = {DoorLock.attributes.LockState} - }, - subscribed_events = { - [capabilities.lockAlarm.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 - }, - }, - supported_capabilities = { - capabilities.lock, - capabilities.lockAlarm - }, - can_handle = is_aqara_products -} - -return aqara_lock_handler - diff --git a/drivers/SmartThings/matter-lock/src/init.lua b/drivers/SmartThings/matter-lock/src/init.lua index 53f75a14c1..a626ab325f 100755 --- a/drivers/SmartThings/matter-lock/src/init.lua +++ b/drivers/SmartThings/matter-lock/src/init.lua @@ -78,7 +78,7 @@ local function lock_state_handler(driver, device, ib, response) local LockState = DoorLock.attributes.LockState local attr = capabilities.lock.lock local LOCK_STATE = { - [LockState.NOT_FULLY_LOCKED] = attr.not_fully_locked(), + [LockState.NOT_FULLY_LOCKED] = attr.unknown(), [LockState.LOCKED] = attr.locked(), [LockState.UNLOCKED] = attr.unlocked(), [UNLATCHED_STATE] = attr.unlocked(), -- Fully unlocked with latch pulled @@ -97,16 +97,6 @@ local function handle_battery_percent_remaining(driver, device, ib, response) end end -local function handle_battery_charge_level(driver, device, ib, response) - if ib.data.value == clusters.PowerSource.types.BatChargeLevelEnum.OK then - device:emit_event(capabilities.batteryLevel.battery.normal()) - elseif ib.data.value == clusters.PowerSource.types.BatChargeLevelEnum.WARNING then - device:emit_event(capabilities.batteryLevel.battery.warning()) - elseif ib.data.value == clusters.PowerSource.types.BatChargeLevelEnum.CRITICAL then - device:emit_event(capabilities.batteryLevel.battery.critical()) - end -end - local function max_pin_code_len_handler(driver, device, ib, response) device:emit_event(capabilities.lockCodes.maxCodeLength(ib.data.value, {visibility = {displayed = false}})) end @@ -583,7 +573,6 @@ local matter_lock_driver = { }, [PowerSource.ID] = { [PowerSource.attributes.BatPercentRemaining.ID] = handle_battery_percent_remaining, - [PowerSource.attributes.BatChargeLevel.ID] = handle_battery_charge_level, }, }, event = { @@ -604,7 +593,6 @@ local matter_lock_driver = { subscribed_attributes = { [capabilities.lock.ID] = {DoorLock.attributes.LockState}, [capabilities.battery.ID] = {PowerSource.attributes.BatPercentRemaining}, - [capabilities.batteryLevel.ID] = {PowerSource.attributes.BatChargeLevel}, }, subscribed_events = { [capabilities.tamperAlert.ID] = {DoorLock.events.DoorLockAlarm, DoorLock.events.LockOperation}, @@ -630,10 +618,9 @@ local matter_lock_driver = { capabilities.lockCodes, capabilities.tamperAlert, capabilities.battery, - capabilities.batteryLevel, }, sub_drivers = { - require("aqara-lock"), + require("new-matter-lock"), }, lifecycle_handlers = {init = device_init, added = device_added}, } diff --git a/drivers/SmartThings/matter-lock/src/lock_utils.lua b/drivers/SmartThings/matter-lock/src/lock_utils.lua index 8bb788d7cc..31f7f6b3f9 100644 --- a/drivers/SmartThings/matter-lock/src/lock_utils.lua +++ b/drivers/SmartThings/matter-lock/src/lock_utils.lua @@ -25,7 +25,13 @@ local lock_utils = { COTA_CODE_NAME = "ST Remote Operation Code", COTA_CRED_INDEX = "cotaCredIndex", NONFUNCTIONAL = "nonFunctional", - COTA_READ_INITIALIZED = "cotaReadInitialized" + COTA_READ_INITIALIZED = "cotaReadInitialized", + BUSY_STATE = "busyState", + COMMAND_NAME = "commandName", + USER_INDEX = "userIndex", + USER_TYPE = "userType", + CRED_INDEX = "credentialIndex", + CRED_DATA = "credentialData" } local capabilities = require "st.capabilities" local json = require "st.json" diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua new file mode 100644 index 0000000000..a253aec0f0 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -0,0 +1,1801 @@ +-- Copyright 2024 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +local device_lib = require "st.device" +local capabilities = require "st.capabilities" +local clusters = require "st.matter.clusters" +local im = require "st.matter.interaction_model" +local lock_utils = require "lock_utils" +local log = require "log" -- needs to remove + +local DoorLock = clusters.DoorLock +local INITIAL_COTA_INDEX = 1 +local ALL_INDEX = 0xFFFE + +local AQARA_MANUFACTURER_ID = 0x115f +local U200_PRODUCT_ID = 0x2802 + +local NEW_MATTER_LOCK_PRODUCTS = { + {0x115f, 0x2802}, -- AQARA, U200 + {0x115f, 0x2801}, -- AQARA, U300 + {0x1533, 0x0001}, -- eufy, Smart Lock E31 + {0x1533, 0x0002}, -- eufy, Smart Lock E30 + {0x1533, 0x0003}, -- eufy, Smart Lock C34 + {0xFFF2, 0x8002}, -- Solity, MT-100C + {0x10E1, 0x2002} -- VDA +} + +local subscribed_attributes = { + [capabilities.lock.ID] = { + DoorLock.attributes.LockState + }, + [capabilities.remoteControlStatus.ID] = { + DoorLock.attributes.OperatingMode + }, + [capabilities.lockUsers.ID] = { + DoorLock.attributes.NumberOfTotalUsersSupported + }, + [capabilities.lockCredentials.ID] = { + DoorLock.attributes.NumberOfPINUsersSupported, + DoorLock.attributes.MaxPINCodeLength, + DoorLock.attributes.MinPINCodeLength, + DoorLock.attributes.RequirePINforRemoteOperation + }, + [capabilities.lockSchedules.ID] = { + DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser, + DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser + } +} + +local subscribed_events = { + [capabilities.lock.ID] = { + DoorLock.events.LockOperation + }, + [capabilities.lockAlarm.ID] = { + DoorLock.events.DoorLockAlarm + }, + [capabilities.lockUser.ID] = { + DoorLock.events.LockUserChange + } +} + +local function is_new_matter_lock_products(opts, driver, device) + if device.network_type ~= device_lib.NETWORK_TYPE_MATTER then + return false + end + for _, p in ipairs(NEW_MATTER_LOCK_PRODUCTS) do + if device.manufacturer_info.vendor_id == p[1] and + device.manufacturer_info.product_id == p[2] then + return true + end + end + return false +end + +local function find_default_endpoint(device, cluster) + local res = device.MATTER_DEFAULT_ENDPOINT + local eps = device:get_endpoints(cluster) + table.sort(eps) + for _, v in ipairs(eps) do + if v ~= 0 then --0 is the matter RootNode endpoint + return v + end + end + device.log.warn(string.format("Did not find default endpoint, will use endpoint %d instead", device.MATTER_DEFAULT_ENDPOINT)) + return res +end + +local function component_to_endpoint(device, component_name) + return find_default_endpoint(device, clusters.DoorLock.ID) +end + +local function device_init(driver, device) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! device_added !!!!!!!!!!!!!")) -- needs to remove + device:set_component_to_endpoint_fn(component_to_endpoint) + device:subscribe() + end + +local function device_added(driver, device) + device:emit_event(capabilities.lockAlarm.alarm.clear({state_change = true})) +end + +local function do_configure(driver, device) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! do_configure !!!!!!!!!!!!!")) -- needs to remove + + local user_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.USER}) + local pin_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.PIN_CREDENTIAL}) + local week_schedule_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.WEEK_DAY_ACCESS_SCHEDULES}) + local year_schedule_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.YEAR_DAY_ACCESS_SCHEDULES}) + + local profile_name = "lock" + if #user_eps > 0 then + profile_name = profile_name .. "-user" + if #pin_eps > 0 then + profile_name = profile_name .. "-pin" + end + if #week_schedule_eps + #year_schedule_eps > 0 then + profile_name = profile_name .. "-schedule" + end + else + profile_name = "base-lock" + end + device.log.info_with({hub_logs=true}, string.format("Updating device profile to %s.", profile_name)) + device:try_update_metadata({profile = profile_name}) +end + +local function info_changed(driver, device, event, args) + for cap_id, attributes in pairs(subscribed_attributes) do + if device:supports_capability_by_id(cap_id) then + for _, attr in ipairs(attributes) do + device:add_subscribed_attribute(attr) + end + end + end + for cap_id, events in pairs(subscribed_events) do + if device:supports_capability_by_id(cap_id) then + for _, e in ipairs(events) do + device:add_subscribed_event(e) + end + end + end + device:subscribe() +end + +-- Matter Handler +---------------- +-- Lock State -- +---------------- +local function lock_state_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! lock_state_handler !!!!!!!!!!!!!")) -- needs to remove + local LockState = DoorLock.attributes.LockState + local attr = capabilities.lock.lock + local LOCK_STATE = { + [LockState.NOT_FULLY_LOCKED] = attr.not_fully_locked(), + [LockState.LOCKED] = attr.locked({visibility = {displayed = false}}), + [LockState.UNLOCKED] = attr.unlocked({visibility = {displayed = false}}), + } + + if ib.data.value ~= nil then + device:emit_event(LOCK_STATE[ib.data.value]) + else + device:emit_event(attr.unknown()) + end +end + +--------------------- +-- Operating Modes -- +--------------------- +local function operating_modes_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! operating_modes_handler!!!!!!!!!!!!!")) -- needs to remove + + local status = capabilities.remoteControlStatus.remoteControlEnabled + local op_type = DoorLock.types.OperatingModeEnum + local opMode_map = { + [op_type.NORMAL] = true, + [op_type.VACATION] = true, + [op_type.PRIVACY] = false, + [op_type.NO_REMOTE_LOCK_UNLOCK] = false, + [op_type.PASSAGE] = false, + } + local result = opMode_map[ib.data.value] + if result == true then + device:emit_event(status("true", {visibility = {displayed = true}})) + device:emit_event(capabilities.lock.supportedLockCommands({"lock", "unlock"}, {visibility = {displayed = false}})) + elseif result == false then + device:emit_event(status("false", {visibility = {displayed = true}})) + device:emit_event(capabilities.lock.supportedLockCommands({}, {visibility = {displayed = false}})) + end +end +------------------------------------- +-- Number Of Total Users Supported -- +------------------------------------- +local function total_users_supported_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! total_users_supported_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + device:emit_event(capabilities.lockUsers.totalUsersSupported(ib.data.value, {visibility = {displayed = false}})) +end + +---------------------------------- +-- Number Of PIN User Supported -- +---------------------------------- +local function pin_users_supported_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! pin_users_supported_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + device:emit_event(capabilities.lockCredentials.pinUsersSupported(ib.data.value, {visibility = {displayed = false}})) +end + +------------------------- +-- Min PIN Code Length -- +------------------------- +local function min_pin_code_len_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! min_pin_code_len_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + device:emit_event(capabilities.lockCredentials.minPinCodeLen(ib.data.value, {visibility = {displayed = false}})) +end + +------------------------- +-- Max PIN Code Length -- +------------------------- +local function max_pin_code_len_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! max_pin_code_len_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + device:emit_event(capabilities.lockCredentials.maxPinCodeLen(ib.data.value, {visibility = {displayed = false}})) +end + +-------------------------------------- +-- Require PIN For Remote Operation -- +-------------------------------------- +--- If a device needs a cota credential this function attempts to set the credential +--- at the index provided. The set_credential_response_handler handles all failures +--- and retries with the appropriate index when necessary. +local function set_cota_credential(device, credential_index) + local eps = device:get_endpoints(DoorLock.ID) + local cota_cred = device:get_field(lock_utils.COTA_CRED) + if cota_cred == nil then + -- Shouldn't happen but defensive to try to figure out if we need the cota cred and set it. + device:send(DoorLock.attributes.RequirePINforRemoteOperation:read(device, #eps > 0 and eps[1] or 1)) + device.thread:call_with_delay(2, function(t) set_cota_credential(device, credential_index) end) + elseif not cota_cred then + device.log.debug("Device does not require PIN for remote operation. Not setting COTA credential") + return + end + + if device:get_field(lock_utils.SET_CREDENTIAL) ~= nil then + device.log.debug("delaying setting COTA credential since a credential is currently being set") + device.thread:call_with_delay(2, function(t) + set_cota_credential(device, credential_index) + end) + return + end + + device:set_field(lock_utils.COTA_CRED_INDEX, credential_index, {persist = true}) + local credential = {credential_type = DoorLock.types.DlCredentialType.PIN, credential_index = credential_index} + -- Set the credential to a code + device:set_field(lock_utils.COMMAND_NAME, "addCredential") + device:set_field(lock_utils.CRED_INDEX, credential_index) + device:set_field(lock_utils.SET_CREDENTIAL, credential_index) + device:set_field(lock_utils.USER_TYPE, "adminMember") + device.log.info(string.format("Attempting to set COTA credential at index %s", credential_index)) + device:send(DoorLock.server.commands.SetCredential( + device, + #eps > 0 and eps[1] or 1, + DoorLock.types.DlDataOperationType.ADD, + credential, + device:get_field(lock_utils.COTA_CRED), + nil, -- nil user_index creates a new user + DoorLock.types.DlUserStatus.OCCUPIED_ENABLED, + DoorLock.types.DlUserType.REMOTE_ONLY_USER + )) +end + +local function generate_cota_cred_for_device(device) + local len = device:get_latest_state("main", capabilities.lockCredentials.ID, capabilities.lockCredentials.maxPinCodeLen.NAME) or 6 + local cred_data = math.floor(math.random() * (10 ^ len)) + cred_data = string.format("%0" .. tostring(len) .. "d", cred_data) + log.info_with({hub_logs=true}, string.format("cota_cred: %s", cred_data)) + device:set_field(lock_utils.COTA_CRED, cred_data, {persist = true}) +end + +local function apply_cota_credentials_if_absent(device) + if not device:get_field(lock_utils.COTA_CRED) then + --Process after all other info blocks have been dispatched to ensure MaxPINCodeLength has been processed + device.thread:call_with_delay(0, function(t) + generate_cota_cred_for_device(device) + -- delay needed to allow test to override the random credential data + device.thread:call_with_delay(0, function(t) + -- Attempt to set cota credential at the lowest index + set_cota_credential(device, INITIAL_COTA_INDEX) + end) + end) + end +end + +local function require_remote_pin_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! require_remote_pin_handler: %s !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + if ib.data.value then + apply_cota_credentials_if_absent(device) + else + device:set_field(lock_utils.COTA_CRED, false, {persist = true}) + end +end + +----------------------------------------------------- +-- Number Of Week Day Schedules Supported Per User -- +----------------------------------------------------- +local function max_week_schedule_of_user_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! max_week_schedule_of_user_handler: %s !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + device:emit_event(capabilities.lockSchedules.weekDaySchedulesPerUser(ib.data.value, {visibility = {displayed = false}})) +end + +----------------------------------------------------- +-- Number Of Year Day Schedules Supported Per User -- +----------------------------------------------------- +local function max_year_schedule_of_user_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! max_year_schedule_of_user_handler: %s !!!!!!!!!!!!!", ib.data.value)) -- needs to remove + device:emit_event(capabilities.lockSchedules.yearDaySchedulesPerUser(ib.data.value, {visibility = {displayed = false}})) +end + +-- Capability Handler +----------------- +-- Lock/Unlock -- +----------------- +local function handle_lock(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_lock !!!!!!!!!!!!!")) -- needs to remove + local ep = device:component_to_endpoint(command.component) + local cota_cred = device:get_field(lock_utils.COTA_CRED) + log.info_with({hub_logs=true}, string.format("cota_cred: %s", cota_cred)) + if cota_cred then + device:send( + DoorLock.server.commands.LockDoor(device, ep, cota_cred) + ) + else + device:send(DoorLock.server.commands.LockDoor(device, ep)) + end +end + +local function handle_unlock(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_unlock !!!!!!!!!!!!!")) -- needs to remove + local ep = device:component_to_endpoint(command.component) + local cota_cred = device:get_field(lock_utils.COTA_CRED) + log.info_with({hub_logs=true}, string.format("cota_cred: %s", cota_cred)) -- needs to remove + if cota_cred then + device:send( + DoorLock.server.commands.UnlockDoor(device, ep, cota_cred) + ) + else + device:send(DoorLock.server.commands.UnlockDoor(device, ep)) + end +end + +---------------- +-- User Table -- +---------------- +local function add_user_to_table(device, userIdx, usrType) + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_user_to_table !!!!!!!!!!!!!")) + log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("usrType: %s", usrType)) + + -- Get latest user table + local user_table = device:get_latest_state( + "main", + capabilities.lockUsers.ID, + capabilities.lockUsers.users.NAME + ) or {} + local new_user_table = {} + + -- Recreate user table + for index, entry in pairs(user_table) do + table.insert(new_user_table, entry) + end + + -- Add new entry to table + table.insert(new_user_table, {userIndex = userIdx, userType = usrType}) + device:emit_event(capabilities.lockUsers.users(new_user_table, {visibility = {displayed = false}})) +end + +local function update_user_in_table(device, userIdx, usrType) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! update_user_in_table !!!!!!!!!!!!!")) -- needs to remove + + -- Get latest user table + local user_table = device:get_latest_state( + "main", + capabilities.lockUsers.ID, + capabilities.lockUsers.users.NAME + ) or {} + local new_user_table = {} + + -- Recreate user table + local i = 0 + for index, entry in pairs(user_table) do + if entry.userIndex == userIdx then + i = index + end + table.insert(new_user_table, entry) + end + + -- Update user entry + if i ~= 0 then + new_user_table[i].userType = usrType + device:emit_event(capabilities.lockUsers.users(new_user_table, {visibility = {displayed = false}})) + end +end + +local function delete_user_from_table(device, userIdx) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_user_from_table !!!!!!!!!!!!!")) -- needs to remove + -- If User Index is ALL_INDEX, remove all entry from the table + if userIdx == ALL_INDEX then + device:emit_event(capabilities.lockUsers.users({}, {visibility = {displayed = false}})) + return + end + + -- Get latest user table + local user_table = device:get_latest_state( + "main", + capabilities.lockUsers.ID, + capabilities.lockUsers.users.NAME + ) or {} + local new_user_table = {} + + -- Recreate user table + for index, entry in pairs(user_table) do + if entry.userIndex ~= userIdx then + table.insert(new_user_table, entry) + end + end + device:emit_event(capabilities.lockUsers.users(new_user_table, {visibility = {displayed = false}})) +end + +---------------------- +-- Credential Table -- +---------------------- +local function add_credential_to_table(device, userIdx, credIdx, credType) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_credential_to_table !!!!!!!!!!!!!")) -- needs to remove + + -- Get latest credential table + local cred_table = device:get_latest_state( + "main", + capabilities.lockCredentials.ID, + capabilities.lockCredentials.credentials.NAME + ) or {} + local new_cred_table = {} + + -- Recreat credential table + for index, entry in pairs(cred_table) do + table.insert(new_cred_table, entry) + end + + -- Add new entry to table + table.insert(new_cred_table, {userIndex = userIdx, credentialIndex = credIdx, credentialType = credType}) + device:emit_event(capabilities.lockCredentials.credentials(new_cred_table, {visibility = {displayed = false}})) +end + +local function delete_credential_from_table(device, credIdx) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_credential_from_table !!!!!!!!!!!!!")) -- needs to remove + -- If Credential Index is ALL_INDEX, remove all entry from the table + if credIdx == ALL_INDEX then + device:emit_event(capabilities.lockCredentials.credentials({})) + end + + -- Get latest credential table + local cred_table = device:get_latest_state( + "main", + capabilities.lockCredentials.ID, + capabilities.lockCredentials.credentials.NAME + ) or {} + local new_cred_table = {} + + -- Recreate credential table + local userIdx = 0 + local i = 0 + for index, entry in pairs(cred_table) do + if entry.credentialIndex ~= credIdx then + table.insert(new_cred_table, entry) + else + userIdx = entry.userIndex + end + end + + device:emit_event(capabilities.lockCredentials.credentials(new_cred_table, {visibility = {displayed = false}})) + return userIdx +end + +local function delete_credential_from_table_as_user(device, userIdx) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_credential_from_table_as_user !!!!!!!!!!!!!")) -- needs to remove + -- If User Index is ALL_INDEX, remove all entry from the table + if userIdx == ALL_INDEX then + device:emit_event(capabilities.lockCredentials.credentials({}, {visibility = {displayed = false}})) + end + + -- Get latest credential table + local cred_table = device:get_latest_state( + "main", + capabilities.lockCredentials.ID, + capabilities.lockCredentials.credentials.NAME + ) or {} + local new_cred_table = {} + + -- Recreate credential table + local i = 0 + for index, entry in pairs(cred_table) do + if entry.userIndex ~= userIdx then + table.insert(new_cred_table, entry) + end + end + + device:emit_event(capabilities.lockCredentials.credentials(new_cred_table, {visibility = {displayed = false}})) +end + +----------------------------- +-- Week Day Schedule Table -- +----------------------------- +local WEEK_DAY_MAP = { + ["Sunday"] = 1, + ["Monday"] = 2, + ["Tuesday"] = 4, + ["Wednesday"] = 8, + ["Thursday"] = 16, + ["Friday"] = 32, + ["Saturday"] = 64, +} + +local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_week_schedule_to_table !!!!!!!!!!!!!")) -- needs to remove + + -- Get latest week day schedule table + local week_schedule_table = device:get_latest_state( + "main", + capabilities.lockSchedules.ID, + capabilities.lockSchedules.weekDaySchedules.NAME + ) or {} + local new_week_schedule_table = {} + + -- Find shcedule list + local i = 0 + for index, entry in pairs(week_schedule_table) do + if entry.userIndex == userIdx then + i = index + end + table.insert(new_week_schedule_table, entry) + end + + -- Recreate weekDays list + local weekDayList = {} + for _, weekday in ipairs(schedule.weekDays) do + table.insert(weekDayList, weekday) + log.info_with({hub_logs=true}, string.format("weekDay: %s", weekday)) -- needs to remove + end + + if i ~= 0 then -- Add schedule for existing user + local new_schedule_table = {} + for index, entry in pairs(new_week_schedule_table[i].schedules) do + if entry.scheduleIndex == scheduleIdx then + return + end + table.insert(new_schedule_table, entry) + end + + table.insert( + new_schedule_table, + { + scheduleIndex = scheduleIdx, + weekdays = weekDayList, + startHour = schedule.startHour, + startMinute = schedule.startMinute, + endHour = schedule.endHour, + endMinute = schedule.endMinute + } + ) + + new_week_schedule_table[i].schedules = new_schedule_table + else -- Add schedule for new user + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_week_schedule_to_table 2!!!!!!!!!!!!!")) -- needs to remove + table.insert( + new_week_schedule_table, + { + userIndex = userIdx, + schedules = {{ + scheduleIndex = scheduleIdx, + weekdays = weekDayList, + startHour = schedule.startHour, + startMinute = schedule.startMinute, + endHour = schedule.endHour, + endMinute = schedule.endMinute + }} + } + ) + end + + device:emit_event(capabilities.lockSchedules.weekDaySchedules(new_week_schedule_table, {visibility = {displayed = false}})) +end + +local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_week_schedule_to_table !!!!!!!!!!!!!")) -- needs to remove + + -- Get latest week day schedule table + local week_schedule_table = device:get_latest_state( + "main", + capabilities.lockSchedules.ID, + capabilities.lockSchedules.weekDaySchedules.NAME + ) or {} + local new_week_schedule_table = {} + + -- Find shcedule list + local i = 0 + for index, entry in pairs(week_schedule_table) do + if entry.userIndex == userIdx then + i = index + end + table.insert(new_week_schedule_table, entry) + end + + -- When there is no userIndex in the table + if i == 0 then + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! No userIndex in Week Day Schedule Table !!!!!!!!!!!!!", i)) -- needs to remove + return + end + + -- Recreate schedule table for the user + local new_schedule_table = {} + for index, entry in pairs(new_week_schedule_table[i].schedules) do + if entry.scheduleIndex ~= scheduleIdx then + table.insert(new_schedule_table, entry) + end + end + + -- If user has no schedule, remove user from the table + if #new_schedule_table == 0 then + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! No schedule for User !!!!!!!!!!!!!", i)) -- needs to remove + table.remove(new_week_schedule_table, i) + else + new_week_schedule_table[i].schedules = new_schedule_table + end + + device:emit_event(capabilities.lockSchedules.weekDaySchedules(new_week_schedule_table, {visibility = {displayed = false}})) +end + +-------------- +-- Add User -- +-------------- +local function handle_add_user(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_add_user !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "addUser" + local userName = command.args.userName + local userType = command.args.lockUserType + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then + userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER + end + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + -- device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userName: %s", userName)) + log.info_with({hub_logs=true}, string.format("userType: %s", userType)) + log.info_with({hub_logs=true}, string.format("userTypeMatter: %s", userTypeMatter)) + + -- Send command + device:send( + DoorLock.server.commands.SetUser( + device, ep, + DoorLock.types.DlDataOperationType.ADD, -- Operation Type: Add(0), Modify(2) + userName, -- User Name + nil, -- Unique ID + nil, -- User Status + userTypeMatter, -- User Type + nil -- Credential Rule + ) + ) +end + +----------------- +-- Update User -- +----------------- +local function handle_update_user(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_update_user !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "updateUser" + local userIdx = command.args.userIndex + local userName = command.args.userName + local userType = command.args.lockUserType + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then + userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER + end + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("userName: %s", userName)) + log.info_with({hub_logs=true}, string.format("userType: %s", userType)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send( + DoorLock.server.commands.SetUser( + device, ep, + DoorLock.types.DlDataOperationType.MODIFY, -- Operation Type: Add(0), Modify(2) + userIdx, -- User Index + userName, -- User Name + nil, -- Unique ID + nil, -- User Status + userTypeMatter, -- User Type + nil -- Credential Rule + ) + ) +end + +----------------------- +-- Set User Response -- +----------------------- +local function set_user_response_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! set_user_response_handler !!!!!!!!!!!!!")) -- needs to remove + + -- Get result + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local userIdx = device:get_field(lock_utils.USER_INDEX) + local userType = device:get_field(lock_utils.USER_TYPE) + local status = "success" + if ib.status == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif ib.status == DoorLock.types.DlStatus.OCCUPIED then + status = "occupied" + elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + end + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("userType: %s", userType)) + log.info_with({hub_logs=true}, string.format("status: %s", status)) + + -- Update User in table + if status == "success" then + if cmdName == "addUser" then + add_user_to_table(device, userIdx, userType) + elseif cmdName == "updateUser" then + update_user_in_table(device, userIdx, userType) + end + end + + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + statusCode = status + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) +end + +----------------- +-- Delete User -- +----------------- +local function handle_delete_user(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_user !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "deleteUser" + local userIdx = command.args.userIndex + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.ClearUser(device, ep, userIdx)) +end + +---------------------- +-- Delete All Users -- +---------------------- +local function handle_delete_all_users(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_all_users !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "deleteAllUsers" + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, ALL_INDEX, {persist = true}) + + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) -- needs to remove + + -- Send command + device:send(DoorLock.server.commands.ClearUser(device, ep, ALL_INDEX)) +end + +------------------------- +-- Clear User Response -- +------------------------- +local function clear_user_response_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! clear_user_response_handler !!!!!!!!!!!!!")) -- needs to remove + + -- Get result + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local userIdx = device:get_field(lock_utils.USER_INDEX) + local status = "success" + if ib.status == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + end + + -- Delete User and Credential from table + if status == "success" then + delete_user_from_table(device, userIdx) + delete_credential_from_table_as_user(device, userIdx) + end + + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + statusCode = status + } + local event = capabilities.lockUsers.commandResult( + result, + { + + visibility = {displayed = false} + }) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) +end + +-------------------- +-- Add Credential -- +-------------------- +local function handle_add_credential(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_add_credential !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "addCredential" + local userIdx = command.args.userIndex + if userIdx == 0 then + userIdx = nil + end + local userType = command.args.userType + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then + userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER + end + local credential = { + credential_type = DoorLock.types.CredentialTypeEnum.PIN, + credential_index = INITIAL_COTA_INDEX + } + local credData = command.args.credentialData + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) + device:set_field(lock_utils.CRED_INDEX, INITIAL_COTA_INDEX, {persist = true}) + device:set_field(lock_utils.CRED_DATA, credData, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("userType: %s", userType)) + log.info_with({hub_logs=true}, string.format("credIndex: %s", INITIAL_COTA_INDEX)) + log.info_with({hub_logs=true}, string.format("credData: %s", credData)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send( + DoorLock.server.commands.SetCredential( + device, ep, + DoorLock.types.DlDataOperationType.ADD, -- Data Operation Type: Add(0), Modify(2) + credential, -- Credential + credData, -- Credential Data + userIdx, -- User Index + nil, -- User Status + userTypeMatter -- User Type + ) + ) +end + +----------------------- +-- Update Credential -- +----------------------- +local function handle_update_credential(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_update_credential !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "updateCredential" + local userIdx = command.args.userIndex + local credIdx = command.args.credentialIndex + local credential = { + credential_type = DoorLock.types.CredentialTypeEnum.PIN, + credential_index = credIdx + } + local credData = command.args.credentialData + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("credentialIndex: %s", credIdx)) + log.info_with({hub_logs=true}, string.format("credData: %s", credData)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send( + DoorLock.server.commands.SetCredential( + device, ep, + DoorLock.types.DlDataOperationType.MODIFY, -- Data Operation Type: Add(0), Modify(2) + credential, -- Credential + credData, -- Credential Data + userIdx, -- User Index + nil, -- User Status + nil -- User Type + ) + ) +end + +----------------------------- +-- Set Credential Response -- +----------------------------- +local function set_credential_response_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! set_credential_response_handler !!!!!!!!!!!!!")) -- needs to remove + + if ib.status ~= im.InteractionResponse.Status.SUCCESS then + device.log.error("Failed to set credential for device") + return + end + + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local userIdx = device:get_field(lock_utils.USER_INDEX) + local credIdx = device:get_field(lock_utils.CRED_INDEX) + local status = "success" + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("cmdName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("credIdx: %s", credIdx)) + + local elements = ib.info_block.data.elements + if elements.status.value == DoorLock.types.DlStatus.SUCCESS then + -- If user is added also, update User table + if userIdx == nil then + local userType = device:get_field(lock_utils.USER_TYPE) + add_user_to_table(device, elements.user_index.value, userType) + end + + -- Update Credential table + userIdx = elements.user_index.value + if cmdName == "addCredential" then + add_credential_to_table(device, userIdx, credIdx, "pin") + end + + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + credentialIndex = credIdx, + statusCode = status + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + return + end + + -- @field public byte_length number 1 + -- @field public SUCCESS number 0 + -- @field public FAILURE number 1 + -- @field public DUPLICATE number 2 + -- @field public OCCUPIED number 3 + -- @field public INVALID_FIELD number 133 + -- @field public RESOURCE_EXHAUSTED number 137 + -- @field public NOT_FOUND number 139 + + -- Update commandResult + status = "occupied" + if elements.status.value == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif elements.status.value == DoorLock.types.DlStatus.DUPLICATE then + status = "duplicate" + elseif elements.status.value == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + elseif elements.status.value == DoorLock.types.DlStatus.RESOURCE_EXHAUSTED then + status = "resourceExhausted" + elseif elements.status.value == DoorLock.types.DlStatus.NOT_FOUND then + status = "failure" + end + log.info_with({hub_logs=true}, string.format("Result: %s", status)) -- needs to remove + + if status ~= "occupied" then + local result = { + commandName = cmdName, + statusCode = status + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + return + end + + if elements.next_credential_index.value ~= nil then + -- Get parameters + local credIdx = elements.next_credential_index.value + local credential = { + credential_type = DoorLock.types.DlCredentialType.PIN, + credential_index = credIdx, + } + local credData = device:get_field(lock_utils.CRED_DATA) + local userIdx = device:get_field(lock_utils.USER_INDEX) + local userType = device:get_field(lock_utils.USER_TYPE) + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then + userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER + end + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("credentialIndex: %s", credIdx)) + log.info_with({hub_logs=true}, string.format("credData: %s", credData)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("userType: %s", userType)) + + device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) + + -- Sned command + local ep = find_default_endpoint(device, DoorLock.ID) + device:send( + DoorLock.server.commands.SetCredential( + device, ep, + DoorLock.types.DlDataOperationType.ADD, -- Data Operation Type: Add(0), Modify(2) + credential, -- Credential + credData, -- Credential Data + userIdx, -- User Index + nil, -- User Status + userTypeMatter -- User Type + ) + ) + else + local result = { + commandName = cmdName, + statusCode = "resourceExhausted" -- No more available credential index + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + end +end + +----------------------- +-- Delete Credential -- +----------------------- +local function handle_delete_credential(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_credential !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "deleteCredential" + local credIdx = command.args.credentialIndex + local credential = { + credential_type = DoorLock.types.DlCredentialType.PIN, + credential_index = credIdx, + } + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("credentialIndex: %s", credIdx)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.ClearCredential(device, ep, credential)) +end + +---------------------------- +-- Delete All Credentials -- +---------------------------- +local function handle_delete_all_credentials(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_all_credentials !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "deleteAllCredentials" + local credential = { + credential_type = DoorLock.types.DlCredentialType.PIN, + credential_index = ALL_INDEX, + } + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.CRED_INDEX, ALL_INDEX, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("credentialIndex: %s", ALL_INDEX)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.ClearUser(device, ep, credential)) +end + +------------------------------- +-- Clear Credential Response -- +------------------------------- +local function clear_credential_response_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! clear_credential_response_handler !!!!!!!!!!!!!")) -- needs to remove + + -- Get result + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local credIdx = device:get_field(lock_utils.CRED_INDEX) + local status = "success" + if ib.status == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + end + + -- Delete User in table + local userIdx = 0 + if status == "success" then + userIdx = delete_credential_from_table(device, credIdx) + end + + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + credentialIndex = credIdx, + statusCode = status + } + local event = capabilities.lockCredentials.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) +end + +--------------------------- +-- Set Week Day Schedule -- +--------------------------- +local function handle_set_week_day_schedule(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_set_week_day_schedule !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "setWeekDaySchedule" + local scheduleIdx = command.args.scheduleIndex + local userIdx = command.args.userIndex + local schedule = command.args.schedule + local scheduleBit = 0 + for _, weekDay in ipairs(schedule.weekDays) do + scheduleBit = scheduleBit + WEEK_DAY_MAP[weekDay] + log.info_with({hub_logs=true}, string.format("%s, %s", WEEK_DAY_MAP[weekDay], weekDay)) -- needs to remove + end + local startHour = schedule.startHour + local startMinute = schedule.startMinute + local endHour = schedule.endHour + local endMinute = schedule.endMinute + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockSchedules.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) + device:set_field(lock_utils.SCHEDULE, schedule, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("scheduleIndex: %s", scheduleIdx)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("weekDay[1]: %s", schedule.weekDays[1])) + log.info_with({hub_logs=true}, string.format("weekDay[2]: %s", schedule.weekDays[2])) + log.info_with({hub_logs=true}, string.format("weekDay[3]: %s", schedule.weekDays[3])) + log.info_with({hub_logs=true}, string.format("weekDay[4]: %s", schedule.weekDays[4])) + log.info_with({hub_logs=true}, string.format("weekDay[5]: %s", schedule.weekDays[5])) + log.info_with({hub_logs=true}, string.format("weekDay[6]: %s", schedule.weekDays[6])) + log.info_with({hub_logs=true}, string.format("weekDay[7]: %s", schedule.weekDays[7])) + log.info_with({hub_logs=true}, string.format("scheduleBit: %s", scheduleBit)) + log.info_with({hub_logs=true}, string.format("startHour: %s", startHour)) + log.info_with({hub_logs=true}, string.format("startMinute: %s", startMinute)) + log.info_with({hub_logs=true}, string.format("endHour: %s", endHour)) + log.info_with({hub_logs=true}, string.format("endMinute: %s", endMinute)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send( + DoorLock.server.commands.SetWeekDaySchedule( + device, ep, + scheduleIdx, -- Week Day Schedule Index + userIdx, -- User Index + scheduleBit, -- Days Mask + startHour, -- Start Hour + startMinute, -- Start Minute + endHour, -- End Hour + endMinute -- End Minute + ) + ) +end + +------------------------------------ +-- Set Week Day Schedule Response -- +------------------------------------ +local function set_week_day_schedule_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! set_week_day_schedule_handler !!!!!!!!!!!!!")) -- needs to remove + + -- Get result + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local userIdx = device:get_field(lock_utils.USER_INDEX) + local scheduleIdx = device:get_field(lock_utils.SCHEDULE_INDEX) + local schedule = device:get_field(lock_utils.SCHEDULE) + local status = "success" + if ib.status == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + end + + -- Add Week Day Schedule to table + if status == "success" then + add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule) + end + + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + scheduleIndex = scheduleIdx, + statusCode = status + } + local event = capabilities.lockSchedules.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) +end + +----------------------------- +-- Clear Week Day Schedule -- +----------------------------- +local function handle_clear_week_day_schedule(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_clear_week_day_schedule !!!!!!!!!!!!!")) -- needs to remove + + -- Get parameters + local cmdName = "clearWeekDaySchedule" + local scheduleIdx = command.args.scheduleIndex + local userIdx = command.args.userIndex + + -- Check busy state + local busy = device:get_field(lock_utils.BUSY_STATE) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockSchedules.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) + log.info_with({hub_logs=true}, string.format("scheduleIndex: %s", scheduleIdx)) + log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) + + -- Send command + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.ClearWeekDaySchedule(device, ep, scheduleIdx, userIdx)) +end + +------------------------------------ +-- Clear Week Day Schedule Response -- +------------------------------------ +local function clear_week_day_schedule_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! clear_week_day_schedule_handler !!!!!!!!!!!!!")) -- needs to remove + + -- Get result + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local scheduleIdx = device:get_field(lock_utils.SCHEDULE_INDEX) + local userIdx = device:get_field(lock_utils.USER_INDEX) + local status = "success" + if ib.status == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + end + + -- Delete Week Day Schedule to table + if status == "success" then + delete_week_schedule_to_table(device, userIdx, scheduleIdx) + end + + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + scheduleIndex = scheduleIdx, + statusCode = status + } + local event = capabilities.lockSchedules.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) +end + +--------------------------- +-- Set Year Day Schedule -- +--------------------------- +local function handle_set_year_day_schedule(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_set_year_day_schedule !!!!!!!!!!!!!")) -- needs to remove +end + +----------------------------- +-- Clear Year Day Schedule -- +----------------------------- +local function handle_clear_year_day_schedule(driver, device, command) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_clear_year_day_schedule !!!!!!!!!!!!!")) -- needs to remove +end + +---------------- +-- Lock Alarm -- +---------------- +local function alarm_event_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! alarm_event_handler !!!!!!!!!!!!!")) -- needs to remove + local DlAlarmCode = DoorLock.types.DlAlarmCode + local alarm_code = ib.data.elements.alarm_code + if alarm_code.value == DlAlarmCode.LOCK_JAMMED then + device:emit_event(capabilities.lockAlarm.alarm.unableToLockTheDoor({state_change = true})) + elseif alarm_code.value == DlAlarmCode.LOCK_FACTORY_RESET then + device:emit_event(capabilities.lockAlarm.alarm.lockFactoryReset({state_change = true})) + elseif alarm_code.value == DlAlarmCode.WRONG_CODE_ENTRY_LIMIT then + device:emit_event(capabilities.lockAlarm.alarm.attemptsExceeded({state_change = true})) + elseif alarm_code.value == DlAlarmCode.FRONT_ESCEUTCHEON_REMOVED then + device:emit_event(capabilities.lockAlarm.alarm.damaged({state_change = true})) + elseif alarm_code.value == DlAlarmCode.DOOR_FORCED_OPEN then + device:emit_event(capabilities.lockAlarm.alarm.forcedOpeningAttempt({state_change = true})) + end +end + +-------------------- +-- Lock Operation -- +-------------------- +local function lock_op_event_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! lock_op_event_handler !!!!!!!!!!!!!")) -- needs to remove + local opType = ib.data.elements.lock_operation_type + local opSource = ib.data.elements.operation_source + local userIdx = ib.data.elements.user_index + local fabricId = ib.data.elements.fabric_index + + if opType == nil or opSource == nil then + return + end + + local Type = DoorLock.types.LockOperationTypeEnum + local Lock = capabilities.lock.lock + if opType.value == Type.LOCK then + opType = Lock.locked + elseif opType.value == Type.UNLOCK then + opType = Lock.unlocked + elseif opType.value == Type.UNLATCH then + opType = Lock.locked + else + return + end + + local Source = DoorLock.types.OperationSourceEnum + if opSource.value == Source.UNSPECIFIED then + opSource = nil + elseif opSource.value == Source.MANUAL then + opSource = "manual" + elseif opSource.value == Source.PROPRIETARY_REMOTE then + opSource = "proprietaryRemote" + elseif opSource.value == Source.KEYPAD then + opSource = "keypad" + elseif opSource.value == Source.AUTO then + opSource = "auto" + elseif opSource.value == Source.BUTTON then + opSource = "button" + elseif opSource.value == Source.SCHEDULE then + opSource = nil + elseif opSource.value == Source.REMOTE then + opSource = "command" + elseif opSource.value == Source.RFID then + opSource = "rfid" + elseif opSource.value == Source.BIOMETRIC then + opSource = "keypad" + elseif opSource.value == Source.ALIRO then + opSource = nil + else + opSource =nil + end + + if fabricId ~= nil then + fabricId = fabricId.value + end + + if userIdx ~= nil then + userIdx = userIdx.value + end + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("opType: %s", opType.NAME)) + log.info_with({hub_logs=true}, string.format("opSource: %s", opSource)) + log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("fabricId: %s", fabricId)) + + local data_obj = {method = opSource, userIndex = userIdx} + device:emit_event(opType({data = data_obj, state_change = true})) +end + +---------------------- +-- Lock User Change -- +---------------------- +local function lock_user_change_event_handler(driver, device, ib, response) + log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! lock_user_change_event_handler !!!!!!!!!!!!!")) -- needs to remove + local lockDataType = ib.data.elements.lock_data_type + local dataOpType = ib.data.elements.data_operation_type + local opSource = ib.data.elements.operation_source + local userIdx = ib.data.elements.user_index + local fabricId = ib.data.elements.fabric_index + + if lockDataType ~= nil then + lockDataType = lockDataType.value + end + + if dataOpType ~= nil then + dataOpType = dataOpType.value + end + + local Source = DoorLock.types.OperationSourceEnum + if opSource.value == Source.UNSPECIFIED then + opSource = nil + elseif opSource.value == Source.MANUAL then + opSource = "manual" + elseif opSource.value == Source.PROPRIETARY_REMOTE then + opSource = "proprietaryRemote" + elseif opSource.value == Source.KEYPAD then + opSource = "keypad" + elseif opSource.value == Source.AUTO then + opSource = "auto" + elseif opSource.value == Source.BUTTON then + opSource = "button" + elseif opSource.value == Source.SCHEDULE then + opSource = nil + elseif opSource.value == Source.REMOTE then + opSource = "command" + elseif opSource.value == Source.RFID then + opSource = "rfid" + elseif opSource.value == Source.BIOMETRIC then + opSource = "keypad" + elseif opSource.value == Source.ALIRO then + opSource = nil + else + opSource =nil + end + + if userIdx ~= nil then + userIdx = userIdx.value + end + + if fabricId ~= nil then + fabricId = fabricId.value + end + + -- needs to remove logs + log.info_with({hub_logs=true}, string.format("lockDataType: %s", lockDataType)) + log.info_with({hub_logs=true}, string.format("dataOpType: %s", dataOpType)) + log.info_with({hub_logs=true}, string.format("opSource: %s", opSource)) + log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) + log.info_with({hub_logs=true}, string.format("fabricId: %s", fabricId)) + + -- local data_obj = {method = opSource, userIndex = userIdx} + -- device:emit_event(opType({data = data_obj}, {state_change = true})) +end + +local function handle_refresh(driver, device, command) + local req = DoorLock.attributes.LockState:read(device) + device:send(req) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) +end + +local new_matter_lock_handler = { + NAME = "New Matter Lock Handler", + lifecycle_handlers = { + init = device_init, + added = device_added, + doConfigure = do_configure, + infoChanged = info_changed, + }, + matter_handlers = { + attr = { + [DoorLock.ID] = { + [DoorLock.attributes.LockState.ID] = lock_state_handler, + [DoorLock.attributes.OperatingMode.ID] = operating_modes_handler, + [DoorLock.attributes.NumberOfTotalUsersSupported.ID] = total_users_supported_handler, + [DoorLock.attributes.NumberOfPINUsersSupported.ID] = pin_users_supported_handler, + [DoorLock.attributes.MinPINCodeLength.ID] = min_pin_code_len_handler, + [DoorLock.attributes.MaxPINCodeLength.ID] = max_pin_code_len_handler, + [DoorLock.attributes.RequirePINforRemoteOperation.ID] = require_remote_pin_handler, + [DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser.ID] = max_week_schedule_of_user_handler, + [DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser.ID] = max_year_schedule_of_user_handler, + } + }, + event = { + [DoorLock.ID] = { + [DoorLock.events.DoorLockAlarm.ID] = alarm_event_handler, + [DoorLock.events.LockOperation.ID] = lock_op_event_handler, + [DoorLock.events.LockUserChange.ID] = lock_user_change_event_handler, + }, + }, + cmd_response = { + [DoorLock.ID] = { + [DoorLock.server.commands.SetUser.ID] = set_user_response_handler, + [DoorLock.server.commands.ClearUser.ID] = clear_user_response_handler, + [DoorLock.client.commands.SetCredentialResponse.ID] = set_credential_response_handler, + [DoorLock.server.commands.ClearCredential.ID] = clear_credential_response_handler, + [DoorLock.server.commands.SetWeekDaySchedule.ID] = set_week_day_schedule_handler, + [DoorLock.server.commands.ClearWeekDaySchedule.ID] = clear_week_day_schedule_handler, + }, + }, + }, + subscribed_attributes = subscribed_attributes, + subscribed_events = subscribed_events, + capability_handlers = { + [capabilities.lock.ID] = { + [capabilities.lock.commands.lock.NAME] = handle_lock, + [capabilities.lock.commands.unlock.NAME] = handle_unlock, + }, + [capabilities.lockUsers.ID] = { + [capabilities.lockUsers.commands.addUser.NAME] = handle_add_user, + [capabilities.lockUsers.commands.updateUser.NAME] = handle_update_user, + [capabilities.lockUsers.commands.deleteUser.NAME] = handle_delete_user, + [capabilities.lockUsers.commands.deleteAllUsers.NAME] = handle_delete_all_users, + }, + [capabilities.lockCredentials.ID] = { + [capabilities.lockCredentials.commands.addCredential.NAME] = handle_add_credential, + [capabilities.lockCredentials.commands.updateCredential.NAME] = handle_update_credential, + [capabilities.lockCredentials.commands.deleteCredential.NAME] = handle_delete_credential, + [capabilities.lockCredentials.commands.deleteAllCredentials.NAME] = handle_delete_all_credentials, + }, + [capabilities.lockSchedules.ID] = { + [capabilities.lockSchedules.commands.setWeekDaySchedule.NAME] = handle_set_week_day_schedule, + [capabilities.lockSchedules.commands.clearWeekDaySchedules.NAME] = handle_clear_week_day_schedule, + [capabilities.lockSchedules.commands.setYearDaySchedule.NAME] = handle_set_year_day_schedule, + [capabilities.lockSchedules.commands.clearYearDaySchedules.NAME] = handle_clear_year_day_schedule, + }, + [capabilities.refresh.ID] = {[capabilities.refresh.commands.refresh.NAME] = handle_refresh} + }, + supported_capabilities = { + capabilities.lock, + capabilities.lockUsers, + capabilities.lockCredentials, + capabilities.lockSchedules + }, + can_handle = is_new_matter_lock_products +} + +return new_matter_lock_handler \ No newline at end of file From 41bc4862fa6297d55cd5b3dc196ee3d3255d0703 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Tue, 10 Sep 2024 21:37:38 +0900 Subject: [PATCH 02/20] Remove logging and fix typo Signed-off-by: Hunsup Jung --- .../SmartThings/matter-lock/fingerprints.yml | 6 +- .../matter-lock/src/new-matter-lock/init.lua | 216 ++---------------- 2 files changed, 18 insertions(+), 204 deletions(-) diff --git a/drivers/SmartThings/matter-lock/fingerprints.yml b/drivers/SmartThings/matter-lock/fingerprints.yml index 9b6431b0b8..1817691cf6 100755 --- a/drivers/SmartThings/matter-lock/fingerprints.yml +++ b/drivers/SmartThings/matter-lock/fingerprints.yml @@ -15,15 +15,15 @@ matterManufacturer: deviceLabel: Aqara Smart Lock U200 vendorId: 0x115F productId: 0x2802 - deviceProfileName: lock-lockalarm-nobattery + deviceProfileName: lock-user-pin - id: "4447/10241" deviceLabel: Aqara Smart Lock U300 vendorId: 0x115F productId: 0x2801 - deviceProfileName: lock-lockalarm-nobattery + deviceProfileName: lock-user-pin matterGeneric: - id: "matter/door-lock" deviceLabel: Matter Door Lock deviceTypes: - id: 0x000A # Door Lock - deviceProfileName: base-lock + deviceProfileName: base-lock \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index a253aec0f0..938f6c9407 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -17,22 +17,13 @@ local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local im = require "st.matter.interaction_model" local lock_utils = require "lock_utils" -local log = require "log" -- needs to remove local DoorLock = clusters.DoorLock local INITIAL_COTA_INDEX = 1 local ALL_INDEX = 0xFFFE - -local AQARA_MANUFACTURER_ID = 0x115f -local U200_PRODUCT_ID = 0x2802 - local NEW_MATTER_LOCK_PRODUCTS = { {0x115f, 0x2802}, -- AQARA, U200 {0x115f, 0x2801}, -- AQARA, U300 - {0x1533, 0x0001}, -- eufy, Smart Lock E31 - {0x1533, 0x0002}, -- eufy, Smart Lock E30 - {0x1533, 0x0003}, -- eufy, Smart Lock C34 - {0xFFF2, 0x8002}, -- Solity, MT-100C {0x10E1, 0x2002} -- VDA } @@ -65,7 +56,7 @@ local subscribed_events = { [capabilities.lockAlarm.ID] = { DoorLock.events.DoorLockAlarm }, - [capabilities.lockUser.ID] = { + [capabilities.lockUsers.ID] = { DoorLock.events.LockUserChange } } @@ -79,7 +70,7 @@ local function is_new_matter_lock_products(opts, driver, device) device.manufacturer_info.product_id == p[2] then return true end - end + end return false end @@ -101,7 +92,6 @@ local function component_to_endpoint(device, component_name) end local function device_init(driver, device) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! device_added !!!!!!!!!!!!!")) -- needs to remove device:set_component_to_endpoint_fn(component_to_endpoint) device:subscribe() end @@ -111,8 +101,6 @@ local function device_added(driver, device) end local function do_configure(driver, device) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! do_configure !!!!!!!!!!!!!")) -- needs to remove - local user_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.USER}) local pin_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.PIN_CREDENTIAL}) local week_schedule_eps = device:get_endpoints(DoorLock.ID, {feature_bitmap = DoorLock.types.Feature.WEEK_DAY_ACCESS_SCHEDULES}) @@ -130,7 +118,7 @@ local function do_configure(driver, device) else profile_name = "base-lock" end - device.log.info_with({hub_logs=true}, string.format("Updating device profile to %s.", profile_name)) + device.log.info(string.format("Updating device profile to %s.", profile_name)) device:try_update_metadata({profile = profile_name}) end @@ -157,7 +145,6 @@ end -- Lock State -- ---------------- local function lock_state_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! lock_state_handler !!!!!!!!!!!!!")) -- needs to remove local LockState = DoorLock.attributes.LockState local attr = capabilities.lock.lock local LOCK_STATE = { @@ -177,8 +164,6 @@ end -- Operating Modes -- --------------------- local function operating_modes_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! operating_modes_handler!!!!!!!!!!!!!")) -- needs to remove - local status = capabilities.remoteControlStatus.remoteControlEnabled local op_type = DoorLock.types.OperatingModeEnum local opMode_map = { @@ -199,33 +184,29 @@ local function operating_modes_handler(driver, device, ib, response) end ------------------------------------- -- Number Of Total Users Supported -- -------------------------------------- +------------------------------------- local function total_users_supported_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! total_users_supported_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove device:emit_event(capabilities.lockUsers.totalUsersSupported(ib.data.value, {visibility = {displayed = false}})) end ---------------------------------- -- Number Of PIN User Supported -- ----------------------------------- +---------------------------------- local function pin_users_supported_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! pin_users_supported_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove device:emit_event(capabilities.lockCredentials.pinUsersSupported(ib.data.value, {visibility = {displayed = false}})) end ------------------------- -- Min PIN Code Length -- -------------------------- +------------------------- local function min_pin_code_len_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! min_pin_code_len_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove device:emit_event(capabilities.lockCredentials.minPinCodeLen(ib.data.value, {visibility = {displayed = false}})) end ------------------------- -- Max PIN Code Length -- -------------------------- +------------------------- local function max_pin_code_len_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! max_pin_code_len_handler: %d !!!!!!!!!!!!!", ib.data.value)) -- needs to remove device:emit_event(capabilities.lockCredentials.maxPinCodeLen(ib.data.value, {visibility = {displayed = false}})) end @@ -279,7 +260,6 @@ local function generate_cota_cred_for_device(device) local len = device:get_latest_state("main", capabilities.lockCredentials.ID, capabilities.lockCredentials.maxPinCodeLen.NAME) or 6 local cred_data = math.floor(math.random() * (10 ^ len)) cred_data = string.format("%0" .. tostring(len) .. "d", cred_data) - log.info_with({hub_logs=true}, string.format("cota_cred: %s", cred_data)) device:set_field(lock_utils.COTA_CRED, cred_data, {persist = true}) end @@ -298,7 +278,6 @@ local function apply_cota_credentials_if_absent(device) end local function require_remote_pin_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! require_remote_pin_handler: %s !!!!!!!!!!!!!", ib.data.value)) -- needs to remove if ib.data.value then apply_cota_credentials_if_absent(device) else @@ -310,7 +289,6 @@ end -- Number Of Week Day Schedules Supported Per User -- ----------------------------------------------------- local function max_week_schedule_of_user_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! max_week_schedule_of_user_handler: %s !!!!!!!!!!!!!", ib.data.value)) -- needs to remove device:emit_event(capabilities.lockSchedules.weekDaySchedulesPerUser(ib.data.value, {visibility = {displayed = false}})) end @@ -318,7 +296,6 @@ end -- Number Of Year Day Schedules Supported Per User -- ----------------------------------------------------- local function max_year_schedule_of_user_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! max_year_schedule_of_user_handler: %s !!!!!!!!!!!!!", ib.data.value)) -- needs to remove device:emit_event(capabilities.lockSchedules.yearDaySchedulesPerUser(ib.data.value, {visibility = {displayed = false}})) end @@ -327,10 +304,8 @@ end -- Lock/Unlock -- ----------------- local function handle_lock(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_lock !!!!!!!!!!!!!")) -- needs to remove local ep = device:component_to_endpoint(command.component) local cota_cred = device:get_field(lock_utils.COTA_CRED) - log.info_with({hub_logs=true}, string.format("cota_cred: %s", cota_cred)) if cota_cred then device:send( DoorLock.server.commands.LockDoor(device, ep, cota_cred) @@ -341,10 +316,8 @@ local function handle_lock(driver, device, command) end local function handle_unlock(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_unlock !!!!!!!!!!!!!")) -- needs to remove local ep = device:component_to_endpoint(command.component) local cota_cred = device:get_field(lock_utils.COTA_CRED) - log.info_with({hub_logs=true}, string.format("cota_cred: %s", cota_cred)) -- needs to remove if cota_cred then device:send( DoorLock.server.commands.UnlockDoor(device, ep, cota_cred) @@ -358,11 +331,6 @@ end -- User Table -- ---------------- local function add_user_to_table(device, userIdx, usrType) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_user_to_table !!!!!!!!!!!!!")) - log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("usrType: %s", usrType)) - -- Get latest user table local user_table = device:get_latest_state( "main", @@ -382,8 +350,6 @@ local function add_user_to_table(device, userIdx, usrType) end local function update_user_in_table(device, userIdx, usrType) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! update_user_in_table !!!!!!!!!!!!!")) -- needs to remove - -- Get latest user table local user_table = device:get_latest_state( "main", @@ -409,7 +375,6 @@ local function update_user_in_table(device, userIdx, usrType) end local function delete_user_from_table(device, userIdx) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_user_from_table !!!!!!!!!!!!!")) -- needs to remove -- If User Index is ALL_INDEX, remove all entry from the table if userIdx == ALL_INDEX then device:emit_event(capabilities.lockUsers.users({}, {visibility = {displayed = false}})) @@ -437,8 +402,6 @@ end -- Credential Table -- ---------------------- local function add_credential_to_table(device, userIdx, credIdx, credType) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_credential_to_table !!!!!!!!!!!!!")) -- needs to remove - -- Get latest credential table local cred_table = device:get_latest_state( "main", @@ -458,7 +421,6 @@ local function add_credential_to_table(device, userIdx, credIdx, credType) end local function delete_credential_from_table(device, credIdx) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_credential_from_table !!!!!!!!!!!!!")) -- needs to remove -- If Credential Index is ALL_INDEX, remove all entry from the table if credIdx == ALL_INDEX then device:emit_event(capabilities.lockCredentials.credentials({})) @@ -474,7 +436,6 @@ local function delete_credential_from_table(device, credIdx) -- Recreate credential table local userIdx = 0 - local i = 0 for index, entry in pairs(cred_table) do if entry.credentialIndex ~= credIdx then table.insert(new_cred_table, entry) @@ -488,7 +449,6 @@ local function delete_credential_from_table(device, credIdx) end local function delete_credential_from_table_as_user(device, userIdx) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_credential_from_table_as_user !!!!!!!!!!!!!")) -- needs to remove -- If User Index is ALL_INDEX, remove all entry from the table if userIdx == ALL_INDEX then device:emit_event(capabilities.lockCredentials.credentials({}, {visibility = {displayed = false}})) @@ -503,7 +463,6 @@ local function delete_credential_from_table_as_user(device, userIdx) local new_cred_table = {} -- Recreate credential table - local i = 0 for index, entry in pairs(cred_table) do if entry.userIndex ~= userIdx then table.insert(new_cred_table, entry) @@ -527,7 +486,6 @@ local WEEK_DAY_MAP = { } local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_week_schedule_to_table !!!!!!!!!!!!!")) -- needs to remove -- Get latest week day schedule table local week_schedule_table = device:get_latest_state( @@ -550,7 +508,6 @@ local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule local weekDayList = {} for _, weekday in ipairs(schedule.weekDays) do table.insert(weekDayList, weekday) - log.info_with({hub_logs=true}, string.format("weekDay: %s", weekday)) -- needs to remove end if i ~= 0 then -- Add schedule for existing user @@ -576,7 +533,6 @@ local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule new_week_schedule_table[i].schedules = new_schedule_table else -- Add schedule for new user - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! add_week_schedule_to_table 2!!!!!!!!!!!!!")) -- needs to remove table.insert( new_week_schedule_table, { @@ -597,8 +553,6 @@ local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule end local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! delete_week_schedule_to_table !!!!!!!!!!!!!")) -- needs to remove - -- Get latest week day schedule table local week_schedule_table = device:get_latest_state( "main", @@ -618,7 +572,6 @@ local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) -- When there is no userIndex in the table if i == 0 then - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! No userIndex in Week Day Schedule Table !!!!!!!!!!!!!", i)) -- needs to remove return end @@ -632,7 +585,6 @@ local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) -- If user has no schedule, remove user from the table if #new_schedule_table == 0 then - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! No schedule for User !!!!!!!!!!!!!", i)) -- needs to remove table.remove(new_week_schedule_table, i) else new_week_schedule_table[i].schedules = new_schedule_table @@ -645,7 +597,6 @@ end -- Add User -- -------------- local function handle_add_user(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_add_user !!!!!!!!!!!!!")) -- needs to remove -- Get parameters local cmdName = "addUser" @@ -675,18 +626,13 @@ local function handle_add_user(driver, device, command) end -- Save values to field - -- device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) - device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + -- device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) -- needs to find empty index device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userName: %s", userName)) - log.info_with({hub_logs=true}, string.format("userType: %s", userType)) - log.info_with({hub_logs=true}, string.format("userTypeMatter: %s", userTypeMatter)) - -- Send command + local ep = device:component_to_endpoint(command.component) device:send( DoorLock.server.commands.SetUser( device, ep, @@ -704,8 +650,6 @@ end -- Update User -- ----------------- local function handle_update_user(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_update_user !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "updateUser" local userIdx = command.args.userIndex @@ -740,12 +684,6 @@ local function handle_update_user(driver, device, command) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("userName: %s", userName)) - log.info_with({hub_logs=true}, string.format("userType: %s", userType)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send( @@ -766,8 +704,6 @@ end -- Set User Response -- ----------------------- local function set_user_response_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! set_user_response_handler !!!!!!!!!!!!!")) -- needs to remove - -- Get result local cmdName = device:get_field(lock_utils.COMMAND_NAME) local userIdx = device:get_field(lock_utils.USER_INDEX) @@ -780,12 +716,6 @@ local function set_user_response_handler(driver, device, ib, response) elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then status = "invalidCommand" end - - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("userType: %s", userType)) - log.info_with({hub_logs=true}, string.format("status: %s", status)) -- Update User in table if status == "success" then @@ -817,8 +747,6 @@ end -- Delete User -- ----------------- local function handle_delete_user(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_user !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "deleteUser" local userIdx = command.args.userIndex @@ -846,10 +774,6 @@ local function handle_delete_user(driver, device, command) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send(DoorLock.server.commands.ClearUser(device, ep, userIdx)) @@ -859,8 +783,6 @@ end -- Delete All Users -- ---------------------- local function handle_delete_all_users(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_all_users !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "deleteAllUsers" @@ -887,9 +809,8 @@ local function handle_delete_all_users(driver, device, command) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, ALL_INDEX, {persist = true}) - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) -- needs to remove - -- Send command + local ep = device:component_to_endpoint(command.component) device:send(DoorLock.server.commands.ClearUser(device, ep, ALL_INDEX)) end @@ -897,8 +818,6 @@ end -- Clear User Response -- ------------------------- local function clear_user_response_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! clear_user_response_handler !!!!!!!!!!!!!")) -- needs to remove - -- Get result local cmdName = device:get_field(lock_utils.COMMAND_NAME) local userIdx = device:get_field(lock_utils.USER_INDEX) @@ -935,8 +854,6 @@ end -- Add Credential -- -------------------- local function handle_add_credential(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_add_credential !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "addCredential" local userIdx = command.args.userIndex @@ -980,13 +897,6 @@ local function handle_add_credential(driver, device, command) device:set_field(lock_utils.CRED_INDEX, INITIAL_COTA_INDEX, {persist = true}) device:set_field(lock_utils.CRED_DATA, credData, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("userType: %s", userType)) - log.info_with({hub_logs=true}, string.format("credIndex: %s", INITIAL_COTA_INDEX)) - log.info_with({hub_logs=true}, string.format("credData: %s", credData)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send( @@ -1006,8 +916,6 @@ end -- Update Credential -- ----------------------- local function handle_update_credential(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_update_credential !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "updateCredential" local userIdx = command.args.userIndex @@ -1042,12 +950,6 @@ local function handle_update_credential(driver, device, command) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("credentialIndex: %s", credIdx)) - log.info_with({hub_logs=true}, string.format("credData: %s", credData)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send( @@ -1067,8 +969,6 @@ end -- Set Credential Response -- ----------------------------- local function set_credential_response_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! set_credential_response_handler !!!!!!!!!!!!!")) -- needs to remove - if ib.status ~= im.InteractionResponse.Status.SUCCESS then device.log.error("Failed to set credential for device") return @@ -1078,12 +978,6 @@ local function set_credential_response_handler(driver, device, ib, response) local userIdx = device:get_field(lock_utils.USER_INDEX) local credIdx = device:get_field(lock_utils.CRED_INDEX) local status = "success" - - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("cmdName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("credIdx: %s", credIdx)) - local elements = ib.info_block.data.elements if elements.status.value == DoorLock.types.DlStatus.SUCCESS then -- If user is added also, update User table @@ -1117,15 +1011,6 @@ local function set_credential_response_handler(driver, device, ib, response) return end - -- @field public byte_length number 1 - -- @field public SUCCESS number 0 - -- @field public FAILURE number 1 - -- @field public DUPLICATE number 2 - -- @field public OCCUPIED number 3 - -- @field public INVALID_FIELD number 133 - -- @field public RESOURCE_EXHAUSTED number 137 - -- @field public NOT_FOUND number 139 - -- Update commandResult status = "occupied" if elements.status.value == DoorLock.types.DlStatus.FAILURE then @@ -1139,8 +1024,6 @@ local function set_credential_response_handler(driver, device, ib, response) elseif elements.status.value == DoorLock.types.DlStatus.NOT_FOUND then status = "failure" end - log.info_with({hub_logs=true}, string.format("Result: %s", status)) -- needs to remove - if status ~= "occupied" then local result = { commandName = cmdName, @@ -1173,15 +1056,9 @@ local function set_credential_response_handler(driver, device, ib, response) userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER end - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("credentialIndex: %s", credIdx)) - log.info_with({hub_logs=true}, string.format("credData: %s", credData)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("userType: %s", userType)) - device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) - -- Sned command + -- Send command local ep = find_default_endpoint(device, DoorLock.ID) device:send( DoorLock.server.commands.SetCredential( @@ -1215,8 +1092,6 @@ end -- Delete Credential -- ----------------------- local function handle_delete_credential(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_credential !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "deleteCredential" local credIdx = command.args.credentialIndex @@ -1248,10 +1123,6 @@ local function handle_delete_credential(driver, device, command) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("credentialIndex: %s", credIdx)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send(DoorLock.server.commands.ClearCredential(device, ep, credential)) @@ -1261,8 +1132,6 @@ end -- Delete All Credentials -- ---------------------------- local function handle_delete_all_credentials(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_delete_all_credentials !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "deleteAllCredentials" local credential = { @@ -1293,10 +1162,6 @@ local function handle_delete_all_credentials(driver, device, command) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.CRED_INDEX, ALL_INDEX, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("credentialIndex: %s", ALL_INDEX)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send(DoorLock.server.commands.ClearUser(device, ep, credential)) @@ -1306,8 +1171,6 @@ end -- Clear Credential Response -- ------------------------------- local function clear_credential_response_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! clear_credential_response_handler !!!!!!!!!!!!!")) -- needs to remove - -- Get result local cmdName = device:get_field(lock_utils.COMMAND_NAME) local credIdx = device:get_field(lock_utils.CRED_INDEX) @@ -1323,7 +1186,7 @@ local function clear_credential_response_handler(driver, device, ib, response) if status == "success" then userIdx = delete_credential_from_table(device, credIdx) end - + -- Update commandResult local result = { commandName = cmdName, @@ -1346,8 +1209,6 @@ end -- Set Week Day Schedule -- --------------------------- local function handle_set_week_day_schedule(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_set_week_day_schedule !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "setWeekDaySchedule" local scheduleIdx = command.args.scheduleIndex @@ -1356,7 +1217,6 @@ local function handle_set_week_day_schedule(driver, device, command) local scheduleBit = 0 for _, weekDay in ipairs(schedule.weekDays) do scheduleBit = scheduleBit + WEEK_DAY_MAP[weekDay] - log.info_with({hub_logs=true}, string.format("%s, %s", WEEK_DAY_MAP[weekDay], weekDay)) -- needs to remove end local startHour = schedule.startHour local startMinute = schedule.startMinute @@ -1388,23 +1248,6 @@ local function handle_set_week_day_schedule(driver, device, command) device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) device:set_field(lock_utils.SCHEDULE, schedule, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("scheduleIndex: %s", scheduleIdx)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("weekDay[1]: %s", schedule.weekDays[1])) - log.info_with({hub_logs=true}, string.format("weekDay[2]: %s", schedule.weekDays[2])) - log.info_with({hub_logs=true}, string.format("weekDay[3]: %s", schedule.weekDays[3])) - log.info_with({hub_logs=true}, string.format("weekDay[4]: %s", schedule.weekDays[4])) - log.info_with({hub_logs=true}, string.format("weekDay[5]: %s", schedule.weekDays[5])) - log.info_with({hub_logs=true}, string.format("weekDay[6]: %s", schedule.weekDays[6])) - log.info_with({hub_logs=true}, string.format("weekDay[7]: %s", schedule.weekDays[7])) - log.info_with({hub_logs=true}, string.format("scheduleBit: %s", scheduleBit)) - log.info_with({hub_logs=true}, string.format("startHour: %s", startHour)) - log.info_with({hub_logs=true}, string.format("startMinute: %s", startMinute)) - log.info_with({hub_logs=true}, string.format("endHour: %s", endHour)) - log.info_with({hub_logs=true}, string.format("endMinute: %s", endMinute)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send( @@ -1425,8 +1268,6 @@ end -- Set Week Day Schedule Response -- ------------------------------------ local function set_week_day_schedule_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! set_week_day_schedule_handler !!!!!!!!!!!!!")) -- needs to remove - -- Get result local cmdName = device:get_field(lock_utils.COMMAND_NAME) local userIdx = device:get_field(lock_utils.USER_INDEX) @@ -1443,7 +1284,7 @@ local function set_week_day_schedule_handler(driver, device, ib, response) if status == "success" then add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule) end - + -- Update commandResult local result = { commandName = cmdName, @@ -1466,8 +1307,6 @@ end -- Clear Week Day Schedule -- ----------------------------- local function handle_clear_week_day_schedule(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_clear_week_day_schedule !!!!!!!!!!!!!")) -- needs to remove - -- Get parameters local cmdName = "clearWeekDaySchedule" local scheduleIdx = command.args.scheduleIndex @@ -1496,11 +1335,6 @@ local function handle_clear_week_day_schedule(driver, device, command) device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("commandName: %s", cmdName)) - log.info_with({hub_logs=true}, string.format("scheduleIndex: %s", scheduleIdx)) - log.info_with({hub_logs=true}, string.format("userIndex: %s", userIdx)) - -- Send command local ep = device:component_to_endpoint(command.component) device:send(DoorLock.server.commands.ClearWeekDaySchedule(device, ep, scheduleIdx, userIdx)) @@ -1510,8 +1344,6 @@ end -- Clear Week Day Schedule Response -- ------------------------------------ local function clear_week_day_schedule_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! clear_week_day_schedule_handler !!!!!!!!!!!!!")) -- needs to remove - -- Get result local cmdName = device:get_field(lock_utils.COMMAND_NAME) local scheduleIdx = device:get_field(lock_utils.SCHEDULE_INDEX) @@ -1550,21 +1382,18 @@ end -- Set Year Day Schedule -- --------------------------- local function handle_set_year_day_schedule(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_set_year_day_schedule !!!!!!!!!!!!!")) -- needs to remove end ----------------------------- -- Clear Year Day Schedule -- ----------------------------- local function handle_clear_year_day_schedule(driver, device, command) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! handle_clear_year_day_schedule !!!!!!!!!!!!!")) -- needs to remove end ---------------- -- Lock Alarm -- ---------------- local function alarm_event_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! alarm_event_handler !!!!!!!!!!!!!")) -- needs to remove local DlAlarmCode = DoorLock.types.DlAlarmCode local alarm_code = ib.data.elements.alarm_code if alarm_code.value == DlAlarmCode.LOCK_JAMMED then @@ -1584,7 +1413,6 @@ end -- Lock Operation -- -------------------- local function lock_op_event_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! lock_op_event_handler !!!!!!!!!!!!!")) -- needs to remove local opType = ib.data.elements.lock_operation_type local opSource = ib.data.elements.operation_source local userIdx = ib.data.elements.user_index @@ -1636,17 +1464,11 @@ local function lock_op_event_handler(driver, device, ib, response) if fabricId ~= nil then fabricId = fabricId.value end - + if userIdx ~= nil then userIdx = userIdx.value end - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("opType: %s", opType.NAME)) - log.info_with({hub_logs=true}, string.format("opSource: %s", opSource)) - log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("fabricId: %s", fabricId)) - local data_obj = {method = opSource, userIndex = userIdx} device:emit_event(opType({data = data_obj, state_change = true})) end @@ -1655,7 +1477,6 @@ end -- Lock User Change -- ---------------------- local function lock_user_change_event_handler(driver, device, ib, response) - log.info_with({hub_logs=true}, string.format("!!!!!!!!!!!!!!! lock_user_change_event_handler !!!!!!!!!!!!!")) -- needs to remove local lockDataType = ib.data.elements.lock_data_type local dataOpType = ib.data.elements.data_operation_type local opSource = ib.data.elements.operation_source @@ -1705,13 +1526,6 @@ local function lock_user_change_event_handler(driver, device, ib, response) fabricId = fabricId.value end - -- needs to remove logs - log.info_with({hub_logs=true}, string.format("lockDataType: %s", lockDataType)) - log.info_with({hub_logs=true}, string.format("dataOpType: %s", dataOpType)) - log.info_with({hub_logs=true}, string.format("opSource: %s", opSource)) - log.info_with({hub_logs=true}, string.format("userIdx: %s", userIdx)) - log.info_with({hub_logs=true}, string.format("fabricId: %s", fabricId)) - -- local data_obj = {method = opSource, userIndex = userIdx} -- device:emit_event(opType({data = data_obj}, {state_change = true})) end From 46870abb6df7e88a06fd0737ac63b507d3f5108c Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Thu, 19 Sep 2024 20:54:15 +0900 Subject: [PATCH 03/20] Add call_with_delay to prevent duplicated event Signed-off-by: Hunsup Jung --- .../matter-lock/src/new-matter-lock/init.lua | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 938f6c9407..fc494a37a2 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -153,11 +153,16 @@ local function lock_state_handler(driver, device, ib, response) [LockState.UNLOCKED] = attr.unlocked({visibility = {displayed = false}}), } - if ib.data.value ~= nil then - device:emit_event(LOCK_STATE[ib.data.value]) - else - device:emit_event(attr.unknown()) - end + -- The lock state is usually updated in lock_state_handler and lock_op_event_handler, respectively. + -- In this case, two events occur. To prevent this, when both functions are called, + -- it send the event after 1 second so that no event occurs in the lock_state_handler. + device.thread:call_with_delay(1, function () + if ib.data.value ~= nil then + device:emit_event(LOCK_STATE[ib.data.value]) + else + device:emit_event(attr.unknown()) + end + end) end --------------------- From a2686045b0ac0636218deb4f8c2c6fb5a109b2bb Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Thu, 19 Sep 2024 21:56:53 +0900 Subject: [PATCH 04/20] Fix some issues Signed-off-by: Hunsup Jung --- .../profiles/lock-user-pin-schedule.yml | 2 ++ .../matter-lock/profiles/lock-user-pin.yml | 2 ++ .../profiles/lock-user-schedule.yml | 2 ++ .../matter-lock/profiles/lock-user.yml | 2 ++ .../matter-lock/src/new-matter-lock/init.lua | 25 ++++++++++++++----- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml b/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml index 911476d6a6..d27423f2b8 100644 --- a/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml +++ b/drivers/SmartThings/matter-lock/profiles/lock-user-pin-schedule.yml @@ -21,6 +21,8 @@ components: version: 1 - id: lockSchedules version: 1 + - id: firmwareUpdate + version: 1 - id: refresh version: 1 categories: diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml b/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml index eb8036c1cd..8a48917392 100644 --- a/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml +++ b/drivers/SmartThings/matter-lock/profiles/lock-user-pin.yml @@ -19,6 +19,8 @@ components: version: 1 - id: lockCredentials version: 1 + - id: firmwareUpdate + version: 1 - id: refresh version: 1 categories: diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml b/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml index 39e51a2523..e4e9daf65a 100644 --- a/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml +++ b/drivers/SmartThings/matter-lock/profiles/lock-user-schedule.yml @@ -19,6 +19,8 @@ components: version: 1 - id: lockSchedules version: 1 + - id: firmwareUpdate + version: 1 - id: refresh version: 1 categories: diff --git a/drivers/SmartThings/matter-lock/profiles/lock-user.yml b/drivers/SmartThings/matter-lock/profiles/lock-user.yml index 614524266f..07ca0dd74e 100644 --- a/drivers/SmartThings/matter-lock/profiles/lock-user.yml +++ b/drivers/SmartThings/matter-lock/profiles/lock-user.yml @@ -17,6 +17,8 @@ components: version: 1 - id: lockUsers version: 1 + - id: firmwareUpdate + version: 1 - id: refresh version: 1 categories: diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index fc494a37a2..fb53bc987c 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -149,8 +149,8 @@ local function lock_state_handler(driver, device, ib, response) local attr = capabilities.lock.lock local LOCK_STATE = { [LockState.NOT_FULLY_LOCKED] = attr.not_fully_locked(), - [LockState.LOCKED] = attr.locked({visibility = {displayed = false}}), - [LockState.UNLOCKED] = attr.unlocked({visibility = {displayed = false}}), + [LockState.LOCKED] = attr.locked(), + [LockState.UNLOCKED] = attr.unlocked(), } -- The lock state is usually updated in lock_state_handler and lock_op_event_handler, respectively. @@ -244,10 +244,11 @@ local function set_cota_credential(device, credential_index) device:set_field(lock_utils.COTA_CRED_INDEX, credential_index, {persist = true}) local credential = {credential_type = DoorLock.types.DlCredentialType.PIN, credential_index = credential_index} -- Set the credential to a code - device:set_field(lock_utils.COMMAND_NAME, "addCredential") + device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + device:set_field(lock_utils.COMMAND_NAME, "addCota") device:set_field(lock_utils.CRED_INDEX, credential_index) device:set_field(lock_utils.SET_CREDENTIAL, credential_index) - device:set_field(lock_utils.USER_TYPE, "adminMember") + device:set_field(lock_utils.USER_TYPE, "remote") device.log.info(string.format("Attempting to set COTA credential at index %s", credential_index)) device:send(DoorLock.server.commands.SetCredential( device, @@ -980,6 +981,11 @@ local function set_credential_response_handler(driver, device, ib, response) end local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local credData = device:get_field(lock_utils.CRED_DATA) + if cmdName == "addCota" then + credData = device:get_field(lock_utils.COTA_CRED) + cmdName = "addCredential" + end local userIdx = device:get_field(lock_utils.USER_INDEX) local credIdx = device:get_field(lock_utils.CRED_INDEX) local status = "success" @@ -1029,6 +1035,13 @@ local function set_credential_response_handler(driver, device, ib, response) elseif elements.status.value == DoorLock.types.DlStatus.NOT_FOUND then status = "failure" end + + -- Error Handling + if status == "duplicate" then + generate_cota_cred_for_device(device) + device.thread:call_with_delay(0, function(t) set_cota_credential(device, credIdx) end) + return + end if status ~= "occupied" then local result = { commandName = cmdName, @@ -1045,7 +1058,6 @@ local function set_credential_response_handler(driver, device, ib, response) device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) return end - if elements.next_credential_index.value ~= nil then -- Get parameters local credIdx = elements.next_credential_index.value @@ -1053,12 +1065,13 @@ local function set_credential_response_handler(driver, device, ib, response) credential_type = DoorLock.types.DlCredentialType.PIN, credential_index = credIdx, } - local credData = device:get_field(lock_utils.CRED_DATA) local userIdx = device:get_field(lock_utils.USER_INDEX) local userType = device:get_field(lock_utils.USER_TYPE) local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER if userType == "guest" then userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER + elseif userType == "remote" then + userTypeMatter = DoorLock.types.DlUserType.REMOTE_ONLY_USER end device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) From ef622e09765274a1664f17645bb6582350626e7c Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Thu, 26 Sep 2024 19:18:21 +0900 Subject: [PATCH 05/20] Add DoorLock cluster for a hub using old lua-libs Signed-off-by: Hunsup Jung --- .../commands/GetCredentialStatusResponse.lua | 129 +++++++ .../client/commands/GetUserResponse.lua | 165 ++++++++ .../commands/GetWeekDayScheduleResponse.lua | 150 ++++++++ .../commands/GetYearDayScheduleResponse.lua | 129 +++++++ .../client/commands/SetCredentialResponse.lua | 115 ++++++ .../src/DoorLock/client/commands/init.lua | 23 ++ .../matter-lock/src/DoorLock/init.lua | 258 +++++++++++++ .../server/attributes/AcceptedCommandList.lua | 74 ++++ .../server/attributes/ActuatorEnabled.lua | 67 ++++ .../attributes/AliroBLEAdvertisingVersion.lua | 67 ++++ ...edTransactionSupportedProtocolVersions.lua | 74 ++++ .../attributes/AliroGroupResolvingKey.lua | 67 ++++ .../attributes/AliroReaderGroupIdentifier.lua | 67 ++++ .../AliroReaderGroupSubIdentifier.lua | 67 ++++ .../attributes/AliroReaderVerificationKey.lua | 67 ++++ .../server/attributes/AttributeList.lua | 74 ++++ .../DoorLock/server/attributes/DoorState.lua | 67 ++++ .../DoorLock/server/attributes/EventList.lua | 74 ++++ .../DoorLock/server/attributes/LockState.lua | 67 ++++ .../server/attributes/MaxPINCodeLength.lua | 67 ++++ .../server/attributes/MinPINCodeLength.lua | 67 ++++ ...erOfAliroCredentialIssuerKeysSupported.lua | 67 ++++ .../NumberOfAliroEndpointKeysSupported.lua | 67 ++++ .../NumberOfCredentialsSupportedPerUser.lua | 67 ++++ .../attributes/NumberOfPINUsersSupported.lua | 67 ++++ .../NumberOfTotalUsersSupported.lua | 67 ++++ ...mberOfWeekDaySchedulesSupportedPerUser.lua | 67 ++++ ...mberOfYearDaySchedulesSupportedPerUser.lua | 67 ++++ .../server/attributes/OperatingMode.lua | 80 ++++ .../RequirePINforRemoteOperation.lua | 80 ++++ .../server/attributes/SendPINOverTheAir.lua | 80 ++++ .../attributes/SupportedOperatingModes.lua | 67 ++++ .../UserCodeTemporaryDisableTime.lua | 80 ++++ .../server/attributes/WrongCodeEntryLimit.lua | 80 ++++ .../src/DoorLock/server/attributes/init.lua | 23 ++ .../commands/ClearAliroReaderConfig.lua | 91 +++++ .../server/commands/ClearCredential.lua | 98 +++++ .../DoorLock/server/commands/ClearUser.lua | 98 +++++ .../server/commands/ClearWeekDaySchedule.lua | 104 +++++ .../server/commands/ClearYearDaySchedule.lua | 104 +++++ .../server/commands/GetCredentialStatus.lua | 86 +++++ .../src/DoorLock/server/commands/GetUser.lua | 86 +++++ .../server/commands/GetWeekDaySchedule.lua | 93 +++++ .../server/commands/GetYearDaySchedule.lua | 93 +++++ .../src/DoorLock/server/commands/LockDoor.lua | 98 +++++ .../server/commands/SetAliroReaderConfig.lua | 119 ++++++ .../server/commands/SetCredential.lua | 122 ++++++ .../src/DoorLock/server/commands/SetUser.lua | 140 +++++++ .../server/commands/SetWeekDaySchedule.lua | 139 +++++++ .../server/commands/SetYearDaySchedule.lua | 118 ++++++ .../DoorLock/server/commands/UnlockDoor.lua | 98 +++++ .../src/DoorLock/server/commands/init.lua | 22 ++ .../DoorLock/server/events/DoorLockAlarm.lua | 100 +++++ .../server/events/DoorStateChange.lua | 100 +++++ .../DoorLock/server/events/LockOperation.lua | 136 +++++++ .../server/events/LockOperationError.lua | 143 +++++++ .../DoorLock/server/events/LockUserChange.lua | 142 +++++++ .../src/DoorLock/server/events/init.lua | 23 ++ .../src/DoorLock/types/AlarmCodeEnum.lua | 45 +++ .../src/DoorLock/types/CredentialRuleEnum.lua | 31 ++ .../src/DoorLock/types/CredentialStruct.lua | 77 ++++ .../src/DoorLock/types/CredentialTypeEnum.lua | 48 +++ .../DoorLock/types/DataOperationTypeEnum.lua | 30 ++ .../src/DoorLock/types/DaysMaskMap.lua | 169 ++++++++ .../types/DlKeypadOperationEventMask.lua | 190 +++++++++ .../types/DlKeypadProgrammingEventMask.lua | 127 ++++++ .../types/DlLocalProgrammingFeatures.lua | 106 +++++ .../src/DoorLock/types/DlLockState.lua | 33 ++ .../types/DlManualOperationEventMask.lua | 253 ++++++++++++ .../types/DlRFIDOperationEventMask.lua | 169 ++++++++ .../types/DlRFIDProgrammingEventMask.lua | 85 +++++ .../types/DlRemoteOperationEventMask.lua | 169 ++++++++ .../types/DlRemoteProgrammingEventMask.lua | 169 ++++++++ .../src/DoorLock/types/DlStatus.lua | 42 ++ .../types/DlSupportedOperatingModes.lua | 127 ++++++ .../src/DoorLock/types/DoorLockDayOfWeek.lua | 169 ++++++++ .../types/DoorLockOperationEventCode.lua | 66 ++++ .../types/DoorLockProgrammingEventCode.lua | 42 ++ .../types/DoorLockSetPinOrIdStatus.lua | 33 ++ .../src/DoorLock/types/DoorLockUserStatus.lua | 33 ++ .../src/DoorLock/types/DoorLockUserType.lua | 39 ++ .../src/DoorLock/types/DoorStateEnum.lua | 39 ++ .../src/DoorLock/types/Feature.lua | 361 ++++++++++++++++++ .../src/DoorLock/types/LockDataTypeEnum.lua | 63 +++ .../DoorLock/types/LockOperationTypeEnum.lua | 36 ++ .../src/DoorLock/types/OperatingModeEnum.lua | 36 ++ .../src/DoorLock/types/OperationErrorEnum.lua | 36 ++ .../DoorLock/types/OperationSourceEnum.lua | 54 +++ .../src/DoorLock/types/UserStatusEnum.lua | 30 ++ .../src/DoorLock/types/UserTypeEnum.lua | 51 +++ .../matter-lock/src/DoorLock/types/init.lua | 14 + .../matter-lock/src/new-matter-lock/init.lua | 103 ++--- 92 files changed, 8244 insertions(+), 78 deletions(-) create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetCredentialStatusResponse.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetUserResponse.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetWeekDayScheduleResponse.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetYearDayScheduleResponse.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/client/commands/SetCredentialResponse.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/client/commands/init.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/init.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AcceptedCommandList.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/ActuatorEnabled.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroBLEAdvertisingVersion.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroExpeditedTransactionSupportedProtocolVersions.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroGroupResolvingKey.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupIdentifier.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupSubIdentifier.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderVerificationKey.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AttributeList.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/DoorState.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/EventList.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/LockState.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MaxPINCodeLength.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MinPINCodeLength.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroCredentialIssuerKeysSupported.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroEndpointKeysSupported.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfCredentialsSupportedPerUser.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfPINUsersSupported.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfTotalUsersSupported.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfWeekDaySchedulesSupportedPerUser.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfYearDaySchedulesSupportedPerUser.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/OperatingMode.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/RequirePINforRemoteOperation.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SendPINOverTheAir.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SupportedOperatingModes.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/UserCodeTemporaryDisableTime.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/WrongCodeEntryLimit.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/init.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearAliroReaderConfig.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearCredential.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearUser.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearWeekDaySchedule.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearYearDaySchedule.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetCredentialStatus.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetUser.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetWeekDaySchedule.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetYearDaySchedule.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/LockDoor.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetAliroReaderConfig.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetCredential.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetUser.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetWeekDaySchedule.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetYearDaySchedule.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/UnlockDoor.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/commands/init.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorLockAlarm.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorStateChange.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperation.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperationError.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockUserChange.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/server/events/init.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/AlarmCodeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialRuleEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialStruct.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialTypeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DataOperationTypeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DaysMaskMap.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadOperationEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadProgrammingEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlLocalProgrammingFeatures.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlLockState.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlManualOperationEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDOperationEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDProgrammingEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteOperationEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteProgrammingEventMask.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlStatus.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DlSupportedOperatingModes.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockDayOfWeek.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockOperationEventCode.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockProgrammingEventCode.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockSetPinOrIdStatus.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserStatus.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserType.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/DoorStateEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/Feature.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/LockDataTypeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/LockOperationTypeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/OperatingModeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/OperationErrorEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/OperationSourceEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/UserStatusEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/UserTypeEnum.lua create mode 100644 drivers/SmartThings/matter-lock/src/DoorLock/types/init.lua diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetCredentialStatusResponse.lua b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetCredentialStatusResponse.lua new file mode 100644 index 0000000000..70d0a6eff1 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetCredentialStatusResponse.lua @@ -0,0 +1,129 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetCredentialStatusResponse = {} + +GetCredentialStatusResponse.NAME = "GetCredentialStatusResponse" +GetCredentialStatusResponse.ID = 0x0025 +GetCredentialStatusResponse.field_defs = { + { + name = "credential_exists", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Boolean", + }, + { + name = "user_index", + field_id = 1, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "creator_fabric_index", + field_id = 2, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "last_modified_fabric_index", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "next_credential_index", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function GetCredentialStatusResponse:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetCredentialStatusResponse:build_test_command_response(device, endpoint_id, credential_exists, user_index, creator_fabric_index, last_modified_fabric_index, next_credential_index, interaction_status) + local function init(self, device, endpoint_id, credential_exists, user_index, creator_fabric_index, last_modified_fabric_index, next_credential_index) + local out = {} + local args = {credential_exists, user_index, creator_fabric_index, last_modified_fabric_index, next_credential_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetCredentialStatusResponse, + __tostring = GetCredentialStatusResponse.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) + end + local self_request = init(self, device, endpoint_id, credential_exists, user_index, creator_fabric_index, last_modified_fabric_index, next_credential_index) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + self_request.info_blocks[1].tlv, + interaction_status + ) +end + +function GetCredentialStatusResponse:init() + return nil +end + +function GetCredentialStatusResponse:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetCredentialStatusResponse:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetCredentialStatusResponse, {__call = GetCredentialStatusResponse.init}) + +return GetCredentialStatusResponse diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetUserResponse.lua b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetUserResponse.lua new file mode 100644 index 0000000000..6ee0bd8792 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetUserResponse.lua @@ -0,0 +1,165 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetUserResponse = {} + +GetUserResponse.NAME = "GetUserResponse" +GetUserResponse.ID = 0x001C +GetUserResponse.field_defs = { + { + name = "user_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "user_name", + field_id = 1, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.UTF8String1", + }, + { + name = "user_uniqueid", + field_id = 2, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint32", + }, + { + name = "user_status", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.UserStatusEnum", + }, + { + name = "user_type", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.UserTypeEnum", + }, + { + name = "credential_rule", + field_id = 5, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.CredentialRuleEnum", + }, + { + name = "credentials", + field_id = 6, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Array", + element_type = require "DoorLock.types.CredentialStruct", + }, + { + name = "creator_fabric_index", + field_id = 7, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "last_modified_fabric_index", + field_id = 8, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "next_user_index", + field_id = 9, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function GetUserResponse:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetUserResponse:build_test_command_response(device, endpoint_id, user_index, user_name, user_uniqueid, user_status, user_type, credential_rule, credentials, creator_fabric_index, last_modified_fabric_index, next_user_index, interaction_status) + local function init(self, device, endpoint_id, user_index, user_name, user_uniqueid, user_status, user_type, credential_rule, credentials, creator_fabric_index, last_modified_fabric_index, next_user_index) + local out = {} + local args = {user_index, user_name, user_uniqueid, user_status, user_type, credential_rule, credentials, creator_fabric_index, last_modified_fabric_index, next_user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetUserResponse, + __tostring = GetUserResponse.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) + end + local self_request = init(self, device, endpoint_id, user_index, user_name, user_uniqueid, user_status, user_type, credential_rule, credentials, creator_fabric_index, last_modified_fabric_index, next_user_index) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + self_request.info_blocks[1].tlv, + interaction_status + ) +end + +function GetUserResponse:init() + return nil +end + +function GetUserResponse:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetUserResponse:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetUserResponse, {__call = GetUserResponse.init}) + +return GetUserResponse diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetWeekDayScheduleResponse.lua b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetWeekDayScheduleResponse.lua new file mode 100644 index 0000000000..86b53a686e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetWeekDayScheduleResponse.lua @@ -0,0 +1,150 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetWeekDayScheduleResponse = {} + +GetWeekDayScheduleResponse.NAME = "GetWeekDayScheduleResponse" +GetWeekDayScheduleResponse.ID = 0x000C +GetWeekDayScheduleResponse.field_defs = { + { + name = "week_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "status", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DlStatus", + }, + { + name = "days_mask", + field_id = 3, + is_nullable = false, + is_optional = true, + data_type = require "DoorLock.types.DaysMaskMap", + }, + { + name = "start_hour", + field_id = 4, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "start_minute", + field_id = 5, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "end_hour", + field_id = 6, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "end_minute", + field_id = 7, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.Uint8", + }, +} + +function GetWeekDayScheduleResponse:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetWeekDayScheduleResponse:build_test_command_response(device, endpoint_id, week_day_index, user_index, status, days_mask, start_hour, start_minute, end_hour, end_minute, interaction_status) + local function init(self, device, endpoint_id, week_day_index, user_index, status, days_mask, start_hour, start_minute, end_hour, end_minute) + local out = {} + local args = {week_day_index, user_index, status, days_mask, start_hour, start_minute, end_hour, end_minute} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetWeekDayScheduleResponse, + __tostring = GetWeekDayScheduleResponse.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) + end + local self_request = init(self, device, endpoint_id, week_day_index, user_index, status, days_mask, start_hour, start_minute, end_hour, end_minute) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + self_request.info_blocks[1].tlv, + interaction_status + ) +end + +function GetWeekDayScheduleResponse:init() + return nil +end + +function GetWeekDayScheduleResponse:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetWeekDayScheduleResponse:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetWeekDayScheduleResponse, {__call = GetWeekDayScheduleResponse.init}) + +return GetWeekDayScheduleResponse diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetYearDayScheduleResponse.lua b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetYearDayScheduleResponse.lua new file mode 100644 index 0000000000..ecb591477e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/GetYearDayScheduleResponse.lua @@ -0,0 +1,129 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetYearDayScheduleResponse = {} + +GetYearDayScheduleResponse.NAME = "GetYearDayScheduleResponse" +GetYearDayScheduleResponse.ID = 0x000F +GetYearDayScheduleResponse.field_defs = { + { + name = "year_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "status", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DlStatus", + }, + { + name = "local_start_time", + field_id = 3, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.Uint32", + }, + { + name = "local_end_time", + field_id = 4, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.Uint32", + }, +} + +function GetYearDayScheduleResponse:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetYearDayScheduleResponse:build_test_command_response(device, endpoint_id, year_day_index, user_index, status, local_start_time, local_end_time, interaction_status) + local function init(self, device, endpoint_id, year_day_index, user_index, status, local_start_time, local_end_time) + local out = {} + local args = {year_day_index, user_index, status, local_start_time, local_end_time} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetYearDayScheduleResponse, + __tostring = GetYearDayScheduleResponse.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) + end + local self_request = init(self, device, endpoint_id, year_day_index, user_index, status, local_start_time, local_end_time) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + self_request.info_blocks[1].tlv, + interaction_status + ) +end + +function GetYearDayScheduleResponse:init() + return nil +end + +function GetYearDayScheduleResponse:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetYearDayScheduleResponse:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetYearDayScheduleResponse, {__call = GetYearDayScheduleResponse.init}) + +return GetYearDayScheduleResponse diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/SetCredentialResponse.lua b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/SetCredentialResponse.lua new file mode 100644 index 0000000000..eaf1658d14 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/SetCredentialResponse.lua @@ -0,0 +1,115 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SetCredentialResponse = {} + +SetCredentialResponse.NAME = "SetCredentialResponse" +SetCredentialResponse.ID = 0x0023 +SetCredentialResponse.field_defs = { + { + name = "status", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DlStatus", + }, + { + name = "user_index", + field_id = 1, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "next_credential_index", + field_id = 2, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function SetCredentialResponse:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function SetCredentialResponse:build_test_command_response(device, endpoint_id, status, user_index, next_credential_index, interaction_status) + local function init(self, device, endpoint_id, status, user_index, next_credential_index) + local out = {} + local args = {status, user_index, next_credential_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = SetCredentialResponse, + __tostring = SetCredentialResponse.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) + end + local self_request = init(self, device, endpoint_id, status, user_index, next_credential_index) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + self_request.info_blocks[1].tlv, + interaction_status + ) +end + +function SetCredentialResponse:init() + return nil +end + +function SetCredentialResponse:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SetCredentialResponse:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SetCredentialResponse, {__call = SetCredentialResponse.init}) + +return SetCredentialResponse diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/init.lua b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/init.lua new file mode 100644 index 0000000000..9148db5f96 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/client/commands/init.lua @@ -0,0 +1,23 @@ +local command_mt = {} +command_mt.__command_cache = {} +command_mt.__index = function(self, key) + if command_mt.__command_cache[key] == nil then + local req_loc = string.format("DoorLock.client.commands.%s", key) + local raw_def = require(req_loc) + local cluster = rawget(self, "_cluster") + command_mt.__command_cache[key] = raw_def:set_parent_cluster(cluster) + end + return command_mt.__command_cache[key] +end + +local DoorLockClientCommands = {} + +function DoorLockClientCommands:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +setmetatable(DoorLockClientCommands, command_mt) + +return DoorLockClientCommands + diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/init.lua b/drivers/SmartThings/matter-lock/src/DoorLock/init.lua new file mode 100644 index 0000000000..b9675ebf77 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/init.lua @@ -0,0 +1,258 @@ +local cluster_base = require "st.matter.cluster_base" +local DoorLockServerAttributes = require "DoorLock.server.attributes" +local DoorLockServerCommands = require "DoorLock.server.commands" +local DoorLockClientCommands = require "DoorLock.client.commands" +local DoorLockEvents = require "DoorLock.server.events" +local DoorLockTypes = require "DoorLock.types" + +local DoorLock = {} + +DoorLock.ID = 0x0101 +DoorLock.NAME = "DoorLock" +DoorLock.server = {} +DoorLock.client = {} +DoorLock.server.attributes = DoorLockServerAttributes:set_parent_cluster(DoorLock) +DoorLock.server.commands = DoorLockServerCommands:set_parent_cluster(DoorLock) +DoorLock.client.commands = DoorLockClientCommands:set_parent_cluster(DoorLock) +DoorLock.server.events = DoorLockEvents:set_parent_cluster(DoorLock) +DoorLock.types = DoorLockTypes + +function DoorLock:get_attribute_by_id(attr_id) + local attr_id_map = { + [0x0000] = "LockState", + [0x0001] = "LockType", + [0x0002] = "ActuatorEnabled", + [0x0003] = "DoorState", + [0x0004] = "DoorOpenEvents", + [0x0005] = "DoorClosedEvents", + [0x0006] = "OpenPeriod", + [0x0011] = "NumberOfTotalUsersSupported", + [0x0012] = "NumberOfPINUsersSupported", + [0x0013] = "NumberOfRFIDUsersSupported", + [0x0014] = "NumberOfWeekDaySchedulesSupportedPerUser", + [0x0015] = "NumberOfYearDaySchedulesSupportedPerUser", + [0x0016] = "NumberOfHolidaySchedulesSupported", + [0x0017] = "MaxPINCodeLength", + [0x0018] = "MinPINCodeLength", + [0x0019] = "MaxRFIDCodeLength", + [0x001A] = "MinRFIDCodeLength", + [0x001B] = "CredentialRulesSupport", + [0x001C] = "NumberOfCredentialsSupportedPerUser", + [0x0021] = "Language", + [0x0022] = "LEDSettings", + [0x0023] = "AutoRelockTime", + [0x0024] = "SoundVolume", + [0x0025] = "OperatingMode", + [0x0026] = "SupportedOperatingModes", + [0x0027] = "DefaultConfigurationRegister", + [0x0028] = "EnableLocalProgramming", + [0x0029] = "EnableOneTouchLocking", + [0x002A] = "EnableInsideStatusLED", + [0x002B] = "EnablePrivacyModeButton", + [0x002C] = "LocalProgrammingFeatures", + [0x0030] = "WrongCodeEntryLimit", + [0x0031] = "UserCodeTemporaryDisableTime", + [0x0032] = "SendPINOverTheAir", + [0x0033] = "RequirePINforRemoteOperation", + [0x0035] = "ExpiringUserTimeout", + [0x0080] = "AliroReaderVerificationKey", + [0x0081] = "AliroReaderGroupIdentifier", + [0x0082] = "AliroReaderGroupSubIdentifier", + [0x0083] = "AliroExpeditedTransactionSupportedProtocolVersions", + [0x0084] = "AliroGroupResolvingKey", + [0x0085] = "AliroSupportedBLEUWBProtocolVersions", + [0x0086] = "AliroBLEAdvertisingVersion", + [0x0087] = "NumberOfAliroCredentialIssuerKeysSupported", + [0x0088] = "NumberOfAliroEndpointKeysSupported", + [0xFFF9] = "AcceptedCommandList", + [0xFFFA] = "EventList", + [0xFFFB] = "AttributeList", + } + local attr_name = attr_id_map[attr_id] + if attr_name ~= nil then + return self.attributes[attr_name] + end + return nil +end + +function DoorLock:get_server_command_by_id(command_id) + local server_id_map = { + [0x0000] = "LockDoor", + [0x0001] = "UnlockDoor", + [0x0003] = "UnlockWithTimeout", + [0x000B] = "SetWeekDaySchedule", + [0x000C] = "GetWeekDaySchedule", + [0x000D] = "ClearWeekDaySchedule", + [0x000E] = "SetYearDaySchedule", + [0x000F] = "GetYearDaySchedule", + [0x0010] = "ClearYearDaySchedule", + [0x0011] = "SetHolidaySchedule", + [0x0012] = "GetHolidaySchedule", + [0x0013] = "ClearHolidaySchedule", + [0x001A] = "SetUser", + [0x001B] = "GetUser", + [0x001D] = "ClearUser", + [0x0022] = "SetCredential", + [0x0024] = "GetCredentialStatus", + [0x0026] = "ClearCredential", + [0x0027] = "UnboltDoor", + [0x0028] = "SetAliroReaderConfig", + [0x0029] = "ClearAliroReaderConfig", + } + if server_id_map[command_id] ~= nil then + return self.server.commands[server_id_map[command_id]] + end + return nil +end + +function DoorLock:get_client_command_by_id(command_id) + local client_id_map = { + [0x000C] = "GetWeekDayScheduleResponse", + [0x000F] = "GetYearDayScheduleResponse", + [0x0012] = "GetHolidayScheduleResponse", + [0x001C] = "GetUserResponse", + [0x0023] = "SetCredentialResponse", + [0x0025] = "GetCredentialStatusResponse", + } + if client_id_map[command_id] ~= nil then + return self.client.commands[client_id_map[command_id]] + end + return nil +end + +function DoorLock:get_event_by_id(event_id) + local event_id_map = { + [0x0000] = "DoorLockAlarm", + [0x0001] = "DoorStateChange", + [0x0002] = "LockOperation", + [0x0003] = "LockOperationError", + [0x0004] = "LockUserChange", + } + if event_id_map[event_id] ~= nil then + return self.server.events[event_id_map[event_id]] + end + return nil +end + +DoorLock.attribute_direction_map = { + ["LockState"] = "server", + ["LockType"] = "server", + ["ActuatorEnabled"] = "server", + ["DoorState"] = "server", + ["DoorOpenEvents"] = "server", + ["DoorClosedEvents"] = "server", + ["OpenPeriod"] = "server", + ["NumberOfTotalUsersSupported"] = "server", + ["NumberOfPINUsersSupported"] = "server", + ["NumberOfRFIDUsersSupported"] = "server", + ["NumberOfWeekDaySchedulesSupportedPerUser"] = "server", + ["NumberOfYearDaySchedulesSupportedPerUser"] = "server", + ["NumberOfHolidaySchedulesSupported"] = "server", + ["MaxPINCodeLength"] = "server", + ["MinPINCodeLength"] = "server", + ["MaxRFIDCodeLength"] = "server", + ["MinRFIDCodeLength"] = "server", + ["CredentialRulesSupport"] = "server", + ["NumberOfCredentialsSupportedPerUser"] = "server", + ["Language"] = "server", + ["LEDSettings"] = "server", + ["AutoRelockTime"] = "server", + ["SoundVolume"] = "server", + ["OperatingMode"] = "server", + ["SupportedOperatingModes"] = "server", + ["DefaultConfigurationRegister"] = "server", + ["EnableLocalProgramming"] = "server", + ["EnableOneTouchLocking"] = "server", + ["EnableInsideStatusLED"] = "server", + ["EnablePrivacyModeButton"] = "server", + ["LocalProgrammingFeatures"] = "server", + ["WrongCodeEntryLimit"] = "server", + ["UserCodeTemporaryDisableTime"] = "server", + ["SendPINOverTheAir"] = "server", + ["RequirePINforRemoteOperation"] = "server", + ["ExpiringUserTimeout"] = "server", + ["AliroReaderVerificationKey"] = "server", + ["AliroReaderGroupIdentifier"] = "server", + ["AliroReaderGroupSubIdentifier"] = "server", + ["AliroExpeditedTransactionSupportedProtocolVersions"] = "server", + ["AliroGroupResolvingKey"] = "server", + ["AliroSupportedBLEUWBProtocolVersions"] = "server", + ["AliroBLEAdvertisingVersion"] = "server", + ["NumberOfAliroCredentialIssuerKeysSupported"] = "server", + ["NumberOfAliroEndpointKeysSupported"] = "server", + ["AcceptedCommandList"] = "server", + ["EventList"] = "server", + ["AttributeList"] = "server", +} + +DoorLock.command_direction_map = { + ["LockDoor"] = "server", + ["UnlockDoor"] = "server", + ["UnlockWithTimeout"] = "server", + ["SetWeekDaySchedule"] = "server", + ["GetWeekDaySchedule"] = "server", + ["ClearWeekDaySchedule"] = "server", + ["SetYearDaySchedule"] = "server", + ["GetYearDaySchedule"] = "server", + ["ClearYearDaySchedule"] = "server", + ["SetHolidaySchedule"] = "server", + ["GetHolidaySchedule"] = "server", + ["ClearHolidaySchedule"] = "server", + ["SetUser"] = "server", + ["GetUser"] = "server", + ["ClearUser"] = "server", + ["SetCredential"] = "server", + ["GetCredentialStatus"] = "server", + ["ClearCredential"] = "server", + ["UnboltDoor"] = "server", + ["SetAliroReaderConfig"] = "server", + ["ClearAliroReaderConfig"] = "server", + ["GetWeekDayScheduleResponse"] = "client", + ["GetYearDayScheduleResponse"] = "client", + ["GetHolidayScheduleResponse"] = "client", + ["GetUserResponse"] = "client", + ["SetCredentialResponse"] = "client", + ["GetCredentialStatusResponse"] = "client", +} + +DoorLock.FeatureMap = DoorLock.types.Feature + +function DoorLock.are_features_supported(feature, feature_map) + if (DoorLock.FeatureMap.bits_are_valid(feature)) then + return (feature & feature_map) == feature + end + return false +end + +local attribute_helper_mt = {} +attribute_helper_mt.__index = function(self, key) + local direction = DoorLock.attribute_direction_map[key] + if direction == nil then + error(string.format("Referenced unknown attribute %s on cluster %s", key, DoorLock.NAME)) + end + return DoorLock[direction].attributes[key] +end +DoorLock.attributes = {} +setmetatable(DoorLock.attributes, attribute_helper_mt) + +local command_helper_mt = {} +command_helper_mt.__index = function(self, key) + local direction = DoorLock.command_direction_map[key] + if direction == nil then + error(string.format("Referenced unknown command %s on cluster %s", key, DoorLock.NAME)) + end + return DoorLock[direction].commands[key] +end +DoorLock.commands = {} +setmetatable(DoorLock.commands, command_helper_mt) + +local event_helper_mt = {} +event_helper_mt.__index = function(self, key) + return DoorLock.server.events[key] +end +DoorLock.events = {} +setmetatable(DoorLock.events, event_helper_mt) + +setmetatable(DoorLock, {__index = cluster_base}) + +return DoorLock \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AcceptedCommandList.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AcceptedCommandList.lua new file mode 100644 index 0000000000..fe8e273558 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AcceptedCommandList.lua @@ -0,0 +1,74 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AcceptedCommandList = { + ID = 0xFFF9, + NAME = "AcceptedCommandList", + base_type = require "st.matter.data_types.Array", + element_type = require "st.matter.data_types.Uint32", +} + +function AcceptedCommandList:augment_type(data_type_obj) + for i, v in ipairs(data_type_obj.elements) do + data_type_obj.elements[i] = data_types.validate_or_build_type(v, AcceptedCommandList.element_type) + end +end + +function AcceptedCommandList:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AcceptedCommandList:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AcceptedCommandList:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AcceptedCommandList:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AcceptedCommandList:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AcceptedCommandList:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AcceptedCommandList, {__call = AcceptedCommandList.new_value, __index = AcceptedCommandList.base_type}) +return AcceptedCommandList \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/ActuatorEnabled.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/ActuatorEnabled.lua new file mode 100644 index 0000000000..359261a551 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/ActuatorEnabled.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local ActuatorEnabled = { + ID = 0x0002, + NAME = "ActuatorEnabled", + base_type = require "st.matter.data_types.Boolean", +} + +function ActuatorEnabled:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function ActuatorEnabled:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function ActuatorEnabled:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil --event_id + ) +end + +function ActuatorEnabled:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function ActuatorEnabled:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function ActuatorEnabled:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(ActuatorEnabled, {__call = ActuatorEnabled.new_value, __index = ActuatorEnabled.base_type}) +return ActuatorEnabled \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroBLEAdvertisingVersion.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroBLEAdvertisingVersion.lua new file mode 100644 index 0000000000..582babc3cb --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroBLEAdvertisingVersion.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AliroBLEAdvertisingVersion = { + ID = 0x0086, + NAME = "AliroBLEAdvertisingVersion", + base_type = require "st.matter.data_types.Uint8", +} + +function AliroBLEAdvertisingVersion:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AliroBLEAdvertisingVersion:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroBLEAdvertisingVersion:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroBLEAdvertisingVersion:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AliroBLEAdvertisingVersion:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AliroBLEAdvertisingVersion:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AliroBLEAdvertisingVersion, {__call = AliroBLEAdvertisingVersion.new_value, __index = AliroBLEAdvertisingVersion.base_type}) +return AliroBLEAdvertisingVersion \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroExpeditedTransactionSupportedProtocolVersions.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroExpeditedTransactionSupportedProtocolVersions.lua new file mode 100644 index 0000000000..1e5ed5f7f5 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroExpeditedTransactionSupportedProtocolVersions.lua @@ -0,0 +1,74 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AliroExpeditedTransactionSupportedProtocolVersions = { + ID = 0x0083, + NAME = "AliroExpeditedTransactionSupportedProtocolVersions", + base_type = require "st.matter.data_types.Array", + element_type = require "st.matter.data_types.OctetString1", +} + +function AliroExpeditedTransactionSupportedProtocolVersions:augment_type(data_type_obj) + for i, v in ipairs(data_type_obj.elements) do + data_type_obj.elements[i] = data_types.validate_or_build_type(v, AliroExpeditedTransactionSupportedProtocolVersions.element_type) + end +end + +function AliroExpeditedTransactionSupportedProtocolVersions:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AliroExpeditedTransactionSupportedProtocolVersions:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroExpeditedTransactionSupportedProtocolVersions:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroExpeditedTransactionSupportedProtocolVersions:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AliroExpeditedTransactionSupportedProtocolVersions:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AliroExpeditedTransactionSupportedProtocolVersions:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AliroExpeditedTransactionSupportedProtocolVersions, {__call = AliroExpeditedTransactionSupportedProtocolVersions.new_value, __index = AliroExpeditedTransactionSupportedProtocolVersions.base_type}) +return AliroExpeditedTransactionSupportedProtocolVersions \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroGroupResolvingKey.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroGroupResolvingKey.lua new file mode 100644 index 0000000000..517cc25aeb --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroGroupResolvingKey.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AliroGroupResolvingKey = { + ID = 0x0084, + NAME = "AliroGroupResolvingKey", + base_type = require "st.matter.data_types.OctetString1", +} + +function AliroGroupResolvingKey:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AliroGroupResolvingKey:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroGroupResolvingKey:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroGroupResolvingKey:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AliroGroupResolvingKey:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AliroGroupResolvingKey:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AliroGroupResolvingKey, {__call = AliroGroupResolvingKey.new_value, __index = AliroGroupResolvingKey.base_type}) +return AliroGroupResolvingKey \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupIdentifier.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupIdentifier.lua new file mode 100644 index 0000000000..bce6f2c049 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupIdentifier.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AliroReaderGroupIdentifier = { + ID = 0x0081, + NAME = "AliroReaderGroupIdentifier", + base_type = require "st.matter.data_types.OctetString1", +} + +function AliroReaderGroupIdentifier:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AliroReaderGroupIdentifier:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroReaderGroupIdentifier:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroReaderGroupIdentifier:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AliroReaderGroupIdentifier:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AliroReaderGroupIdentifier:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AliroReaderGroupIdentifier, {__call = AliroReaderGroupIdentifier.new_value, __index = AliroReaderGroupIdentifier.base_type}) +return AliroReaderGroupIdentifier \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupSubIdentifier.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupSubIdentifier.lua new file mode 100644 index 0000000000..867dbcce93 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderGroupSubIdentifier.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AliroReaderGroupSubIdentifier = { + ID = 0x0082, + NAME = "AliroReaderGroupSubIdentifier", + base_type = require "st.matter.data_types.OctetString1", +} + +function AliroReaderGroupSubIdentifier:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AliroReaderGroupSubIdentifier:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroReaderGroupSubIdentifier:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroReaderGroupSubIdentifier:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AliroReaderGroupSubIdentifier:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AliroReaderGroupSubIdentifier:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AliroReaderGroupSubIdentifier, {__call = AliroReaderGroupSubIdentifier.new_value, __index = AliroReaderGroupSubIdentifier.base_type}) +return AliroReaderGroupSubIdentifier \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderVerificationKey.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderVerificationKey.lua new file mode 100644 index 0000000000..ccf8ac37a0 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AliroReaderVerificationKey.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AliroReaderVerificationKey = { + ID = 0x0080, + NAME = "AliroReaderVerificationKey", + base_type = require "st.matter.data_types.OctetString1", +} + +function AliroReaderVerificationKey:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AliroReaderVerificationKey:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroReaderVerificationKey:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AliroReaderVerificationKey:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AliroReaderVerificationKey:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AliroReaderVerificationKey:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AliroReaderVerificationKey, {__call = AliroReaderVerificationKey.new_value, __index = AliroReaderVerificationKey.base_type}) +return AliroReaderVerificationKey \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AttributeList.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AttributeList.lua new file mode 100644 index 0000000000..c191ec3d5a --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/AttributeList.lua @@ -0,0 +1,74 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local AttributeList = { + ID = 0xFFFB, + NAME = "AttributeList", + base_type = require "st.matter.data_types.Array", + element_type = require "st.matter.data_types.Uint32", +} + +function AttributeList:augment_type(data_type_obj) + for i, v in ipairs(data_type_obj.elements) do + data_type_obj.elements[i] = data_types.validate_or_build_type(v, AttributeList.element_type) + end +end + +function AttributeList:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function AttributeList:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AttributeList:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function AttributeList:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function AttributeList:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function AttributeList:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(AttributeList, {__call = AttributeList.new_value, __index = AttributeList.base_type}) +return AttributeList \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/DoorState.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/DoorState.lua new file mode 100644 index 0000000000..59fd6cbe79 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/DoorState.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local DoorState = { + ID = 0x0003, + NAME = "DoorState", + base_type = require "DoorLock.types.DoorStateEnum", +} + +function DoorState:new_value(...) + local o = self.base_type(table.unpack({...})) + self:augment_type(o) + return o +end + +function DoorState:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function DoorState:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil --event_id + ) +end + +function DoorState:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function DoorState:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + self:augment_type(data) + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function DoorState:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(DoorState, {__call = DoorState.new_value, __index = DoorState.base_type}) +return DoorState \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/EventList.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/EventList.lua new file mode 100644 index 0000000000..616bbf92bc --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/EventList.lua @@ -0,0 +1,74 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local EventList = { + ID = 0xFFFA, + NAME = "EventList", + base_type = require "st.matter.data_types.Array", + element_type = require "st.matter.data_types.Uint32", +} + +function EventList:augment_type(data_type_obj) + for i, v in ipairs(data_type_obj.elements) do + data_type_obj.elements[i] = data_types.validate_or_build_type(v, EventList.element_type) + end +end + +function EventList:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function EventList:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function EventList:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function EventList:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function EventList:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function EventList:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(EventList, {__call = EventList.new_value, __index = EventList.base_type}) +return EventList \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/LockState.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/LockState.lua new file mode 100644 index 0000000000..5d7615e2c6 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/LockState.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local LockState = { + ID = 0x0000, + NAME = "LockState", + base_type = require "DoorLock.types.DlLockState", +} + +function LockState:new_value(...) + local o = self.base_type(table.unpack({...})) + self:augment_type(o) + return o +end + +function LockState:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function LockState:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function LockState:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function LockState:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + self:augment_type(data) + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function LockState:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(LockState, {__call = LockState.new_value, __index = LockState.base_type}) +return LockState \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MaxPINCodeLength.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MaxPINCodeLength.lua new file mode 100644 index 0000000000..efdef6065c --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MaxPINCodeLength.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local MaxPINCodeLength = { + ID = 0x0017, + NAME = "MaxPINCodeLength", + base_type = require "st.matter.data_types.Uint8", +} + +function MaxPINCodeLength:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function MaxPINCodeLength:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function MaxPINCodeLength:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function MaxPINCodeLength:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function MaxPINCodeLength:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function MaxPINCodeLength:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(MaxPINCodeLength, {__call = MaxPINCodeLength.new_value, __index = MaxPINCodeLength.base_type}) +return MaxPINCodeLength \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MinPINCodeLength.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MinPINCodeLength.lua new file mode 100644 index 0000000000..f94a777a64 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/MinPINCodeLength.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local MinPINCodeLength = { + ID = 0x0018, + NAME = "MinPINCodeLength", + base_type = require "st.matter.data_types.Uint8", +} + +function MinPINCodeLength:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function MinPINCodeLength:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function MinPINCodeLength:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function MinPINCodeLength:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function MinPINCodeLength:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function MinPINCodeLength:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(MinPINCodeLength, {__call = MinPINCodeLength.new_value, __index = MinPINCodeLength.base_type}) +return MinPINCodeLength \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroCredentialIssuerKeysSupported.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroCredentialIssuerKeysSupported.lua new file mode 100644 index 0000000000..f28e356e3c --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroCredentialIssuerKeysSupported.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfAliroCredentialIssuerKeysSupported = { + ID = 0x0087, + NAME = "NumberOfAliroCredentialIssuerKeysSupported", + base_type = require "st.matter.data_types.Uint16", +} + +function NumberOfAliroCredentialIssuerKeysSupported:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfAliroCredentialIssuerKeysSupported:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfAliroCredentialIssuerKeysSupported:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfAliroCredentialIssuerKeysSupported:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfAliroCredentialIssuerKeysSupported:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfAliroCredentialIssuerKeysSupported:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfAliroCredentialIssuerKeysSupported, {__call = NumberOfAliroCredentialIssuerKeysSupported.new_value, __index = NumberOfAliroCredentialIssuerKeysSupported.base_type}) +return NumberOfAliroCredentialIssuerKeysSupported \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroEndpointKeysSupported.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroEndpointKeysSupported.lua new file mode 100644 index 0000000000..b40d6c7df4 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfAliroEndpointKeysSupported.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfAliroEndpointKeysSupported = { + ID = 0x0088, + NAME = "NumberOfAliroEndpointKeysSupported", + base_type = require "st.matter.data_types.Uint16", +} + +function NumberOfAliroEndpointKeysSupported:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfAliroEndpointKeysSupported:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfAliroEndpointKeysSupported:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfAliroEndpointKeysSupported:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfAliroEndpointKeysSupported:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfAliroEndpointKeysSupported:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfAliroEndpointKeysSupported, {__call = NumberOfAliroEndpointKeysSupported.new_value, __index = NumberOfAliroEndpointKeysSupported.base_type}) +return NumberOfAliroEndpointKeysSupported \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfCredentialsSupportedPerUser.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfCredentialsSupportedPerUser.lua new file mode 100644 index 0000000000..48f08cf19c --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfCredentialsSupportedPerUser.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfCredentialsSupportedPerUser = { + ID = 0x001C, + NAME = "NumberOfCredentialsSupportedPerUser", + base_type = require "st.matter.data_types.Uint8", +} + +function NumberOfCredentialsSupportedPerUser:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfCredentialsSupportedPerUser:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfCredentialsSupportedPerUser:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfCredentialsSupportedPerUser:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfCredentialsSupportedPerUser:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfCredentialsSupportedPerUser:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfCredentialsSupportedPerUser, {__call = NumberOfCredentialsSupportedPerUser.new_value, __index = NumberOfCredentialsSupportedPerUser.base_type}) +return NumberOfCredentialsSupportedPerUser \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfPINUsersSupported.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfPINUsersSupported.lua new file mode 100644 index 0000000000..c9a2da141d --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfPINUsersSupported.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfPINUsersSupported = { + ID = 0x0012, + NAME = "NumberOfPINUsersSupported", + base_type = require "st.matter.data_types.Uint16", +} + +function NumberOfPINUsersSupported:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfPINUsersSupported:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfPINUsersSupported:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfPINUsersSupported:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfPINUsersSupported:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfPINUsersSupported:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfPINUsersSupported, {__call = NumberOfPINUsersSupported.new_value, __index = NumberOfPINUsersSupported.base_type}) +return NumberOfPINUsersSupported \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfTotalUsersSupported.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfTotalUsersSupported.lua new file mode 100644 index 0000000000..ff0cd93791 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfTotalUsersSupported.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfTotalUsersSupported = { + ID = 0x0011, + NAME = "NumberOfTotalUsersSupported", + base_type = require "st.matter.data_types.Uint16", +} + +function NumberOfTotalUsersSupported:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfTotalUsersSupported:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfTotalUsersSupported:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfTotalUsersSupported:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfTotalUsersSupported:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfTotalUsersSupported:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfTotalUsersSupported, {__call = NumberOfTotalUsersSupported.new_value, __index = NumberOfTotalUsersSupported.base_type}) +return NumberOfTotalUsersSupported \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfWeekDaySchedulesSupportedPerUser.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfWeekDaySchedulesSupportedPerUser.lua new file mode 100644 index 0000000000..f5878babee --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfWeekDaySchedulesSupportedPerUser.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfWeekDaySchedulesSupportedPerUser = { + ID = 0x0014, + NAME = "NumberOfWeekDaySchedulesSupportedPerUser", + base_type = require "st.matter.data_types.Uint8", +} + +function NumberOfWeekDaySchedulesSupportedPerUser:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfWeekDaySchedulesSupportedPerUser:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfWeekDaySchedulesSupportedPerUser:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfWeekDaySchedulesSupportedPerUser:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfWeekDaySchedulesSupportedPerUser:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfWeekDaySchedulesSupportedPerUser:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfWeekDaySchedulesSupportedPerUser, {__call = NumberOfWeekDaySchedulesSupportedPerUser.new_value, __index = NumberOfWeekDaySchedulesSupportedPerUser.base_type}) +return NumberOfWeekDaySchedulesSupportedPerUser \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfYearDaySchedulesSupportedPerUser.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfYearDaySchedulesSupportedPerUser.lua new file mode 100644 index 0000000000..4039dab170 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/NumberOfYearDaySchedulesSupportedPerUser.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local NumberOfYearDaySchedulesSupportedPerUser = { + ID = 0x0015, + NAME = "NumberOfYearDaySchedulesSupportedPerUser", + base_type = require "st.matter.data_types.Uint8", +} + +function NumberOfYearDaySchedulesSupportedPerUser:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function NumberOfYearDaySchedulesSupportedPerUser:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfYearDaySchedulesSupportedPerUser:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function NumberOfYearDaySchedulesSupportedPerUser:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function NumberOfYearDaySchedulesSupportedPerUser:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function NumberOfYearDaySchedulesSupportedPerUser:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(NumberOfYearDaySchedulesSupportedPerUser, {__call = NumberOfYearDaySchedulesSupportedPerUser.new_value, __index = NumberOfYearDaySchedulesSupportedPerUser.base_type}) +return NumberOfYearDaySchedulesSupportedPerUser \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/OperatingMode.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/OperatingMode.lua new file mode 100644 index 0000000000..79823fb0e4 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/OperatingMode.lua @@ -0,0 +1,80 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local OperatingMode = { + ID = 0x0025, + NAME = "OperatingMode", + base_type = require "DoorLock.types.OperatingModeEnum", +} + +function OperatingMode:new_value(...) + local o = self.base_type(table.unpack({...})) + self:augment_type(o) + return o +end + +function OperatingMode:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function OperatingMode:write(device, endpoint_id, value) + local data = data_types.validate_or_build_type(value, self.base_type) + self:augment_type(data) + return cluster_base.write( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + data + ) +end + +function OperatingMode:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function OperatingMode:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function OperatingMode:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + self:augment_type(data) + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function OperatingMode:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(OperatingMode, {__call = OperatingMode.new_value, __index = OperatingMode.base_type}) +return OperatingMode \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/RequirePINforRemoteOperation.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/RequirePINforRemoteOperation.lua new file mode 100644 index 0000000000..6512d9e530 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/RequirePINforRemoteOperation.lua @@ -0,0 +1,80 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local RequirePINforRemoteOperation = { + ID = 0x0033, + NAME = "RequirePINforRemoteOperation", + base_type = require "st.matter.data_types.Boolean", +} + +function RequirePINforRemoteOperation:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function RequirePINforRemoteOperation:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function RequirePINforRemoteOperation:write(device, endpoint_id, value) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.write( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + data + ) +end + +function RequirePINforRemoteOperation:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function RequirePINforRemoteOperation:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function RequirePINforRemoteOperation:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function RequirePINforRemoteOperation:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(RequirePINforRemoteOperation, {__call = RequirePINforRemoteOperation.new_value, __index = RequirePINforRemoteOperation.base_type}) +return RequirePINforRemoteOperation \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SendPINOverTheAir.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SendPINOverTheAir.lua new file mode 100644 index 0000000000..5b52a9b583 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SendPINOverTheAir.lua @@ -0,0 +1,80 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SendPINOverTheAir = { + ID = 0x0032, + NAME = "SendPINOverTheAir", + base_type = require "st.matter.data_types.Boolean", +} + +function SendPINOverTheAir:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function SendPINOverTheAir:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function SendPINOverTheAir:write(device, endpoint_id, value) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.write( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + data + ) +end + +function SendPINOverTheAir:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function SendPINOverTheAir:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SendPINOverTheAir:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function SendPINOverTheAir:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(SendPINOverTheAir, {__call = SendPINOverTheAir.new_value, __index = SendPINOverTheAir.base_type}) +return SendPINOverTheAir \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SupportedOperatingModes.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SupportedOperatingModes.lua new file mode 100644 index 0000000000..7859d8346e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/SupportedOperatingModes.lua @@ -0,0 +1,67 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SupportedOperatingModes = { + ID = 0x0026, + NAME = "SupportedOperatingModes", + base_type = require "DoorLock.types.DlSupportedOperatingModes", +} + +function SupportedOperatingModes:new_value(...) + local o = self.base_type(table.unpack({...})) + self:augment_type(o) + return o +end + +function SupportedOperatingModes:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function SupportedOperatingModes:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function SupportedOperatingModes:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SupportedOperatingModes:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + self:augment_type(data) + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function SupportedOperatingModes:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SupportedOperatingModes, {__call = SupportedOperatingModes.new_value, __index = SupportedOperatingModes.base_type}) +return SupportedOperatingModes \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/UserCodeTemporaryDisableTime.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/UserCodeTemporaryDisableTime.lua new file mode 100644 index 0000000000..26226e667c --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/UserCodeTemporaryDisableTime.lua @@ -0,0 +1,80 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local UserCodeTemporaryDisableTime = { + ID = 0x0031, + NAME = "UserCodeTemporaryDisableTime", + base_type = require "st.matter.data_types.Uint8", +} + +function UserCodeTemporaryDisableTime:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function UserCodeTemporaryDisableTime:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function UserCodeTemporaryDisableTime:write(device, endpoint_id, value) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.write( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + data + ) +end + +function UserCodeTemporaryDisableTime:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function UserCodeTemporaryDisableTime:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function UserCodeTemporaryDisableTime:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function UserCodeTemporaryDisableTime:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(UserCodeTemporaryDisableTime, {__call = UserCodeTemporaryDisableTime.new_value, __index = UserCodeTemporaryDisableTime.base_type}) +return UserCodeTemporaryDisableTime \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/WrongCodeEntryLimit.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/WrongCodeEntryLimit.lua new file mode 100644 index 0000000000..2109ef3945 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/WrongCodeEntryLimit.lua @@ -0,0 +1,80 @@ +local cluster_base = require "st.matter.cluster_base" +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local WrongCodeEntryLimit = { + ID = 0x0030, + NAME = "WrongCodeEntryLimit", + base_type = require "st.matter.data_types.Uint8", +} + +function WrongCodeEntryLimit:new_value(...) + local o = self.base_type(table.unpack({...})) + + return o +end + +function WrongCodeEntryLimit:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function WrongCodeEntryLimit:write(device, endpoint_id, value) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.write( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + data + ) +end + +function WrongCodeEntryLimit:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil + ) +end + +function WrongCodeEntryLimit:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function WrongCodeEntryLimit:build_test_report_data( + device, + endpoint_id, + value, + status +) + local data = data_types.validate_or_build_type(value, self.base_type) + + return cluster_base.build_test_report_data( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function WrongCodeEntryLimit:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + + return data +end + +setmetatable(WrongCodeEntryLimit, {__call = WrongCodeEntryLimit.new_value, __index = WrongCodeEntryLimit.base_type}) +return WrongCodeEntryLimit \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/init.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/init.lua new file mode 100644 index 0000000000..9e35b63132 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/attributes/init.lua @@ -0,0 +1,23 @@ +local attr_mt = {} +attr_mt.__attr_cache = {} +attr_mt.__index = function(self, key) + if attr_mt.__attr_cache[key] == nil then + local req_loc = string.format("DoorLock.server.attributes.%s", key) + local raw_def = require(req_loc) + local cluster = rawget(self, "_cluster") + raw_def:set_parent_cluster(cluster) + attr_mt.__attr_cache[key] = raw_def + end + return attr_mt.__attr_cache[key] +end + +local DoorLockServerAttributes = {} + +function DoorLockServerAttributes:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +setmetatable(DoorLockServerAttributes, attr_mt) + +return DoorLockServerAttributes \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearAliroReaderConfig.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearAliroReaderConfig.lua new file mode 100644 index 0000000000..007104e3ec --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearAliroReaderConfig.lua @@ -0,0 +1,91 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local ClearAliroReaderConfig = {} + +ClearAliroReaderConfig.NAME = "ClearAliroReaderConfig" +ClearAliroReaderConfig.ID = 0x0029 +ClearAliroReaderConfig.field_defs = { +} + +function ClearAliroReaderConfig:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function ClearAliroReaderConfig:init(device, endpoint_id) + local out = {} + local args = {} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = ClearAliroReaderConfig, + __tostring = ClearAliroReaderConfig.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function ClearAliroReaderConfig:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function ClearAliroReaderConfig:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function ClearAliroReaderConfig:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(ClearAliroReaderConfig, {__call = ClearAliroReaderConfig.init}) + +return ClearAliroReaderConfig \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearCredential.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearCredential.lua new file mode 100644 index 0000000000..07244d15a5 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearCredential.lua @@ -0,0 +1,98 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local ClearCredential = {} + +ClearCredential.NAME = "ClearCredential" +ClearCredential.ID = 0x0026 +ClearCredential.field_defs = { + { + name = "credential", + field_id = 0, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.CredentialStruct", + }, +} + +function ClearCredential:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function ClearCredential:init(device, endpoint_id, credential) + local out = {} + local args = {credential} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = ClearCredential, + __tostring = ClearCredential.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function ClearCredential:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function ClearCredential:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function ClearCredential:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(ClearCredential, {__call = ClearCredential.init}) + +return ClearCredential \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearUser.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearUser.lua new file mode 100644 index 0000000000..2e5b7ba51b --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearUser.lua @@ -0,0 +1,98 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local ClearUser = {} + +ClearUser.NAME = "ClearUser" +ClearUser.ID = 0x001D +ClearUser.field_defs = { + { + name = "user_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function ClearUser:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function ClearUser:init(device, endpoint_id, user_index) + local out = {} + local args = {user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = ClearUser, + __tostring = ClearUser.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function ClearUser:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function ClearUser:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function ClearUser:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(ClearUser, {__call = ClearUser.init}) + +return ClearUser \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearWeekDaySchedule.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearWeekDaySchedule.lua new file mode 100644 index 0000000000..30ddd45933 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearWeekDaySchedule.lua @@ -0,0 +1,104 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local ClearWeekDaySchedule = {} + +ClearWeekDaySchedule.NAME = "ClearWeekDaySchedule" +ClearWeekDaySchedule.ID = 0x000D +ClearWeekDaySchedule.field_defs = { + { + name = "week_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function ClearWeekDaySchedule:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function ClearWeekDaySchedule:init(device, endpoint_id, week_day_index, user_index) + local out = {} + local args = {week_day_index, user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = ClearWeekDaySchedule, + __tostring = ClearWeekDaySchedule.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function ClearWeekDaySchedule:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function ClearWeekDaySchedule:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function ClearWeekDaySchedule:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(ClearWeekDaySchedule, {__call = ClearWeekDaySchedule.init}) + +return ClearWeekDaySchedule \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearYearDaySchedule.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearYearDaySchedule.lua new file mode 100644 index 0000000000..ba9380b114 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/ClearYearDaySchedule.lua @@ -0,0 +1,104 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local ClearYearDaySchedule = {} + +ClearYearDaySchedule.NAME = "ClearYearDaySchedule" +ClearYearDaySchedule.ID = 0x0010 +ClearYearDaySchedule.field_defs = { + { + name = "year_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function ClearYearDaySchedule:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function ClearYearDaySchedule:init(device, endpoint_id, year_day_index, user_index) + local out = {} + local args = {year_day_index, user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = ClearYearDaySchedule, + __tostring = ClearYearDaySchedule.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function ClearYearDaySchedule:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function ClearYearDaySchedule:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function ClearYearDaySchedule:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(ClearYearDaySchedule, {__call = ClearYearDaySchedule.init}) + +return ClearYearDaySchedule \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetCredentialStatus.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetCredentialStatus.lua new file mode 100644 index 0000000000..9b1d37355e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetCredentialStatus.lua @@ -0,0 +1,86 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetCredentialStatus = {} + +GetCredentialStatus.NAME = "GetCredentialStatus" +GetCredentialStatus.ID = 0x0024 +GetCredentialStatus.field_defs = { + { + name = "credential", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.CredentialStruct", + }, +} + +function GetCredentialStatus:init(device, endpoint_id, credential) + local out = {} + local args = {credential} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetCredentialStatus, + __tostring = GetCredentialStatus.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function GetCredentialStatus:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetCredentialStatus:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetCredentialStatus:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetCredentialStatus, {__call = GetCredentialStatus.init}) + +return GetCredentialStatus \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetUser.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetUser.lua new file mode 100644 index 0000000000..ecdf60bdcd --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetUser.lua @@ -0,0 +1,86 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetUser = {} + +GetUser.NAME = "GetUser" +GetUser.ID = 0x001B +GetUser.field_defs = { + { + name = "user_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function GetUser:init(device, endpoint_id, user_index) + local out = {} + local args = {user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetUser, + __tostring = GetUser.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function GetUser:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetUser:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetUser:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetUser, {__call = GetUser.init}) + +return GetUser \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetWeekDaySchedule.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetWeekDaySchedule.lua new file mode 100644 index 0000000000..817c57cda4 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetWeekDaySchedule.lua @@ -0,0 +1,93 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetWeekDaySchedule = {} + +GetWeekDaySchedule.NAME = "GetWeekDaySchedule" +GetWeekDaySchedule.ID = 0x000C +GetWeekDaySchedule.field_defs = { + { + name = "week_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function GetWeekDaySchedule:init(device, endpoint_id, week_day_index, user_index) + local out = {} + local args = {week_day_index, user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetWeekDaySchedule, + __tostring = GetWeekDaySchedule.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function GetWeekDaySchedule:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetWeekDaySchedule:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetWeekDaySchedule:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetWeekDaySchedule, {__call = GetWeekDaySchedule.init}) + +return GetWeekDaySchedule \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetYearDaySchedule.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetYearDaySchedule.lua new file mode 100644 index 0000000000..35ea38a3f8 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/GetYearDaySchedule.lua @@ -0,0 +1,93 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local GetYearDaySchedule = {} + +GetYearDaySchedule.NAME = "GetYearDaySchedule" +GetYearDaySchedule.ID = 0x000F +GetYearDaySchedule.field_defs = { + { + name = "year_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function GetYearDaySchedule:init(device, endpoint_id, year_day_index, user_index) + local out = {} + local args = {year_day_index, user_index} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = GetYearDaySchedule, + __tostring = GetYearDaySchedule.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function GetYearDaySchedule:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function GetYearDaySchedule:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function GetYearDaySchedule:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(GetYearDaySchedule, {__call = GetYearDaySchedule.init}) + +return GetYearDaySchedule \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/LockDoor.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/LockDoor.lua new file mode 100644 index 0000000000..9440546cab --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/LockDoor.lua @@ -0,0 +1,98 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local LockDoor = {} + +LockDoor.NAME = "LockDoor" +LockDoor.ID = 0x0000 +LockDoor.field_defs = { + { + name = "pin_code", + field_id = 0, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.OctetString1", + }, +} + +function LockDoor:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function LockDoor:init(device, endpoint_id, pin_code) + local out = {} + local args = {pin_code} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = LockDoor, + __tostring = LockDoor.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function LockDoor:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function LockDoor:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function LockDoor:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(LockDoor, {__call = LockDoor.init}) + +return LockDoor \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetAliroReaderConfig.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetAliroReaderConfig.lua new file mode 100644 index 0000000000..8317db64b7 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetAliroReaderConfig.lua @@ -0,0 +1,119 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SetAliroReaderConfig = {} + +SetAliroReaderConfig.NAME = "SetAliroReaderConfig" +SetAliroReaderConfig.ID = 0x0028 +SetAliroReaderConfig.field_defs = { + { + name = "signing_key", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.OctetString1", + }, + { + name = "verification_key", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.OctetString1", + }, + { + name = "group_identifier", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.OctetString1", + }, + { + name = "group_resolving_key", + field_id = 3, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.OctetString1", + }, +} + +function SetAliroReaderConfig:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function SetAliroReaderConfig:init(device, endpoint_id, signing_key, verification_key, group_identifier, group_resolving_key) + local out = {} + local args = {signing_key, verification_key, group_identifier, group_resolving_key} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = SetAliroReaderConfig, + __tostring = SetAliroReaderConfig.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function SetAliroReaderConfig:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SetAliroReaderConfig:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function SetAliroReaderConfig:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SetAliroReaderConfig, {__call = SetAliroReaderConfig.init}) + +return SetAliroReaderConfig \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetCredential.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetCredential.lua new file mode 100644 index 0000000000..ad024b9619 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetCredential.lua @@ -0,0 +1,122 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SetCredential = {} + +SetCredential.NAME = "SetCredential" +SetCredential.ID = 0x0022 +SetCredential.field_defs = { + { + name = "operation_type", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DataOperationTypeEnum", + }, + { + name = "credential", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.CredentialStruct", + }, + { + name = "credential_data", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.OctetString2", + }, + { + name = "user_index", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "user_status", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.UserStatusEnum", + }, + { + name = "user_type", + field_id = 5, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.UserTypeEnum", + }, +} + +function SetCredential:init(device, endpoint_id, operation_type, credential, credential_data, user_index, user_status, user_type) + local out = {} + local args = {operation_type, credential, credential_data, user_index, user_status, user_type} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = SetCredential, + __tostring = SetCredential.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function SetCredential:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SetCredential:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function SetCredential:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SetCredential, {__call = SetCredential.init}) + +return SetCredential \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetUser.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetUser.lua new file mode 100644 index 0000000000..a115db2b57 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetUser.lua @@ -0,0 +1,140 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SetUser = {} + +SetUser.NAME = "SetUser" +SetUser.ID = 0x001A +SetUser.field_defs = { + { + name = "operation_type", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DataOperationTypeEnum", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "user_name", + field_id = 2, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.UTF8String1", + }, + { + name = "user_uniqueid", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint32", + }, + { + name = "user_status", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.UserStatusEnum", + }, + { + name = "user_type", + field_id = 5, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.UserTypeEnum", + }, + { + name = "credential_rule", + field_id = 6, + is_nullable = true, + is_optional = false, + data_type = require "DoorLock.types.CredentialRuleEnum", + }, +} + +function SetUser:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function SetUser:init(device, endpoint_id, operation_type, user_index, user_name, user_uniqueid, user_status, user_type, credential_rule) + local out = {} + local args = {operation_type, user_index, user_name, user_uniqueid, user_status, user_type, credential_rule} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = SetUser, + __tostring = SetUser.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function SetUser:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SetUser:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function SetUser:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SetUser, {__call = SetUser.init}) + +return SetUser \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetWeekDaySchedule.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetWeekDaySchedule.lua new file mode 100644 index 0000000000..c13f677303 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetWeekDaySchedule.lua @@ -0,0 +1,139 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SetWeekDaySchedule = {} + +SetWeekDaySchedule.NAME = "SetWeekDaySchedule" +SetWeekDaySchedule.ID = 0x000B +SetWeekDaySchedule.field_defs = { + { + name = "week_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "days_mask", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DaysMaskMap", + }, + { + name = "start_hour", + field_id = 3, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "start_minute", + field_id = 4, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "end_hour", + field_id = 5, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "end_minute", + field_id = 6, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, +} + +function SetWeekDaySchedule:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function SetWeekDaySchedule:init(device, endpoint_id, week_day_index, user_index, days_mask, start_hour, start_minute, end_hour, end_minute) + local out = {} + local args = {week_day_index, user_index, days_mask, start_hour, start_minute, end_hour, end_minute} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = SetWeekDaySchedule, + __tostring = SetWeekDaySchedule.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function SetWeekDaySchedule:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SetWeekDaySchedule:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function SetWeekDaySchedule:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SetWeekDaySchedule, {__call = SetWeekDaySchedule.init}) + +return SetWeekDaySchedule \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetYearDaySchedule.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetYearDaySchedule.lua new file mode 100644 index 0000000000..0e65d0027e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/SetYearDaySchedule.lua @@ -0,0 +1,118 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local SetYearDaySchedule = {} + +SetYearDaySchedule.NAME = "SetYearDaySchedule" +SetYearDaySchedule.ID = 0x000E +SetYearDaySchedule.field_defs = { + { + name = "year_day_index", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "user_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "local_start_time", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint32", + }, + { + name = "local_end_time", + field_id = 3, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint32", + }, +} + +function SetYearDaySchedule:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, + status + ) +end + +function SetYearDaySchedule:init(device, endpoint_id, year_day_index, user_index, local_start_time, local_end_time) + local out = {} + local args = {year_day_index, user_index, local_start_time, local_end_time} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = SetYearDaySchedule, + __tostring = SetYearDaySchedule.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID + ) +end + +function SetYearDaySchedule:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function SetYearDaySchedule:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function SetYearDaySchedule:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(SetYearDaySchedule, {__call = SetYearDaySchedule.init}) + +return SetYearDaySchedule \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/UnlockDoor.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/UnlockDoor.lua new file mode 100644 index 0000000000..32bfd9fb3d --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/UnlockDoor.lua @@ -0,0 +1,98 @@ +local data_types = require "st.matter.data_types" +local TLVParser = require "st.matter.TLV.TLVParser" + +local UnlockDoor = {} + +UnlockDoor.NAME = "UnlockDoor" +UnlockDoor.ID = 0x0001 +UnlockDoor.field_defs = { + { + name = "pin_code", + field_id = 0, + is_nullable = false, + is_optional = true, + data_type = require "st.matter.data_types.OctetString1", + }, +} + +function UnlockDoor:build_test_command_response(device, endpoint_id, status) + return self._cluster:build_test_command_response( + device, + endpoint_id, + self._cluster.ID, + self.ID, + nil, --tlv + status + ) +end + +function UnlockDoor:init(device, endpoint_id, pin_code) + local out = {} + local args = {pin_code} + if #args > #self.field_defs then + error(self.NAME .. " received too many arguments") + end + for i,v in ipairs(self.field_defs) do + if v.is_optional and args[i] == nil then + out[v.name] = nil + elseif v.is_nullable and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(args[i], data_types.Null, v.name) + out[v.name].field_id = v.field_id + elseif not v.is_optional and args[i] == nil then + out[v.name] = data_types.validate_or_build_type(v.default, v.data_type, v.name) + out[v.name].field_id = v.field_id + else + out[v.name] = data_types.validate_or_build_type(args[i], v.data_type, v.name) + out[v.name].field_id = v.field_id + end + end + setmetatable(out, { + __index = UnlockDoor, + __tostring = UnlockDoor.pretty_print + }) + return self._cluster:build_cluster_command( + device, + out, + endpoint_id, + self._cluster.ID, + self.ID, + true + ) +end + +function UnlockDoor:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +function UnlockDoor:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function UnlockDoor:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +setmetatable(UnlockDoor, {__call = UnlockDoor.init}) + +return UnlockDoor \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/init.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/init.lua new file mode 100644 index 0000000000..ee8db4a85f --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/commands/init.lua @@ -0,0 +1,22 @@ +local command_mt = {} +command_mt.__command_cache = {} +command_mt.__index = function(self, key) + if command_mt.__command_cache[key] == nil then + local req_loc = string.format("DoorLock.server.commands.%s", key) + local raw_def = require(req_loc) + local cluster = rawget(self, "_cluster") + command_mt.__command_cache[key] = raw_def:set_parent_cluster(cluster) + end + return command_mt.__command_cache[key] +end + +local DoorLockServerCommands = {} + +function DoorLockServerCommands:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +setmetatable(DoorLockServerCommands, command_mt) + +return DoorLockServerCommands \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorLockAlarm.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorLockAlarm.lua new file mode 100644 index 0000000000..da5f1ed0d1 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorLockAlarm.lua @@ -0,0 +1,100 @@ +local data_types = require "st.matter.data_types" +local cluster_base = require "st.matter.cluster_base" +local TLVParser = require "st.matter.TLV.TLVParser" +local StructureABC = require "st.matter.data_types.base_defs.StructureABC" + +local DoorLockAlarm = { + ID = 0x0000, + NAME = "DoorLockAlarm", + base_type = data_types.Structure, +} + +DoorLockAlarm.field_defs = { + { + name = "alarm_code", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.AlarmCodeEnum", + }, +} + +function DoorLockAlarm:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and not + ((field_def.is_nullable or field_def.is_optional) and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function DoorLockAlarm:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function DoorLockAlarm:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function DoorLockAlarm:build_test_event_report( + device, + endpoint_id, + fields, + status +) + local data = {} + data.elements = {} + data.num_elements = 0 + setmetatable(data, StructureABC.new_mt({NAME = "DoorLockAlarmEventData", ID = 0x15})) + for idx, field_def in ipairs(self.field_defs) do --Note: idx is 1 when field_id is 0 + if (not field_def.is_optional and not field_def.is_nullable) and not fields[field_def.name] then + error("Missing non optional or non_nullable field: " .. field_def.name) + elseif fields[field_def.name] then + data.elements[field_def.name] = data_types.validate_or_build_type(fields[field_def.name], field_def.data_type, field_def.name) + data.elements[field_def.name].field_id = field_def.field_id + data.num_elements = data.num_elements + 1 + end + end + return cluster_base.build_test_event_report( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function DoorLockAlarm:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +function DoorLockAlarm:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +return DoorLockAlarm \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorStateChange.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorStateChange.lua new file mode 100644 index 0000000000..da106194be --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/DoorStateChange.lua @@ -0,0 +1,100 @@ +local data_types = require "st.matter.data_types" +local cluster_base = require "st.matter.cluster_base" +local TLVParser = require "st.matter.TLV.TLVParser" +local StructureABC = require "st.matter.data_types.base_defs.StructureABC" + +local DoorStateChange = { + ID = 0x0001, + NAME = "DoorStateChange", + base_type = data_types.Structure, +} + +DoorStateChange.field_defs = { + { + name = "door_state", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DoorStateEnum", + }, +} + +function DoorStateChange:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and not + ((field_def.is_nullable or field_def.is_optional) and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function DoorStateChange:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function DoorStateChange:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function DoorStateChange:build_test_event_report( + device, + endpoint_id, + fields, + status +) + local data = {} + data.elements = {} + data.num_elements = 0 + setmetatable(data, StructureABC.new_mt({NAME = "DoorStateChangeEventData", ID = 0x15})) + for idx, field_def in ipairs(self.field_defs) do --Note: idx is 1 when field_id is 0 + if (not field_def.is_optional and not field_def.is_nullable) and not fields[field_def.name] then + error("Missing non optional or non_nullable field: " .. field_def.name) + elseif fields[field_def.name] then + data.elements[field_def.name] = data_types.validate_or_build_type(fields[field_def.name], field_def.data_type, field_def.name) + data.elements[field_def.name].field_id = field_def.field_id + data.num_elements = data.num_elements + 1 + end + end + return cluster_base.build_test_event_report( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function DoorStateChange:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +function DoorStateChange:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +return DoorStateChange \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperation.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperation.lua new file mode 100644 index 0000000000..8171c09c2e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperation.lua @@ -0,0 +1,136 @@ +local data_types = require "st.matter.data_types" +local cluster_base = require "st.matter.cluster_base" +local TLVParser = require "st.matter.TLV.TLVParser" +local StructureABC = require "st.matter.data_types.base_defs.StructureABC" + +local LockOperation = { + ID = 0x0002, + NAME = "LockOperation", + base_type = data_types.Structure, +} + +LockOperation.field_defs = { + { + name = "lock_operation_type", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.LockOperationTypeEnum", + }, + { + name = "operation_source", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.OperationSourceEnum", + }, + { + name = "user_index", + field_id = 2, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "fabric_index", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "source_node", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint64", + }, + { + name = "credentials", + field_id = 5, + is_nullable = true, + is_optional = true, + data_type = require "st.matter.data_types.Array", + element_type = require "DoorLock.types.CredentialStruct", + }, +} + +function LockOperation:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and not + ((field_def.is_nullable or field_def.is_optional) and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function LockOperation:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function LockOperation:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function LockOperation:build_test_event_report( + device, + endpoint_id, + fields, + status +) + local data = {} + data.elements = {} + data.num_elements = 0 + setmetatable(data, StructureABC.new_mt({NAME = "LockOperationEventData", ID = 0x15})) + for idx, field_def in ipairs(self.field_defs) do + if (not field_def.is_optional and not field_def.is_nullable) and not fields[field_def.name] then + error("Missing non optional or non_nullable field: " .. field_def.name) + elseif fields[field_def.name] then + data.elements[field_def.name] = data_types.validate_or_build_type(fields[field_def.name], field_def.data_type, field_def.name) + data.elements[field_def.name].field_id = field_def.field_id + data.num_elements = data.num_elements + 1 + end + end + return cluster_base.build_test_event_report( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function LockOperation:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +function LockOperation:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +return LockOperation \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperationError.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperationError.lua new file mode 100644 index 0000000000..a5363437e4 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockOperationError.lua @@ -0,0 +1,143 @@ +local data_types = require "st.matter.data_types" +local cluster_base = require "st.matter.cluster_base" +local TLVParser = require "st.matter.TLV.TLVParser" +local StructureABC = require "st.matter.data_types.base_defs.StructureABC" + +local LockOperationError = { + ID = 0x0003, + NAME = "LockOperationError", + base_type = data_types.Structure, +} + +LockOperationError.field_defs = { + { + name = "lock_operation_type", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.LockOperationTypeEnum", + }, + { + name = "operation_source", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.OperationSourceEnum", + }, + { + name = "operation_error", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.OperationErrorEnum", + }, + { + name = "user_index", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "fabric_index", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "source_node", + field_id = 5, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint64", + }, + { + name = "credentials", + field_id = 6, + is_nullable = true, + is_optional = true, + data_type = require "st.matter.data_types.Array", + element_type = require "DoorLock.types.CredentialStruct", + }, +} + +function LockOperationError:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and not + ((field_def.is_nullable or field_def.is_optional) and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function LockOperationError:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function LockOperationError:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function LockOperationError:build_test_event_report( + device, + endpoint_id, + fields, + status +) + local data = {} + data.elements = {} + data.num_elements = 0 + setmetatable(data, StructureABC.new_mt({NAME = "LockOperationErrorEventData", ID = 0x15})) + for idx, field_def in ipairs(self.field_defs) do + if (not field_def.is_optional and not field_def.is_nullable) and not fields[field_def.name] then + error("Missing non optional or non_nullable field: " .. field_def.name) + elseif fields[field_def.name] then + data.elements[field_def.name] = data_types.validate_or_build_type(fields[field_def.name], field_def.data_type, field_def.name) + data.elements[field_def.name].field_id = field_def.field_id + data.num_elements = data.num_elements + 1 + end + end + return cluster_base.build_test_event_report( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function LockOperationError:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +function LockOperationError:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +return LockOperationError \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockUserChange.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockUserChange.lua new file mode 100644 index 0000000000..2566f27c06 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/LockUserChange.lua @@ -0,0 +1,142 @@ +local data_types = require "st.matter.data_types" +local cluster_base = require "st.matter.cluster_base" +local TLVParser = require "st.matter.TLV.TLVParser" +local StructureABC = require "st.matter.data_types.base_defs.StructureABC" + +local LockUserChange = { + ID = 0x0004, + NAME = "LockUserChange", + base_type = data_types.Structure, +} + +LockUserChange.field_defs = { + { + name = "lock_data_type", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.LockDataTypeEnum", + }, + { + name = "data_operation_type", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.DataOperationTypeEnum", + }, + { + name = "operation_source", + field_id = 2, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.OperationSourceEnum", + }, + { + name = "user_index", + field_id = 3, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, + { + name = "fabric_index", + field_id = 4, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint8", + }, + { + name = "source_node", + field_id = 5, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint64", + }, + { + name = "data_index", + field_id = 6, + is_nullable = true, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +function LockUserChange:augment_type(base_type_obj) + local elems = {} + for _, v in ipairs(base_type_obj.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and not + ((field_def.is_nullable or field_def.is_optional) and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + base_type_obj.elements = elems +end + +function LockUserChange:read(device, endpoint_id) + return cluster_base.read( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function LockUserChange:subscribe(device, endpoint_id) + return cluster_base.subscribe( + device, + endpoint_id, + self._cluster.ID, + nil, + self.ID + ) +end + +function LockUserChange:build_test_event_report( + device, + endpoint_id, + fields, + status +) + local data = {} + data.elements = {} + data.num_elements = 0 + setmetatable(data, StructureABC.new_mt({NAME = "LockUserChangeEventData", ID = 0x15})) + for idx, field_def in ipairs(self.field_defs) do + if (not field_def.is_optional and not field_def.is_nullable) and not fields[field_def.name] then + error("Missing non optional or non_nullable field: " .. field_def.name) + elseif fields[field_def.name] then + data.elements[field_def.name] = data_types.validate_or_build_type(fields[field_def.name], field_def.data_type, field_def.name) + data.elements[field_def.name].field_id = field_def.field_id + data.num_elements = data.num_elements + 1 + end + end + return cluster_base.build_test_event_report( + device, + endpoint_id, + self._cluster.ID, + self.ID, + data, + status + ) +end + +function LockUserChange:deserialize(tlv_buf) + local data = TLVParser.decode_tlv(tlv_buf) + self:augment_type(data) + return data +end + +function LockUserChange:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +return LockUserChange \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/server/events/init.lua b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/init.lua new file mode 100644 index 0000000000..0079543a93 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/server/events/init.lua @@ -0,0 +1,23 @@ +local event_mt = {} +event_mt.__event_cache = {} +event_mt.__index = function(self, key) + if event_mt.__event_cache[key] == nil then + local req_loc = string.format("DoorLock.server.events.%s", key) + local raw_def = require(req_loc) + local cluster = rawget(self, "_cluster") + raw_def:set_parent_cluster(cluster) + event_mt.__event_cache[key] = raw_def + end + return event_mt.__event_cache[key] +end + +local DoorLockEvents = {} + +function DoorLockEvents:set_parent_cluster(cluster) + self._cluster = cluster + return self +end + +setmetatable(DoorLockEvents, event_mt) + +return DoorLockEvents \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/AlarmCodeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/AlarmCodeEnum.lua new file mode 100644 index 0000000000..06460249f2 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/AlarmCodeEnum.lua @@ -0,0 +1,45 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local AlarmCodeEnum = {} +local new_mt = UintABC.new_mt({NAME = "AlarmCodeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.LOCK_JAMMED] = "LOCK_JAMMED", + [self.LOCK_FACTORY_RESET] = "LOCK_FACTORY_RESET", + [self.LOCK_RADIO_POWER_CYCLED] = "LOCK_RADIO_POWER_CYCLED", + [self.WRONG_CODE_ENTRY_LIMIT] = "WRONG_CODE_ENTRY_LIMIT", + [self.FRONT_ESCEUTCHEON_REMOVED] = "FRONT_ESCEUTCHEON_REMOVED", + [self.DOOR_FORCED_OPEN] = "DOOR_FORCED_OPEN", + [self.DOOR_AJAR] = "DOOR_AJAR", + [self.FORCED_USER] = "FORCED_USER", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.LOCK_JAMMED = 0x00 +new_mt.__index.LOCK_FACTORY_RESET = 0x01 +new_mt.__index.LOCK_RADIO_POWER_CYCLED = 0x03 +new_mt.__index.WRONG_CODE_ENTRY_LIMIT = 0x04 +new_mt.__index.FRONT_ESCEUTCHEON_REMOVED = 0x05 +new_mt.__index.DOOR_FORCED_OPEN = 0x06 +new_mt.__index.DOOR_AJAR = 0x07 +new_mt.__index.FORCED_USER = 0x08 + +AlarmCodeEnum.LOCK_JAMMED = 0x00 +AlarmCodeEnum.LOCK_FACTORY_RESET = 0x01 +AlarmCodeEnum.LOCK_RADIO_POWER_CYCLED = 0x03 +AlarmCodeEnum.WRONG_CODE_ENTRY_LIMIT = 0x04 +AlarmCodeEnum.FRONT_ESCEUTCHEON_REMOVED = 0x05 +AlarmCodeEnum.DOOR_FORCED_OPEN = 0x06 +AlarmCodeEnum.DOOR_AJAR = 0x07 +AlarmCodeEnum.FORCED_USER = 0x08 + +AlarmCodeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(AlarmCodeEnum, new_mt) + +return AlarmCodeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialRuleEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialRuleEnum.lua new file mode 100644 index 0000000000..ead4d559b7 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialRuleEnum.lua @@ -0,0 +1,31 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local CredentialRuleEnum = {} +local new_mt = UintABC.new_mt({NAME = "CredentialRuleEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.SINGLE] = "SINGLE", + [self.DUAL] = "DUAL", + [self.TRI] = "TRI", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.SINGLE = 0x00 +new_mt.__index.DUAL = 0x01 +new_mt.__index.TRI = 0x02 + +CredentialRuleEnum.SINGLE = 0x00 +CredentialRuleEnum.DUAL = 0x01 +CredentialRuleEnum.TRI = 0x02 + +CredentialRuleEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(CredentialRuleEnum, new_mt) + +return CredentialRuleEnum + diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialStruct.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialStruct.lua new file mode 100644 index 0000000000..d58c170334 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialStruct.lua @@ -0,0 +1,77 @@ +local data_types = require "st.matter.data_types" +local StructureABC = require "st.matter.data_types.base_defs.StructureABC" + +local CredentialStruct = {} +local new_mt = StructureABC.new_mt({NAME = "CredentialStruct", ID = data_types.name_to_id_map["Structure"]}) + +CredentialStruct.field_defs = { + { + name = "credential_type", + field_id = 0, + is_nullable = false, + is_optional = false, + data_type = require "DoorLock.types.CredentialTypeEnum", + }, + { + name = "credential_index", + field_id = 1, + is_nullable = false, + is_optional = false, + data_type = require "st.matter.data_types.Uint16", + }, +} + +CredentialStruct.init = function(cls, tbl) + local o = {} + o.elements = {} + o.num_elements = 0 + setmetatable(o, new_mt) + for idx, field_def in ipairs(cls.field_defs) do + if (not field_def.is_optional and not field_def.is_nullable) and not tbl[field_def.name] then + error("Missing non optional or non_nullable field: " .. field_def.name) + else + o.elements[field_def.name] = data_types.validate_or_build_type(tbl[field_def.name], field_def.data_type, field_def.name) + o.elements[field_def.name].field_id = field_def.field_id + o.num_elements = o.num_elements + 1 + end + end + return o +end + +CredentialStruct.serialize = function(self, buf, include_control, tag) + return data_types['Structure'].serialize(self.elements, buf, include_control, tag) +end + +new_mt.__call = CredentialStruct.init +new_mt.__index.serialize = CredentialStruct.serialize + +CredentialStruct.augment_type = function(self, val) + local elems = {} + local num_elements = 0 + for _, v in pairs(val.elements) do + for _, field_def in ipairs(self.field_defs) do + if field_def.field_id == v.field_id and + field_def.is_nullable and + (v.value == nil and v.elements == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, data_types.Null, field_def.field_name) + num_elements = num_elements + 1 + elseif field_def.field_id == v.field_id and not + (field_def.is_optional and v.value == nil) then + elems[field_def.name] = data_types.validate_or_build_type(v, field_def.data_type, field_def.field_name) + num_elements = num_elements + 1 + if field_def.element_type ~= nil then + for i, e in ipairs(elems[field_def.name].elements) do + elems[field_def.name].elements[i] = data_types.validate_or_build_type(e, field_def.element_type) + end + end + end + end + end + val.elements = elems + val.num_elements = num_elements + setmetatable(val, new_mt) +end + +setmetatable(CredentialStruct, new_mt) + +return CredentialStruct \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialTypeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialTypeEnum.lua new file mode 100644 index 0000000000..0a09054948 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/CredentialTypeEnum.lua @@ -0,0 +1,48 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local CredentialTypeEnum = {} +local new_mt = UintABC.new_mt({NAME = "CredentialTypeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.PROGRAMMINGPIN] = "PROGRAMMINGPIN", + [self.PIN] = "PIN", + [self.RFID] = "RFID", + [self.FINGERPRINT] = "FINGERPRINT", + [self.FINGER_VEIN] = "FINGER_VEIN", + [self.FACE] = "FACE", + [self.ALIRO_CREDENTIAL_ISSUER_KEY] = "ALIRO_CREDENTIAL_ISSUER_KEY", + [self.ALIRO_EVICTABLE_ENDPOINT_KEY] = "ALIRO_EVICTABLE_ENDPOINT_KEY", + [self.ALIRO_NON_EVICTABLE_ENDPOINT_KEY] = "ALIRO_NON_EVICTABLE_ENDPOINT_KEY", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.PROGRAMMINGPIN = 0x00 +new_mt.__index.PIN = 0x01 +new_mt.__index.RFID = 0x02 +new_mt.__index.FINGERPRINT = 0x03 +new_mt.__index.FINGER_VEIN = 0x04 +new_mt.__index.FACE = 0x05 +new_mt.__index.ALIRO_CREDENTIAL_ISSUER_KEY = 0x06 +new_mt.__index.ALIRO_EVICTABLE_ENDPOINT_KEY = 0x07 +new_mt.__index.ALIRO_NON_EVICTABLE_ENDPOINT_KEY = 0x08 + +CredentialTypeEnum.PROGRAMMINGPIN = 0x00 +CredentialTypeEnum.PIN = 0x01 +CredentialTypeEnum.RFID = 0x02 +CredentialTypeEnum.FINGERPRINT = 0x03 +CredentialTypeEnum.FINGER_VEIN = 0x04 +CredentialTypeEnum.FACE = 0x05 +CredentialTypeEnum.ALIRO_CREDENTIAL_ISSUER_KEY = 0x06 +CredentialTypeEnum.ALIRO_EVICTABLE_ENDPOINT_KEY = 0x07 +CredentialTypeEnum.ALIRO_NON_EVICTABLE_ENDPOINT_KEY = 0x08 + +CredentialTypeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(CredentialTypeEnum, new_mt) + +return CredentialTypeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DataOperationTypeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DataOperationTypeEnum.lua new file mode 100644 index 0000000000..4aa540aae4 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DataOperationTypeEnum.lua @@ -0,0 +1,30 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DataOperationTypeEnum = {} +local new_mt = UintABC.new_mt({NAME = "DataOperationTypeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.ADD] = "ADD", + [self.CLEAR] = "CLEAR", + [self.MODIFY] = "MODIFY", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.ADD = 0x00 +new_mt.__index.CLEAR = 0x01 +new_mt.__index.MODIFY = 0x02 + +DataOperationTypeEnum.ADD = 0x00 +DataOperationTypeEnum.CLEAR = 0x01 +DataOperationTypeEnum.MODIFY = 0x02 + +DataOperationTypeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DataOperationTypeEnum, new_mt) + +return DataOperationTypeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DaysMaskMap.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DaysMaskMap.lua new file mode 100644 index 0000000000..b4c7ea7f21 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DaysMaskMap.lua @@ -0,0 +1,169 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DaysMaskMap = {} +local new_mt = UintABC.new_mt({NAME = "DaysMaskMap", ID = data_types.name_to_id_map["Uint8"]}, 1) + +DaysMaskMap.BASE_MASK = 0xFFFF +DaysMaskMap.SUNDAY = 0x0001 +DaysMaskMap.MONDAY = 0x0002 +DaysMaskMap.TUESDAY = 0x0004 +DaysMaskMap.WEDNESDAY = 0x0008 +DaysMaskMap.THURSDAY = 0x0010 +DaysMaskMap.FRIDAY = 0x0020 +DaysMaskMap.SATURDAY = 0x0040 + +DaysMaskMap.mask_fields = { + BASE_MASK = 0xFFFF, + SUNDAY = 0x0001, + MONDAY = 0x0002, + TUESDAY = 0x0004, + WEDNESDAY = 0x0008, + THURSDAY = 0x0010, + FRIDAY = 0x0020, + SATURDAY = 0x0040, +} + +DaysMaskMap.is_sunday_set = function(self) + return (self.value & self.SUNDAY) ~= 0 +end + +DaysMaskMap.set_sunday = function(self) + if self.value ~= nil then + self.value = self.value | self.SUNDAY + else + self.value = self.SUNDAY + end +end + +DaysMaskMap.unset_sunday = function(self) + self.value = self.value & (~self.SUNDAY & self.BASE_MASK) +end + +DaysMaskMap.is_monday_set = function(self) + return (self.value & self.MONDAY) ~= 0 +end + +DaysMaskMap.set_monday = function(self) + if self.value ~= nil then + self.value = self.value | self.MONDAY + else + self.value = self.MONDAY + end +end + +DaysMaskMap.unset_monday = function(self) + self.value = self.value & (~self.MONDAY & self.BASE_MASK) +end + +DaysMaskMap.is_tuesday_set = function(self) + return (self.value & self.TUESDAY) ~= 0 +end + +DaysMaskMap.set_tuesday = function(self) + if self.value ~= nil then + self.value = self.value | self.TUESDAY + else + self.value = self.TUESDAY + end +end + +DaysMaskMap.unset_tuesday = function(self) + self.value = self.value & (~self.TUESDAY & self.BASE_MASK) +end + +DaysMaskMap.is_wednesday_set = function(self) + return (self.value & self.WEDNESDAY) ~= 0 +end + +DaysMaskMap.set_wednesday = function(self) + if self.value ~= nil then + self.value = self.value | self.WEDNESDAY + else + self.value = self.WEDNESDAY + end +end + +DaysMaskMap.unset_wednesday = function(self) + self.value = self.value & (~self.WEDNESDAY & self.BASE_MASK) +end + +DaysMaskMap.is_thursday_set = function(self) + return (self.value & self.THURSDAY) ~= 0 +end + +DaysMaskMap.set_thursday = function(self) + if self.value ~= nil then + self.value = self.value | self.THURSDAY + else + self.value = self.THURSDAY + end +end + +DaysMaskMap.unset_thursday = function(self) + self.value = self.value & (~self.THURSDAY & self.BASE_MASK) +end + +DaysMaskMap.is_friday_set = function(self) + return (self.value & self.FRIDAY) ~= 0 +end + +DaysMaskMap.set_friday = function(self) + if self.value ~= nil then + self.value = self.value | self.FRIDAY + else + self.value = self.FRIDAY + end +end + +DaysMaskMap.unset_friday = function(self) + self.value = self.value & (~self.FRIDAY & self.BASE_MASK) +end + +DaysMaskMap.is_saturday_set = function(self) + return (self.value & self.SATURDAY) ~= 0 +end + +DaysMaskMap.set_saturday = function(self) + if self.value ~= nil then + self.value = self.value | self.SATURDAY + else + self.value = self.SATURDAY + end +end + +DaysMaskMap.unset_saturday = function(self) + self.value = self.value & (~self.SATURDAY & self.BASE_MASK) +end + +DaysMaskMap.mask_methods = { + is_sunday_set = DaysMaskMap.is_sunday_set, + set_sunday = DaysMaskMap.set_sunday, + unset_sunday = DaysMaskMap.unset_sunday, + is_monday_set = DaysMaskMap.is_monday_set, + set_monday = DaysMaskMap.set_monday, + unset_monday = DaysMaskMap.unset_monday, + is_tuesday_set = DaysMaskMap.is_tuesday_set, + set_tuesday = DaysMaskMap.set_tuesday, + unset_tuesday = DaysMaskMap.unset_tuesday, + is_wednesday_set = DaysMaskMap.is_wednesday_set, + set_wednesday = DaysMaskMap.set_wednesday, + unset_wednesday = DaysMaskMap.unset_wednesday, + is_thursday_set = DaysMaskMap.is_thursday_set, + set_thursday = DaysMaskMap.set_thursday, + unset_thursday = DaysMaskMap.unset_thursday, + is_friday_set = DaysMaskMap.is_friday_set, + set_friday = DaysMaskMap.set_friday, + unset_friday = DaysMaskMap.unset_friday, + is_saturday_set = DaysMaskMap.is_saturday_set, + set_saturday = DaysMaskMap.set_saturday, + unset_saturday = DaysMaskMap.unset_saturday, +} + +DaysMaskMap.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DaysMaskMap, new_mt) + +return DaysMaskMap \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadOperationEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadOperationEventMask.lua new file mode 100644 index 0000000000..06dd9b829b --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadOperationEventMask.lua @@ -0,0 +1,190 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlKeypadOperationEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlKeypadOperationEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlKeypadOperationEventMask.BASE_MASK = 0xFFFF +DlKeypadOperationEventMask.UNKNOWN = 0x0001 +DlKeypadOperationEventMask.LOCK = 0x0002 +DlKeypadOperationEventMask.UNLOCK = 0x0004 +DlKeypadOperationEventMask.LOCK_INVALIDPIN = 0x0008 +DlKeypadOperationEventMask.LOCK_INVALID_SCHEDULE = 0x0010 +DlKeypadOperationEventMask.UNLOCK_INVALID_CODE = 0x0020 +DlKeypadOperationEventMask.UNLOCK_INVALID_SCHEDULE = 0x0040 +DlKeypadOperationEventMask.NON_ACCESS_USER_OP_EVENT = 0x0080 + +DlKeypadOperationEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + LOCK = 0x0002, + UNLOCK = 0x0004, + LOCK_INVALIDPIN = 0x0008, + LOCK_INVALID_SCHEDULE = 0x0010, + UNLOCK_INVALID_CODE = 0x0020, + UNLOCK_INVALID_SCHEDULE = 0x0040, + NON_ACCESS_USER_OP_EVENT = 0x0080, +} + +DlKeypadOperationEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlKeypadOperationEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlKeypadOperationEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_lock_set = function(self) + return (self.value & self.LOCK) ~= 0 +end + +DlKeypadOperationEventMask.set_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK + else + self.value = self.LOCK + end +end + +DlKeypadOperationEventMask.unset_lock = function(self) + self.value = self.value & (~self.LOCK & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_unlock_set = function(self) + return (self.value & self.UNLOCK) ~= 0 +end + +DlKeypadOperationEventMask.set_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK + else + self.value = self.UNLOCK + end +end + +DlKeypadOperationEventMask.unset_unlock = function(self) + self.value = self.value & (~self.UNLOCK & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_lock_invalidpin_set = function(self) + return (self.value & self.LOCK_INVALIDPIN) ~= 0 +end + +DlKeypadOperationEventMask.set_lock_invalidpin = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK_INVALIDPIN + else + self.value = self.LOCK_INVALIDPIN + end +end + +DlKeypadOperationEventMask.unset_lock_invalidpin = function(self) + self.value = self.value & (~self.LOCK_INVALIDPIN & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_lock_invalid_schedule_set = function(self) + return (self.value & self.LOCK_INVALID_SCHEDULE) ~= 0 +end + +DlKeypadOperationEventMask.set_lock_invalid_schedule = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK_INVALID_SCHEDULE + else + self.value = self.LOCK_INVALID_SCHEDULE + end +end + +DlKeypadOperationEventMask.unset_lock_invalid_schedule = function(self) + self.value = self.value & (~self.LOCK_INVALID_SCHEDULE & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_unlock_invalid_code_set = function(self) + return (self.value & self.UNLOCK_INVALID_CODE) ~= 0 +end + +DlKeypadOperationEventMask.set_unlock_invalid_code = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK_INVALID_CODE + else + self.value = self.UNLOCK_INVALID_CODE + end +end + +DlKeypadOperationEventMask.unset_unlock_invalid_code = function(self) + self.value = self.value & (~self.UNLOCK_INVALID_CODE & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_unlock_invalid_schedule_set = function(self) + return (self.value & self.UNLOCK_INVALID_SCHEDULE) ~= 0 +end + +DlKeypadOperationEventMask.set_unlock_invalid_schedule = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK_INVALID_SCHEDULE + else + self.value = self.UNLOCK_INVALID_SCHEDULE + end +end + +DlKeypadOperationEventMask.unset_unlock_invalid_schedule = function(self) + self.value = self.value & (~self.UNLOCK_INVALID_SCHEDULE & self.BASE_MASK) +end + +DlKeypadOperationEventMask.is_non_access_user_op_event_set = function(self) + return (self.value & self.NON_ACCESS_USER_OP_EVENT) ~= 0 +end + +DlKeypadOperationEventMask.set_non_access_user_op_event = function(self) + if self.value ~= nil then + self.value = self.value | self.NON_ACCESS_USER_OP_EVENT + else + self.value = self.NON_ACCESS_USER_OP_EVENT + end +end + +DlKeypadOperationEventMask.unset_non_access_user_op_event = function(self) + self.value = self.value & (~self.NON_ACCESS_USER_OP_EVENT & self.BASE_MASK) +end + +DlKeypadOperationEventMask.mask_methods = { + is_unknown_set = DlKeypadOperationEventMask.is_unknown_set, + set_unknown = DlKeypadOperationEventMask.set_unknown, + unset_unknown = DlKeypadOperationEventMask.unset_unknown, + is_lock_set = DlKeypadOperationEventMask.is_lock_set, + set_lock = DlKeypadOperationEventMask.set_lock, + unset_lock = DlKeypadOperationEventMask.unset_lock, + is_unlock_set = DlKeypadOperationEventMask.is_unlock_set, + set_unlock = DlKeypadOperationEventMask.set_unlock, + unset_unlock = DlKeypadOperationEventMask.unset_unlock, + is_lock_invalidpin_set = DlKeypadOperationEventMask.is_lock_invalidpin_set, + set_lock_invalidpin = DlKeypadOperationEventMask.set_lock_invalidpin, + unset_lock_invalidpin = DlKeypadOperationEventMask.unset_lock_invalidpin, + is_lock_invalid_schedule_set = DlKeypadOperationEventMask.is_lock_invalid_schedule_set, + set_lock_invalid_schedule = DlKeypadOperationEventMask.set_lock_invalid_schedule, + unset_lock_invalid_schedule = DlKeypadOperationEventMask.unset_lock_invalid_schedule, + is_unlock_invalid_code_set = DlKeypadOperationEventMask.is_unlock_invalid_code_set, + set_unlock_invalid_code = DlKeypadOperationEventMask.set_unlock_invalid_code, + unset_unlock_invalid_code = DlKeypadOperationEventMask.unset_unlock_invalid_code, + is_unlock_invalid_schedule_set = DlKeypadOperationEventMask.is_unlock_invalid_schedule_set, + set_unlock_invalid_schedule = DlKeypadOperationEventMask.set_unlock_invalid_schedule, + unset_unlock_invalid_schedule = DlKeypadOperationEventMask.unset_unlock_invalid_schedule, + is_non_access_user_op_event_set = DlKeypadOperationEventMask.is_non_access_user_op_event_set, + set_non_access_user_op_event = DlKeypadOperationEventMask.set_non_access_user_op_event, + unset_non_access_user_op_event = DlKeypadOperationEventMask.unset_non_access_user_op_event, +} + +DlKeypadOperationEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlKeypadOperationEventMask, new_mt) + +return DlKeypadOperationEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadProgrammingEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadProgrammingEventMask.lua new file mode 100644 index 0000000000..d7b3c1c6f6 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlKeypadProgrammingEventMask.lua @@ -0,0 +1,127 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlKeypadProgrammingEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlKeypadProgrammingEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlKeypadProgrammingEventMask.BASE_MASK = 0xFFFF +DlKeypadProgrammingEventMask.UNKNOWN = 0x0001 +DlKeypadProgrammingEventMask.PROGRAMMINGPIN_CHANGED = 0x0002 +DlKeypadProgrammingEventMask.PIN_ADDED = 0x0004 +DlKeypadProgrammingEventMask.PIN_CLEARED = 0x0008 +DlKeypadProgrammingEventMask.PIN_CHANGED = 0x0010 + +DlKeypadProgrammingEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + PROGRAMMINGPIN_CHANGED = 0x0002, + PIN_ADDED = 0x0004, + PIN_CLEARED = 0x0008, + PIN_CHANGED = 0x0010, +} + +DlKeypadProgrammingEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlKeypadProgrammingEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlKeypadProgrammingEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlKeypadProgrammingEventMask.is_programmingpin_changed_set = function(self) + return (self.value & self.PROGRAMMINGPIN_CHANGED) ~= 0 +end + +DlKeypadProgrammingEventMask.set_programmingpin_changed = function(self) + if self.value ~= nil then + self.value = self.value | self.PROGRAMMINGPIN_CHANGED + else + self.value = self.PROGRAMMINGPIN_CHANGED + end +end + +DlKeypadProgrammingEventMask.unset_programmingpin_changed = function(self) + self.value = self.value & (~self.PROGRAMMINGPIN_CHANGED & self.BASE_MASK) +end + +DlKeypadProgrammingEventMask.is_pin_added_set = function(self) + return (self.value & self.PIN_ADDED) ~= 0 +end + +DlKeypadProgrammingEventMask.set_pin_added = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_ADDED + else + self.value = self.PIN_ADDED + end +end + +DlKeypadProgrammingEventMask.unset_pin_added = function(self) + self.value = self.value & (~self.PIN_ADDED & self.BASE_MASK) +end + +DlKeypadProgrammingEventMask.is_pin_cleared_set = function(self) + return (self.value & self.PIN_CLEARED) ~= 0 +end + +DlKeypadProgrammingEventMask.set_pin_cleared = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_CLEARED + else + self.value = self.PIN_CLEARED + end +end + +DlKeypadProgrammingEventMask.unset_pin_cleared = function(self) + self.value = self.value & (~self.PIN_CLEARED & self.BASE_MASK) +end + +DlKeypadProgrammingEventMask.is_pin_changed_set = function(self) + return (self.value & self.PIN_CHANGED) ~= 0 +end + +DlKeypadProgrammingEventMask.set_pin_changed = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_CHANGED + else + self.value = self.PIN_CHANGED + end +end + +DlKeypadProgrammingEventMask.unset_pin_changed = function(self) + self.value = self.value & (~self.PIN_CHANGED & self.BASE_MASK) +end + +DlKeypadProgrammingEventMask.mask_methods = { + is_unknown_set = DlKeypadProgrammingEventMask.is_unknown_set, + set_unknown = DlKeypadProgrammingEventMask.set_unknown, + unset_unknown = DlKeypadProgrammingEventMask.unset_unknown, + is_programmingpin_changed_set = DlKeypadProgrammingEventMask.is_programmingpin_changed_set, + set_programmingpin_changed = DlKeypadProgrammingEventMask.set_programmingpin_changed, + unset_programmingpin_changed = DlKeypadProgrammingEventMask.unset_programmingpin_changed, + is_pin_added_set = DlKeypadProgrammingEventMask.is_pin_added_set, + set_pin_added = DlKeypadProgrammingEventMask.set_pin_added, + unset_pin_added = DlKeypadProgrammingEventMask.unset_pin_added, + is_pin_cleared_set = DlKeypadProgrammingEventMask.is_pin_cleared_set, + set_pin_cleared = DlKeypadProgrammingEventMask.set_pin_cleared, + unset_pin_cleared = DlKeypadProgrammingEventMask.unset_pin_cleared, + is_pin_changed_set = DlKeypadProgrammingEventMask.is_pin_changed_set, + set_pin_changed = DlKeypadProgrammingEventMask.set_pin_changed, + unset_pin_changed = DlKeypadProgrammingEventMask.unset_pin_changed, +} + +DlKeypadProgrammingEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlKeypadProgrammingEventMask, new_mt) + +return DlKeypadProgrammingEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlLocalProgrammingFeatures.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlLocalProgrammingFeatures.lua new file mode 100644 index 0000000000..937a59daf9 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlLocalProgrammingFeatures.lua @@ -0,0 +1,106 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlLocalProgrammingFeatures = {} +local new_mt = UintABC.new_mt({NAME = "DlLocalProgrammingFeatures", ID = data_types.name_to_id_map["Uint8"]}, 1) + +DlLocalProgrammingFeatures.BASE_MASK = 0xFFFF +DlLocalProgrammingFeatures.ADD_USERS_CREDENTIALS_SCHEDULES_LOCALLY = 0x0001 +DlLocalProgrammingFeatures.MODIFY_USERS_CREDENTIALS_SCHEDULES_LOCALLY = 0x0002 +DlLocalProgrammingFeatures.CLEAR_USERS_CREDENTIALS_SCHEDULES_LOCALLY = 0x0004 +DlLocalProgrammingFeatures.ADJUST_LOCK_SETTINGS_LOCALLY = 0x0008 + +DlLocalProgrammingFeatures.mask_fields = { + BASE_MASK = 0xFFFF, + ADD_USERS_CREDENTIALS_SCHEDULES_LOCALLY = 0x0001, + MODIFY_USERS_CREDENTIALS_SCHEDULES_LOCALLY = 0x0002, + CLEAR_USERS_CREDENTIALS_SCHEDULES_LOCALLY = 0x0004, + ADJUST_LOCK_SETTINGS_LOCALLY = 0x0008, +} + +DlLocalProgrammingFeatures.is_add_users_credentials_schedules_locally_set = function(self) + return (self.value & self.ADD_USERS_CREDENTIALS_SCHEDULES_LOCALLY) ~= 0 +end + +DlLocalProgrammingFeatures.set_add_users_credentials_schedules_locally = function(self) + if self.value ~= nil then + self.value = self.value | self.ADD_USERS_CREDENTIALS_SCHEDULES_LOCALLY + else + self.value = self.ADD_USERS_CREDENTIALS_SCHEDULES_LOCALLY + end +end + +DlLocalProgrammingFeatures.unset_add_users_credentials_schedules_locally = function(self) + self.value = self.value & (~self.ADD_USERS_CREDENTIALS_SCHEDULES_LOCALLY & self.BASE_MASK) +end + +DlLocalProgrammingFeatures.is_modify_users_credentials_schedules_locally_set = function(self) + return (self.value & self.MODIFY_USERS_CREDENTIALS_SCHEDULES_LOCALLY) ~= 0 +end + +DlLocalProgrammingFeatures.set_modify_users_credentials_schedules_locally = function(self) + if self.value ~= nil then + self.value = self.value | self.MODIFY_USERS_CREDENTIALS_SCHEDULES_LOCALLY + else + self.value = self.MODIFY_USERS_CREDENTIALS_SCHEDULES_LOCALLY + end +end + +DlLocalProgrammingFeatures.unset_modify_users_credentials_schedules_locally = function(self) + self.value = self.value & (~self.MODIFY_USERS_CREDENTIALS_SCHEDULES_LOCALLY & self.BASE_MASK) +end + +DlLocalProgrammingFeatures.is_clear_users_credentials_schedules_locally_set = function(self) + return (self.value & self.CLEAR_USERS_CREDENTIALS_SCHEDULES_LOCALLY) ~= 0 +end + +DlLocalProgrammingFeatures.set_clear_users_credentials_schedules_locally = function(self) + if self.value ~= nil then + self.value = self.value | self.CLEAR_USERS_CREDENTIALS_SCHEDULES_LOCALLY + else + self.value = self.CLEAR_USERS_CREDENTIALS_SCHEDULES_LOCALLY + end +end + +DlLocalProgrammingFeatures.unset_clear_users_credentials_schedules_locally = function(self) + self.value = self.value & (~self.CLEAR_USERS_CREDENTIALS_SCHEDULES_LOCALLY & self.BASE_MASK) +end + +DlLocalProgrammingFeatures.is_adjust_lock_settings_locally_set = function(self) + return (self.value & self.ADJUST_LOCK_SETTINGS_LOCALLY) ~= 0 +end + +DlLocalProgrammingFeatures.set_adjust_lock_settings_locally = function(self) + if self.value ~= nil then + self.value = self.value | self.ADJUST_LOCK_SETTINGS_LOCALLY + else + self.value = self.ADJUST_LOCK_SETTINGS_LOCALLY + end +end + +DlLocalProgrammingFeatures.unset_adjust_lock_settings_locally = function(self) + self.value = self.value & (~self.ADJUST_LOCK_SETTINGS_LOCALLY & self.BASE_MASK) +end + +DlLocalProgrammingFeatures.mask_methods = { + is_add_users_credentials_schedules_locally_set = DlLocalProgrammingFeatures.is_add_users_credentials_schedules_locally_set, + set_add_users_credentials_schedules_locally = DlLocalProgrammingFeatures.set_add_users_credentials_schedules_locally, + unset_add_users_credentials_schedules_locally = DlLocalProgrammingFeatures.unset_add_users_credentials_schedules_locally, + is_modify_users_credentials_schedules_locally_set = DlLocalProgrammingFeatures.is_modify_users_credentials_schedules_locally_set, + set_modify_users_credentials_schedules_locally = DlLocalProgrammingFeatures.set_modify_users_credentials_schedules_locally, + unset_modify_users_credentials_schedules_locally = DlLocalProgrammingFeatures.unset_modify_users_credentials_schedules_locally, + is_clear_users_credentials_schedules_locally_set = DlLocalProgrammingFeatures.is_clear_users_credentials_schedules_locally_set, + set_clear_users_credentials_schedules_locally = DlLocalProgrammingFeatures.set_clear_users_credentials_schedules_locally, + unset_clear_users_credentials_schedules_locally = DlLocalProgrammingFeatures.unset_clear_users_credentials_schedules_locally, + is_adjust_lock_settings_locally_set = DlLocalProgrammingFeatures.is_adjust_lock_settings_locally_set, + set_adjust_lock_settings_locally = DlLocalProgrammingFeatures.set_adjust_lock_settings_locally, + unset_adjust_lock_settings_locally = DlLocalProgrammingFeatures.unset_adjust_lock_settings_locally, +} + +DlLocalProgrammingFeatures.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlLocalProgrammingFeatures, new_mt) + +return DlLocalProgrammingFeatures \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlLockState.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlLockState.lua new file mode 100644 index 0000000000..49fa7d2eb6 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlLockState.lua @@ -0,0 +1,33 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlLockState = {} +local new_mt = UintABC.new_mt({NAME = "DlLockState", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.NOT_FULLY_LOCKED] = "NOT_FULLY_LOCKED", + [self.LOCKED] = "LOCKED", + [self.UNLOCKED] = "UNLOCKED", + [self.UNLATCHED] = "UNLATCHED", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.NOT_FULLY_LOCKED = 0x00 +new_mt.__index.LOCKED = 0x01 +new_mt.__index.UNLOCKED = 0x02 +new_mt.__index.UNLATCHED = 0x03 + +DlLockState.NOT_FULLY_LOCKED = 0x00 +DlLockState.LOCKED = 0x01 +DlLockState.UNLOCKED = 0x02 +DlLockState.UNLATCHED = 0x03 + +DlLockState.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlLockState, new_mt) + +return DlLockState \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlManualOperationEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlManualOperationEventMask.lua new file mode 100644 index 0000000000..9c9803125d --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlManualOperationEventMask.lua @@ -0,0 +1,253 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlManualOperationEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlManualOperationEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlManualOperationEventMask.BASE_MASK = 0xFFFF +DlManualOperationEventMask.UNKNOWN = 0x0001 +DlManualOperationEventMask.THUMBTURN_LOCK = 0x0002 +DlManualOperationEventMask.THUMBTURN_UNLOCK = 0x0004 +DlManualOperationEventMask.ONE_TOUCH_LOCK = 0x0008 +DlManualOperationEventMask.KEY_LOCK = 0x0010 +DlManualOperationEventMask.KEY_UNLOCK = 0x0020 +DlManualOperationEventMask.AUTO_LOCK = 0x0040 +DlManualOperationEventMask.SCHEDULE_LOCK = 0x0080 +DlManualOperationEventMask.SCHEDULE_UNLOCK = 0x0100 +DlManualOperationEventMask.MANUAL_LOCK = 0x0200 +DlManualOperationEventMask.MANUAL_UNLOCK = 0x0400 + +DlManualOperationEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + THUMBTURN_LOCK = 0x0002, + THUMBTURN_UNLOCK = 0x0004, + ONE_TOUCH_LOCK = 0x0008, + KEY_LOCK = 0x0010, + KEY_UNLOCK = 0x0020, + AUTO_LOCK = 0x0040, + SCHEDULE_LOCK = 0x0080, + SCHEDULE_UNLOCK = 0x0100, + MANUAL_LOCK = 0x0200, + MANUAL_UNLOCK = 0x0400, +} + +DlManualOperationEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlManualOperationEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlManualOperationEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlManualOperationEventMask.is_thumbturn_lock_set = function(self) + return (self.value & self.THUMBTURN_LOCK) ~= 0 +end + +DlManualOperationEventMask.set_thumbturn_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.THUMBTURN_LOCK + else + self.value = self.THUMBTURN_LOCK + end +end + +DlManualOperationEventMask.unset_thumbturn_lock = function(self) + self.value = self.value & (~self.THUMBTURN_LOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_thumbturn_unlock_set = function(self) + return (self.value & self.THUMBTURN_UNLOCK) ~= 0 +end + +DlManualOperationEventMask.set_thumbturn_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.THUMBTURN_UNLOCK + else + self.value = self.THUMBTURN_UNLOCK + end +end + +DlManualOperationEventMask.unset_thumbturn_unlock = function(self) + self.value = self.value & (~self.THUMBTURN_UNLOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_one_touch_lock_set = function(self) + return (self.value & self.ONE_TOUCH_LOCK) ~= 0 +end + +DlManualOperationEventMask.set_one_touch_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.ONE_TOUCH_LOCK + else + self.value = self.ONE_TOUCH_LOCK + end +end + +DlManualOperationEventMask.unset_one_touch_lock = function(self) + self.value = self.value & (~self.ONE_TOUCH_LOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_key_lock_set = function(self) + return (self.value & self.KEY_LOCK) ~= 0 +end + +DlManualOperationEventMask.set_key_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.KEY_LOCK + else + self.value = self.KEY_LOCK + end +end + +DlManualOperationEventMask.unset_key_lock = function(self) + self.value = self.value & (~self.KEY_LOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_key_unlock_set = function(self) + return (self.value & self.KEY_UNLOCK) ~= 0 +end + +DlManualOperationEventMask.set_key_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.KEY_UNLOCK + else + self.value = self.KEY_UNLOCK + end +end + +DlManualOperationEventMask.unset_key_unlock = function(self) + self.value = self.value & (~self.KEY_UNLOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_auto_lock_set = function(self) + return (self.value & self.AUTO_LOCK) ~= 0 +end + +DlManualOperationEventMask.set_auto_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.AUTO_LOCK + else + self.value = self.AUTO_LOCK + end +end + +DlManualOperationEventMask.unset_auto_lock = function(self) + self.value = self.value & (~self.AUTO_LOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_schedule_lock_set = function(self) + return (self.value & self.SCHEDULE_LOCK) ~= 0 +end + +DlManualOperationEventMask.set_schedule_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.SCHEDULE_LOCK + else + self.value = self.SCHEDULE_LOCK + end +end + +DlManualOperationEventMask.unset_schedule_lock = function(self) + self.value = self.value & (~self.SCHEDULE_LOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_schedule_unlock_set = function(self) + return (self.value & self.SCHEDULE_UNLOCK) ~= 0 +end + +DlManualOperationEventMask.set_schedule_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.SCHEDULE_UNLOCK + else + self.value = self.SCHEDULE_UNLOCK + end +end + +DlManualOperationEventMask.unset_schedule_unlock = function(self) + self.value = self.value & (~self.SCHEDULE_UNLOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_manual_lock_set = function(self) + return (self.value & self.MANUAL_LOCK) ~= 0 +end + +DlManualOperationEventMask.set_manual_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.MANUAL_LOCK + else + self.value = self.MANUAL_LOCK + end +end + +DlManualOperationEventMask.unset_manual_lock = function(self) + self.value = self.value & (~self.MANUAL_LOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.is_manual_unlock_set = function(self) + return (self.value & self.MANUAL_UNLOCK) ~= 0 +end + +DlManualOperationEventMask.set_manual_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.MANUAL_UNLOCK + else + self.value = self.MANUAL_UNLOCK + end +end + +DlManualOperationEventMask.unset_manual_unlock = function(self) + self.value = self.value & (~self.MANUAL_UNLOCK & self.BASE_MASK) +end + +DlManualOperationEventMask.mask_methods = { + is_unknown_set = DlManualOperationEventMask.is_unknown_set, + set_unknown = DlManualOperationEventMask.set_unknown, + unset_unknown = DlManualOperationEventMask.unset_unknown, + is_thumbturn_lock_set = DlManualOperationEventMask.is_thumbturn_lock_set, + set_thumbturn_lock = DlManualOperationEventMask.set_thumbturn_lock, + unset_thumbturn_lock = DlManualOperationEventMask.unset_thumbturn_lock, + is_thumbturn_unlock_set = DlManualOperationEventMask.is_thumbturn_unlock_set, + set_thumbturn_unlock = DlManualOperationEventMask.set_thumbturn_unlock, + unset_thumbturn_unlock = DlManualOperationEventMask.unset_thumbturn_unlock, + is_one_touch_lock_set = DlManualOperationEventMask.is_one_touch_lock_set, + set_one_touch_lock = DlManualOperationEventMask.set_one_touch_lock, + unset_one_touch_lock = DlManualOperationEventMask.unset_one_touch_lock, + is_key_lock_set = DlManualOperationEventMask.is_key_lock_set, + set_key_lock = DlManualOperationEventMask.set_key_lock, + unset_key_lock = DlManualOperationEventMask.unset_key_lock, + is_key_unlock_set = DlManualOperationEventMask.is_key_unlock_set, + set_key_unlock = DlManualOperationEventMask.set_key_unlock, + unset_key_unlock = DlManualOperationEventMask.unset_key_unlock, + is_auto_lock_set = DlManualOperationEventMask.is_auto_lock_set, + set_auto_lock = DlManualOperationEventMask.set_auto_lock, + unset_auto_lock = DlManualOperationEventMask.unset_auto_lock, + is_schedule_lock_set = DlManualOperationEventMask.is_schedule_lock_set, + set_schedule_lock = DlManualOperationEventMask.set_schedule_lock, + unset_schedule_lock = DlManualOperationEventMask.unset_schedule_lock, + is_schedule_unlock_set = DlManualOperationEventMask.is_schedule_unlock_set, + set_schedule_unlock = DlManualOperationEventMask.set_schedule_unlock, + unset_schedule_unlock = DlManualOperationEventMask.unset_schedule_unlock, + is_manual_lock_set = DlManualOperationEventMask.is_manual_lock_set, + set_manual_lock = DlManualOperationEventMask.set_manual_lock, + unset_manual_lock = DlManualOperationEventMask.unset_manual_lock, + is_manual_unlock_set = DlManualOperationEventMask.is_manual_unlock_set, + set_manual_unlock = DlManualOperationEventMask.set_manual_unlock, + unset_manual_unlock = DlManualOperationEventMask.unset_manual_unlock, +} + +DlManualOperationEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlManualOperationEventMask, new_mt) + +return DlManualOperationEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDOperationEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDOperationEventMask.lua new file mode 100644 index 0000000000..3877280e5e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDOperationEventMask.lua @@ -0,0 +1,169 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlRFIDOperationEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlRFIDOperationEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlRFIDOperationEventMask.BASE_MASK = 0xFFFF +DlRFIDOperationEventMask.UNKNOWN = 0x0001 +DlRFIDOperationEventMask.LOCK = 0x0002 +DlRFIDOperationEventMask.UNLOCK = 0x0004 +DlRFIDOperationEventMask.LOCK_INVALIDRFID = 0x0008 +DlRFIDOperationEventMask.LOCK_INVALID_SCHEDULE = 0x0010 +DlRFIDOperationEventMask.UNLOCK_INVALIDRFID = 0x0020 +DlRFIDOperationEventMask.UNLOCK_INVALID_SCHEDULE = 0x0040 + +DlRFIDOperationEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + LOCK = 0x0002, + UNLOCK = 0x0004, + LOCK_INVALIDRFID = 0x0008, + LOCK_INVALID_SCHEDULE = 0x0010, + UNLOCK_INVALIDRFID = 0x0020, + UNLOCK_INVALID_SCHEDULE = 0x0040, +} + +DlRFIDOperationEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlRFIDOperationEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlRFIDOperationEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlRFIDOperationEventMask.is_lock_set = function(self) + return (self.value & self.LOCK) ~= 0 +end + +DlRFIDOperationEventMask.set_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK + else + self.value = self.LOCK + end +end + +DlRFIDOperationEventMask.unset_lock = function(self) + self.value = self.value & (~self.LOCK & self.BASE_MASK) +end + +DlRFIDOperationEventMask.is_unlock_set = function(self) + return (self.value & self.UNLOCK) ~= 0 +end + +DlRFIDOperationEventMask.set_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK + else + self.value = self.UNLOCK + end +end + +DlRFIDOperationEventMask.unset_unlock = function(self) + self.value = self.value & (~self.UNLOCK & self.BASE_MASK) +end + +DlRFIDOperationEventMask.is_lock_invalidrfid_set = function(self) + return (self.value & self.LOCK_INVALIDRFID) ~= 0 +end + +DlRFIDOperationEventMask.set_lock_invalidrfid = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK_INVALIDRFID + else + self.value = self.LOCK_INVALIDRFID + end +end + +DlRFIDOperationEventMask.unset_lock_invalidrfid = function(self) + self.value = self.value & (~self.LOCK_INVALIDRFID & self.BASE_MASK) +end + +DlRFIDOperationEventMask.is_lock_invalid_schedule_set = function(self) + return (self.value & self.LOCK_INVALID_SCHEDULE) ~= 0 +end + +DlRFIDOperationEventMask.set_lock_invalid_schedule = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK_INVALID_SCHEDULE + else + self.value = self.LOCK_INVALID_SCHEDULE + end +end + +DlRFIDOperationEventMask.unset_lock_invalid_schedule = function(self) + self.value = self.value & (~self.LOCK_INVALID_SCHEDULE & self.BASE_MASK) +end + +DlRFIDOperationEventMask.is_unlock_invalidrfid_set = function(self) + return (self.value & self.UNLOCK_INVALIDRFID) ~= 0 +end + +DlRFIDOperationEventMask.set_unlock_invalidrfid = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK_INVALIDRFID + else + self.value = self.UNLOCK_INVALIDRFID + end +end + +DlRFIDOperationEventMask.unset_unlock_invalidrfid = function(self) + self.value = self.value & (~self.UNLOCK_INVALIDRFID & self.BASE_MASK) +end + +DlRFIDOperationEventMask.is_unlock_invalid_schedule_set = function(self) + return (self.value & self.UNLOCK_INVALID_SCHEDULE) ~= 0 +end + +DlRFIDOperationEventMask.set_unlock_invalid_schedule = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK_INVALID_SCHEDULE + else + self.value = self.UNLOCK_INVALID_SCHEDULE + end +end + +DlRFIDOperationEventMask.unset_unlock_invalid_schedule = function(self) + self.value = self.value & (~self.UNLOCK_INVALID_SCHEDULE & self.BASE_MASK) +end + +DlRFIDOperationEventMask.mask_methods = { + is_unknown_set = DlRFIDOperationEventMask.is_unknown_set, + set_unknown = DlRFIDOperationEventMask.set_unknown, + unset_unknown = DlRFIDOperationEventMask.unset_unknown, + is_lock_set = DlRFIDOperationEventMask.is_lock_set, + set_lock = DlRFIDOperationEventMask.set_lock, + unset_lock = DlRFIDOperationEventMask.unset_lock, + is_unlock_set = DlRFIDOperationEventMask.is_unlock_set, + set_unlock = DlRFIDOperationEventMask.set_unlock, + unset_unlock = DlRFIDOperationEventMask.unset_unlock, + is_lock_invalidrfid_set = DlRFIDOperationEventMask.is_lock_invalidrfid_set, + set_lock_invalidrfid = DlRFIDOperationEventMask.set_lock_invalidrfid, + unset_lock_invalidrfid = DlRFIDOperationEventMask.unset_lock_invalidrfid, + is_lock_invalid_schedule_set = DlRFIDOperationEventMask.is_lock_invalid_schedule_set, + set_lock_invalid_schedule = DlRFIDOperationEventMask.set_lock_invalid_schedule, + unset_lock_invalid_schedule = DlRFIDOperationEventMask.unset_lock_invalid_schedule, + is_unlock_invalidrfid_set = DlRFIDOperationEventMask.is_unlock_invalidrfid_set, + set_unlock_invalidrfid = DlRFIDOperationEventMask.set_unlock_invalidrfid, + unset_unlock_invalidrfid = DlRFIDOperationEventMask.unset_unlock_invalidrfid, + is_unlock_invalid_schedule_set = DlRFIDOperationEventMask.is_unlock_invalid_schedule_set, + set_unlock_invalid_schedule = DlRFIDOperationEventMask.set_unlock_invalid_schedule, + unset_unlock_invalid_schedule = DlRFIDOperationEventMask.unset_unlock_invalid_schedule, +} + +DlRFIDOperationEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlRFIDOperationEventMask, new_mt) + +return DlRFIDOperationEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDProgrammingEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDProgrammingEventMask.lua new file mode 100644 index 0000000000..439f0ebbff --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRFIDProgrammingEventMask.lua @@ -0,0 +1,85 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlRFIDProgrammingEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlRFIDProgrammingEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlRFIDProgrammingEventMask.BASE_MASK = 0xFFFF +DlRFIDProgrammingEventMask.UNKNOWN = 0x0001 +DlRFIDProgrammingEventMask.RFID_CODE_ADDED = 0x0020 +DlRFIDProgrammingEventMask.RFID_CODE_CLEARED = 0x0040 + +DlRFIDProgrammingEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + RFID_CODE_ADDED = 0x0020, + RFID_CODE_CLEARED = 0x0040, +} + +DlRFIDProgrammingEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlRFIDProgrammingEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlRFIDProgrammingEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlRFIDProgrammingEventMask.is_rfid_code_added_set = function(self) + return (self.value & self.RFID_CODE_ADDED) ~= 0 +end + +DlRFIDProgrammingEventMask.set_rfid_code_added = function(self) + if self.value ~= nil then + self.value = self.value | self.RFID_CODE_ADDED + else + self.value = self.RFID_CODE_ADDED + end +end + +DlRFIDProgrammingEventMask.unset_rfid_code_added = function(self) + self.value = self.value & (~self.RFID_CODE_ADDED & self.BASE_MASK) +end + +DlRFIDProgrammingEventMask.is_rfid_code_cleared_set = function(self) + return (self.value & self.RFID_CODE_CLEARED) ~= 0 +end + +DlRFIDProgrammingEventMask.set_rfid_code_cleared = function(self) + if self.value ~= nil then + self.value = self.value | self.RFID_CODE_CLEARED + else + self.value = self.RFID_CODE_CLEARED + end +end + +DlRFIDProgrammingEventMask.unset_rfid_code_cleared = function(self) + self.value = self.value & (~self.RFID_CODE_CLEARED & self.BASE_MASK) +end + +DlRFIDProgrammingEventMask.mask_methods = { + is_unknown_set = DlRFIDProgrammingEventMask.is_unknown_set, + set_unknown = DlRFIDProgrammingEventMask.set_unknown, + unset_unknown = DlRFIDProgrammingEventMask.unset_unknown, + is_rfid_code_added_set = DlRFIDProgrammingEventMask.is_rfid_code_added_set, + set_rfid_code_added = DlRFIDProgrammingEventMask.set_rfid_code_added, + unset_rfid_code_added = DlRFIDProgrammingEventMask.unset_rfid_code_added, + is_rfid_code_cleared_set = DlRFIDProgrammingEventMask.is_rfid_code_cleared_set, + set_rfid_code_cleared = DlRFIDProgrammingEventMask.set_rfid_code_cleared, + unset_rfid_code_cleared = DlRFIDProgrammingEventMask.unset_rfid_code_cleared, +} + +DlRFIDProgrammingEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlRFIDProgrammingEventMask, new_mt) + +return DlRFIDProgrammingEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteOperationEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteOperationEventMask.lua new file mode 100644 index 0000000000..0dfed6af72 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteOperationEventMask.lua @@ -0,0 +1,169 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlRemoteOperationEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlRemoteOperationEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlRemoteOperationEventMask.BASE_MASK = 0xFFFF +DlRemoteOperationEventMask.UNKNOWN = 0x0001 +DlRemoteOperationEventMask.LOCK = 0x0002 +DlRemoteOperationEventMask.UNLOCK = 0x0004 +DlRemoteOperationEventMask.LOCK_INVALID_CODE = 0x0008 +DlRemoteOperationEventMask.LOCK_INVALID_SCHEDULE = 0x0010 +DlRemoteOperationEventMask.UNLOCK_INVALID_CODE = 0x0020 +DlRemoteOperationEventMask.UNLOCK_INVALID_SCHEDULE = 0x0040 + +DlRemoteOperationEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + LOCK = 0x0002, + UNLOCK = 0x0004, + LOCK_INVALID_CODE = 0x0008, + LOCK_INVALID_SCHEDULE = 0x0010, + UNLOCK_INVALID_CODE = 0x0020, + UNLOCK_INVALID_SCHEDULE = 0x0040, +} + +DlRemoteOperationEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlRemoteOperationEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlRemoteOperationEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlRemoteOperationEventMask.is_lock_set = function(self) + return (self.value & self.LOCK) ~= 0 +end + +DlRemoteOperationEventMask.set_lock = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK + else + self.value = self.LOCK + end +end + +DlRemoteOperationEventMask.unset_lock = function(self) + self.value = self.value & (~self.LOCK & self.BASE_MASK) +end + +DlRemoteOperationEventMask.is_unlock_set = function(self) + return (self.value & self.UNLOCK) ~= 0 +end + +DlRemoteOperationEventMask.set_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK + else + self.value = self.UNLOCK + end +end + +DlRemoteOperationEventMask.unset_unlock = function(self) + self.value = self.value & (~self.UNLOCK & self.BASE_MASK) +end + +DlRemoteOperationEventMask.is_lock_invalid_code_set = function(self) + return (self.value & self.LOCK_INVALID_CODE) ~= 0 +end + +DlRemoteOperationEventMask.set_lock_invalid_code = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK_INVALID_CODE + else + self.value = self.LOCK_INVALID_CODE + end +end + +DlRemoteOperationEventMask.unset_lock_invalid_code = function(self) + self.value = self.value & (~self.LOCK_INVALID_CODE & self.BASE_MASK) +end + +DlRemoteOperationEventMask.is_lock_invalid_schedule_set = function(self) + return (self.value & self.LOCK_INVALID_SCHEDULE) ~= 0 +end + +DlRemoteOperationEventMask.set_lock_invalid_schedule = function(self) + if self.value ~= nil then + self.value = self.value | self.LOCK_INVALID_SCHEDULE + else + self.value = self.LOCK_INVALID_SCHEDULE + end +end + +DlRemoteOperationEventMask.unset_lock_invalid_schedule = function(self) + self.value = self.value & (~self.LOCK_INVALID_SCHEDULE & self.BASE_MASK) +end + +DlRemoteOperationEventMask.is_unlock_invalid_code_set = function(self) + return (self.value & self.UNLOCK_INVALID_CODE) ~= 0 +end + +DlRemoteOperationEventMask.set_unlock_invalid_code = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK_INVALID_CODE + else + self.value = self.UNLOCK_INVALID_CODE + end +end + +DlRemoteOperationEventMask.unset_unlock_invalid_code = function(self) + self.value = self.value & (~self.UNLOCK_INVALID_CODE & self.BASE_MASK) +end + +DlRemoteOperationEventMask.is_unlock_invalid_schedule_set = function(self) + return (self.value & self.UNLOCK_INVALID_SCHEDULE) ~= 0 +end + +DlRemoteOperationEventMask.set_unlock_invalid_schedule = function(self) + if self.value ~= nil then + self.value = self.value | self.UNLOCK_INVALID_SCHEDULE + else + self.value = self.UNLOCK_INVALID_SCHEDULE + end +end + +DlRemoteOperationEventMask.unset_unlock_invalid_schedule = function(self) + self.value = self.value & (~self.UNLOCK_INVALID_SCHEDULE & self.BASE_MASK) +end + +DlRemoteOperationEventMask.mask_methods = { + is_unknown_set = DlRemoteOperationEventMask.is_unknown_set, + set_unknown = DlRemoteOperationEventMask.set_unknown, + unset_unknown = DlRemoteOperationEventMask.unset_unknown, + is_lock_set = DlRemoteOperationEventMask.is_lock_set, + set_lock = DlRemoteOperationEventMask.set_lock, + unset_lock = DlRemoteOperationEventMask.unset_lock, + is_unlock_set = DlRemoteOperationEventMask.is_unlock_set, + set_unlock = DlRemoteOperationEventMask.set_unlock, + unset_unlock = DlRemoteOperationEventMask.unset_unlock, + is_lock_invalid_code_set = DlRemoteOperationEventMask.is_lock_invalid_code_set, + set_lock_invalid_code = DlRemoteOperationEventMask.set_lock_invalid_code, + unset_lock_invalid_code = DlRemoteOperationEventMask.unset_lock_invalid_code, + is_lock_invalid_schedule_set = DlRemoteOperationEventMask.is_lock_invalid_schedule_set, + set_lock_invalid_schedule = DlRemoteOperationEventMask.set_lock_invalid_schedule, + unset_lock_invalid_schedule = DlRemoteOperationEventMask.unset_lock_invalid_schedule, + is_unlock_invalid_code_set = DlRemoteOperationEventMask.is_unlock_invalid_code_set, + set_unlock_invalid_code = DlRemoteOperationEventMask.set_unlock_invalid_code, + unset_unlock_invalid_code = DlRemoteOperationEventMask.unset_unlock_invalid_code, + is_unlock_invalid_schedule_set = DlRemoteOperationEventMask.is_unlock_invalid_schedule_set, + set_unlock_invalid_schedule = DlRemoteOperationEventMask.set_unlock_invalid_schedule, + unset_unlock_invalid_schedule = DlRemoteOperationEventMask.unset_unlock_invalid_schedule, +} + +DlRemoteOperationEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlRemoteOperationEventMask, new_mt) + +return DlRemoteOperationEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteProgrammingEventMask.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteProgrammingEventMask.lua new file mode 100644 index 0000000000..c0a14c5e1a --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlRemoteProgrammingEventMask.lua @@ -0,0 +1,169 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlRemoteProgrammingEventMask = {} +local new_mt = UintABC.new_mt({NAME = "DlRemoteProgrammingEventMask", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlRemoteProgrammingEventMask.BASE_MASK = 0xFFFF +DlRemoteProgrammingEventMask.UNKNOWN = 0x0001 +DlRemoteProgrammingEventMask.PROGRAMMINGPIN_CHANGED = 0x0002 +DlRemoteProgrammingEventMask.PIN_ADDED = 0x0004 +DlRemoteProgrammingEventMask.PIN_CLEARED = 0x0008 +DlRemoteProgrammingEventMask.PIN_CHANGED = 0x0010 +DlRemoteProgrammingEventMask.RFID_CODE_ADDED = 0x0020 +DlRemoteProgrammingEventMask.RFID_CODE_CLEARED = 0x0040 + +DlRemoteProgrammingEventMask.mask_fields = { + BASE_MASK = 0xFFFF, + UNKNOWN = 0x0001, + PROGRAMMINGPIN_CHANGED = 0x0002, + PIN_ADDED = 0x0004, + PIN_CLEARED = 0x0008, + PIN_CHANGED = 0x0010, + RFID_CODE_ADDED = 0x0020, + RFID_CODE_CLEARED = 0x0040, +} + +DlRemoteProgrammingEventMask.is_unknown_set = function(self) + return (self.value & self.UNKNOWN) ~= 0 +end + +DlRemoteProgrammingEventMask.set_unknown = function(self) + if self.value ~= nil then + self.value = self.value | self.UNKNOWN + else + self.value = self.UNKNOWN + end +end + +DlRemoteProgrammingEventMask.unset_unknown = function(self) + self.value = self.value & (~self.UNKNOWN & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.is_programmingpin_changed_set = function(self) + return (self.value & self.PROGRAMMINGPIN_CHANGED) ~= 0 +end + +DlRemoteProgrammingEventMask.set_programmingpin_changed = function(self) + if self.value ~= nil then + self.value = self.value | self.PROGRAMMINGPIN_CHANGED + else + self.value = self.PROGRAMMINGPIN_CHANGED + end +end + +DlRemoteProgrammingEventMask.unset_programmingpin_changed = function(self) + self.value = self.value & (~self.PROGRAMMINGPIN_CHANGED & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.is_pin_added_set = function(self) + return (self.value & self.PIN_ADDED) ~= 0 +end + +DlRemoteProgrammingEventMask.set_pin_added = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_ADDED + else + self.value = self.PIN_ADDED + end +end + +DlRemoteProgrammingEventMask.unset_pin_added = function(self) + self.value = self.value & (~self.PIN_ADDED & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.is_pin_cleared_set = function(self) + return (self.value & self.PIN_CLEARED) ~= 0 +end + +DlRemoteProgrammingEventMask.set_pin_cleared = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_CLEARED + else + self.value = self.PIN_CLEARED + end +end + +DlRemoteProgrammingEventMask.unset_pin_cleared = function(self) + self.value = self.value & (~self.PIN_CLEARED & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.is_pin_changed_set = function(self) + return (self.value & self.PIN_CHANGED) ~= 0 +end + +DlRemoteProgrammingEventMask.set_pin_changed = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_CHANGED + else + self.value = self.PIN_CHANGED + end +end + +DlRemoteProgrammingEventMask.unset_pin_changed = function(self) + self.value = self.value & (~self.PIN_CHANGED & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.is_rfid_code_added_set = function(self) + return (self.value & self.RFID_CODE_ADDED) ~= 0 +end + +DlRemoteProgrammingEventMask.set_rfid_code_added = function(self) + if self.value ~= nil then + self.value = self.value | self.RFID_CODE_ADDED + else + self.value = self.RFID_CODE_ADDED + end +end + +DlRemoteProgrammingEventMask.unset_rfid_code_added = function(self) + self.value = self.value & (~self.RFID_CODE_ADDED & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.is_rfid_code_cleared_set = function(self) + return (self.value & self.RFID_CODE_CLEARED) ~= 0 +end + +DlRemoteProgrammingEventMask.set_rfid_code_cleared = function(self) + if self.value ~= nil then + self.value = self.value | self.RFID_CODE_CLEARED + else + self.value = self.RFID_CODE_CLEARED + end +end + +DlRemoteProgrammingEventMask.unset_rfid_code_cleared = function(self) + self.value = self.value & (~self.RFID_CODE_CLEARED & self.BASE_MASK) +end + +DlRemoteProgrammingEventMask.mask_methods = { + is_unknown_set = DlRemoteProgrammingEventMask.is_unknown_set, + set_unknown = DlRemoteProgrammingEventMask.set_unknown, + unset_unknown = DlRemoteProgrammingEventMask.unset_unknown, + is_programmingpin_changed_set = DlRemoteProgrammingEventMask.is_programmingpin_changed_set, + set_programmingpin_changed = DlRemoteProgrammingEventMask.set_programmingpin_changed, + unset_programmingpin_changed = DlRemoteProgrammingEventMask.unset_programmingpin_changed, + is_pin_added_set = DlRemoteProgrammingEventMask.is_pin_added_set, + set_pin_added = DlRemoteProgrammingEventMask.set_pin_added, + unset_pin_added = DlRemoteProgrammingEventMask.unset_pin_added, + is_pin_cleared_set = DlRemoteProgrammingEventMask.is_pin_cleared_set, + set_pin_cleared = DlRemoteProgrammingEventMask.set_pin_cleared, + unset_pin_cleared = DlRemoteProgrammingEventMask.unset_pin_cleared, + is_pin_changed_set = DlRemoteProgrammingEventMask.is_pin_changed_set, + set_pin_changed = DlRemoteProgrammingEventMask.set_pin_changed, + unset_pin_changed = DlRemoteProgrammingEventMask.unset_pin_changed, + is_rfid_code_added_set = DlRemoteProgrammingEventMask.is_rfid_code_added_set, + set_rfid_code_added = DlRemoteProgrammingEventMask.set_rfid_code_added, + unset_rfid_code_added = DlRemoteProgrammingEventMask.unset_rfid_code_added, + is_rfid_code_cleared_set = DlRemoteProgrammingEventMask.is_rfid_code_cleared_set, + set_rfid_code_cleared = DlRemoteProgrammingEventMask.set_rfid_code_cleared, + unset_rfid_code_cleared = DlRemoteProgrammingEventMask.unset_rfid_code_cleared, +} + +DlRemoteProgrammingEventMask.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlRemoteProgrammingEventMask, new_mt) + +return DlRemoteProgrammingEventMask \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlStatus.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlStatus.lua new file mode 100644 index 0000000000..b681fd8018 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlStatus.lua @@ -0,0 +1,42 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlStatus = {} +local new_mt = UintABC.new_mt({NAME = "DlStatus", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.SUCCESS] = "SUCCESS", + [self.FAILURE] = "FAILURE", + [self.DUPLICATE] = "DUPLICATE", + [self.OCCUPIED] = "OCCUPIED", + [self.INVALID_FIELD] = "INVALID_FIELD", + [self.RESOURCE_EXHAUSTED] = "RESOURCE_EXHAUSTED", + [self.NOT_FOUND] = "NOT_FOUND", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.SUCCESS = 0x00 +new_mt.__index.FAILURE = 0x01 +new_mt.__index.DUPLICATE = 0x02 +new_mt.__index.OCCUPIED = 0x03 +new_mt.__index.INVALID_FIELD = 0x85 +new_mt.__index.RESOURCE_EXHAUSTED = 0x89 +new_mt.__index.NOT_FOUND = 0x8B + +DlStatus.SUCCESS = 0x00 +DlStatus.FAILURE = 0x01 +DlStatus.DUPLICATE = 0x02 +DlStatus.OCCUPIED = 0x03 +DlStatus.INVALID_FIELD = 0x85 +DlStatus.RESOURCE_EXHAUSTED = 0x89 +DlStatus.NOT_FOUND = 0x8B + +DlStatus.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlStatus, new_mt) + +return DlStatus \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DlSupportedOperatingModes.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlSupportedOperatingModes.lua new file mode 100644 index 0000000000..5e529146c2 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DlSupportedOperatingModes.lua @@ -0,0 +1,127 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DlSupportedOperatingModes = {} +local new_mt = UintABC.new_mt({NAME = "DlSupportedOperatingModes", ID = data_types.name_to_id_map["Uint16"]}, 2) + +DlSupportedOperatingModes.BASE_MASK = 0xFFFF +DlSupportedOperatingModes.NORMAL = 0x0001 +DlSupportedOperatingModes.VACATION = 0x0002 +DlSupportedOperatingModes.PRIVACY = 0x0004 +DlSupportedOperatingModes.NO_REMOTE_LOCK_UNLOCK = 0x0008 +DlSupportedOperatingModes.PASSAGE = 0x0010 + +DlSupportedOperatingModes.mask_fields = { + BASE_MASK = 0xFFFF, + NORMAL = 0x0001, + VACATION = 0x0002, + PRIVACY = 0x0004, + NO_REMOTE_LOCK_UNLOCK = 0x0008, + PASSAGE = 0x0010, +} + +DlSupportedOperatingModes.is_normal_set = function(self) + return (self.value & self.NORMAL) ~= 0 +end + +DlSupportedOperatingModes.set_normal = function(self) + if self.value ~= nil then + self.value = self.value | self.NORMAL + else + self.value = self.NORMAL + end +end + +DlSupportedOperatingModes.unset_normal = function(self) + self.value = self.value & (~self.NORMAL & self.BASE_MASK) +end + +DlSupportedOperatingModes.is_vacation_set = function(self) + return (self.value & self.VACATION) ~= 0 +end + +DlSupportedOperatingModes.set_vacation = function(self) + if self.value ~= nil then + self.value = self.value | self.VACATION + else + self.value = self.VACATION + end +end + +DlSupportedOperatingModes.unset_vacation = function(self) + self.value = self.value & (~self.VACATION & self.BASE_MASK) +end + +DlSupportedOperatingModes.is_privacy_set = function(self) + return (self.value & self.PRIVACY) ~= 0 +end + +DlSupportedOperatingModes.set_privacy = function(self) + if self.value ~= nil then + self.value = self.value | self.PRIVACY + else + self.value = self.PRIVACY + end +end + +DlSupportedOperatingModes.unset_privacy = function(self) + self.value = self.value & (~self.PRIVACY & self.BASE_MASK) +end + +DlSupportedOperatingModes.is_no_remote_lock_unlock_set = function(self) + return (self.value & self.NO_REMOTE_LOCK_UNLOCK) ~= 0 +end + +DlSupportedOperatingModes.set_no_remote_lock_unlock = function(self) + if self.value ~= nil then + self.value = self.value | self.NO_REMOTE_LOCK_UNLOCK + else + self.value = self.NO_REMOTE_LOCK_UNLOCK + end +end + +DlSupportedOperatingModes.unset_no_remote_lock_unlock = function(self) + self.value = self.value & (~self.NO_REMOTE_LOCK_UNLOCK & self.BASE_MASK) +end + +DlSupportedOperatingModes.is_passage_set = function(self) + return (self.value & self.PASSAGE) ~= 0 +end + +DlSupportedOperatingModes.set_passage = function(self) + if self.value ~= nil then + self.value = self.value | self.PASSAGE + else + self.value = self.PASSAGE + end +end + +DlSupportedOperatingModes.unset_passage = function(self) + self.value = self.value & (~self.PASSAGE & self.BASE_MASK) +end + +DlSupportedOperatingModes.mask_methods = { + is_normal_set = DlSupportedOperatingModes.is_normal_set, + set_normal = DlSupportedOperatingModes.set_normal, + unset_normal = DlSupportedOperatingModes.unset_normal, + is_vacation_set = DlSupportedOperatingModes.is_vacation_set, + set_vacation = DlSupportedOperatingModes.set_vacation, + unset_vacation = DlSupportedOperatingModes.unset_vacation, + is_privacy_set = DlSupportedOperatingModes.is_privacy_set, + set_privacy = DlSupportedOperatingModes.set_privacy, + unset_privacy = DlSupportedOperatingModes.unset_privacy, + is_no_remote_lock_unlock_set = DlSupportedOperatingModes.is_no_remote_lock_unlock_set, + set_no_remote_lock_unlock = DlSupportedOperatingModes.set_no_remote_lock_unlock, + unset_no_remote_lock_unlock = DlSupportedOperatingModes.unset_no_remote_lock_unlock, + is_passage_set = DlSupportedOperatingModes.is_passage_set, + set_passage = DlSupportedOperatingModes.set_passage, + unset_passage = DlSupportedOperatingModes.unset_passage, +} + +DlSupportedOperatingModes.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DlSupportedOperatingModes, new_mt) + +return DlSupportedOperatingModes \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockDayOfWeek.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockDayOfWeek.lua new file mode 100644 index 0000000000..9a03693d35 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockDayOfWeek.lua @@ -0,0 +1,169 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorLockDayOfWeek = {} +local new_mt = UintABC.new_mt({NAME = "DoorLockDayOfWeek", ID = data_types.name_to_id_map["Uint8"]}, 1) + +DoorLockDayOfWeek.BASE_MASK = 0xFFFF +DoorLockDayOfWeek.SUNDAY = 0x0001 +DoorLockDayOfWeek.MONDAY = 0x0002 +DoorLockDayOfWeek.TUESDAY = 0x0004 +DoorLockDayOfWeek.WEDNESDAY = 0x0008 +DoorLockDayOfWeek.THURSDAY = 0x0010 +DoorLockDayOfWeek.FRIDAY = 0x0020 +DoorLockDayOfWeek.SATURDAY = 0x0040 + +DoorLockDayOfWeek.mask_fields = { + BASE_MASK = 0xFFFF, + SUNDAY = 0x0001, + MONDAY = 0x0002, + TUESDAY = 0x0004, + WEDNESDAY = 0x0008, + THURSDAY = 0x0010, + FRIDAY = 0x0020, + SATURDAY = 0x0040, +} + +DoorLockDayOfWeek.is_sunday_set = function(self) + return (self.value & self.SUNDAY) ~= 0 +end + +DoorLockDayOfWeek.set_sunday = function(self) + if self.value ~= nil then + self.value = self.value | self.SUNDAY + else + self.value = self.SUNDAY + end +end + +DoorLockDayOfWeek.unset_sunday = function(self) + self.value = self.value & (~self.SUNDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.is_monday_set = function(self) + return (self.value & self.MONDAY) ~= 0 +end + +DoorLockDayOfWeek.set_monday = function(self) + if self.value ~= nil then + self.value = self.value | self.MONDAY + else + self.value = self.MONDAY + end +end + +DoorLockDayOfWeek.unset_monday = function(self) + self.value = self.value & (~self.MONDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.is_tuesday_set = function(self) + return (self.value & self.TUESDAY) ~= 0 +end + +DoorLockDayOfWeek.set_tuesday = function(self) + if self.value ~= nil then + self.value = self.value | self.TUESDAY + else + self.value = self.TUESDAY + end +end + +DoorLockDayOfWeek.unset_tuesday = function(self) + self.value = self.value & (~self.TUESDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.is_wednesday_set = function(self) + return (self.value & self.WEDNESDAY) ~= 0 +end + +DoorLockDayOfWeek.set_wednesday = function(self) + if self.value ~= nil then + self.value = self.value | self.WEDNESDAY + else + self.value = self.WEDNESDAY + end +end + +DoorLockDayOfWeek.unset_wednesday = function(self) + self.value = self.value & (~self.WEDNESDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.is_thursday_set = function(self) + return (self.value & self.THURSDAY) ~= 0 +end + +DoorLockDayOfWeek.set_thursday = function(self) + if self.value ~= nil then + self.value = self.value | self.THURSDAY + else + self.value = self.THURSDAY + end +end + +DoorLockDayOfWeek.unset_thursday = function(self) + self.value = self.value & (~self.THURSDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.is_friday_set = function(self) + return (self.value & self.FRIDAY) ~= 0 +end + +DoorLockDayOfWeek.set_friday = function(self) + if self.value ~= nil then + self.value = self.value | self.FRIDAY + else + self.value = self.FRIDAY + end +end + +DoorLockDayOfWeek.unset_friday = function(self) + self.value = self.value & (~self.FRIDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.is_saturday_set = function(self) + return (self.value & self.SATURDAY) ~= 0 +end + +DoorLockDayOfWeek.set_saturday = function(self) + if self.value ~= nil then + self.value = self.value | self.SATURDAY + else + self.value = self.SATURDAY + end +end + +DoorLockDayOfWeek.unset_saturday = function(self) + self.value = self.value & (~self.SATURDAY & self.BASE_MASK) +end + +DoorLockDayOfWeek.mask_methods = { + is_sunday_set = DoorLockDayOfWeek.is_sunday_set, + set_sunday = DoorLockDayOfWeek.set_sunday, + unset_sunday = DoorLockDayOfWeek.unset_sunday, + is_monday_set = DoorLockDayOfWeek.is_monday_set, + set_monday = DoorLockDayOfWeek.set_monday, + unset_monday = DoorLockDayOfWeek.unset_monday, + is_tuesday_set = DoorLockDayOfWeek.is_tuesday_set, + set_tuesday = DoorLockDayOfWeek.set_tuesday, + unset_tuesday = DoorLockDayOfWeek.unset_tuesday, + is_wednesday_set = DoorLockDayOfWeek.is_wednesday_set, + set_wednesday = DoorLockDayOfWeek.set_wednesday, + unset_wednesday = DoorLockDayOfWeek.unset_wednesday, + is_thursday_set = DoorLockDayOfWeek.is_thursday_set, + set_thursday = DoorLockDayOfWeek.set_thursday, + unset_thursday = DoorLockDayOfWeek.unset_thursday, + is_friday_set = DoorLockDayOfWeek.is_friday_set, + set_friday = DoorLockDayOfWeek.set_friday, + unset_friday = DoorLockDayOfWeek.unset_friday, + is_saturday_set = DoorLockDayOfWeek.is_saturday_set, + set_saturday = DoorLockDayOfWeek.set_saturday, + unset_saturday = DoorLockDayOfWeek.unset_saturday, +} + +DoorLockDayOfWeek.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorLockDayOfWeek, new_mt) + +return DoorLockDayOfWeek \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockOperationEventCode.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockOperationEventCode.lua new file mode 100644 index 0000000000..556fdff0cd --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockOperationEventCode.lua @@ -0,0 +1,66 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorLockOperationEventCode = {} +local new_mt = UintABC.new_mt({NAME = "DoorLockOperationEventCode", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNKNOWN_OR_MFG_SPECIFIC] = "UNKNOWN_OR_MFG_SPECIFIC", + [self.LOCK] = "LOCK", + [self.UNLOCK] = "UNLOCK", + [self.LOCK_INVALID_PIN_OR_ID] = "LOCK_INVALID_PIN_OR_ID", + [self.LOCK_INVALID_SCHEDULE] = "LOCK_INVALID_SCHEDULE", + [self.UNLOCK_INVALID_PIN_OR_ID] = "UNLOCK_INVALID_PIN_OR_ID", + [self.UNLOCK_INVALID_SCHEDULE] = "UNLOCK_INVALID_SCHEDULE", + [self.ONE_TOUCH_LOCK] = "ONE_TOUCH_LOCK", + [self.KEY_LOCK] = "KEY_LOCK", + [self.KEY_UNLOCK] = "KEY_UNLOCK", + [self.AUTO_LOCK] = "AUTO_LOCK", + [self.SCHEDULE_LOCK] = "SCHEDULE_LOCK", + [self.SCHEDULE_UNLOCK] = "SCHEDULE_UNLOCK", + [self.MANUAL_LOCK] = "MANUAL_LOCK", + [self.MANUAL_UNLOCK] = "MANUAL_UNLOCK", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNKNOWN_OR_MFG_SPECIFIC = 0x00 +new_mt.__index.LOCK = 0x01 +new_mt.__index.UNLOCK = 0x02 +new_mt.__index.LOCK_INVALID_PIN_OR_ID = 0x03 +new_mt.__index.LOCK_INVALID_SCHEDULE = 0x04 +new_mt.__index.UNLOCK_INVALID_PIN_OR_ID = 0x05 +new_mt.__index.UNLOCK_INVALID_SCHEDULE = 0x06 +new_mt.__index.ONE_TOUCH_LOCK = 0x07 +new_mt.__index.KEY_LOCK = 0x08 +new_mt.__index.KEY_UNLOCK = 0x09 +new_mt.__index.AUTO_LOCK = 0x0A +new_mt.__index.SCHEDULE_LOCK = 0x0B +new_mt.__index.SCHEDULE_UNLOCK = 0x0C +new_mt.__index.MANUAL_LOCK = 0x0D +new_mt.__index.MANUAL_UNLOCK = 0x0E + +DoorLockOperationEventCode.UNKNOWN_OR_MFG_SPECIFIC = 0x00 +DoorLockOperationEventCode.LOCK = 0x01 +DoorLockOperationEventCode.UNLOCK = 0x02 +DoorLockOperationEventCode.LOCK_INVALID_PIN_OR_ID = 0x03 +DoorLockOperationEventCode.LOCK_INVALID_SCHEDULE = 0x04 +DoorLockOperationEventCode.UNLOCK_INVALID_PIN_OR_ID = 0x05 +DoorLockOperationEventCode.UNLOCK_INVALID_SCHEDULE = 0x06 +DoorLockOperationEventCode.ONE_TOUCH_LOCK = 0x07 +DoorLockOperationEventCode.KEY_LOCK = 0x08 +DoorLockOperationEventCode.KEY_UNLOCK = 0x09 +DoorLockOperationEventCode.AUTO_LOCK = 0x0A +DoorLockOperationEventCode.SCHEDULE_LOCK = 0x0B +DoorLockOperationEventCode.SCHEDULE_UNLOCK = 0x0C +DoorLockOperationEventCode.MANUAL_LOCK = 0x0D +DoorLockOperationEventCode.MANUAL_UNLOCK = 0x0E + +DoorLockOperationEventCode.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorLockOperationEventCode, new_mt) + +return DoorLockOperationEventCode \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockProgrammingEventCode.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockProgrammingEventCode.lua new file mode 100644 index 0000000000..ffb91d592f --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockProgrammingEventCode.lua @@ -0,0 +1,42 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorLockProgrammingEventCode = {} +local new_mt = UintABC.new_mt({NAME = "DoorLockProgrammingEventCode", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNKNOWN_OR_MFG_SPECIFIC] = "UNKNOWN_OR_MFG_SPECIFIC", + [self.MASTER_CODE_CHANGED] = "MASTER_CODE_CHANGED", + [self.PIN_ADDED] = "PIN_ADDED", + [self.PIN_DELETED] = "PIN_DELETED", + [self.PIN_CHANGED] = "PIN_CHANGED", + [self.ID_ADDED] = "ID_ADDED", + [self.ID_DELETED] = "ID_DELETED", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNKNOWN_OR_MFG_SPECIFIC = 0x00 +new_mt.__index.MASTER_CODE_CHANGED = 0x01 +new_mt.__index.PIN_ADDED = 0x02 +new_mt.__index.PIN_DELETED = 0x03 +new_mt.__index.PIN_CHANGED = 0x04 +new_mt.__index.ID_ADDED = 0x05 +new_mt.__index.ID_DELETED = 0x06 + +DoorLockProgrammingEventCode.UNKNOWN_OR_MFG_SPECIFIC = 0x00 +DoorLockProgrammingEventCode.MASTER_CODE_CHANGED = 0x01 +DoorLockProgrammingEventCode.PIN_ADDED = 0x02 +DoorLockProgrammingEventCode.PIN_DELETED = 0x03 +DoorLockProgrammingEventCode.PIN_CHANGED = 0x04 +DoorLockProgrammingEventCode.ID_ADDED = 0x05 +DoorLockProgrammingEventCode.ID_DELETED = 0x06 + +DoorLockProgrammingEventCode.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorLockProgrammingEventCode, new_mt) + +return DoorLockProgrammingEventCode \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockSetPinOrIdStatus.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockSetPinOrIdStatus.lua new file mode 100644 index 0000000000..6e32459354 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockSetPinOrIdStatus.lua @@ -0,0 +1,33 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorLockSetPinOrIdStatus = {} +local new_mt = UintABC.new_mt({NAME = "DoorLockSetPinOrIdStatus", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.SUCCESS] = "SUCCESS", + [self.GENERAL_FAILURE] = "GENERAL_FAILURE", + [self.MEMORY_FULL] = "MEMORY_FULL", + [self.DUPLICATE_CODE_ERROR] = "DUPLICATE_CODE_ERROR", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.SUCCESS = 0x00 +new_mt.__index.GENERAL_FAILURE = 0x01 +new_mt.__index.MEMORY_FULL = 0x02 +new_mt.__index.DUPLICATE_CODE_ERROR = 0x03 + +DoorLockSetPinOrIdStatus.SUCCESS = 0x00 +DoorLockSetPinOrIdStatus.GENERAL_FAILURE = 0x01 +DoorLockSetPinOrIdStatus.MEMORY_FULL = 0x02 +DoorLockSetPinOrIdStatus.DUPLICATE_CODE_ERROR = 0x03 + +DoorLockSetPinOrIdStatus.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorLockSetPinOrIdStatus, new_mt) + +return DoorLockSetPinOrIdStatus \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserStatus.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserStatus.lua new file mode 100644 index 0000000000..b755a48bb5 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserStatus.lua @@ -0,0 +1,33 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorLockUserStatus = {} +local new_mt = UintABC.new_mt({NAME = "DoorLockUserStatus", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.AVAILABLE] = "AVAILABLE", + [self.OCCUPIED_ENABLED] = "OCCUPIED_ENABLED", + [self.OCCUPIED_DISABLED] = "OCCUPIED_DISABLED", + [self.NOT_SUPPORTED] = "NOT_SUPPORTED", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.AVAILABLE = 0x00 +new_mt.__index.OCCUPIED_ENABLED = 0x01 +new_mt.__index.OCCUPIED_DISABLED = 0x03 +new_mt.__index.NOT_SUPPORTED = 0xFF + +DoorLockUserStatus.AVAILABLE = 0x00 +DoorLockUserStatus.OCCUPIED_ENABLED = 0x01 +DoorLockUserStatus.OCCUPIED_DISABLED = 0x03 +DoorLockUserStatus.NOT_SUPPORTED = 0xFF + +DoorLockUserStatus.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorLockUserStatus, new_mt) + +return DoorLockUserStatus \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserType.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserType.lua new file mode 100644 index 0000000000..b8f6724f46 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorLockUserType.lua @@ -0,0 +1,39 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorLockUserType = {} +local new_mt = UintABC.new_mt({NAME = "DoorLockUserType", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNRESTRICTED] = "UNRESTRICTED", + [self.YEAR_DAY_SCHEDULE_USER] = "YEAR_DAY_SCHEDULE_USER", + [self.WEEK_DAY_SCHEDULE_USER] = "WEEK_DAY_SCHEDULE_USER", + [self.MASTER_USER] = "MASTER_USER", + [self.NON_ACCESS_USER] = "NON_ACCESS_USER", + [self.NOT_SUPPORTED] = "NOT_SUPPORTED", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNRESTRICTED = 0x00 +new_mt.__index.YEAR_DAY_SCHEDULE_USER = 0x01 +new_mt.__index.WEEK_DAY_SCHEDULE_USER = 0x02 +new_mt.__index.MASTER_USER = 0x03 +new_mt.__index.NON_ACCESS_USER = 0x04 +new_mt.__index.NOT_SUPPORTED = 0xFF + +DoorLockUserType.UNRESTRICTED = 0x00 +DoorLockUserType.YEAR_DAY_SCHEDULE_USER = 0x01 +DoorLockUserType.WEEK_DAY_SCHEDULE_USER = 0x02 +DoorLockUserType.MASTER_USER = 0x03 +DoorLockUserType.NON_ACCESS_USER = 0x04 +DoorLockUserType.NOT_SUPPORTED = 0xFF + +DoorLockUserType.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorLockUserType, new_mt) + +return DoorLockUserType \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorStateEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorStateEnum.lua new file mode 100644 index 0000000000..ae01ab195c --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/DoorStateEnum.lua @@ -0,0 +1,39 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local DoorStateEnum = {} +local new_mt = UintABC.new_mt({NAME = "DoorStateEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.DOOR_OPEN] = "DOOR_OPEN", + [self.DOOR_CLOSED] = "DOOR_CLOSED", + [self.DOOR_JAMMED] = "DOOR_JAMMED", + [self.DOOR_FORCED_OPEN] = "DOOR_FORCED_OPEN", + [self.DOOR_UNSPECIFIED_ERROR] = "DOOR_UNSPECIFIED_ERROR", + [self.DOOR_AJAR] = "DOOR_AJAR", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.DOOR_OPEN = 0x00 +new_mt.__index.DOOR_CLOSED = 0x01 +new_mt.__index.DOOR_JAMMED = 0x02 +new_mt.__index.DOOR_FORCED_OPEN = 0x03 +new_mt.__index.DOOR_UNSPECIFIED_ERROR = 0x04 +new_mt.__index.DOOR_AJAR = 0x05 + +DoorStateEnum.DOOR_OPEN = 0x00 +DoorStateEnum.DOOR_CLOSED = 0x01 +DoorStateEnum.DOOR_JAMMED = 0x02 +DoorStateEnum.DOOR_FORCED_OPEN = 0x03 +DoorStateEnum.DOOR_UNSPECIFIED_ERROR = 0x04 +DoorStateEnum.DOOR_AJAR = 0x05 + +DoorStateEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(DoorStateEnum, new_mt) + +return DoorStateEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/Feature.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/Feature.lua new file mode 100644 index 0000000000..d45915c86c --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/Feature.lua @@ -0,0 +1,361 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local Feature = {} +local new_mt = UintABC.new_mt({NAME = "Feature", ID = data_types.name_to_id_map["Uint32"]}, 4) + +Feature.BASE_MASK = 0xFFFF +Feature.PIN_CREDENTIAL = 0x0001 +Feature.RFID_CREDENTIAL = 0x0002 +Feature.FINGER_CREDENTIALS = 0x0004 +Feature.LOGGING = 0x0008 +Feature.WEEK_DAY_ACCESS_SCHEDULES = 0x0010 +Feature.DOOR_POSITION_SENSOR = 0x0020 +Feature.FACE_CREDENTIALS = 0x0040 +Feature.CREDENTIALS_OVER_THE_AIR_ACCESS = 0x0080 +Feature.USER = 0x0100 +Feature.NOTIFICATION = 0x0200 +Feature.YEAR_DAY_ACCESS_SCHEDULES = 0x0400 +Feature.HOLIDAY_SCHEDULES = 0x0800 +Feature.UNBOLT = 0x1000 +Feature.ALIRO_PROVISIONING = 0x2000 +Feature.ALIROBLEUWB = 0x4000 + +Feature.mask_fields = { + BASE_MASK = 0xFFFF, + PIN_CREDENTIAL = 0x0001, + RFID_CREDENTIAL = 0x0002, + FINGER_CREDENTIALS = 0x0004, + LOGGING = 0x0008, + WEEK_DAY_ACCESS_SCHEDULES = 0x0010, + DOOR_POSITION_SENSOR = 0x0020, + FACE_CREDENTIALS = 0x0040, + CREDENTIALS_OVER_THE_AIR_ACCESS = 0x0080, + USER = 0x0100, + NOTIFICATION = 0x0200, + YEAR_DAY_ACCESS_SCHEDULES = 0x0400, + HOLIDAY_SCHEDULES = 0x0800, + UNBOLT = 0x1000, + ALIRO_PROVISIONING = 0x2000, + ALIROBLEUWB = 0x4000, +} + +Feature.is_pin_credential_set = function(self) + return (self.value & self.PIN_CREDENTIAL) ~= 0 +end + +Feature.set_pin_credential = function(self) + if self.value ~= nil then + self.value = self.value | self.PIN_CREDENTIAL + else + self.value = self.PIN_CREDENTIAL + end +end + +Feature.unset_pin_credential = function(self) + self.value = self.value & (~self.PIN_CREDENTIAL & self.BASE_MASK) +end + +Feature.is_rfid_credential_set = function(self) + return (self.value & self.RFID_CREDENTIAL) ~= 0 +end + +Feature.set_rfid_credential = function(self) + if self.value ~= nil then + self.value = self.value | self.RFID_CREDENTIAL + else + self.value = self.RFID_CREDENTIAL + end +end + +Feature.unset_rfid_credential = function(self) + self.value = self.value & (~self.RFID_CREDENTIAL & self.BASE_MASK) +end + +Feature.is_finger_credentials_set = function(self) + return (self.value & self.FINGER_CREDENTIALS) ~= 0 +end + +Feature.set_finger_credentials = function(self) + if self.value ~= nil then + self.value = self.value | self.FINGER_CREDENTIALS + else + self.value = self.FINGER_CREDENTIALS + end +end + +Feature.unset_finger_credentials = function(self) + self.value = self.value & (~self.FINGER_CREDENTIALS & self.BASE_MASK) +end + +Feature.is_logging_set = function(self) + return (self.value & self.LOGGING) ~= 0 +end + +Feature.set_logging = function(self) + if self.value ~= nil then + self.value = self.value | self.LOGGING + else + self.value = self.LOGGING + end +end + +Feature.unset_logging = function(self) + self.value = self.value & (~self.LOGGING & self.BASE_MASK) +end + +Feature.is_week_day_access_schedules_set = function(self) + return (self.value & self.WEEK_DAY_ACCESS_SCHEDULES) ~= 0 +end + +Feature.set_week_day_access_schedules = function(self) + if self.value ~= nil then + self.value = self.value | self.WEEK_DAY_ACCESS_SCHEDULES + else + self.value = self.WEEK_DAY_ACCESS_SCHEDULES + end +end + +Feature.unset_week_day_access_schedules = function(self) + self.value = self.value & (~self.WEEK_DAY_ACCESS_SCHEDULES & self.BASE_MASK) +end + +Feature.is_door_position_sensor_set = function(self) + return (self.value & self.DOOR_POSITION_SENSOR) ~= 0 +end + +Feature.set_door_position_sensor = function(self) + if self.value ~= nil then + self.value = self.value | self.DOOR_POSITION_SENSOR + else + self.value = self.DOOR_POSITION_SENSOR + end +end + +Feature.unset_door_position_sensor = function(self) + self.value = self.value & (~self.DOOR_POSITION_SENSOR & self.BASE_MASK) +end + +Feature.is_face_credentials_set = function(self) + return (self.value & self.FACE_CREDENTIALS) ~= 0 +end + +Feature.set_face_credentials = function(self) + if self.value ~= nil then + self.value = self.value | self.FACE_CREDENTIALS + else + self.value = self.FACE_CREDENTIALS + end +end + +Feature.unset_face_credentials = function(self) + self.value = self.value & (~self.FACE_CREDENTIALS & self.BASE_MASK) +end + +Feature.is_credentials_over_the_air_access_set = function(self) + return (self.value & self.CREDENTIALS_OVER_THE_AIR_ACCESS) ~= 0 +end + +Feature.set_credentials_over_the_air_access = function(self) + if self.value ~= nil then + self.value = self.value | self.CREDENTIALS_OVER_THE_AIR_ACCESS + else + self.value = self.CREDENTIALS_OVER_THE_AIR_ACCESS + end +end + +Feature.unset_credentials_over_the_air_access = function(self) + self.value = self.value & (~self.CREDENTIALS_OVER_THE_AIR_ACCESS & self.BASE_MASK) +end + +Feature.is_user_set = function(self) + return (self.value & self.USER) ~= 0 +end + +Feature.set_user = function(self) + if self.value ~= nil then + self.value = self.value | self.USER + else + self.value = self.USER + end +end + +Feature.unset_user = function(self) + self.value = self.value & (~self.USER & self.BASE_MASK) +end + +Feature.is_notification_set = function(self) + return (self.value & self.NOTIFICATION) ~= 0 +end + +Feature.set_notification = function(self) + if self.value ~= nil then + self.value = self.value | self.NOTIFICATION + else + self.value = self.NOTIFICATION + end +end + +Feature.unset_notification = function(self) + self.value = self.value & (~self.NOTIFICATION & self.BASE_MASK) +end + +Feature.is_year_day_access_schedules_set = function(self) + return (self.value & self.YEAR_DAY_ACCESS_SCHEDULES) ~= 0 +end + +Feature.set_year_day_access_schedules = function(self) + if self.value ~= nil then + self.value = self.value | self.YEAR_DAY_ACCESS_SCHEDULES + else + self.value = self.YEAR_DAY_ACCESS_SCHEDULES + end +end + +Feature.unset_year_day_access_schedules = function(self) + self.value = self.value & (~self.YEAR_DAY_ACCESS_SCHEDULES & self.BASE_MASK) +end + +Feature.is_holiday_schedules_set = function(self) + return (self.value & self.HOLIDAY_SCHEDULES) ~= 0 +end + +Feature.set_holiday_schedules = function(self) + if self.value ~= nil then + self.value = self.value | self.HOLIDAY_SCHEDULES + else + self.value = self.HOLIDAY_SCHEDULES + end +end + +Feature.unset_holiday_schedules = function(self) + self.value = self.value & (~self.HOLIDAY_SCHEDULES & self.BASE_MASK) +end + +Feature.is_unbolt_set = function(self) + return (self.value & self.UNBOLT) ~= 0 +end + +Feature.set_unbolt = function(self) + if self.value ~= nil then + self.value = self.value | self.UNBOLT + else + self.value = self.UNBOLT + end +end + +Feature.unset_unbolt = function(self) + self.value = self.value & (~self.UNBOLT & self.BASE_MASK) +end + +Feature.is_aliro_provisioning_set = function(self) + return (self.value & self.ALIRO_PROVISIONING) ~= 0 +end + +Feature.set_aliro_provisioning = function(self) + if self.value ~= nil then + self.value = self.value | self.ALIRO_PROVISIONING + else + self.value = self.ALIRO_PROVISIONING + end +end + +Feature.unset_aliro_provisioning = function(self) + self.value = self.value & (~self.ALIRO_PROVISIONING & self.BASE_MASK) +end + +Feature.is_alirobleuwb_set = function(self) + return (self.value & self.ALIROBLEUWB) ~= 0 +end + +Feature.set_alirobleuwb = function(self) + if self.value ~= nil then + self.value = self.value | self.ALIROBLEUWB + else + self.value = self.ALIROBLEUWB + end +end + +Feature.unset_alirobleuwb = function(self) + self.value = self.value & (~self.ALIROBLEUWB & self.BASE_MASK) +end + +function Feature.bits_are_valid(feature) + local max = + Feature.PIN_CREDENTIAL | + Feature.RFID_CREDENTIAL | + Feature.FINGER_CREDENTIALS | + Feature.LOGGING | + Feature.WEEK_DAY_ACCESS_SCHEDULES | + Feature.DOOR_POSITION_SENSOR | + Feature.FACE_CREDENTIALS | + Feature.CREDENTIALS_OVER_THE_AIR_ACCESS | + Feature.USER | + Feature.NOTIFICATION | + Feature.YEAR_DAY_ACCESS_SCHEDULES | + Feature.HOLIDAY_SCHEDULES | + Feature.UNBOLT | + Feature.ALIRO_PROVISIONING | + Feature.ALIROBLEUWB + if (feature <= max) and (feature >= 1) then + return true + else + return false + end +end + +Feature.mask_methods = { + is_pin_credential_set = Feature.is_pin_credential_set, + set_pin_credential = Feature.set_pin_credential, + unset_pin_credential = Feature.unset_pin_credential, + is_rfid_credential_set = Feature.is_rfid_credential_set, + set_rfid_credential = Feature.set_rfid_credential, + unset_rfid_credential = Feature.unset_rfid_credential, + is_finger_credentials_set = Feature.is_finger_credentials_set, + set_finger_credentials = Feature.set_finger_credentials, + unset_finger_credentials = Feature.unset_finger_credentials, + is_logging_set = Feature.is_logging_set, + set_logging = Feature.set_logging, + unset_logging = Feature.unset_logging, + is_week_day_access_schedules_set = Feature.is_week_day_access_schedules_set, + set_week_day_access_schedules = Feature.set_week_day_access_schedules, + unset_week_day_access_schedules = Feature.unset_week_day_access_schedules, + is_door_position_sensor_set = Feature.is_door_position_sensor_set, + set_door_position_sensor = Feature.set_door_position_sensor, + unset_door_position_sensor = Feature.unset_door_position_sensor, + is_face_credentials_set = Feature.is_face_credentials_set, + set_face_credentials = Feature.set_face_credentials, + unset_face_credentials = Feature.unset_face_credentials, + is_credentials_over_the_air_access_set = Feature.is_credentials_over_the_air_access_set, + set_credentials_over_the_air_access = Feature.set_credentials_over_the_air_access, + unset_credentials_over_the_air_access = Feature.unset_credentials_over_the_air_access, + is_user_set = Feature.is_user_set, + set_user = Feature.set_user, + unset_user = Feature.unset_user, + is_notification_set = Feature.is_notification_set, + set_notification = Feature.set_notification, + unset_notification = Feature.unset_notification, + is_year_day_access_schedules_set = Feature.is_year_day_access_schedules_set, + set_year_day_access_schedules = Feature.set_year_day_access_schedules, + unset_year_day_access_schedules = Feature.unset_year_day_access_schedules, + is_holiday_schedules_set = Feature.is_holiday_schedules_set, + set_holiday_schedules = Feature.set_holiday_schedules, + unset_holiday_schedules = Feature.unset_holiday_schedules, + is_unbolt_set = Feature.is_unbolt_set, + set_unbolt = Feature.set_unbolt, + unset_unbolt = Feature.unset_unbolt, + is_aliro_provisioning_set = Feature.is_aliro_provisioning_set, + set_aliro_provisioning = Feature.set_aliro_provisioning, + unset_aliro_provisioning = Feature.unset_aliro_provisioning, + is_alirobleuwb_set = Feature.is_alirobleuwb_set, + set_alirobleuwb = Feature.set_alirobleuwb, + unset_alirobleuwb = Feature.unset_alirobleuwb, +} + +Feature.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(Feature, new_mt) + +return Feature \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/LockDataTypeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/LockDataTypeEnum.lua new file mode 100644 index 0000000000..a278831c3b --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/LockDataTypeEnum.lua @@ -0,0 +1,63 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local LockDataTypeEnum = {} +local new_mt = UintABC.new_mt({NAME = "LockDataTypeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNSPECIFIED] = "UNSPECIFIED", + [self.PROGRAMMING_CODE] = "PROGRAMMING_CODE", + [self.USER_INDEX] = "USER_INDEX", + [self.WEEK_DAY_SCHEDULE] = "WEEK_DAY_SCHEDULE", + [self.YEAR_DAY_SCHEDULE] = "YEAR_DAY_SCHEDULE", + [self.HOLIDAY_SCHEDULE] = "HOLIDAY_SCHEDULE", + [self.PIN] = "PIN", + [self.RFID] = "RFID", + [self.FINGERPRINT] = "FINGERPRINT", + [self.FINGER_VEIN] = "FINGER_VEIN", + [self.FACE] = "FACE", + [self.ALIRO_CREDENTIAL_ISSUER_KEY] = "ALIRO_CREDENTIAL_ISSUER_KEY", + [self.ALIRO_EVICTABLE_ENDPOINT_KEY] = "ALIRO_EVICTABLE_ENDPOINT_KEY", + [self.ALIRO_NON_EVICTABLE_ENDPOINT_KEY] = "ALIRO_NON_EVICTABLE_ENDPOINT_KEY", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNSPECIFIED = 0x00 +new_mt.__index.PROGRAMMING_CODE = 0x01 +new_mt.__index.USER_INDEX = 0x02 +new_mt.__index.WEEK_DAY_SCHEDULE = 0x03 +new_mt.__index.YEAR_DAY_SCHEDULE = 0x04 +new_mt.__index.HOLIDAY_SCHEDULE = 0x05 +new_mt.__index.PIN = 0x06 +new_mt.__index.RFID = 0x07 +new_mt.__index.FINGERPRINT = 0x08 +new_mt.__index.FINGER_VEIN = 0x09 +new_mt.__index.FACE = 0x0A +new_mt.__index.ALIRO_CREDENTIAL_ISSUER_KEY = 0x0B +new_mt.__index.ALIRO_EVICTABLE_ENDPOINT_KEY = 0x0C +new_mt.__index.ALIRO_NON_EVICTABLE_ENDPOINT_KEY = 0x0D + +LockDataTypeEnum.UNSPECIFIED = 0x00 +LockDataTypeEnum.PROGRAMMING_CODE = 0x01 +LockDataTypeEnum.USER_INDEX = 0x02 +LockDataTypeEnum.WEEK_DAY_SCHEDULE = 0x03 +LockDataTypeEnum.YEAR_DAY_SCHEDULE = 0x04 +LockDataTypeEnum.HOLIDAY_SCHEDULE = 0x05 +LockDataTypeEnum.PIN = 0x06 +LockDataTypeEnum.RFID = 0x07 +LockDataTypeEnum.FINGERPRINT = 0x08 +LockDataTypeEnum.FINGER_VEIN = 0x09 +LockDataTypeEnum.FACE = 0x0A +LockDataTypeEnum.ALIRO_CREDENTIAL_ISSUER_KEY = 0x0B +LockDataTypeEnum.ALIRO_EVICTABLE_ENDPOINT_KEY = 0x0C +LockDataTypeEnum.ALIRO_NON_EVICTABLE_ENDPOINT_KEY = 0x0D + +LockDataTypeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(LockDataTypeEnum, new_mt) + +return LockDataTypeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/LockOperationTypeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/LockOperationTypeEnum.lua new file mode 100644 index 0000000000..3d28c27a7e --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/LockOperationTypeEnum.lua @@ -0,0 +1,36 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local LockOperationTypeEnum = {} +local new_mt = UintABC.new_mt({NAME = "LockOperationTypeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.LOCK] = "LOCK", + [self.UNLOCK] = "UNLOCK", + [self.NON_ACCESS_USER_EVENT] = "NON_ACCESS_USER_EVENT", + [self.FORCED_USER_EVENT] = "FORCED_USER_EVENT", + [self.UNLATCH] = "UNLATCH", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.LOCK = 0x00 +new_mt.__index.UNLOCK = 0x01 +new_mt.__index.NON_ACCESS_USER_EVENT = 0x02 +new_mt.__index.FORCED_USER_EVENT = 0x03 +new_mt.__index.UNLATCH = 0x04 + +LockOperationTypeEnum.LOCK = 0x00 +LockOperationTypeEnum.UNLOCK = 0x01 +LockOperationTypeEnum.NON_ACCESS_USER_EVENT = 0x02 +LockOperationTypeEnum.FORCED_USER_EVENT = 0x03 +LockOperationTypeEnum.UNLATCH = 0x04 + +LockOperationTypeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(LockOperationTypeEnum, new_mt) + +return LockOperationTypeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/OperatingModeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/OperatingModeEnum.lua new file mode 100644 index 0000000000..fc6c61c757 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/OperatingModeEnum.lua @@ -0,0 +1,36 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local OperatingModeEnum = {} +local new_mt = UintABC.new_mt({NAME = "OperatingModeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.NORMAL] = "NORMAL", + [self.VACATION] = "VACATION", + [self.PRIVACY] = "PRIVACY", + [self.NO_REMOTE_LOCK_UNLOCK] = "NO_REMOTE_LOCK_UNLOCK", + [self.PASSAGE] = "PASSAGE", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.NORMAL = 0x00 +new_mt.__index.VACATION = 0x01 +new_mt.__index.PRIVACY = 0x02 +new_mt.__index.NO_REMOTE_LOCK_UNLOCK = 0x03 +new_mt.__index.PASSAGE = 0x04 + +OperatingModeEnum.NORMAL = 0x00 +OperatingModeEnum.VACATION = 0x01 +OperatingModeEnum.PRIVACY = 0x02 +OperatingModeEnum.NO_REMOTE_LOCK_UNLOCK = 0x03 +OperatingModeEnum.PASSAGE = 0x04 + +OperatingModeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(OperatingModeEnum, new_mt) + +return OperatingModeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/OperationErrorEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/OperationErrorEnum.lua new file mode 100644 index 0000000000..79da0a7c58 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/OperationErrorEnum.lua @@ -0,0 +1,36 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local OperationErrorEnum = {} +local new_mt = UintABC.new_mt({NAME = "OperationErrorEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNSPECIFIED] = "UNSPECIFIED", + [self.INVALID_CREDENTIAL] = "INVALID_CREDENTIAL", + [self.DISABLED_USER_DENIED] = "DISABLED_USER_DENIED", + [self.RESTRICTED] = "RESTRICTED", + [self.INSUFFICIENT_BATTERY] = "INSUFFICIENT_BATTERY", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNSPECIFIED = 0x00 +new_mt.__index.INVALID_CREDENTIAL = 0x01 +new_mt.__index.DISABLED_USER_DENIED = 0x02 +new_mt.__index.RESTRICTED = 0x03 +new_mt.__index.INSUFFICIENT_BATTERY = 0x04 + +OperationErrorEnum.UNSPECIFIED = 0x00 +OperationErrorEnum.INVALID_CREDENTIAL = 0x01 +OperationErrorEnum.DISABLED_USER_DENIED = 0x02 +OperationErrorEnum.RESTRICTED = 0x03 +OperationErrorEnum.INSUFFICIENT_BATTERY = 0x04 + +OperationErrorEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(OperationErrorEnum, new_mt) + +return OperationErrorEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/OperationSourceEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/OperationSourceEnum.lua new file mode 100644 index 0000000000..5d5e9ef592 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/OperationSourceEnum.lua @@ -0,0 +1,54 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local OperationSourceEnum = {} +local new_mt = UintABC.new_mt({NAME = "OperationSourceEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNSPECIFIED] = "UNSPECIFIED", + [self.MANUAL] = "MANUAL", + [self.PROPRIETARY_REMOTE] = "PROPRIETARY_REMOTE", + [self.KEYPAD] = "KEYPAD", + [self.AUTO] = "AUTO", + [self.BUTTON] = "BUTTON", + [self.SCHEDULE] = "SCHEDULE", + [self.REMOTE] = "REMOTE", + [self.RFID] = "RFID", + [self.BIOMETRIC] = "BIOMETRIC", + [self.ALIRO] = "ALIRO", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNSPECIFIED = 0x00 +new_mt.__index.MANUAL = 0x01 +new_mt.__index.PROPRIETARY_REMOTE = 0x02 +new_mt.__index.KEYPAD = 0x03 +new_mt.__index.AUTO = 0x04 +new_mt.__index.BUTTON = 0x05 +new_mt.__index.SCHEDULE = 0x06 +new_mt.__index.REMOTE = 0x07 +new_mt.__index.RFID = 0x08 +new_mt.__index.BIOMETRIC = 0x09 +new_mt.__index.ALIRO = 0x0A + +OperationSourceEnum.UNSPECIFIED = 0x00 +OperationSourceEnum.MANUAL = 0x01 +OperationSourceEnum.PROPRIETARY_REMOTE = 0x02 +OperationSourceEnum.KEYPAD = 0x03 +OperationSourceEnum.AUTO = 0x04 +OperationSourceEnum.BUTTON = 0x05 +OperationSourceEnum.SCHEDULE = 0x06 +OperationSourceEnum.REMOTE = 0x07 +OperationSourceEnum.RFID = 0x08 +OperationSourceEnum.BIOMETRIC = 0x09 +OperationSourceEnum.ALIRO = 0x0A + +OperationSourceEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(OperationSourceEnum, new_mt) + +return OperationSourceEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/UserStatusEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/UserStatusEnum.lua new file mode 100644 index 0000000000..11e20c7a3a --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/UserStatusEnum.lua @@ -0,0 +1,30 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local UserStatusEnum = {} +local new_mt = UintABC.new_mt({NAME = "UserStatusEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.AVAILABLE] = "AVAILABLE", + [self.OCCUPIED_ENABLED] = "OCCUPIED_ENABLED", + [self.OCCUPIED_DISABLED] = "OCCUPIED_DISABLED", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.AVAILABLE = 0x00 +new_mt.__index.OCCUPIED_ENABLED = 0x01 +new_mt.__index.OCCUPIED_DISABLED = 0x03 + +UserStatusEnum.AVAILABLE = 0x00 +UserStatusEnum.OCCUPIED_ENABLED = 0x01 +UserStatusEnum.OCCUPIED_DISABLED = 0x03 + +UserStatusEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(UserStatusEnum, new_mt) + +return UserStatusEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/UserTypeEnum.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/UserTypeEnum.lua new file mode 100644 index 0000000000..9d00c2b940 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/UserTypeEnum.lua @@ -0,0 +1,51 @@ +local data_types = require "st.matter.data_types" +local UintABC = require "st.matter.data_types.base_defs.UintABC" + +local UserTypeEnum = {} +local new_mt = UintABC.new_mt({NAME = "UserTypeEnum", ID = data_types.name_to_id_map["Uint8"]}, 1) +new_mt.__index.pretty_print = function(self) + local name_lookup = { + [self.UNRESTRICTED_USER] = "UNRESTRICTED_USER", + [self.YEAR_DAY_SCHEDULE_USER] = "YEAR_DAY_SCHEDULE_USER", + [self.WEEK_DAY_SCHEDULE_USER] = "WEEK_DAY_SCHEDULE_USER", + [self.PROGRAMMING_USER] = "PROGRAMMING_USER", + [self.NON_ACCESS_USER] = "NON_ACCESS_USER", + [self.FORCED_USER] = "FORCED_USER", + [self.DISPOSABLE_USER] = "DISPOSABLE_USER", + [self.EXPIRING_USER] = "EXPIRING_USER", + [self.SCHEDULE_RESTRICTED_USER] = "SCHEDULE_RESTRICTED_USER", + [self.REMOTE_ONLY_USER] = "REMOTE_ONLY_USER", + } + return string.format("%s: %s", self.field_name or self.NAME, name_lookup[self.value] or string.format("%d", self.value)) +end +new_mt.__tostring = new_mt.__index.pretty_print + +new_mt.__index.UNRESTRICTED_USER = 0x00 +new_mt.__index.YEAR_DAY_SCHEDULE_USER = 0x01 +new_mt.__index.WEEK_DAY_SCHEDULE_USER = 0x02 +new_mt.__index.PROGRAMMING_USER = 0x03 +new_mt.__index.NON_ACCESS_USER = 0x04 +new_mt.__index.FORCED_USER = 0x05 +new_mt.__index.DISPOSABLE_USER = 0x06 +new_mt.__index.EXPIRING_USER = 0x07 +new_mt.__index.SCHEDULE_RESTRICTED_USER = 0x08 +new_mt.__index.REMOTE_ONLY_USER = 0x09 + +UserTypeEnum.UNRESTRICTED_USER = 0x00 +UserTypeEnum.YEAR_DAY_SCHEDULE_USER = 0x01 +UserTypeEnum.WEEK_DAY_SCHEDULE_USER = 0x02 +UserTypeEnum.PROGRAMMING_USER = 0x03 +UserTypeEnum.NON_ACCESS_USER = 0x04 +UserTypeEnum.FORCED_USER = 0x05 +UserTypeEnum.DISPOSABLE_USER = 0x06 +UserTypeEnum.EXPIRING_USER = 0x07 +UserTypeEnum.SCHEDULE_RESTRICTED_USER = 0x08 +UserTypeEnum.REMOTE_ONLY_USER = 0x09 + +UserTypeEnum.augment_type = function(cls, val) + setmetatable(val, new_mt) +end + +setmetatable(UserTypeEnum, new_mt) + +return UserTypeEnum \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/DoorLock/types/init.lua b/drivers/SmartThings/matter-lock/src/DoorLock/types/init.lua new file mode 100644 index 0000000000..461d914f84 --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/DoorLock/types/init.lua @@ -0,0 +1,14 @@ +local types_mt = {} +types_mt.__types_cache = {} +types_mt.__index = function(self, key) + if types_mt.__types_cache[key] == nil then + types_mt.__types_cache[key] = require("DoorLock.types." .. key) + end + return types_mt.__types_cache[key] +end + +local DoorLockTypes = {} + +setmetatable(DoorLockTypes, types_mt) + +return DoorLockTypes \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index fb53bc987c..9a8d720430 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -18,9 +18,15 @@ local clusters = require "st.matter.clusters" local im = require "st.matter.interaction_model" local lock_utils = require "lock_utils" +local version = require "version" +if version.api < 10 then + clusters.DoorLock = require "DoorLock" +end + local DoorLock = clusters.DoorLock local INITIAL_COTA_INDEX = 1 local ALL_INDEX = 0xFFFE + local NEW_MATTER_LOCK_PRODUCTS = { {0x115f, 0x2802}, -- AQARA, U200 {0x115f, 0x2801}, -- AQARA, U300 @@ -155,7 +161,7 @@ local function lock_state_handler(driver, device, ib, response) -- The lock state is usually updated in lock_state_handler and lock_op_event_handler, respectively. -- In this case, two events occur. To prevent this, when both functions are called, - -- it send the event after 1 second so that no event occurs in the lock_state_handler. + -- it send the event after 1 second so that no event occurs in the lock_state_handler. device.thread:call_with_delay(1, function () if ib.data.value ~= nil then device:emit_event(LOCK_STATE[ib.data.value]) @@ -242,7 +248,7 @@ local function set_cota_credential(device, credential_index) end device:set_field(lock_utils.COTA_CRED_INDEX, credential_index, {persist = true}) - local credential = {credential_type = DoorLock.types.DlCredentialType.PIN, credential_index = credential_index} + local credential = {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = credential_index} -- Set the credential to a code device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, "addCota") @@ -253,12 +259,12 @@ local function set_cota_credential(device, credential_index) device:send(DoorLock.server.commands.SetCredential( device, #eps > 0 and eps[1] or 1, - DoorLock.types.DlDataOperationType.ADD, + DoorLock.types.DataOperationTypeEnum.ADD, credential, device:get_field(lock_utils.COTA_CRED), nil, -- nil user_index creates a new user - DoorLock.types.DlUserStatus.OCCUPIED_ENABLED, - DoorLock.types.DlUserType.REMOTE_ONLY_USER + DoorLock.types.UserStatusEnum.OCCUPIED_ENABLED, + DoorLock.types.UserTypeEnum.REMOTE_ONLY_USER )) end @@ -642,7 +648,7 @@ local function handle_add_user(driver, device, command) device:send( DoorLock.server.commands.SetUser( device, ep, - DoorLock.types.DlDataOperationType.ADD, -- Operation Type: Add(0), Modify(2) + DoorLock.types.DataOperationTypeEnum.ADD, -- Operation Type: Add(0), Modify(2) userName, -- User Name nil, -- Unique ID nil, -- User Status @@ -695,7 +701,7 @@ local function handle_update_user(driver, device, command) device:send( DoorLock.server.commands.SetUser( device, ep, - DoorLock.types.DlDataOperationType.MODIFY, -- Operation Type: Add(0), Modify(2) + DoorLock.types.DataOperationTypeEnum.MODIFY, -- Operation Type: Add(0), Modify(2) userIdx, -- User Index userName, -- User Name nil, -- Unique ID @@ -908,7 +914,7 @@ local function handle_add_credential(driver, device, command) device:send( DoorLock.server.commands.SetCredential( device, ep, - DoorLock.types.DlDataOperationType.ADD, -- Data Operation Type: Add(0), Modify(2) + DoorLock.types.DataOperationTypeEnum.ADD, -- Data Operation Type: Add(0), Modify(2) credential, -- Credential credData, -- Credential Data userIdx, -- User Index @@ -961,7 +967,7 @@ local function handle_update_credential(driver, device, command) device:send( DoorLock.server.commands.SetCredential( device, ep, - DoorLock.types.DlDataOperationType.MODIFY, -- Data Operation Type: Add(0), Modify(2) + DoorLock.types.DataOperationTypeEnum.MODIFY, -- Data Operation Type: Add(0), Modify(2) credential, -- Credential credData, -- Credential Data userIdx, -- User Index @@ -994,6 +1000,9 @@ local function set_credential_response_handler(driver, device, ib, response) -- If user is added also, update User table if userIdx == nil then local userType = device:get_field(lock_utils.USER_TYPE) + if userType == "remote" then + userType = "adminMember" + end add_user_to_table(device, elements.user_index.value, userType) end @@ -1062,7 +1071,7 @@ local function set_credential_response_handler(driver, device, ib, response) -- Get parameters local credIdx = elements.next_credential_index.value local credential = { - credential_type = DoorLock.types.DlCredentialType.PIN, + credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = credIdx, } local userIdx = device:get_field(lock_utils.USER_INDEX) @@ -1071,7 +1080,7 @@ local function set_credential_response_handler(driver, device, ib, response) if userType == "guest" then userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER elseif userType == "remote" then - userTypeMatter = DoorLock.types.DlUserType.REMOTE_ONLY_USER + userTypeMatter = DoorLock.types.UserTypeEnum.REMOTE_ONLY_USER end device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) @@ -1081,7 +1090,7 @@ local function set_credential_response_handler(driver, device, ib, response) device:send( DoorLock.server.commands.SetCredential( device, ep, - DoorLock.types.DlDataOperationType.ADD, -- Data Operation Type: Add(0), Modify(2) + DoorLock.types.DataOperationTypeEnum.ADD, -- Data Operation Type: Add(0), Modify(2) credential, -- Credential credData, -- Credential Data userIdx, -- User Index @@ -1114,7 +1123,7 @@ local function handle_delete_credential(driver, device, command) local cmdName = "deleteCredential" local credIdx = command.args.credentialIndex local credential = { - credential_type = DoorLock.types.DlCredentialType.PIN, + credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = credIdx, } @@ -1153,7 +1162,7 @@ local function handle_delete_all_credentials(driver, device, command) -- Get parameters local cmdName = "deleteAllCredentials" local credential = { - credential_type = DoorLock.types.DlCredentialType.PIN, + credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = ALL_INDEX, } @@ -1377,7 +1386,7 @@ local function clear_week_day_schedule_handler(driver, device, ib, response) if status == "success" then delete_week_schedule_to_table(device, userIdx, scheduleIdx) end - + -- Update commandResult local result = { commandName = cmdName, @@ -1434,7 +1443,7 @@ local function lock_op_event_handler(driver, device, ib, response) local opType = ib.data.elements.lock_operation_type local opSource = ib.data.elements.operation_source local userIdx = ib.data.elements.user_index - local fabricId = ib.data.elements.fabric_index + -- TODO: This handler can check fabric index and exclude other fabric events if opType == nil or opSource == nil then return @@ -1479,10 +1488,6 @@ local function lock_op_event_handler(driver, device, ib, response) opSource =nil end - if fabricId ~= nil then - fabricId = fabricId.value - end - if userIdx ~= nil then userIdx = userIdx.value end @@ -1491,63 +1496,6 @@ local function lock_op_event_handler(driver, device, ib, response) device:emit_event(opType({data = data_obj, state_change = true})) end ----------------------- --- Lock User Change -- ----------------------- -local function lock_user_change_event_handler(driver, device, ib, response) - local lockDataType = ib.data.elements.lock_data_type - local dataOpType = ib.data.elements.data_operation_type - local opSource = ib.data.elements.operation_source - local userIdx = ib.data.elements.user_index - local fabricId = ib.data.elements.fabric_index - - if lockDataType ~= nil then - lockDataType = lockDataType.value - end - - if dataOpType ~= nil then - dataOpType = dataOpType.value - end - - local Source = DoorLock.types.OperationSourceEnum - if opSource.value == Source.UNSPECIFIED then - opSource = nil - elseif opSource.value == Source.MANUAL then - opSource = "manual" - elseif opSource.value == Source.PROPRIETARY_REMOTE then - opSource = "proprietaryRemote" - elseif opSource.value == Source.KEYPAD then - opSource = "keypad" - elseif opSource.value == Source.AUTO then - opSource = "auto" - elseif opSource.value == Source.BUTTON then - opSource = "button" - elseif opSource.value == Source.SCHEDULE then - opSource = nil - elseif opSource.value == Source.REMOTE then - opSource = "command" - elseif opSource.value == Source.RFID then - opSource = "rfid" - elseif opSource.value == Source.BIOMETRIC then - opSource = "keypad" - elseif opSource.value == Source.ALIRO then - opSource = nil - else - opSource =nil - end - - if userIdx ~= nil then - userIdx = userIdx.value - end - - if fabricId ~= nil then - fabricId = fabricId.value - end - - -- local data_obj = {method = opSource, userIndex = userIdx} - -- device:emit_event(opType({data = data_obj}, {state_change = true})) -end - local function handle_refresh(driver, device, command) local req = DoorLock.attributes.LockState:read(device) device:send(req) @@ -1580,7 +1528,6 @@ local new_matter_lock_handler = { [DoorLock.ID] = { [DoorLock.events.DoorLockAlarm.ID] = alarm_event_handler, [DoorLock.events.LockOperation.ID] = lock_op_event_handler, - [DoorLock.events.LockUserChange.ID] = lock_user_change_event_handler, }, }, cmd_response = { From 45e3606570973d82eeec50db9881f37f2189e59c Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 2 Oct 2024 19:10:18 +0900 Subject: [PATCH 06/20] Remove duplicated guest after driver is changed Signed-off-by: Hunsup Jung --- drivers/SmartThings/matter-lock/src/init.lua | 30 +++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/init.lua b/drivers/SmartThings/matter-lock/src/init.lua index a626ab325f..d234edd637 100755 --- a/drivers/SmartThings/matter-lock/src/init.lua +++ b/drivers/SmartThings/matter-lock/src/init.lua @@ -78,7 +78,7 @@ local function lock_state_handler(driver, device, ib, response) local LockState = DoorLock.attributes.LockState local attr = capabilities.lock.lock local LOCK_STATE = { - [LockState.NOT_FULLY_LOCKED] = attr.unknown(), + [LockState.NOT_FULLY_LOCKED] = attr.not_fully_locked(), [LockState.LOCKED] = attr.locked(), [LockState.UNLOCKED] = attr.unlocked(), [UNLATCHED_STATE] = attr.unlocked(), -- Fully unlocked with latch pulled @@ -97,6 +97,16 @@ local function handle_battery_percent_remaining(driver, device, ib, response) end end +local function handle_battery_charge_level(driver, device, ib, response) + if ib.data.value == clusters.PowerSource.types.BatChargeLevelEnum.OK then + device:emit_event(capabilities.batteryLevel.battery.normal()) + elseif ib.data.value == clusters.PowerSource.types.BatChargeLevelEnum.WARNING then + device:emit_event(capabilities.batteryLevel.battery.warning()) + elseif ib.data.value == clusters.PowerSource.types.BatChargeLevelEnum.CRITICAL then + device:emit_event(capabilities.batteryLevel.battery.critical()) + end +end + local function max_pin_code_len_handler(driver, device, ib, response) device:emit_event(capabilities.lockCodes.maxCodeLength(ib.data.value, {visibility = {displayed = false}})) end @@ -416,19 +426,22 @@ end local function handle_reload_all_codes(driver, device, command) if (device:get_field(lock_utils.CHECKING_CREDENTIAL) == nil) then + lock_utils.lock_codes_event(device, {}) device:set_field(lock_utils.CHECKING_CREDENTIAL, 1) else device.log.info(string.format("Delaying scanning since currently checking credential %d", device:get_field(lock_utils.CHECKING_CREDENTIAL))) device.thread:call_with_delay(2, function(t) handle_reload_all_codes(driver, device, command) end) return end - device:emit_event(capabilities.lockCodes.scanCodes("Scanning")) - device:send( - clusters.DoorLock.server.commands.GetCredentialStatus( - device, device:component_to_endpoint(command.component), - {credential_type = DoorLock.types.DlCredentialType.PIN, credential_index = device:get_field(lock_utils.CHECKING_CREDENTIAL)} + device.thread:call_with_delay(5, function(t) + device:emit_event(capabilities.lockCodes.scanCodes("Scanning")) + device:send( + clusters.DoorLock.server.commands.GetCredentialStatus( + device, device:component_to_endpoint(command.component), + {credential_type = DoorLock.types.DlCredentialType.PIN, credential_index = device:get_field(lock_utils.CHECKING_CREDENTIAL)} + ) ) - ) + end) end local function handle_request_code(driver, device, command) @@ -573,6 +586,7 @@ local matter_lock_driver = { }, [PowerSource.ID] = { [PowerSource.attributes.BatPercentRemaining.ID] = handle_battery_percent_remaining, + [PowerSource.attributes.BatChargeLevel.ID] = handle_battery_charge_level, }, }, event = { @@ -593,6 +607,7 @@ local matter_lock_driver = { subscribed_attributes = { [capabilities.lock.ID] = {DoorLock.attributes.LockState}, [capabilities.battery.ID] = {PowerSource.attributes.BatPercentRemaining}, + [capabilities.batteryLevel.ID] = {PowerSource.attributes.BatChargeLevel}, }, subscribed_events = { [capabilities.tamperAlert.ID] = {DoorLock.events.DoorLockAlarm, DoorLock.events.LockOperation}, @@ -618,6 +633,7 @@ local matter_lock_driver = { capabilities.lockCodes, capabilities.tamperAlert, capabilities.battery, + capabilities.batteryLevel, }, sub_drivers = { require("new-matter-lock"), From 1b19d30237bb12a222214720136790b459b7f120 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 2 Oct 2024 21:36:10 +0900 Subject: [PATCH 07/20] Modify test case Signed-off-by: Hunsup Jung --- .../src/test/test_aqara_matter_lock.lua | 83 +++++++++---------- .../src/test/test_matter_lock_codes.lua | 48 ++++++++++- .../src/test/test_matter_lock_cota.lua | 9 ++ 3 files changed, 94 insertions(+), 46 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua index 9b2cd282ed..85baf6df4e 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua @@ -19,7 +19,7 @@ local t_utils = require "integration_test.utils" local clusters = require "st.matter.clusters" local mock_device = test.mock_device.build_test_matter_device({ - profile = t_utils.get_profile_definition("lock-lockalarm-nobattery.yml"), + profile = t_utils.get_profile_definition("lock-user-pin.yml"), manufacturer_info = { vendor_id = 0x115f, product_id = 0x2802, @@ -99,64 +99,61 @@ test.register_message_test( } ) -test.register_message_test( - "Handle received LockState.LOCKED from Matter device.", { - { - channel = "matter", - direction = "receive", - message = { +test.register_coroutine_test( + "Handle received LockState.LOCKED from Matter device.", + function() + test.socket.matter:__queue_receive( + { mock_device.id, clusters.DoorLock.attributes.LockState:build_test_report_data( mock_device, 1, clusters.DoorLock.attributes.LockState.LOCKED ), - }, - }, - { - channel = "capability", - direction = "send", - message = mock_device:generate_test_message("main", capabilities.lock.lock.locked()), - }, - } + } + ) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.mock_time.advance_time(1) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.lock.locked()) + ) + end ) -test.register_message_test( - "Handle received LockState.UNLOCKED from Matter device.", { - { - channel = "matter", - direction = "receive", - message = { +test.register_coroutine_test( + "Handle received LockState.UNLOCKED from Matter device.", + function() + test.socket.matter:__queue_receive( + { mock_device.id, clusters.DoorLock.attributes.LockState:build_test_report_data( mock_device, 1, clusters.DoorLock.attributes.LockState.UNLOCKED ), - }, - }, - { - channel = "capability", - direction = "send", - message = mock_device:generate_test_message("main", capabilities.lock.lock.unlocked()), - }, - } + } + ) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.mock_time.advance_time(1) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.lock.unlocked()) + ) + end ) -test.register_message_test( - "Handle received LockState.NOT_FULLY_LOCKED from Matter device.", { - { - channel = "matter", - direction = "receive", - message = { +test.register_coroutine_test( + "Handle received LockState.NOT_FULLY_LOCKED from Matter device.", + function() + test.socket.matter:__queue_receive( + { mock_device.id, clusters.DoorLock.attributes.LockState:build_test_report_data( mock_device, 1, clusters.DoorLock.attributes.LockState.NOT_FULLY_LOCKED ), - }, - }, - { - channel = "capability", - direction = "send", - message = mock_device:generate_test_message("main", capabilities.lock.lock.not_fully_locked()), - }, - } + } + ) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.mock_time.advance_time(1) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.lock.not_fully_locked()) + ) + end ) local function refresh_commands(dev) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua index dd83af4651..e1775074ff 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_codes.lua @@ -76,6 +76,15 @@ end test.set_test_init_function(test_init) local expect_reload_all_codes_messages = function(dev) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", capabilities.lockCodes.lockCodes( + json.encode({}), {visibility = {displayed = false}} + ) + ) + ) + test.timer.__create_and_queue_test_time_advance_timer(5, "oneshot") + test.mock_time.advance_time(5) local credential = types.DlCredential({credential_type = types.DlCredentialType.PIN, credential_index = 1}) test.socket.capability:__expect_send( dev:generate_test_message( @@ -459,6 +468,15 @@ test.register_coroutine_test( {capability = capabilities.lockCodes.ID, command = "reloadAllCodes", args = {}}, } ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", capabilities.lockCodes.lockCodes( + json.encode({}), {visibility = {displayed = false}} + ) + ) + ) + test.timer.__create_and_queue_test_time_advance_timer(5, "oneshot") + test.mock_time.advance_time(5) local credential = types.DlCredential({credential_type = types.DlCredentialType.PIN, credential_index = 1}) test.socket.capability:__expect_send( mock_device:generate_test_message( @@ -469,7 +487,6 @@ test.register_coroutine_test( {mock_device.id, DoorLock.server.commands.GetCredentialStatus(mock_device, 10, credential)} ) test.wait_for_events() - test.socket.matter:__queue_receive( { mock_device.id, @@ -479,14 +496,38 @@ test.register_coroutine_test( 1, --user_index nil, --creator fabric index nil, --last modified fabric index - nil + 2 --next credential index ), } ) test.socket.capability:__expect_send( mock_device:generate_test_message( "main", capabilities.lockCodes - .codeChanged("1 deleted", {data = {codeName = "Code 1"}, state_change = true}) + .codeChanged("1 unset", {data = {codeName = "Code 1"}, state_change = true}) + ) + ) + credential = types.DlCredential({credential_type = types.DlCredentialType.PIN, credential_index = 2}) + test.socket.matter:__expect_send( + {mock_device.id, DoorLock.server.commands.GetCredentialStatus(mock_device, 10, credential)} + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.GetCredentialStatusResponse:build_test_command_response( + mock_device, 10, -- endpoint + true, --credential exists + 2, --user_index + nil, --creator fabric index + nil, --last modified fabric index + nil --next credential index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", capabilities.lockCodes + .codeChanged("2 set", {data = {codeName = "Code 2"}, state_change = true}) ) ) test.socket.capability:__expect_send( @@ -511,6 +552,7 @@ test.register_coroutine_test( ) end ) + test.register_coroutine_test( "Deleting a user code should be handled", function() init_code_slot(1, "initialName", mock_device) diff --git a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua index a4752fb843..fce2dcdc87 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_matter_lock_cota.lua @@ -77,6 +77,15 @@ end test.set_test_init_function(test_init) local expect_reload_all_codes_messages = function(dev) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", capabilities.lockCodes.lockCodes( + json.encode({}), {visibility = {displayed = false}} + ) + ) + ) + test.timer.__create_and_queue_test_time_advance_timer(5, "oneshot") + test.mock_time.advance_time(5) local credential = types.DlCredential({credential_type = types.DlCredentialType.PIN, credential_index = 1}) test.socket.capability:__expect_send( dev:generate_test_message( From 4ff6766c6bf6dab0a70076542b8a28c9b06a6b6b Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Tue, 8 Oct 2024 17:14:41 +0900 Subject: [PATCH 08/20] Update PR with some patch - Fix typo - Remove unnecessary function - Add newline - Add error logging Signed-off-by: Hunsup Jung --- .../SmartThings/matter-lock/fingerprints.yml | 3 +- .../matter-lock/src/new-matter-lock/init.lua | 75 ++++--------------- 2 files changed, 18 insertions(+), 60 deletions(-) diff --git a/drivers/SmartThings/matter-lock/fingerprints.yml b/drivers/SmartThings/matter-lock/fingerprints.yml index d0a262176b..cef1bd4ffe 100755 --- a/drivers/SmartThings/matter-lock/fingerprints.yml +++ b/drivers/SmartThings/matter-lock/fingerprints.yml @@ -32,4 +32,5 @@ matterGeneric: deviceLabel: Matter Door Lock deviceTypes: - id: 0x000A # Door Lock - deviceProfileName: base-lock \ No newline at end of file + deviceProfileName: base-lock + \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 9a8d720430..2da869e5ae 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -166,7 +166,7 @@ local function lock_state_handler(driver, device, ib, response) if ib.data.value ~= nil then device:emit_event(LOCK_STATE[ib.data.value]) else - device:emit_event(attr.unknown()) + device.log.warn("Lock State is nil") end end) end @@ -201,7 +201,7 @@ local function total_users_supported_handler(driver, device, ib, response) end ---------------------------------- --- Number Of PIN User Supported -- +-- Number Of PIN Users Supported -- ---------------------------------- local function pin_users_supported_handler(driver, device, ib, response) device:emit_event(capabilities.lockCredentials.pinUsersSupported(ib.data.value, {visibility = {displayed = false}})) @@ -433,7 +433,7 @@ local function add_credential_to_table(device, userIdx, credIdx, credType) end local function delete_credential_from_table(device, credIdx) - -- If Credential Index is ALL_INDEX, remove all entry from the table + -- If Credential Index is ALL_INDEX, remove all entries from the table if credIdx == ALL_INDEX then device:emit_event(capabilities.lockCredentials.credentials({})) end @@ -507,7 +507,7 @@ local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule ) or {} local new_week_schedule_table = {} - -- Find shcedule list + -- Find schedule list local i = 0 for index, entry in pairs(week_schedule_table) do if entry.userIndex == userIdx then @@ -605,59 +605,6 @@ local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) device:emit_event(capabilities.lockSchedules.weekDaySchedules(new_week_schedule_table, {visibility = {displayed = false}})) end --------------- --- Add User -- --------------- -local function handle_add_user(driver, device, command) - - -- Get parameters - local cmdName = "addUser" - local userName = command.args.userName - local userType = command.args.lockUserType - local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER - if userType == "guest" then - userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER - end - - -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) - if busy == true then - local result = { - commandName = cmdName, - statusCode = "busy" - } - local event = capabilities.lockUsers.commandResult( - result, - { - state_change = true, - visibility = {displayed = false} - } - ) - device:emit_event(event) - return - end - - -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) - device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) - -- device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) -- needs to find empty index - device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) - - -- Send command - local ep = device:component_to_endpoint(command.component) - device:send( - DoorLock.server.commands.SetUser( - device, ep, - DoorLock.types.DataOperationTypeEnum.ADD, -- Operation Type: Add(0), Modify(2) - userName, -- User Name - nil, -- Unique ID - nil, -- User Status - userTypeMatter, -- User Type - nil -- Credential Rule - ) - ) -end - ----------------- -- Update User -- ----------------- @@ -736,6 +683,8 @@ local function set_user_response_handler(driver, device, ib, response) elseif cmdName == "updateUser" then update_user_in_table(device, userIdx, userType) end + else + device.log.warn(string.format("Failed to set user: %s", status)) end -- Update commandResult @@ -844,6 +793,8 @@ local function clear_user_response_handler(driver, device, ib, response) if status == "success" then delete_user_from_table(device, userIdx) delete_credential_from_table_as_user(device, userIdx) + else + device.log.warn(string.format("Failed to clear user: %s", status)) end -- Update commandResult @@ -1044,6 +995,7 @@ local function set_credential_response_handler(driver, device, ib, response) elseif elements.status.value == DoorLock.types.DlStatus.NOT_FOUND then status = "failure" end + device.log.warn(string.format("Failed to set credential: %s", status)) -- Error Handling if status == "duplicate" then @@ -1212,6 +1164,8 @@ local function clear_credential_response_handler(driver, device, ib, response) local userIdx = 0 if status == "success" then userIdx = delete_credential_from_table(device, credIdx) + else + device.log.warn(string.format("Failed to clear credential: %s", status)) end -- Update commandResult @@ -1310,6 +1264,8 @@ local function set_week_day_schedule_handler(driver, device, ib, response) -- Add Week Day Schedule to table if status == "success" then add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule) + else + device.log.warn(string.format("Failed to set week day schedule: %s", status)) end -- Update commandResult @@ -1385,6 +1341,8 @@ local function clear_week_day_schedule_handler(driver, device, ib, response) -- Delete Week Day Schedule to table if status == "success" then delete_week_schedule_to_table(device, userIdx, scheduleIdx) + else + device.log.warn(string.format("Failed to clear week day schedule: %s", status)) end -- Update commandResult @@ -1549,7 +1507,6 @@ local new_matter_lock_handler = { [capabilities.lock.commands.unlock.NAME] = handle_unlock, }, [capabilities.lockUsers.ID] = { - [capabilities.lockUsers.commands.addUser.NAME] = handle_add_user, [capabilities.lockUsers.commands.updateUser.NAME] = handle_update_user, [capabilities.lockUsers.commands.deleteUser.NAME] = handle_delete_user, [capabilities.lockUsers.commands.deleteAllUsers.NAME] = handle_delete_all_users, @@ -1577,4 +1534,4 @@ local new_matter_lock_handler = { can_handle = is_new_matter_lock_products } -return new_matter_lock_handler \ No newline at end of file +return new_matter_lock_handler From 9fdde26b8710b8a7d414052c95e1bef961f80ded Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Tue, 8 Oct 2024 18:51:33 +0900 Subject: [PATCH 09/20] Update subscribed_attributes and subscribed_events Signed-off-by: Hunsup Jung --- .../matter-lock/src/new-matter-lock/init.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 2da869e5ae..06b72f64c5 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -99,6 +99,20 @@ end local function device_init(driver, device) device:set_component_to_endpoint_fn(component_to_endpoint) + for cap_id, attributes in pairs(subscribed_attributes) do + if device:supports_capability_by_id(cap_id) then + for _, attr in ipairs(attributes) do + device:add_subscribed_attribute(attr) + end + end + end + for cap_id, events in pairs(subscribed_events) do + if device:supports_capability_by_id(cap_id) then + for _, e in ipairs(events) do + device:add_subscribed_event(e) + end + end + end device:subscribe() end @@ -129,6 +143,9 @@ local function do_configure(driver, device) end local function info_changed(driver, device, event, args) + if device.profile.id == args.old_st_store.profile.id then + return + end for cap_id, attributes in pairs(subscribed_attributes) do if device:supports_capability_by_id(cap_id) then for _, attr in ipairs(attributes) do From 7dc105c2d1344cb2a4107295ae0ed5ff0d97d13c Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Tue, 8 Oct 2024 20:33:31 +0900 Subject: [PATCH 10/20] Update process to check the busy state Signed-off-by: Hunsup Jung --- .../matter-lock/src/new-matter-lock/init.lua | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 06b72f64c5..a9800e2b5a 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -163,6 +163,18 @@ local function info_changed(driver, device, event, args) device:subscribe() end +-- This function check busy_state and if busy_state is false, set it to true(current time) +local function check_busy_state(device) + local c_time = os.time() + local busy_state = device:get_field(lock_utils.BUSY_STATE) or false + if busy_state == false or c_time - busy_state > 10 then + device:set_field(lock_utils.BUSY_STATE, c_time, {persist = true}) + return false + else + return true + end +end + -- Matter Handler ---------------- -- Lock State -- @@ -267,7 +279,7 @@ local function set_cota_credential(device, credential_index) device:set_field(lock_utils.COTA_CRED_INDEX, credential_index, {persist = true}) local credential = {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = credential_index} -- Set the credential to a code - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + check_busy_state(device) device:set_field(lock_utils.COMMAND_NAME, "addCota") device:set_field(lock_utils.CRED_INDEX, credential_index) device:set_field(lock_utils.SET_CREDENTIAL, credential_index) @@ -637,7 +649,7 @@ local function handle_update_user(driver, device, command) end -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -655,7 +667,6 @@ local function handle_update_user(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) @@ -730,7 +741,7 @@ local function handle_delete_user(driver, device, command) local userIdx = command.args.userIndex -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -748,7 +759,6 @@ local function handle_delete_user(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) @@ -765,7 +775,7 @@ local function handle_delete_all_users(driver, device, command) local cmdName = "deleteAllUsers" -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -783,7 +793,6 @@ local function handle_delete_all_users(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, ALL_INDEX, {persist = true}) @@ -852,7 +861,7 @@ local function handle_add_credential(driver, device, command) local credData = command.args.credentialData -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -870,7 +879,6 @@ local function handle_add_credential(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) @@ -907,7 +915,7 @@ local function handle_update_credential(driver, device, command) local credData = command.args.credentialData -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -925,7 +933,6 @@ local function handle_update_credential(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) @@ -1097,7 +1104,7 @@ local function handle_delete_credential(driver, device, command) } -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -1115,7 +1122,6 @@ local function handle_delete_credential(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.CRED_INDEX, credIdx, {persist = true}) @@ -1136,7 +1142,7 @@ local function handle_delete_all_credentials(driver, device, command) } -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -1154,7 +1160,6 @@ local function handle_delete_all_credentials(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.CRED_INDEX, ALL_INDEX, {persist = true}) @@ -1222,7 +1227,7 @@ local function handle_set_week_day_schedule(driver, device, command) local endMinute = schedule.endMinute -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -1240,7 +1245,6 @@ local function handle_set_week_day_schedule(driver, device, command) end -- Save values to field - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) @@ -1313,7 +1317,7 @@ local function handle_clear_week_day_schedule(driver, device, command) local userIdx = command.args.userIndex -- Check busy state - local busy = device:get_field(lock_utils.BUSY_STATE) + local busy = check_busy_state(device) if busy == true then local result = { commandName = cmdName, @@ -1330,7 +1334,7 @@ local function handle_clear_week_day_schedule(driver, device, command) return end - device:set_field(lock_utils.BUSY_STATE, true, {persist = true}) + -- Save values to field device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) From 6e09690ca47fbaf0454df1e01944eb049b6d0864 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 9 Oct 2024 14:42:48 +0900 Subject: [PATCH 11/20] Add lock profile for a door lock that does not support user and pin Signed-off-by: Hunsup Jung --- .../SmartThings/matter-lock/profiles/lock.yml | 23 +++++++++++++++++++ .../matter-lock/src/new-matter-lock/init.lua | 2 -- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 drivers/SmartThings/matter-lock/profiles/lock.yml diff --git a/drivers/SmartThings/matter-lock/profiles/lock.yml b/drivers/SmartThings/matter-lock/profiles/lock.yml new file mode 100644 index 0000000000..9f0bf30a43 --- /dev/null +++ b/drivers/SmartThings/matter-lock/profiles/lock.yml @@ -0,0 +1,23 @@ +name: lock +components: +- id: main + capabilities: + - id: lock + version: 1 + config: + values: + - key: "lock.value" + enabledValues: + - locked + - unlocked + - not fully locked + - id: lockAlarm + version: 1 + - id: remoteControlStatus + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmartLock diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index a9800e2b5a..2eefd455b8 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -135,8 +135,6 @@ local function do_configure(driver, device) if #week_schedule_eps + #year_schedule_eps > 0 then profile_name = profile_name .. "-schedule" end - else - profile_name = "base-lock" end device.log.info(string.format("Updating device profile to %s.", profile_name)) device:try_update_metadata({profile = profile_name}) From fcbcc3fcedb7d3aa5383216827dc13a0cfe258c5 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 9 Oct 2024 14:44:27 +0900 Subject: [PATCH 12/20] Modify set_cota_credential function Signed-off-by: Hunsup Jung --- drivers/SmartThings/matter-lock/fingerprints.yml | 1 - drivers/SmartThings/matter-lock/src/init.lua | 2 +- drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/matter-lock/fingerprints.yml b/drivers/SmartThings/matter-lock/fingerprints.yml index cef1bd4ffe..2bb1119079 100755 --- a/drivers/SmartThings/matter-lock/fingerprints.yml +++ b/drivers/SmartThings/matter-lock/fingerprints.yml @@ -33,4 +33,3 @@ matterGeneric: deviceTypes: - id: 0x000A # Door Lock deviceProfileName: base-lock - \ No newline at end of file diff --git a/drivers/SmartThings/matter-lock/src/init.lua b/drivers/SmartThings/matter-lock/src/init.lua index d234edd637..dbd04c522a 100755 --- a/drivers/SmartThings/matter-lock/src/init.lua +++ b/drivers/SmartThings/matter-lock/src/init.lua @@ -36,7 +36,7 @@ local function set_cota_credential(device, credential_index) if cota_cred == nil then -- Shouldn't happen but defensive to try to figure out if we need the cota cred and set it. device:send(DoorLock.attributes.RequirePINforRemoteOperation:read(device, #eps > 0 and eps[1] or 1)) - device.thread:call_with_delay(2, function(t) set_cota_credential(device, credential_index) end) + return elseif not cota_cred then device.log.debug("Device does not require PIN for remote operation. Not setting COTA credential") return diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 2eefd455b8..04c921af02 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -260,7 +260,7 @@ local function set_cota_credential(device, credential_index) if cota_cred == nil then -- Shouldn't happen but defensive to try to figure out if we need the cota cred and set it. device:send(DoorLock.attributes.RequirePINforRemoteOperation:read(device, #eps > 0 and eps[1] or 1)) - device.thread:call_with_delay(2, function(t) set_cota_credential(device, credential_index) end) + return elseif not cota_cred then device.log.debug("Device does not require PIN for remote operation. Not setting COTA credential") return From beb5dc17a25e027fcf6c6b181b2dc88cbf3f3361 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 9 Oct 2024 15:36:16 +0900 Subject: [PATCH 13/20] Modify test_aqara_matter_lock Signed-off-by: Hunsup Jung --- .../matter-lock/src/test/test_aqara_matter_lock.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua index 85baf6df4e..b64324d8f7 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_aqara_matter_lock.lua @@ -53,7 +53,15 @@ local mock_device = test.mock_device.build_test_matter_device({ local function test_init() local subscribe_request = clusters.DoorLock.attributes.LockState:subscribe(mock_device) + subscribe_request:merge(clusters.DoorLock.attributes.OperatingMode:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.attributes.NumberOfTotalUsersSupported:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.attributes.NumberOfPINUsersSupported:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.attributes.MaxPINCodeLength:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.attributes.MinPINCodeLength:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.events.LockOperation:subscribe(mock_device)) subscribe_request:merge(clusters.DoorLock.events.DoorLockAlarm:subscribe(mock_device)) + subscribe_request:merge(clusters.DoorLock.events.LockUserChange:subscribe(mock_device)) test.socket["matter"]:__expect_send({mock_device.id, subscribe_request}) test.mock_device.add_test_device(mock_device) end From aca90c2d6ab4e13894a7b34cd57572c25508fec9 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Thu, 10 Oct 2024 18:39:45 +0900 Subject: [PATCH 14/20] Simplify the operation related to the tables Signed-off-by: Hunsup Jung --- .../matter-lock/src/new-matter-lock/init.lua | 141 ++++++++---------- 1 file changed, 65 insertions(+), 76 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 04c921af02..34c2a72b79 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -16,6 +16,7 @@ local device_lib = require "st.device" local capabilities = require "st.capabilities" local clusters = require "st.matter.clusters" local im = require "st.matter.interaction_model" +local utils = require "st.utils" local lock_utils = require "lock_utils" local version = require "version" @@ -371,45 +372,40 @@ end ---------------- local function add_user_to_table(device, userIdx, usrType) -- Get latest user table - local user_table = device:get_latest_state( + local user_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockUsers.ID, - capabilities.lockUsers.users.NAME - ) or {} - local new_user_table = {} - - -- Recreate user table - for index, entry in pairs(user_table) do - table.insert(new_user_table, entry) - end + capabilities.lockUsers.users.NAME, + {} + )) -- Add new entry to table - table.insert(new_user_table, {userIndex = userIdx, userType = usrType}) - device:emit_event(capabilities.lockUsers.users(new_user_table, {visibility = {displayed = false}})) + table.insert(user_table, {userIndex = userIdx, userType = usrType}) + device:emit_event(capabilities.lockUsers.users(user_table, {visibility = {displayed = false}})) end local function update_user_in_table(device, userIdx, usrType) -- Get latest user table - local user_table = device:get_latest_state( + local user_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockUsers.ID, - capabilities.lockUsers.users.NAME - ) or {} - local new_user_table = {} + capabilities.lockUsers.users.NAME, + {} + )) - -- Recreate user table + -- Find user entry local i = 0 for index, entry in pairs(user_table) do if entry.userIndex == userIdx then i = index + break end - table.insert(new_user_table, entry) end -- Update user entry if i ~= 0 then - new_user_table[i].userType = usrType - device:emit_event(capabilities.lockUsers.users(new_user_table, {visibility = {displayed = false}})) + user_table[i].userType = usrType + device:emit_event(capabilities.lockUsers.users(user_table, {visibility = {displayed = false}})) end end @@ -421,20 +417,21 @@ local function delete_user_from_table(device, userIdx) end -- Get latest user table - local user_table = device:get_latest_state( + local user_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockUsers.ID, - capabilities.lockUsers.users.NAME - ) or {} - local new_user_table = {} + capabilities.lockUsers.users.NAME, + {} + )) - -- Recreate user table + -- Re-create user table for index, entry in pairs(user_table) do - if entry.userIndex ~= userIdx then - table.insert(new_user_table, entry) + if entry.userIndex == userIdx then + table.remove(user_table, index) + break end end - device:emit_event(capabilities.lockUsers.users(new_user_table, {visibility = {displayed = false}})) + device:emit_event(capabilities.lockUsers.users(user_table, {visibility = {displayed = false}})) end ---------------------- @@ -442,21 +439,16 @@ end ---------------------- local function add_credential_to_table(device, userIdx, credIdx, credType) -- Get latest credential table - local cred_table = device:get_latest_state( + local cred_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockCredentials.ID, - capabilities.lockCredentials.credentials.NAME - ) or {} - local new_cred_table = {} - - -- Recreat credential table - for index, entry in pairs(cred_table) do - table.insert(new_cred_table, entry) - end + capabilities.lockCredentials.credentials.NAME, + {} + )) -- Add new entry to table - table.insert(new_cred_table, {userIndex = userIdx, credentialIndex = credIdx, credentialType = credType}) - device:emit_event(capabilities.lockCredentials.credentials(new_cred_table, {visibility = {displayed = false}})) + table.insert(cred_table, {userIndex = userIdx, credentialIndex = credIdx, credentialType = credType}) + device:emit_event(capabilities.lockCredentials.credentials(cred_table, {visibility = {displayed = false}})) end local function delete_credential_from_table(device, credIdx) @@ -466,24 +458,24 @@ local function delete_credential_from_table(device, credIdx) end -- Get latest credential table - local cred_table = device:get_latest_state( + local cred_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockCredentials.ID, - capabilities.lockCredentials.credentials.NAME - ) or {} - local new_cred_table = {} + capabilities.lockCredentials.credentials.NAME, + {} + )) - -- Recreate credential table + -- Delete an entry from credential table local userIdx = 0 for index, entry in pairs(cred_table) do - if entry.credentialIndex ~= credIdx then - table.insert(new_cred_table, entry) - else + if entry.credentialIndex == credIdx then + table.remove(cred_table, index) userIdx = entry.userIndex + break end end - device:emit_event(capabilities.lockCredentials.credentials(new_cred_table, {visibility = {displayed = false}})) + device:emit_event(capabilities.lockCredentials.credentials(cred_table, {visibility = {displayed = false}})) return userIdx end @@ -501,7 +493,7 @@ local function delete_credential_from_table_as_user(device, userIdx) ) or {} local new_cred_table = {} - -- Recreate credential table + -- Re-create credential table for index, entry in pairs(cred_table) do if entry.userIndex ~= userIdx then table.insert(new_cred_table, entry) @@ -525,39 +517,37 @@ local WEEK_DAY_MAP = { } local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule) - -- Get latest week day schedule table - local week_schedule_table = device:get_latest_state( + local week_schedule_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockSchedules.ID, - capabilities.lockSchedules.weekDaySchedules.NAME - ) or {} - local new_week_schedule_table = {} + capabilities.lockSchedules.weekDaySchedules.NAME, + {} + )) - -- Find schedule list + -- Find schedule for specific user local i = 0 for index, entry in pairs(week_schedule_table) do if entry.userIndex == userIdx then i = index end - table.insert(new_week_schedule_table, entry) end - -- Recreate weekDays list + -- Re-create weekDays list local weekDayList = {} for _, weekday in ipairs(schedule.weekDays) do table.insert(weekDayList, weekday) end if i ~= 0 then -- Add schedule for existing user + -- Exclude same scheduleIdx local new_schedule_table = {} - for index, entry in pairs(new_week_schedule_table[i].schedules) do - if entry.scheduleIndex == scheduleIdx then - return + for index, entry in pairs(week_schedule_table[i].schedules) do + if entry.scheduleIndex ~= scheduleIdx then + table.insert(new_schedule_table, entry) end - table.insert(new_schedule_table, entry) end - + -- Add new entry to table table.insert( new_schedule_table, { @@ -569,11 +559,11 @@ local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule endMinute = schedule.endMinute } ) - - new_week_schedule_table[i].schedules = new_schedule_table + -- Update schedule for specific user + week_schedule_table[i].schedules = new_schedule_table else -- Add schedule for new user table.insert( - new_week_schedule_table, + week_schedule_table, { userIndex = userIdx, schedules = {{ @@ -588,25 +578,24 @@ local function add_week_schedule_to_table(device, userIdx, scheduleIdx, schedule ) end - device:emit_event(capabilities.lockSchedules.weekDaySchedules(new_week_schedule_table, {visibility = {displayed = false}})) + device:emit_event(capabilities.lockSchedules.weekDaySchedules(week_schedule_table, {visibility = {displayed = false}})) end local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) -- Get latest week day schedule table - local week_schedule_table = device:get_latest_state( + local week_schedule_table = utils.deep_copy(device:get_latest_state( "main", capabilities.lockSchedules.ID, - capabilities.lockSchedules.weekDaySchedules.NAME - ) or {} - local new_week_schedule_table = {} + capabilities.lockSchedules.weekDaySchedules.NAME, + {} + )) - -- Find shcedule list + -- Find schedule for specific user local i = 0 for index, entry in pairs(week_schedule_table) do if entry.userIndex == userIdx then i = index end - table.insert(new_week_schedule_table, entry) end -- When there is no userIndex in the table @@ -614,9 +603,9 @@ local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) return end - -- Recreate schedule table for the user + -- Re-create schedule table for the user local new_schedule_table = {} - for index, entry in pairs(new_week_schedule_table[i].schedules) do + for index, entry in pairs(week_schedule_table[i].schedules) do if entry.scheduleIndex ~= scheduleIdx then table.insert(new_schedule_table, entry) end @@ -624,12 +613,12 @@ local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) -- If user has no schedule, remove user from the table if #new_schedule_table == 0 then - table.remove(new_week_schedule_table, i) + table.remove(week_schedule_table, i) else - new_week_schedule_table[i].schedules = new_schedule_table + week_schedule_table[i].schedules = new_schedule_table end - device:emit_event(capabilities.lockSchedules.weekDaySchedules(new_week_schedule_table, {visibility = {displayed = false}})) + device:emit_event(capabilities.lockSchedules.weekDaySchedules(week_schedule_table, {visibility = {displayed = false}})) end ----------------- From 65d52f9ba90c415185f9e139956f7d0ad20a05f0 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Thu, 10 Oct 2024 20:22:11 +0900 Subject: [PATCH 15/20] Add addUser command and sequence Signed-off-by: Hunsup Jung --- .../matter-lock/src/lock_utils.lua | 1 + .../matter-lock/src/new-matter-lock/init.lua | 125 ++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/drivers/SmartThings/matter-lock/src/lock_utils.lua b/drivers/SmartThings/matter-lock/src/lock_utils.lua index 31f7f6b3f9..4a6bde828e 100644 --- a/drivers/SmartThings/matter-lock/src/lock_utils.lua +++ b/drivers/SmartThings/matter-lock/src/lock_utils.lua @@ -28,6 +28,7 @@ local lock_utils = { COTA_READ_INITIALIZED = "cotaReadInitialized", BUSY_STATE = "busyState", COMMAND_NAME = "commandName", + USER_NAME = "userName", USER_INDEX = "userIndex", USER_TYPE = "userType", CRED_INDEX = "credentialIndex", diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 34c2a72b79..87a73f593c 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -621,6 +621,44 @@ local function delete_week_schedule_to_table(device, userIdx, scheduleIdx) device:emit_event(capabilities.lockSchedules.weekDaySchedules(week_schedule_table, {visibility = {displayed = false}})) end +-------------- +-- Add User -- +-------------- +local function handle_add_user(driver, device, command) + -- Get parameters + local cmdName = "addUser" + local userName = command.args.userName + local userType = command.args.lockUserType + + -- Check busy state + local busy = check_busy_state(device) + if busy == true then + local result = { + commandName = cmdName, + statusCode = "busy" + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + return + end + + -- Save values to field + device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) + device:set_field(lock_utils.USER_INDEX, INITIAL_COTA_INDEX, {persist = true}) + device:set_field(lock_utils.USER_NAME, userName, {persist = true}) + device:set_field(lock_utils.USER_TYPE, userType, {persist = true}) + + -- Get available user index + local ep = device:component_to_endpoint(command.component) + device:send(DoorLock.server.commands.GetUser(device, ep, INITIAL_COTA_INDEX)) +end + ----------------- -- Update User -- ----------------- @@ -674,6 +712,91 @@ local function handle_update_user(driver, device, command) ) end +----------------------- +-- Get User Response -- +----------------------- +local function get_user_response_handler(driver, device, ib, response) + local elements = ib.info_block.data.elements + local userIdx = elements.user_index.value + local cmdName = device:get_field(lock_utils.COMMAND_NAME) + local status = "success" + if ib.status == DoorLock.types.DlStatus.FAILURE then + status = "failure" + elseif ib.status == DoorLock.types.DlStatus.INVALID_FIELD then + status = "invalidCommand" + end + if status ~= "success" then + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + statusCode = status + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + end + + local ep = find_default_endpoint(device, DoorLock.ID) + local status = elements.user_status.value + local maxUser = device:get_latest_state( + "main", + capabilities.lockUsers.ID, + capabilities.lockUsers.totalUsersSupported.NAME + ) or 10 + + -- Found available user index + if status == nil or status == DoorLock.types.UserStatusEnum.AVAILABLE then + local userName = device:get_field(lock_utils.USER_NAME) + local userType = device:get_field(lock_utils.USER_TYPE) + local userTypeMatter = DoorLock.types.UserTypeEnum.UNRESTRICTED_USER + if userType == "guest" then + userTypeMatter = DoorLock.types.UserTypeEnum.SCHEDULE_RESTRICTED_USER + end + + -- Save values to field + device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) + + -- Send command + device:send( + DoorLock.server.commands.SetUser( + device, ep, + DoorLock.types.DataOperationTypeEnum.ADD, -- Operation Type: Add(0), Modify(2) + userIdx, -- User Index + userName, -- User Name + nil, -- Unique ID + nil, -- User Status + userTypeMatter, -- User Type + nil -- Credential Rule + ) + ) + elseif userIdx >= maxUser then -- There's no available user index + -- Update commandResult + local result = { + commandName = cmdName, + userIndex = userIdx, + statusCode = "resourceExhausted" + } + local event = capabilities.lockUsers.commandResult( + result, + { + state_change = true, + visibility = {displayed = false} + } + ) + device:emit_event(event) + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + else -- Check next user index + device:send(DoorLock.server.commands.GetUser(device, ep, userIdx + 1)) + end +end + ----------------------- -- Set User Response -- ----------------------- @@ -1499,6 +1622,7 @@ local new_matter_lock_handler = { cmd_response = { [DoorLock.ID] = { [DoorLock.server.commands.SetUser.ID] = set_user_response_handler, + [DoorLock.client.commands.GetUserResponse.ID] = get_user_response_handler, [DoorLock.server.commands.ClearUser.ID] = clear_user_response_handler, [DoorLock.client.commands.SetCredentialResponse.ID] = set_credential_response_handler, [DoorLock.server.commands.ClearCredential.ID] = clear_credential_response_handler, @@ -1515,6 +1639,7 @@ local new_matter_lock_handler = { [capabilities.lock.commands.unlock.NAME] = handle_unlock, }, [capabilities.lockUsers.ID] = { + [capabilities.lockUsers.commands.addUser.NAME] = handle_add_user, [capabilities.lockUsers.commands.updateUser.NAME] = handle_update_user, [capabilities.lockUsers.commands.deleteUser.NAME] = handle_delete_user, [capabilities.lockUsers.commands.deleteAllUsers.NAME] = handle_delete_all_users, From 17d81484e97dcb2f4b3faf3fcfed33cd3181ecc9 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Fri, 11 Oct 2024 10:55:49 +0900 Subject: [PATCH 16/20] Modify some code that are not clear Signed-off-by: Hunsup Jung --- drivers/SmartThings/matter-lock/src/init.lua | 2 +- drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/init.lua b/drivers/SmartThings/matter-lock/src/init.lua index dbd04c522a..ccb3110c08 100755 --- a/drivers/SmartThings/matter-lock/src/init.lua +++ b/drivers/SmartThings/matter-lock/src/init.lua @@ -37,7 +37,7 @@ local function set_cota_credential(device, credential_index) -- Shouldn't happen but defensive to try to figure out if we need the cota cred and set it. device:send(DoorLock.attributes.RequirePINforRemoteOperation:read(device, #eps > 0 and eps[1] or 1)) return - elseif not cota_cred then + elseif cota_cred == false then device.log.debug("Device does not require PIN for remote operation. Not setting COTA credential") return end diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 87a73f593c..b86b12bcf7 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -262,7 +262,7 @@ local function set_cota_credential(device, credential_index) -- Shouldn't happen but defensive to try to figure out if we need the cota cred and set it. device:send(DoorLock.attributes.RequirePINforRemoteOperation:read(device, #eps > 0 and eps[1] or 1)) return - elseif not cota_cred then + elseif cota_cred == false then device.log.debug("Device does not require PIN for remote operation. Not setting COTA credential") return end @@ -424,7 +424,7 @@ local function delete_user_from_table(device, userIdx) {} )) - -- Re-create user table + -- Remove element from user table for index, entry in pairs(user_table) do if entry.userIndex == userIdx then table.remove(user_table, index) From 3035dbcfb78d9a6ba6867374e6713855274e072b Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Fri, 11 Oct 2024 19:10:09 +0900 Subject: [PATCH 17/20] Add test unit file for new door lock driver Signed-off-by: Hunsup Jung --- .../matter-lock/src/lock_utils.lua | 4 +- .../matter-lock/src/new-matter-lock/init.lua | 2 +- .../src/test/test_new_matter_lock.lua | 649 ++++++++++++++++++ 3 files changed, 653 insertions(+), 2 deletions(-) create mode 100644 drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua diff --git a/drivers/SmartThings/matter-lock/src/lock_utils.lua b/drivers/SmartThings/matter-lock/src/lock_utils.lua index 4a6bde828e..0081065707 100644 --- a/drivers/SmartThings/matter-lock/src/lock_utils.lua +++ b/drivers/SmartThings/matter-lock/src/lock_utils.lua @@ -32,7 +32,9 @@ local lock_utils = { USER_INDEX = "userIndex", USER_TYPE = "userType", CRED_INDEX = "credentialIndex", - CRED_DATA = "credentialData" + CRED_DATA = "credentialData", + SCHEDULE_INDEX = "scheduleIndex", + SCHEDULE = "schedule" } local capabilities = require "st.capabilities" local json = require "st.json" diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index b86b12bcf7..7464b71389 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -1275,7 +1275,7 @@ local function handle_delete_all_credentials(driver, device, command) -- Send command local ep = device:component_to_endpoint(command.component) - device:send(DoorLock.server.commands.ClearUser(device, ep, credential)) + device:send(DoorLock.server.commands.ClearCredential(device, ep, credential)) end ------------------------------- diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua new file mode 100644 index 0000000000..16fb94f94d --- /dev/null +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -0,0 +1,649 @@ +-- Copyright 2023 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +local test = require "integration_test" +local capabilities = require "st.capabilities" +test.add_package_capability("lockAlarm.yml") +local t_utils = require "integration_test.utils" +local clusters = require "st.matter.clusters" +local DoorLock = clusters.DoorLock +local types = DoorLock.types + +local mock_device = test.mock_device.build_test_matter_device({ + profile = t_utils.get_profile_definition("lock-user-pin-schedule.yml"), + manufacturer_info = { + vendor_id = 0x115f, + product_id = 0x2802, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + { cluster_id = clusters.Basic.ID, cluster_type = "SERVER" }, + }, + device_types = { + { device_type_id = 0x0016, device_type_revision = 1 } -- RootNode + } + }, + { + endpoint_id = 1, + clusters = { + { + cluster_id = DoorLock.ID, + cluster_type = "SERVER", + cluster_revision = 1, + feature_map = 0x0001, --u32 bitmap + } + }, + device_types = { + { device_type_id = 0x000A, device_type_revision = 1 } -- Door Lock + } + } + } +}) + +local function test_init() + local subscribe_request = DoorLock.attributes.LockState:subscribe(mock_device) + subscribe_request:merge(DoorLock.attributes.OperatingMode:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfTotalUsersSupported:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfPINUsersSupported:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.MaxPINCodeLength:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.MinPINCodeLength:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.RequirePINforRemoteOperation:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:subscribe(mock_device)) + subscribe_request:merge(DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:subscribe(mock_device)) + subscribe_request:merge(DoorLock.events.LockOperation:subscribe(mock_device)) + subscribe_request:merge(DoorLock.events.DoorLockAlarm:subscribe(mock_device)) + subscribe_request:merge(DoorLock.events.LockUserChange:subscribe(mock_device)) + test.socket["matter"]:__expect_send({mock_device.id, subscribe_request}) + test.mock_device.add_test_device(mock_device) +end + +test.set_test_init_function(test_init) + +test.register_message_test( + "Handle Lock command received from SmartThings.", { + { + channel = "capability", + direction = "receive", + message = { + mock_device.id, + {capability = "lock", component = "main", command = "lock", args = {}}, + }, + }, + { + channel = "matter", + direction = "send", + message = {mock_device.id, DoorLock.server.commands.LockDoor(mock_device, 1)}, + }, + } +) + +test.register_message_test( + "Handle Unlock command received from SmartThings.", { + { + channel = "capability", + direction = "receive", + message = { + mock_device.id, + {capability = "lock", component = "main", command = "unlock", args = {}}, + }, + }, + { + channel = "matter", + direction = "send", + message = { + mock_device.id, + DoorLock.server.commands.UnlockDoor(mock_device, 1), + }, + }, + } +) + +test.register_coroutine_test( + "Handle received LockState.LOCKED from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.LockState:build_test_report_data( + mock_device, 1, DoorLock.attributes.LockState.LOCKED + ), + } + ) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.mock_time.advance_time(1) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.lock.locked()) + ) + end +) + +test.register_coroutine_test( + "Handle received LockState.UNLOCKED from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.LockState:build_test_report_data( + mock_device, 1, DoorLock.attributes.LockState.UNLOCKED + ), + } + ) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.mock_time.advance_time(1) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.lock.unlocked()) + ) + end +) + +test.register_coroutine_test( + "Handle received LockState.NOT_FULLY_LOCKED from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.LockState:build_test_report_data( + mock_device, 1, DoorLock.attributes.LockState.NOT_FULLY_LOCKED + ), + } + ) + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.mock_time.advance_time(1) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.lock.not_fully_locked()) + ) + end +) + +local function refresh_commands(dev) + local req = DoorLock.attributes.LockState:read(dev) + return req +end + +test.register_message_test( + "Handle received refresh.", { + { + channel = "capability", + direction = "receive", + message = { + mock_device.id, + {capability = "refresh", component = "main", command = "refresh", args = {}}, + }, + }, + { + channel = "matter", + direction = "send", + message = {mock_device.id, refresh_commands(mock_device)}, + }, + } +) + +local DlAlarmCode = DoorLock.types.DlAlarmCode +test.register_message_test( + "Handle DoorLockAlarm event from Matter device.", { + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.DoorLockAlarm:build_test_event_report( + mock_device, 1, {alarm_code = DlAlarmCode.LOCK_JAMMED} + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.unableToLockTheDoor({state_change = true}) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.DoorLockAlarm:build_test_event_report( + mock_device, 1, {alarm_code = DlAlarmCode.LOCK_FACTORY_RESET} + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.lockFactoryReset({state_change = true}) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.DoorLockAlarm:build_test_event_report( + mock_device, 1, {alarm_code = DlAlarmCode.WRONG_CODE_ENTRY_LIMIT} + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.attemptsExceeded({state_change = true}) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.DoorLockAlarm:build_test_event_report( + mock_device, 1, {alarm_code = DlAlarmCode.FRONT_ESCEUTCHEON_REMOVED} + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.damaged({state_change = true}) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.DoorLockAlarm:build_test_event_report( + mock_device, 1, {alarm_code = DlAlarmCode.DOOR_FORCED_OPEN} + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.forcedOpeningAttempt({state_change = true}) + ), + }, + } +) + +test.register_message_test( + "Handle Lock Operation event from Matter device.", { + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLOCK, + operation_source = types.OperationSourceEnum.KEYPAD, + user_index = 1, + fabric_index = 1, + source_node = 1, + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ) + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.unlocked( + {data = {method = "keypad", userIndex = 1}, state_change = true} + ) + ), + } + } +) + +test.register_coroutine_test( + "Added lifecycle event lock nocodes nobattery", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.clear({state_change = true}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Add User command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "addUser", + args = {"Guest1", "adminMember"} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.GetUser( + mock_device, 1, + 1 -- user_index + ) + }) + test.wait_for_events() + test.socket.matter:__queue_receive({ + mock_device.id, + DoorLock.client.commands.GetUserResponse:build_test_command_response( + mock_device, 1, + 1, --user_index + nil, nil, nil, nil, nil, nil, nil, nil, nil + ), + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.SetUser( + mock_device, 1, + types.DataOperationTypeEnum.ADD, + 1, + "Guest1", + nil, + nil, + types.UserTypeEnum.UNRESTRICTED_USER, + nil + ) + }) + end +) + +test.register_coroutine_test( + "Handle Update User command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "updateUser", + args = {1, "Guest1", "adminMember"} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.SetUser( + mock_device, 1, + types.DataOperationTypeEnum.MODIFY, + 1, + "Guest1", + nil, + nil, + types.UserTypeEnum.UNRESTRICTED_USER, + nil + ) + }) + end +) + +test.register_coroutine_test( + "Handle delete User command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "deleteUser", + args = {1} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.ClearUser( + mock_device, 1, + 1 + ) + }) + end +) + +test.register_coroutine_test( + "Handle delete all Users command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "deleteAllUsers", + args = {} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.ClearUser( + mock_device, 1, + 0xFFFE + ) + }) + end +) + +test.register_coroutine_test( + "Handle Add Credential command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "addCredential", + args = {1, "adminMember", "pin", "654123"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + 1, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, -- endpoint_id + DoorLock.types.DlStatus.SUCCESS, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.credentials( + {{credentialIndex=1, credentialType="pin", userIndex=1}}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="addCredential", credentialIndex=1, statusCode="success", userIndex=1}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Update Credential command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "updateCredential", + args = {1, 1, "pin", "654123"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.MODIFY, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + 1, -- user_index + nil, -- user_status + nil -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, -- endpoint_id + DoorLock.types.DlStatus.SUCCESS, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="updateCredential", credentialIndex=1, statusCode="success", userIndex=1}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Delete Credential command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "deleteCredential", + args = {1, "pin"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.ClearCredential( + mock_device, 1, -- endpoint + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ) + ), + } + ) + end +) + +test.register_coroutine_test( + "Handle Delete all Credentials command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "deleteAllCredentials", + args = {"pin"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.ClearCredential( + mock_device, 1, -- endpoint + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 0xFFFE} + ) + ), + } + ) + end +) + +test.register_coroutine_test( + "Handle Clear Week Day Schedule command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockSchedules.ID, + command = "clearWeekDaySchedules", + args = { + 1, -- user index + 1, -- schedule index + } + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.ClearWeekDaySchedule( + mock_device, 1, -- endpoint + 1, -- schedule index + 1 -- user index + ), + } + ) + end +) + +test.run_registered_tests() From 5a79c2124fd09859d9903e5c2f9237cf565421bc Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 16 Oct 2024 04:02:04 +0900 Subject: [PATCH 18/20] Fix the process for COTA and some issues Signed-off-by: Hunsup Jung --- .../matter-lock/src/lock_utils.lua | 6 +- .../matter-lock/src/new-matter-lock/init.lua | 96 +++++++++++-------- 2 files changed, 63 insertions(+), 39 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/lock_utils.lua b/drivers/SmartThings/matter-lock/src/lock_utils.lua index 0081065707..d9c43c30d2 100644 --- a/drivers/SmartThings/matter-lock/src/lock_utils.lua +++ b/drivers/SmartThings/matter-lock/src/lock_utils.lua @@ -34,7 +34,11 @@ local lock_utils = { CRED_INDEX = "credentialIndex", CRED_DATA = "credentialData", SCHEDULE_INDEX = "scheduleIndex", - SCHEDULE = "schedule" + SCHEDULE_WEEK_DAYS = "scheduleWeekDays", + SCHEDULE_START_HOUR = "scheduleStartHour", + SCHEDULE_START_MINUTE = "scheduleStartMinute", + SCHEDULE_END_HOUR = "scheduleEndHour", + SCHEDULE_END_MINUTE = "scheduleEndMinute" } local capabilities = require "st.capabilities" local json = require "st.json" diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index 7464b71389..a089873d92 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -252,9 +252,6 @@ end -------------------------------------- -- Require PIN For Remote Operation -- -------------------------------------- ---- If a device needs a cota credential this function attempts to set the credential ---- at the index provided. The set_credential_response_handler handles all failures ---- and retries with the appropriate index when necessary. local function set_cota_credential(device, credential_index) local eps = device:get_endpoints(DoorLock.ID) local cota_cred = device:get_field(lock_utils.COTA_CRED) @@ -267,7 +264,8 @@ local function set_cota_credential(device, credential_index) return end - if device:get_field(lock_utils.SET_CREDENTIAL) ~= nil then + -- Check Busy State + if check_busy_state(device) == true then device.log.debug("delaying setting COTA credential since a credential is currently being set") device.thread:call_with_delay(2, function(t) set_cota_credential(device, credential_index) @@ -275,15 +273,18 @@ local function set_cota_credential(device, credential_index) return end - device:set_field(lock_utils.COTA_CRED_INDEX, credential_index, {persist = true}) - local credential = {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = credential_index} - -- Set the credential to a code - check_busy_state(device) + -- Save values to field device:set_field(lock_utils.COMMAND_NAME, "addCota") device:set_field(lock_utils.CRED_INDEX, credential_index) - device:set_field(lock_utils.SET_CREDENTIAL, credential_index) + device:set_field(lock_utils.COTA_CRED_INDEX, credential_index, {persist = true}) device:set_field(lock_utils.USER_TYPE, "remote") + + -- Send command device.log.info(string.format("Attempting to set COTA credential at index %s", credential_index)) + local credential = { + credential_type = DoorLock.types.CredentialTypeEnum.PIN, + credential_index = credential_index + } device:send(DoorLock.server.commands.SetCredential( device, #eps > 0 and eps[1] or 1, @@ -454,7 +455,8 @@ end local function delete_credential_from_table(device, credIdx) -- If Credential Index is ALL_INDEX, remove all entries from the table if credIdx == ALL_INDEX then - device:emit_event(capabilities.lockCredentials.credentials({})) + device:emit_event(capabilities.lockCredentials.credentials({}, {visibility = {displayed = false}})) + return end -- Get latest credential table @@ -483,6 +485,7 @@ local function delete_credential_from_table_as_user(device, userIdx) -- If User Index is ALL_INDEX, remove all entry from the table if userIdx == ALL_INDEX then device:emit_event(capabilities.lockCredentials.credentials({}, {visibility = {displayed = false}})) + return end -- Get latest credential table @@ -628,7 +631,7 @@ local function handle_add_user(driver, device, command) -- Get parameters local cmdName = "addUser" local userName = command.args.userName - local userType = command.args.lockUserType + local userType = command.args.userType -- Check busy state local busy = check_busy_state(device) @@ -942,7 +945,7 @@ local function clear_user_response_handler(driver, device, ib, response) local event = capabilities.lockUsers.commandResult( result, { - + state_change = true, visibility = {displayed = false} }) device:emit_event(event) @@ -1065,6 +1068,15 @@ end ----------------------------- -- Set Credential Response -- ----------------------------- +local RESPONSE_STATUS_MAP = { + [DoorLock.types.DlStatus.FAILURE] = "failure", + [DoorLock.types.DlStatus.DUPLICATE] = "duplicate", + [DoorLock.types.DlStatus.OCCUPIED] = "occupied", + [DoorLock.types.DlStatus.INVALID_FIELD] = "invalidCommand", + [DoorLock.types.DlStatus.RESOURCE_EXHAUSTED] = "resourceExhausted", + [DoorLock.types.DlStatus.NOT_FOUND] = "failure" +} + local function set_credential_response_handler(driver, device, ib, response) if ib.status ~= im.InteractionResponse.Status.SUCCESS then device.log.error("Failed to set credential for device") @@ -1073,21 +1085,20 @@ local function set_credential_response_handler(driver, device, ib, response) local cmdName = device:get_field(lock_utils.COMMAND_NAME) local credData = device:get_field(lock_utils.CRED_DATA) - if cmdName == "addCota" then - credData = device:get_field(lock_utils.COTA_CRED) - cmdName = "addCredential" - end local userIdx = device:get_field(lock_utils.USER_INDEX) local credIdx = device:get_field(lock_utils.CRED_INDEX) local status = "success" local elements = ib.info_block.data.elements if elements.status.value == DoorLock.types.DlStatus.SUCCESS then + -- Don't save user and credential for COTA + if cmdName == "addCota" then + device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) + return + end + -- If user is added also, update User table if userIdx == nil then local userType = device:get_field(lock_utils.USER_TYPE) - if userType == "remote" then - userType = "adminMember" - end add_user_to_table(device, elements.user_index.value, userType) end @@ -1117,27 +1128,15 @@ local function set_credential_response_handler(driver, device, ib, response) end -- Update commandResult - status = "occupied" - if elements.status.value == DoorLock.types.DlStatus.FAILURE then - status = "failure" - elseif elements.status.value == DoorLock.types.DlStatus.DUPLICATE then - status = "duplicate" - elseif elements.status.value == DoorLock.types.DlStatus.INVALID_FIELD then - status = "invalidCommand" - elseif elements.status.value == DoorLock.types.DlStatus.RESOURCE_EXHAUSTED then - status = "resourceExhausted" - elseif elements.status.value == DoorLock.types.DlStatus.NOT_FOUND then - status = "failure" - end + status = RESPONSE_STATUS_MAP[elements.status.value] device.log.warn(string.format("Failed to set credential: %s", status)) - -- Error Handling - if status == "duplicate" then + -- Set commandResult to error status + if status == "duplicate" and cmdName == "addCota" then generate_cota_cred_for_device(device) device.thread:call_with_delay(0, function(t) set_cota_credential(device, credIdx) end) return - end - if status ~= "occupied" then + elseif status ~= "occupied" then local result = { commandName = cmdName, statusCode = status @@ -1153,6 +1152,7 @@ local function set_credential_response_handler(driver, device, ib, response) device:set_field(lock_utils.BUSY_STATE, false, {persist = true}) return end + if elements.next_credential_index.value ~= nil then -- Get parameters local credIdx = elements.next_credential_index.value @@ -1296,6 +1296,9 @@ local function clear_credential_response_handler(driver, device, ib, response) local userIdx = 0 if status == "success" then userIdx = delete_credential_from_table(device, credIdx) + if userIdx == 0 then + userIdx = nil + end else device.log.warn(string.format("Failed to clear credential: %s", status)) end @@ -1327,9 +1330,11 @@ local function handle_set_week_day_schedule(driver, device, command) local scheduleIdx = command.args.scheduleIndex local userIdx = command.args.userIndex local schedule = command.args.schedule + local wDays = {} local scheduleBit = 0 for _, weekDay in ipairs(schedule.weekDays) do scheduleBit = scheduleBit + WEEK_DAY_MAP[weekDay] + table.insert(wDays, weekDay) end local startHour = schedule.startHour local startMinute = schedule.startMinute @@ -1358,7 +1363,11 @@ local function handle_set_week_day_schedule(driver, device, command) device:set_field(lock_utils.COMMAND_NAME, cmdName, {persist = true}) device:set_field(lock_utils.USER_INDEX, userIdx, {persist = true}) device:set_field(lock_utils.SCHEDULE_INDEX, scheduleIdx, {persist = true}) - device:set_field(lock_utils.SCHEDULE, schedule, {persist = true}) + device:set_field(lock_utils.SCHEDULE_WEEK_DAYS, wDays, {persist = true}) + device:set_field(lock_utils.SCHEDULE_START_HOUR, startHour, {persist = true}) + device:set_field(lock_utils.SCHEDULE_START_MINUTE, startMinute, {persist = true}) + device:set_field(lock_utils.SCHEDULE_END_HOUR, endHour, {persist = true}) + device:set_field(lock_utils.SCHEDULE_END_MINUTE, endMinute, {persist = true}) -- Send command local ep = device:component_to_endpoint(command.component) @@ -1384,7 +1393,18 @@ local function set_week_day_schedule_handler(driver, device, ib, response) local cmdName = device:get_field(lock_utils.COMMAND_NAME) local userIdx = device:get_field(lock_utils.USER_INDEX) local scheduleIdx = device:get_field(lock_utils.SCHEDULE_INDEX) - local schedule = device:get_field(lock_utils.SCHEDULE) + local days = device:get_field(lock_utils.SCHEDULE_WEEK_DAYS) + local sHour = device:get_field(lock_utils.SCHEDULE_START_HOUR) + local sMinute = device:get_field(lock_utils.SCHEDULE_START_MINUTE) + local eHour = device:get_field(lock_utils.SCHEDULE_END_HOUR) + local eMinute = device:get_field(lock_utils.SCHEDULE_END_MINUTE) + local schedule = { + weekDays = days, + startHour = sHour, + startMinute = sMinute, + endHour = eHour, + endMinute = eMinute + } local status = "success" if ib.status == DoorLock.types.DlStatus.FAILURE then status = "failure" @@ -1422,7 +1442,7 @@ end ----------------------------- local function handle_clear_week_day_schedule(driver, device, command) -- Get parameters - local cmdName = "clearWeekDaySchedule" + local cmdName = "clearWeekDaySchedules" local scheduleIdx = command.args.scheduleIndex local userIdx = command.args.userIndex From 966c64bae91f68775f0e25305135d49b5681334c Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Wed, 16 Oct 2024 04:03:09 +0900 Subject: [PATCH 19/20] Update test unit file for new door lock driver Signed-off-by: Hunsup Jung --- .../src/test/test_new_matter_lock.lua | 1438 +++++++++++++++-- 1 file changed, 1324 insertions(+), 114 deletions(-) diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua index 16fb94f94d..2d42e6cd57 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -19,6 +19,7 @@ local t_utils = require "integration_test.utils" local clusters = require "st.matter.clusters" local DoorLock = clusters.DoorLock local types = DoorLock.types +local lock_utils = require "lock_utils" local mock_device = test.mock_device.build_test_matter_device({ profile = t_utils.get_profile_definition("lock-user-pin-schedule.yml"), @@ -30,7 +31,7 @@ local mock_device = test.mock_device.build_test_matter_device({ { endpoint_id = 0, clusters = { - { cluster_id = clusters.Basic.ID, cluster_type = "SERVER" }, + { cluster_id = clusters.BasicInformation.ID, cluster_type = "SERVER" }, }, device_types = { { device_type_id = 0x0016, device_type_revision = 1 } -- RootNode @@ -43,7 +44,7 @@ local mock_device = test.mock_device.build_test_matter_device({ cluster_id = DoorLock.ID, cluster_type = "SERVER", cluster_revision = 1, - feature_map = 0x0001, --u32 bitmap + feature_map = 0x0181, -- PIN & USR & COTA } }, device_types = { @@ -72,6 +73,246 @@ end test.set_test_init_function(test_init) +test.register_coroutine_test( + "Assert profile applied over doConfigure", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + mock_device:expect_metadata_update({ profile = "lock-user-pin" }) + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Handle received OperatingMode(Normal, Vacation) from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.OperatingMode:build_test_report_data( + mock_device, 1, DoorLock.attributes.OperatingMode.NORMAL + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.remoteControlStatus.remoteControlEnabled("true", {visibility = {displayed = true}})) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({"lock", "unlock"}, {visibility = {displayed = false}})) + ) + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.OperatingMode:build_test_report_data( + mock_device, 1, DoorLock.attributes.OperatingMode.VACATION + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.remoteControlStatus.remoteControlEnabled("true", {visibility = {displayed = true}})) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({"lock", "unlock"}, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received OperatingMode(Privacy, No Remote Lock UnLock, Passage) from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.OperatingMode:build_test_report_data( + mock_device, 1, DoorLock.attributes.OperatingMode.PRIVACY + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.remoteControlStatus.remoteControlEnabled("false", {visibility = {displayed = true}})) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({}, {visibility = {displayed = false}})) + ) + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.OperatingMode:build_test_report_data( + mock_device, 1, DoorLock.attributes.OperatingMode.NO_REMOTE_LOCK_UNLOCK + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.remoteControlStatus.remoteControlEnabled("false", {visibility = {displayed = true}})) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({}, {visibility = {displayed = false}})) + ) + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.OperatingMode:build_test_report_data( + mock_device, 1, DoorLock.attributes.OperatingMode.PASSAGE + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.remoteControlStatus.remoteControlEnabled("false", {visibility = {displayed = true}})) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lock.supportedLockCommands({}, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received NumberOfTotalUsersSupported from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.NumberOfTotalUsersSupported:build_test_report_data( + mock_device, 1, DoorLock.attributes.NumberOfTotalUsersSupported(10) + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockUsers.totalUsersSupported(10, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received NumberOfPINUsersSupported from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.NumberOfPINUsersSupported:build_test_report_data( + mock_device, 1, DoorLock.attributes.NumberOfPINUsersSupported(10) + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockCredentials.pinUsersSupported(10, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received MinPINCodeLength from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.MinPINCodeLength:build_test_report_data( + mock_device, 1, DoorLock.attributes.MinPINCodeLength(6) + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockCredentials.minPinCodeLen(6, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received MaxPINCodeLength from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.MaxPINCodeLength:build_test_report_data( + mock_device, 1, DoorLock.attributes.MaxPINCodeLength(8) + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockCredentials.maxPinCodeLen(8, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received NumberOfWeekDaySchedulesSupportedPerUser from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser:build_test_report_data( + mock_device, 1, DoorLock.attributes.NumberOfWeekDaySchedulesSupportedPerUser(5) + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockSchedules.weekDaySchedulesPerUser(5, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received NumberOfYearDaySchedulesSupportedPerUser from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser:build_test_report_data( + mock_device, 1, DoorLock.attributes.NumberOfYearDaySchedulesSupportedPerUser(5) + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message("main", capabilities.lockSchedules.yearDaySchedulesPerUser(5, {visibility = {displayed = false}})) + ) + end +) + +test.register_coroutine_test( + "Handle received RequirePINforRemoteOperation(false) from Matter device.", + function() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.RequirePINforRemoteOperation:build_test_report_data( + mock_device, 1, DoorLock.attributes.RequirePINforRemoteOperation(false) + ), + } + ) + end +) + +test.register_coroutine_test( + "UnlockDoor uses cota cred when present", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + {capability = capabilities.lock.ID, command = "unlock", args = {}} + } + ) + mock_device:set_field(lock_utils.COTA_CRED, "654123") + test.socket.matter:__expect_send({ + mock_device.id, + clusters.DoorLock.server.commands.UnlockDoor(mock_device, 1, "654123"), + }) + end +) + +test.register_coroutine_test( + "LockDoor uses cota cred when present", function() + test.socket.capability:__queue_receive( + { + mock_device.id, + {capability = capabilities.lock.ID, command = "lock", args = {}} + } + ) + mock_device:set_field(lock_utils.COTA_CRED, "654123") + test.socket.matter:__expect_send({ + mock_device.id, + clusters.DoorLock.server.commands.LockDoor(mock_device, 1, "654123"), + }) + end +) + test.register_message_test( "Handle Lock command received from SmartThings.", { { @@ -191,7 +432,7 @@ test.register_message_test( } ) -local DlAlarmCode = DoorLock.types.DlAlarmCode +local AlarmCodeEnum = DoorLock.types.AlarmCodeEnum test.register_message_test( "Handle DoorLockAlarm event from Matter device.", { { @@ -200,7 +441,7 @@ test.register_message_test( message = { mock_device.id, DoorLock.events.DoorLockAlarm:build_test_event_report( - mock_device, 1, {alarm_code = DlAlarmCode.LOCK_JAMMED} + mock_device, 1, {alarm_code = AlarmCodeEnum.LOCK_JAMMED} ), }, }, @@ -218,7 +459,7 @@ test.register_message_test( message = { mock_device.id, DoorLock.events.DoorLockAlarm:build_test_event_report( - mock_device, 1, {alarm_code = DlAlarmCode.LOCK_FACTORY_RESET} + mock_device, 1, {alarm_code = AlarmCodeEnum.LOCK_FACTORY_RESET} ), }, }, @@ -236,7 +477,7 @@ test.register_message_test( message = { mock_device.id, DoorLock.events.DoorLockAlarm:build_test_event_report( - mock_device, 1, {alarm_code = DlAlarmCode.WRONG_CODE_ENTRY_LIMIT} + mock_device, 1, {alarm_code = AlarmCodeEnum.WRONG_CODE_ENTRY_LIMIT} ), }, }, @@ -254,7 +495,7 @@ test.register_message_test( message = { mock_device.id, DoorLock.events.DoorLockAlarm:build_test_event_report( - mock_device, 1, {alarm_code = DlAlarmCode.FRONT_ESCEUTCHEON_REMOVED} + mock_device, 1, {alarm_code = AlarmCodeEnum.FRONT_ESCEUTCHEON_REMOVED} ), }, }, @@ -272,7 +513,7 @@ test.register_message_test( message = { mock_device.id, DoorLock.events.DoorLockAlarm:build_test_event_report( - mock_device, 1, {alarm_code = DlAlarmCode.DOOR_FORCED_OPEN} + mock_device, 1, {alarm_code = AlarmCodeEnum.DOOR_FORCED_OPEN} ), }, }, @@ -318,138 +559,849 @@ test.register_message_test( {data = {method = "keypad", userIndex = 1}, state_change = true} ) ), - } - } -) - -test.register_coroutine_test( - "Added lifecycle event lock nocodes nobattery", - function() - test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) - - test.socket.capability:__expect_send( - mock_device:generate_test_message( - "main", - capabilities.lockAlarm.alarm.clear({state_change = true}) - ) - ) - end -) - -test.register_coroutine_test( - "Handle Add User command received from SmartThings.", - function() - test.socket.capability:__queue_receive({ - mock_device.id, - { - capability = capabilities.lockUsers.ID, - command = "addUser", - args = {"Guest1", "adminMember"} + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.LOCK, + operation_source = types.OperationSourceEnum.UNSPECIFIED, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), }, - }) - test.socket.matter:__expect_send({ - mock_device.id, - DoorLock.server.commands.GetUser( - mock_device, 1, - 1 -- user_index - ) - }) - test.wait_for_events() - test.socket.matter:__queue_receive({ - mock_device.id, - DoorLock.client.commands.GetUserResponse:build_test_command_response( - mock_device, 1, - 1, --user_index - nil, nil, nil, nil, nil, nil, nil, nil, nil + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.locked( + {data = {userIndex = 1}, state_change = true} + ) ), - }) - test.socket.matter:__expect_send({ - mock_device.id, - DoorLock.server.commands.SetUser( - mock_device, 1, - types.DataOperationTypeEnum.ADD, - 1, - "Guest1", - nil, - nil, - types.UserTypeEnum.UNRESTRICTED_USER, - nil - ) - }) - end -) - + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLATCH, + operation_source = types.OperationSourceEnum.MANUAL, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.locked( + {data = {method = "manual", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLOCK, + operation_source = types.OperationSourceEnum.PROPRIETARY_REMOTE, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.unlocked( + {data = {method = "proprietaryRemote", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.LOCK, + operation_source = types.OperationSourceEnum.AUTO, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.locked( + {data = {method = "auto", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLATCH, + operation_source = types.OperationSourceEnum.BUTTON, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.locked( + {data = {method = "button", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLOCK, + operation_source = types.OperationSourceEnum.SCHEDULE, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.unlocked( + {data = {userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.LOCK, + operation_source = types.OperationSourceEnum.REMOTE, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.locked( + {data = {method = "command", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLATCH, + operation_source = types.OperationSourceEnum.RFID, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.locked( + {data = {method = "rfid", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLOCK, + operation_source = types.OperationSourceEnum.BIOMETRIC, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.unlocked( + {data = {method = "keypad", userIndex = 1}, state_change = true} + ) + ), + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + DoorLock.events.LockOperation:build_test_event_report( + mock_device, 1, + { + lock_operation_type = types.LockOperationTypeEnum.UNLOCK, + operation_source = types.OperationSourceEnum.ALIRO, + user_index = 1, + fabric_index = 1, + source_node = 1 + } + ), + }, + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message( + "main", + capabilities.lock.lock.unlocked( + {data = {userIndex = 1}, state_change = true} + ) + ), + } + } +) + +test.register_coroutine_test( + "Added lifecycle event lock nocodes nobattery", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockAlarm.alarm.clear({state_change = true}) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Add User command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "addUser", + args = {"Guest1", "adminMember"} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.GetUser( + mock_device, 1, + 1 -- user_index + ) + }) + test.wait_for_events() + test.socket.matter:__queue_receive({ + mock_device.id, + DoorLock.client.commands.GetUserResponse:build_test_command_response( + mock_device, 1, + 1, --user_index + nil, nil, nil, nil, nil, nil, nil, nil, nil + ), + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.SetUser( + mock_device, 1, + types.DataOperationTypeEnum.ADD, + 1, + "Guest1", + nil, + nil, + types.UserTypeEnum.UNRESTRICTED_USER, + nil + ) + }) + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.SetUser:build_test_command_response( + mock_device, 1 + ) + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users({{userIndex = 1, userType = "adminMember"}}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="addUser", statusCode="success", userIndex=1}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Add User command received from SmartThings and commandResult is busy", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "addUser", + args = {"Guest1", "adminMember"} + }, + }) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="addUser", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Add User command received from SmartThings and commandResult is resourceExhausted", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "addUser", + args = {"Guest1", "adminMember"} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.GetUser( + mock_device, 1, + 1 -- user_index + ) + }) + test.wait_for_events() + test.socket.matter:__queue_receive({ + mock_device.id, + DoorLock.client.commands.GetUserResponse:build_test_command_response( + mock_device, 1, + 10, --user_index + nil, nil, + DoorLock.types.UserStatusEnum.OCCUPIED_ENABLED, --user_state + nil, nil, nil, nil, nil, nil + ), + }) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="addUser", statusCode="resourceExhausted", userIndex=10}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Update User command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "updateUser", + args = {1, "Guest1", "adminMember"} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.SetUser( + mock_device, 1, + types.DataOperationTypeEnum.MODIFY, + 1, + "Guest1", + nil, + nil, + types.UserTypeEnum.UNRESTRICTED_USER, + nil + ) + }) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.SetUser:build_test_command_response( + mock_device, 1 + ) + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="updateUser", statusCode="success", userIndex=1}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + test.wait_for_events() + end +) + +test.register_coroutine_test( + "Update User command received from SmartThings and send busy state", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "updateUser", + args = {1, "Guest1", "adminMember"} + }, + }) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="updateUser", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Delete User command received from SmartThings.", + function() + test.socket.capability:__queue_receive({ + mock_device.id, + { + capability = capabilities.lockUsers.ID, + command = "deleteUser", + args = {1} + }, + }) + test.socket.matter:__expect_send({ + mock_device.id, + DoorLock.server.commands.ClearUser( + mock_device, 1, + 1 + ) + }) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearUser:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.credentials({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="deleteUser", statusCode="success", userIndex=1}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + test.register_coroutine_test( - "Handle Update User command received from SmartThings.", + "Delete User command received from SmartThings and send busy state", function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) test.socket.capability:__queue_receive({ mock_device.id, { capability = capabilities.lockUsers.ID, - command = "updateUser", - args = {1, "Guest1", "adminMember"} + command = "deleteUser", + args = {1} }, }) - test.socket.matter:__expect_send({ - mock_device.id, - DoorLock.server.commands.SetUser( - mock_device, 1, - types.DataOperationTypeEnum.MODIFY, - 1, - "Guest1", - nil, - nil, - types.UserTypeEnum.UNRESTRICTED_USER, - nil + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="deleteUser", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) ) - }) + ) end ) test.register_coroutine_test( - "Handle delete User command received from SmartThings.", + "Handle Delete All Users command received from SmartThings.", function() test.socket.capability:__queue_receive({ mock_device.id, { capability = capabilities.lockUsers.ID, - command = "deleteUser", - args = {1} + command = "deleteAllUsers", + args = {} }, }) test.socket.matter:__expect_send({ mock_device.id, DoorLock.server.commands.ClearUser( mock_device, 1, - 1 + 0xFFFE ) }) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearUser:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.users({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.credentials({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="deleteAllUsers", statusCode="success", userIndex=65534}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) end ) test.register_coroutine_test( - "Handle delete all Users command received from SmartThings.", + "Delete All Users command received from SmartThings and send busy state", function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) test.socket.capability:__queue_receive({ mock_device.id, { - capability = capabilities.lockUsers.ID, - command = "deleteAllUsers", - args = {} - }, - }) - test.socket.matter:__expect_send({ - mock_device.id, - DoorLock.server.commands.ClearUser( - mock_device, 1, - 0xFFFE - ) - }) + capability = capabilities.lockUsers.ID, + command = "deleteAllUsers", + args = {} + }, + }) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockUsers.commandResult( + {commandName="deleteAllUsers", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Add Credential command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "addCredential", + args = {1, "adminMember", "pin", "654123"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + 1, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.SUCCESS, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.credentials( + {{credentialIndex=1, credentialType="pin", userIndex=1}}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="addCredential", credentialIndex=1, statusCode="success", userIndex=1}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Add Credential command received from SmartThings and commandResult is busy", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "addCredential", + args = {1, "adminMember", "pin", "654123"} + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="addCredential", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Add Credential command received from SmartThings and commandResult is invalidCommand", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "addCredential", + args = {1, "adminMember", "pin", "654123"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + 1, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.INVALID_FIELD, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="addCredential", statusCode="invalidCommand"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Add Credential command received from SmartThings and user_index is occupied", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "addCredential", + args = {1, "adminMember", "pin", "654123"} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + 1, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.OCCUPIED, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 2} + ), -- credential + "654123", -- credential_data + 1, -- user_index + nil, -- user_status + DoorLock.types.DlUserType.UNRESTRICTED_USER -- user_type + ), + } + ) + test.wait_for_events() end ) test.register_coroutine_test( - "Handle Add Credential command received from SmartThings.", + "Add Credential command received from SmartThings and commandResult is resourceExhausted", function() test.socket.capability:__queue_receive( { @@ -482,27 +1434,18 @@ test.register_coroutine_test( { mock_device.id, DoorLock.client.commands.SetCredentialResponse:build_test_command_response( - mock_device, 1, -- endpoint_id - DoorLock.types.DlStatus.SUCCESS, -- status + mock_device, 1, + DoorLock.types.DlStatus.OCCUPIED, -- status 1, -- user_index - 2 -- next_credential_index + nil -- next_credential_index ), } ) - test.socket.capability:__expect_send( - mock_device:generate_test_message( - "main", - capabilities.lockCredentials.credentials( - {{credentialIndex=1, credentialType="pin", userIndex=1}}, - {visibility={displayed=false}} - ) - ) - ) test.socket.capability:__expect_send( mock_device:generate_test_message( "main", capabilities.lockCredentials.commandResult( - {commandName="addCredential", credentialIndex=1, statusCode="success", userIndex=1}, + {commandName="addCredential", statusCode="resourceExhausted"}, {state_change=true, visibility={displayed=false}} ) ) @@ -544,7 +1487,7 @@ test.register_coroutine_test( { mock_device.id, DoorLock.client.commands.SetCredentialResponse:build_test_command_response( - mock_device, 1, -- endpoint_id + mock_device, 1, DoorLock.types.DlStatus.SUCCESS, -- status 1, -- user_index 2 -- next_credential_index @@ -563,6 +1506,32 @@ test.register_coroutine_test( end ) +test.register_coroutine_test( + "Update Credential command received from SmartThings and send busy state", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "updateCredential", + args = {1, 1, "pin", "654123"} + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="updateCredential", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + test.register_coroutine_test( "Handle Delete Credential command received from SmartThings.", function() @@ -587,6 +1556,56 @@ test.register_coroutine_test( ), } ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearCredential:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.credentials({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="deleteCredential", credentialIndex=1, statusCode="success"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Delete Credential command received from SmartThings and send busy state", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "deleteCredential", + args = {1, "pin"} + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="deleteCredential", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) end ) @@ -614,6 +1633,150 @@ test.register_coroutine_test( ), } ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearCredential:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.credentials({}, {visibility={displayed=false}}) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="deleteAllCredentials", credentialIndex=65534, statusCode="success"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Delete all Credentials command received from SmartThings and send busy state", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockCredentials.ID, + command = "deleteAllCredentials", + args = {"pin"} + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockCredentials.commandResult( + {commandName="deleteAllCredentials", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Handle Add Week Day Schedule command received from SmartThings.", + function() + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockSchedules.ID, + command = "setWeekDaySchedule", + args = {1, 1, {weekDays={"Monday"}, startHour=12, startMinute=30, endHour=17, endMinute=30}} + }, + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetWeekDaySchedule( + mock_device, 1, -- endpoint + 1, -- Week Day Schedule Index + 1, -- User Index + 2, -- Days Mask + 12, -- Start Hour + 30, -- Start Minute + 17, -- End Hour + 30 -- End Minute + ), + } + ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.SetWeekDaySchedule:build_test_command_response( + mock_device, 1 + ) + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.weekDaySchedules( + {{ + userIndex=1, + schedules={{ + scheduleIndex=1, + weekdays={"Monday"}, + startHour=12, + startMinute=30, + endHour=17, + endMinute=30 + }}, + }}, + {visibility={displayed=false}} + ) + ) + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.commandResult( + {commandName="setWeekDaySchedule", userIndex=1, scheduleIndex=1, statusCode="success"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Add Week Day Schedule command received from SmartThings and send busy state", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockSchedules.ID, + command = "setWeekDaySchedule", + args = {1, 1, {weekDays={"Monday"}, startHour=12, startMinute=30, endHour=17, endMinute=30}} + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.commandResult( + {commandName="setWeekDaySchedule", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) end ) @@ -643,6 +1806,53 @@ test.register_coroutine_test( ), } ) + test.wait_for_events() + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.server.commands.ClearWeekDaySchedule:build_test_command_response( + mock_device, 1 + ), + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.commandResult( + {commandName="clearWeekDaySchedules", userIndex = 1, scheduleIndex=1, statusCode="success"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) + end +) + +test.register_coroutine_test( + "Clear Week Day Schedule command received from SmartThings and send busy state", + function() + mock_device:set_field(lock_utils.BUSY_STATE, os.time(), {persist = true}) + test.socket.capability:__queue_receive( + { + mock_device.id, + { + capability = capabilities.lockSchedules.ID, + command = "clearWeekDaySchedules", + args = { + 1, -- user index + 1, -- schedule index + } + }, + } + ) + test.socket.capability:__expect_send( + mock_device:generate_test_message( + "main", + capabilities.lockSchedules.commandResult( + {commandName="clearWeekDaySchedules", statusCode="busy"}, + {state_change=true, visibility={displayed=false}} + ) + ) + ) end ) From 37709e807e3112146180af997d88615e5c8f90b3 Mon Sep 17 00:00:00 2001 From: Hunsup Jung Date: Thu, 17 Oct 2024 19:36:53 +0900 Subject: [PATCH 20/20] Fix COTA issue and add test unit for COTA Signed-off-by: Hunsup Jung --- .../matter-lock/src/new-matter-lock/init.lua | 5 +- .../src/test/test_new_matter_lock.lua | 146 ++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua index a089873d92..c4cefed6cf 100644 --- a/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua +++ b/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua @@ -306,7 +306,7 @@ end local function apply_cota_credentials_if_absent(device) if not device:get_field(lock_utils.COTA_CRED) then - --Process after all other info blocks have been dispatched to ensure MaxPINCodeLength has been processed + -- Process after all other info blocks have been dispatched to ensure MaxPINCodeLength has been processed device.thread:call_with_delay(0, function(t) generate_cota_cred_for_device(device) -- delay needed to allow test to override the random credential data @@ -1085,6 +1085,9 @@ local function set_credential_response_handler(driver, device, ib, response) local cmdName = device:get_field(lock_utils.COMMAND_NAME) local credData = device:get_field(lock_utils.CRED_DATA) + if cmdName == "addCota" then + credData = device:get_field(lock_utils.COTA_CRED) + end local userIdx = device:get_field(lock_utils.USER_INDEX) local credIdx = device:get_field(lock_utils.CRED_INDEX) local status = "success" diff --git a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua index 2d42e6cd57..836ad6fb7e 100644 --- a/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua +++ b/drivers/SmartThings/matter-lock/src/test/test_new_matter_lock.lua @@ -266,6 +266,152 @@ test.register_coroutine_test( end ) +test.register_coroutine_test( + "Handle received RequirePINforRemoteOperation(true) from Matter device.", + function() + test.socket.matter:__set_channel_ordering("relaxed") + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.RequirePINforRemoteOperation:build_test_report_data( + mock_device, 1, DoorLock.attributes.RequirePINforRemoteOperation(true) + ), + } + ) + test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") + test.mock_time.advance_time(1) + test.wait_for_events() + mock_device:set_field(lock_utils.COTA_CRED, "654123", {persist = true}) --overwrite random cred for test expectation + test.timer.__create_and_queue_test_time_advance_timer(3, "oneshot") + + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + nil, -- user_index + DoorLock.types.UserStatusEnum.OCCUPIED_ENABLED, -- user_status + DoorLock.types.UserTypeEnum.REMOTE_ONLY_USER -- user_type + ), + } + ) + test.mock_time.advance_time(1) + test.wait_for_events() + + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.OCCUPIED, -- status + nil, -- user_index + 2 -- next_credential_index + ), + } + ) + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 2} + ), -- credential + "654123", -- credential_data + nil, -- user_index + nil, -- user_status + DoorLock.types.UserTypeEnum.REMOTE_ONLY_USER -- user_type + ), + } + ) + end +) + +test.register_coroutine_test( +"Handle for duplicated pincode during COTA setting", +function() + test.socket.matter:__set_channel_ordering("relaxed") + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.attributes.RequirePINforRemoteOperation:build_test_report_data( + mock_device, 1, DoorLock.attributes.RequirePINforRemoteOperation(true) + ), + } + ) + test.timer.__create_and_queue_test_time_advance_timer(2, "oneshot") + test.mock_time.advance_time(1) + test.wait_for_events() + mock_device:set_field(lock_utils.COTA_CRED, "654123", {persist = true}) --overwrite random cred for test expectation + test.timer.__create_and_queue_test_time_advance_timer(3, "oneshot") + + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + nil, -- user_index + DoorLock.types.UserStatusEnum.OCCUPIED_ENABLED, -- user_status + DoorLock.types.UserTypeEnum.REMOTE_ONLY_USER -- user_type + ), + } + ) + test.mock_time.advance_time(1) + test.wait_for_events() + + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + + test.socket.matter:__queue_receive( + { + mock_device.id, + DoorLock.client.commands.SetCredentialResponse:build_test_command_response( + mock_device, 1, + DoorLock.types.DlStatus.DUPLICATE, -- status + 1, -- user_index + 2 -- next_credential_index + ), + } + ) + test.timer.__create_and_queue_test_time_advance_timer(11, "oneshot") + test.mock_time.advance_time(10) --trigger remote pin handling + test.wait_for_events() + mock_device:set_field(lock_utils.COTA_CRED, "654123", {persist = true}) --overwrite random cred for test expectation + test.timer.__create_and_queue_test_time_advance_timer(3, "oneshot") + + test.socket.matter:__expect_send( + { + mock_device.id, + DoorLock.server.commands.SetCredential( + mock_device, 1, -- endpoint + DoorLock.types.DataOperationTypeEnum.ADD, -- operation_type + DoorLock.types.CredentialStruct( + {credential_type = DoorLock.types.CredentialTypeEnum.PIN, credential_index = 1} + ), -- credential + "654123", -- credential_data + nil, -- user_index + DoorLock.types.UserStatusEnum.OCCUPIED_ENABLED, -- user_status + DoorLock.types.UserTypeEnum.REMOTE_ONLY_USER -- user_type + ), + } + ) + test.mock_time.advance_time(1) + test.wait_for_events() +end +) + test.register_coroutine_test( "Handle received RequirePINforRemoteOperation(false) from Matter device.", function()