11import time
22from datetime import datetime , timezone , timedelta
33from seamapi .types import (
4+ AbstractUnmanagedAccessCodes ,
5+ UnmanagedAccessCode ,
46 WaitForAccessCodeFailedException ,
57 AbstractAccessCodes ,
68 AccessCode ,
@@ -30,12 +32,16 @@ class AccessCodes(AbstractAccessCodes):
3032
3133 Methods
3234 -------
33- list(device)
35+ list(device, access_codes=None )
3436 Gets a list of access codes for a device
3537 get(access_code=None, device=None)
3638 Gets a certain access code of a device
3739 create(device, name=None, code=None, starts_at=None, ends_at=None, attempt_for_offline_device=None, wait_for_code=None, timeout=None, allow_external_modification=None, prefer_native_scheduling=None, use_backup_access_code_pool=None)
3840 Creates an access code on a device
41+ create_multiple(devices, name=None, code=None, starts_at=None, ends_at=None)
42+ Creates multiple access codes across devices
43+ update(access_code, device=None, name=None, code=None, starts_at=None, ends_at=None, type=None, allow_external_modification=None)
44+ Updates an access code on a device
3945 delete(access_code, device=None)
4046 Deletes an access code on a device
4147 pull_backup_access_code(access_code)
@@ -53,6 +59,7 @@ def __init__(self, seam: Seam):
5359 """
5460
5561 self .seam = seam
62+ self .unmanaged = UnmanagedAccessCodes (seam )
5663
5764 @report_error
5865 def list (
@@ -339,6 +346,7 @@ def update(
339346 starts_at : Optional [str ] = None ,
340347 ends_at : Optional [str ] = None ,
341348 type : Optional [str ] = None ,
349+ allow_external_modification : Optional [bool ] = None ,
342350 ) -> AccessCode :
343351 """Updates an access code on a device.
344352
@@ -358,6 +366,8 @@ def update(
358366 Time when access code ceases to be effective
359367 type : str, optional
360368 Access code type eg. ongoing or time_bound
369+ allow_external_modification : bool, optional:
370+ Allow external modifications of the access code e.g. through the lock provider's app. False by default.
361371
362372 Raises
363373 ------
@@ -383,6 +393,10 @@ def update(
383393 update_payload ["ends_at" ] = ends_at
384394 if type is not None :
385395 update_payload ["type" ] = type
396+ if allow_external_modification is not None :
397+ update_payload [
398+ "allow_external_modification"
399+ ] = allow_external_modification
386400
387401 res = self .seam .make_request (
388402 "POST" ,
@@ -470,3 +484,161 @@ def pull_backup_access_code(
470484 )
471485
472486 return AccessCode .from_dict (res ["backup_access_code" ])
487+
488+
489+ class UnmanagedAccessCodes (AbstractUnmanagedAccessCodes ):
490+ """
491+ A class used to retrieve unmanaged access code data
492+ through interaction with Seam API
493+
494+ ...
495+
496+ Attributes
497+ ----------
498+ seam : Seam
499+ Initial seam class
500+
501+ Methods
502+ -------
503+ get(device=None, access_code=None, code=None)
504+ Gets an unmanaged access code
505+ list(device)
506+ Gets a list of unmanaged access codes
507+ convert_to_managed(access_code, allow_external_modification=None)
508+ Converts an unmanaged access code to a managed one
509+ """
510+
511+ seam : Seam
512+
513+ def __init__ (self , seam : Seam ):
514+ """
515+ Parameters
516+ ----------
517+ seam : Seam
518+ Initial seam class
519+ """
520+
521+ self .seam = seam
522+
523+ @report_error
524+ def get (
525+ self ,
526+ access_code : Optional [Union [AccessCodeId , AccessCode ]] = None ,
527+ device : Optional [Union [DeviceId , Device ]] = None ,
528+ code : Optional [str ] = None ,
529+ ) -> UnmanagedAccessCode :
530+ """Gets an unmanaged access code.
531+
532+ Parameters
533+ ----------
534+ access_code : Union[AccessCodeId, UnmanagedAccessCode], optional
535+ Access Code ID or Access Code
536+ device : Union[DeviceId, Device], optional
537+ Device ID or Device
538+ code : str, optional
539+ Pin code of an access code
540+
541+ Raises
542+ ------
543+ Exception
544+ If the API request wasn't successful.
545+
546+ Returns
547+ ------
548+ An unmanaged access code.
549+ """
550+
551+ params = {}
552+
553+ if device :
554+ params ["device_id" ] = to_device_id (device )
555+ if access_code :
556+ params ["access_code_id" ] = to_access_code_id (access_code )
557+ if code :
558+ params ["code" ] = code
559+
560+ res = self .seam .make_request (
561+ "GET" ,
562+ "/access_codes/unmanaged/get" ,
563+ params = params ,
564+ )
565+ json_access_code = res ["access_code" ]
566+
567+ return UnmanagedAccessCode .from_dict (json_access_code )
568+
569+ @report_error
570+ def list (
571+ self ,
572+ device : Union [DeviceId , Device ],
573+ ) -> List [UnmanagedAccessCode ]:
574+ """Gets a list of unmanaged access codes.
575+
576+ Parameters
577+ ----------
578+ device : Union[DeviceId, Device], optional
579+ Device ID or Device
580+
581+ Raises
582+ ------
583+ Exception
584+ If the API request wasn't successful.
585+
586+ Returns
587+ ------
588+ A list of unmanaged access codes.
589+ """
590+
591+ res = self .seam .make_request (
592+ "GET" ,
593+ "/access_codes/unmanaged/list" ,
594+ params = {"device_id" : to_device_id (device )},
595+ )
596+ access_codes = res ["access_codes" ]
597+
598+ return [UnmanagedAccessCode .from_dict (ac ) for ac in access_codes ]
599+
600+ @report_error
601+ def convert_to_managed (
602+ self ,
603+ access_code : Union [AccessCodeId , UnmanagedAccessCode ],
604+ allow_external_modification : Optional [bool ] = None ,
605+ ) -> ActionAttempt :
606+ """Converts an unmanaged access code to a managed one.
607+
608+ Parameters
609+ ----------
610+ access_code : AccessCodeId or UnmanagedAccessCode
611+ Access Code ID or UnmanagedAccessCode
612+ allow_external_modification : bool
613+ Allow external modifications of the access code e.g. through the lock provider's app. False by default.
614+
615+ Raises
616+ ------
617+ Exception
618+ If the API request wasn't successful.
619+
620+ Returns
621+ ------
622+ ActionAttempt
623+ """
624+
625+ payload = {
626+ "access_code_id" : to_access_code_id (access_code ),
627+ }
628+
629+ if allow_external_modification is not None :
630+ payload [
631+ "allow_external_modification"
632+ ] = allow_external_modification
633+
634+ res = self .seam .make_request (
635+ "POST" ,
636+ "/access_codes/unmanaged/convert_to_managed" ,
637+ json = payload ,
638+ )
639+
640+ action_attempt = self .seam .action_attempts .poll_until_ready (
641+ res ["action_attempt" ]["action_attempt_id" ]
642+ )
643+
644+ return action_attempt
0 commit comments