When integrating with the Visionline system, ASSA ABLOY requires handling a set of common scenarios to meet their integration requirements. This topic explains some of these key scenarios.
Issue Guest Mobile Credentials
This section describes how to issue guest mobile credentials of various types.
guest_room_1 = seam.acs.entrances.list( acs_system_id=hotel_acs_system_id)[0]guest_room_2 = seam.acs.entrances.list( acs_system_id=hotel_acs_system_id)[0]first_acs_user = seam.acs.user.get(acs_user_id="xxx")# First credential should be an override credential.first_credential = seam.acs.credentials.create( acs_user_id=first_acs_user.acs_user_id credential_manager_acs_system_id="xxx" is_multi_phone_sync_credential=True, access_method="mobile_key", starts_at="2023-01-01 10:40:00.000", ends_at="2023-01-04 10:40:00.000", allowed_acs_entrance_ids=[ guest_room_1.acs_entrance_id, guest_room_2.acs_entrance_id, main_entrance.acs_entrance_id ], visionline_metadata={"cardFormat": "rfid48","cardType": "guest","label": "%ROOMNUM% - %SITENAME%","is_override_key": True })second_acs_user = seam.acs.user.get(acs_user_id="yyy")# Subsequent credentials should be joiners to the first credential.seam.acs.credentials.create( acs_user_id=second_acs_user.acs_user_id credential_manager_acs_system_id="xxx" is_multi_phone_sync_credential=True, access_method="mobile_key", starts_at="2023-01-01 10:40:00.000", ends_at="2023-01-04 10:40:00.000", allowed_acs_entrance_ids=[ guest_room_1.acs_entrance_id, guest_room_2.acs_entrance_id, main_entrance.acs_entrance_id ], visionline_metadata={"cardFormat": "rfid48","cardType": "guest","label": "%ROOMNUM% - %SITENAME%","joiner_acs_credential_ids": [first_credential.acs_credential_id] })
Issue Joiner Credentials
This section describes how to issue joiner credentials of various types.
Join to a Seam Mobile Credential
You can select either the multi-phone sync credential or its child credentials. Make sure to grab the acs_credential_id to include in the joiner_acs_credential_ids list.
joiners = [joiner_mobile_parent_sync_credential, joiner_mobile_child_credential]# Create the mobile credential.cred = seam.acs.credentials.create({ acs_user_id: "xxx", credential_manager_acs_system_id="xxs" is_multi_phone_sync_credential: True, access_method = "mobile_key", starts_at: "2023-01-01 10:40:00.000", ends_at: "2023-01-04 10:40:00.000", visionline_metadata: {"cardFormat": "rfid48","label": "%ROOMNUM% - %SITENAME%","joiner_acs_credential_ids": [ joiner.acs_credential_id for joiner in joiners ] }})
Join to a Plastic Card
joiners = [joiner_plastic_card_credential]# Create the mobile credential.cred = seam.acs.credentials.create({ acs_user_id: "xxx", credential_manager_acs_system_id="xxs" is_multi_phone_sync_credential: True, access_method = "mobile_key", starts_at: "2023-01-01 10:40:00.000", ends_at: "2023-01-04 10:40:00.000", visionline_metadata: {"cardFormat": "rfid48","label": "%ROOMNUM% - %SITENAME%","joiner_acs_credential_ids": [ joiner.acs_credential_id for joiner in joiners ] }})
Update Guest Mobile Credentials
Instead of updating the guest credential, you can issue a new joiner credential with the updated parameters. Seam automatically replaces the old credential with the new one.
# Creating a new mobile credential automatically revokes # the previous one.seam.acs.credentials.create({ acs_user_id: "xxx", credential_manager_acs_system_id="xxx" is_multi_phone_sync_credential: True, access_method = "mobile_key", starts_at: "2023-01-01 10:40:00.000", ends_at: "2023-01-04 10:40:00.000", visionline_metadata: {"cardFormat": "rfid48","label": "%ROOMNUM% - %SITENAME%","joiners": ["xxx", "yyy" ] }})
Revoke a Mobile Credential
Seam issues a discard command for the Visionline card. If deleting a multi-phone sync credential, Seam discards all of the credentials that were created underneath it.
To delete a user identity, you must first delete any ACS credentials and enrollment automations associated with the user identity. You must also deactivate any associated phones. Then, delete the user identity.
import asyncioasyncdefdelete_user_identity(user_identity_id):# Delete the client sessions. client_sessions =await seam.client_sessions.list( user_identity_id=user_identity_id )for session in client_sessions:await seam.client_sessions.delete( session_id=session['client_session_id'] )# Delete the ACS users and credentials. acs_users =await seam.acs.users.list( user_identity_id=user_identity_id )for acs_user in acs_users: credentials =await seam.acs.credentials.list( acs_user_id=acs_user['acs_user_id'] )for credential in credentials:await seam.acs.credentials.delete( acs_credential_id=credential['acs_credential_id'] )await asyncio.gather(*[wait_for_acs_credential_deleted(credential) for credential in credentials ])await seam.acs.users.delete( acs_user_id=acs_user['acs_user_id'] )await asyncio.gather(*[wait_for_acs_user_deleted(acs_user) for acs_user in acs_users ])# Delete the enrollment automations. enrollment_automations =await seam.user_identities.enrollment_automations.list( user_identity_id=user_identity_id )for automation in enrollment_automations:await seam.user_identities.enrollment_automations.delete( enrollment_automation_id=automation['enrollment_automation_id'] )await asyncio.gather(*[wait_for_enrollment_automation_deleted(automation) for automation in enrollment_automations ])# Delete the phones. phones =await seam.phones.list( owner_user_identity_id=user_identity_id )for phone in phones:await seam.phones.deactivate( device_id=phone['device_id'] )await asyncio.gather(*[wait_for_phone_deactivated(phone) for phone in phones ])# Finally, delete the user identity.await seam.user_identities.delete( user_identity_id=user_identity_id )# Helper functions for waiting on deletion eventsasyncdefwait_for_event(event_type,event_filter):whileTrue: events =await seam.events.list(event_type=event_type)ifany(event_filter(event) for event in events):breakasyncdefwait_for_acs_user_deleted(acs_user):awaitwait_for_event('acs_user.deleted',lambdaevent: 'acs_user_id'in event and event.acs_user_id == acs_user.acs_user_id )asyncdefwait_for_enrollment_automation_deleted(enrollment_automation):awaitwait_for_event('enrollment_automation.deleted',lambdaevent: 'enrollment_automation_id'in event and event.enrollment_automation_id == enrollment_automation.enrollment_automation_id )asyncdefwait_for_acs_credential_deleted(acs_credential):awaitwait_for_event('acs_credential.deleted',lambdaevent: 'acs_credential_id'in event and event.acs_credential_id == acs_credential.acs_credential_id )awaitdelete_user_identity("xxx")