diff --git a/package-lock.json b/package-lock.json index 178c4443..ea6c8aa3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "@seamapi/blueprint": "^1.12.0", "@seamapi/fake-seam-connect": "2.0.6", "@seamapi/smith": "^1.1.0", - "@seamapi/types": "1.1096.0", + "@seamapi/types": "1.1113.0", "change-case": "^5.4.4", "prettier": "^3.2.5" }, @@ -853,9 +853,9 @@ } }, "node_modules/@seamapi/types": { - "version": "1.1096.0", - "resolved": "https://registry.npmjs.org/@seamapi/types/-/types-1.1096.0.tgz", - "integrity": "sha512-JMfk6KOq/U7l3InqXZRKLDrZ+OM/5Vfc+kaeZfkWwXPchBKn7nKBiJgEHQJ6V1BIycelFX+qsUXDju3XHoVN+g==", + "version": "1.1113.0", + "resolved": "https://registry.npmjs.org/@seamapi/types/-/types-1.1113.0.tgz", + "integrity": "sha512-lkOl4x/2kPppPp5p2PoT2ohAI3pnKziv1przlDZscNnkVed0sDu7DZa+B4kyJ6YFmrPrbLNsf8i1c0D+Aw8byQ==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 62f2b4c1..d5af60ce 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@seamapi/blueprint": "^1.12.0", "@seamapi/fake-seam-connect": "2.0.6", "@seamapi/smith": "^1.1.0", - "@seamapi/types": "1.1096.0", + "@seamapi/types": "1.1113.0", "change-case": "^5.4.4", "prettier": "^3.2.5" } diff --git a/seam/resources/__init__.py b/seam/resources/__init__.py index b765dd08..dee899c4 100644 --- a/seam/resources/__init__.py +++ b/seam/resources/__init__.py @@ -53,6 +53,24 @@ ConfigureAutoLockSuccessActionAttempt, ConfigureAutoLockPendingActionAttempt, ConfigureAutoLockErrorActionAttempt, + ConvertAccessCodeToManagedSuccessActionAttempt, + ConvertAccessCodeToManagedPendingActionAttempt, + ConvertAccessCodeToManagedErrorActionAttempt, + SetSpeakerVolumeSuccessActionAttempt, + SetSpeakerVolumePendingActionAttempt, + SetSpeakerVolumeErrorActionAttempt, + SetSpeakerMuteSuccessActionAttempt, + SetSpeakerMutePendingActionAttempt, + SetSpeakerMuteErrorActionAttempt, + PauseSpeakerPlaybackSuccessActionAttempt, + PauseSpeakerPlaybackPendingActionAttempt, + PauseSpeakerPlaybackErrorActionAttempt, + ResumeSpeakerPlaybackSuccessActionAttempt, + ResumeSpeakerPlaybackPendingActionAttempt, + ResumeSpeakerPlaybackErrorActionAttempt, + PlaySpeakerChimeSuccessActionAttempt, + PlaySpeakerChimePendingActionAttempt, + PlaySpeakerChimeErrorActionAttempt, SyncAccessCodesSuccessActionAttempt, SyncAccessCodesPendingActionAttempt, SyncAccessCodesErrorActionAttempt, @@ -89,6 +107,12 @@ SimulateManualLockViaKeypadActionAttempt, PushThermostatProgramsActionAttempt, ConfigureAutoLockActionAttempt, + ConvertAccessCodeToManagedActionAttempt, + SetSpeakerVolumeActionAttempt, + SetSpeakerMuteActionAttempt, + PauseSpeakerPlaybackActionAttempt, + ResumeSpeakerPlaybackActionAttempt, + PlaySpeakerChimeActionAttempt, SyncAccessCodesActionAttempt, CreateAccessCodeActionAttempt, DeleteAccessCodeActionAttempt, diff --git a/seam/resources/access_grant.py b/seam/resources/access_grant.py index db9a5498..968c69c5 100644 --- a/seam/resources/access_grant.py +++ b/seam/resources/access_grant.py @@ -84,6 +84,29 @@ def from_dict(cls, d: Any): missing_device_ids=d.get("missing_device_ids", None), ) + @dataclass + class AccessNotProvisionedError(ResourceMapping): + """Indicates that the access system rejected the access that Seam tried to set up for this access grant, so its credentials cannot open the affected entrances. For example, a hotel room may already be reserved or checked in for another guest. The message contains the reason that the access system gave. Seam keeps retrying, and this error clears automatically once the access system accepts the access. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["access_not_provisioned"] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + message=d.get("message", None), + ) + @dataclass class UpdatingSpacesPendingMutation(ResourceMapping): """Seam is in the process of updating the devices/spaces associated with this access grant. @@ -324,12 +347,12 @@ class FailedDevices(ResourceMapping): :ivar device_id: Device whose access code could not be revoked. - :ivar error_code: Reason the access code could not be revoked (e.g. ``offline_access_code_not_revocable``). + :ivar error_code: Reason the access code could not be revoked. :ivar message: Human-readable description of why revocation failed.""" device_id: str - error_code: str + error_code: Literal["offline_access_code_not_revocable"] message: str @classmethod @@ -479,9 +502,10 @@ def from_dict(cls, d: Any): warning_code=d.get("warning_code", None), ) - Errors = Union[CannotCreateRequestedAccessMethodsError] + Errors = Union[CannotCreateRequestedAccessMethodsError, AccessNotProvisionedError] _ErrorsVariants = { "cannot_create_requested_access_methods": CannotCreateRequestedAccessMethodsError, + "access_not_provisioned": AccessNotProvisionedError, } PendingMutations = Union[ diff --git a/seam/resources/access_method.py b/seam/resources/access_method.py index a95bdf87..47cf56cd 100644 --- a/seam/resources/access_method.py +++ b/seam/resources/access_method.py @@ -41,7 +41,7 @@ class AccessMethod: :ivar is_ready_for_assignment: Indicates whether the access method is ready for card assignment. This is true when the access method is in card mode, has not yet been issued, and the system supports credential assignment. - :ivar is_ready_for_encoding: Indicates whether the access method is ready to be encoded. This is true when the credential has been created and the card has not yet been issued. + :ivar is_ready_for_encoding: Indicates whether the access method is ready to be encoded. This is true when the card has not yet been issued and the access system has received all the access the card needs. While it is false, ``pending_mutations`` contains ``waiting_for_access_on_acs_system``. :ivar issued_at: Date and time at which the access method was issued. @@ -76,6 +76,29 @@ def from_dict(cls, d: Any): message=d.get("message", None), ) + @dataclass + class AccessNotProvisionedError(ResourceMapping): + """Indicates that the access system rejected the access that Seam tried to set up for this access method, so its credential cannot open the affected entrances, even after it is issued. For example, a hotel room may already be reserved or checked in for another guest. The message contains the reason that the access system gave. Seam keeps retrying, and this error clears automatically once the access system accepts the access. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["access_not_provisioned"] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + message=d.get("message", None), + ) + @dataclass class ProvisioningAccessPendingMutation(ResourceMapping): """Seam is in the process of provisioning access for this access method on new devices. @@ -270,6 +293,29 @@ def from_dict(cls, d: Any): to=cls.To.from_dict(d.get("to")) if d.get("to") is not None else None, ) + @dataclass + class WaitingForAccessOnAcsSystemPendingMutation(ResourceMapping): + """The access system has not yet received all the access this card needs. A card encoded now would carry only the access the system already has, so wait until this clears before encoding. + + :ivar created_at: Date and time at which the mutation was created. + + :ivar message: Detailed description of the mutation. + + :ivar mutation_code: Mutation code to indicate that the access system has not yet received all the access this card needs, so the card is not ready to be encoded. + """ + + created_at: str + message: str + mutation_code: Literal["waiting_for_access_on_acs_system"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + mutation_code=d.get("mutation_code", None), + ) + @dataclass class BeingDeletedWarning(ResourceMapping): """Indicates that the `access method `_ is being deleted. @@ -412,20 +458,23 @@ def from_dict(cls, d: Any): warning_code=d.get("warning_code", None), ) - Errors = Union[FailedToIssueError] + Errors = Union[FailedToIssueError, AccessNotProvisionedError] _ErrorsVariants = { "failed_to_issue": FailedToIssueError, + "access_not_provisioned": AccessNotProvisionedError, } PendingMutations = Union[ ProvisioningAccessPendingMutation, RevokingAccessPendingMutation, UpdatingAccessTimesPendingMutation, + WaitingForAccessOnAcsSystemPendingMutation, ] _PendingMutationsVariants = { "provisioning_access": ProvisioningAccessPendingMutation, "revoking_access": RevokingAccessPendingMutation, "updating_access_times": UpdatingAccessTimesPendingMutation, + "waiting_for_access_on_acs_system": WaitingForAccessOnAcsSystemPendingMutation, } Warnings = Union[ diff --git a/seam/resources/acs_entrance.py b/seam/resources/acs_entrance.py index 13426755..038e8098 100644 --- a/seam/resources/acs_entrance.py +++ b/seam/resources/acs_entrance.py @@ -236,8 +236,8 @@ def from_dict(cls, d: Any): ) @dataclass - class Errors(ResourceMapping): - """Errors associated with the `entrance `_. + class EntranceRemovedError(ResourceMapping): + """Indicates that the `entrance `_ was removed from the connected account, so Seam can no longer sync it. :ivar created_at: Date and time at which Seam created the error. @@ -247,7 +247,7 @@ class Errors(ResourceMapping): """ created_at: str - error_code: str + error_code: Literal["entrance_removed"] message: str @classmethod @@ -546,6 +546,11 @@ def from_dict(cls, d: Any): warning_code=d.get("warning_code", None), ) + Errors = Union[EntranceRemovedError] + _ErrorsVariants = { + "entrance_removed": EntranceRemovedError, + } + Warnings = Union[ SaltoKsEntranceAccessCodeSupportRemovedWarning, EntranceSharesZoneWarning, @@ -636,7 +641,10 @@ def from_dict(cls, d: Any): if d.get("dormakaba_community_metadata") is not None else None ), - errors=[cls.Errors.from_dict(i) for i in d.get("errors") or []], + errors=[ + _from_discriminated_dict(i, cls._ErrorsVariants, "error_code") + for i in d.get("errors") or [] + ], hotek_metadata=( cls.HotekMetadata.from_dict(d.get("hotek_metadata")) if d.get("hotek_metadata") is not None diff --git a/seam/resources/acs_system.py b/seam/resources/acs_system.py index 485d614c..3af7551a 100644 --- a/seam/resources/acs_system.py +++ b/seam/resources/acs_system.py @@ -161,6 +161,29 @@ def from_dict(cls, d: Any): message=d.get("message", None), ) + @dataclass + class UserLicenseLimitReachedError(ResourceMapping): + """Indicates that the access control system has reached the maximum number of users its license allows, so Seam cannot create new users on it and access for new guests is not provisioned. Remove unused users from the access control system or increase its license. The error clears once Seam can create users again. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["user_license_limit_reached"] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + message=d.get("message", None), + ) + @dataclass class InsufficientPermissionsError(ResourceMapping): """Indicates that the provider's system backing this `access control system `_ is not letting Seam act on it, so access cannot be managed until this is resolved. The error message says which of two causes applies. Either Seam's integration user does not have sufficient permissions on the provider's system, or has been suspended there: grant the integration user the required permissions in the provider's system, or reauthorize the connected account in Seam. Or the provider account or site does not have a valid subscription with the provider: set up or renew that subscription with the provider. @@ -417,6 +440,7 @@ def from_dict(cls, d: Any): BridgeDisconnectedError, VisionlineInstanceUnreachableError, SaltoKsSubscriptionLimitExceededError, + UserLicenseLimitReachedError, InsufficientPermissionsError, AcsSystemDisconnectedError, AccountDisconnectedError, @@ -428,6 +452,7 @@ def from_dict(cls, d: Any): "bridge_disconnected": BridgeDisconnectedError, "visionline_instance_unreachable": VisionlineInstanceUnreachableError, "salto_ks_subscription_limit_exceeded": SaltoKsSubscriptionLimitExceededError, + "user_license_limit_reached": UserLicenseLimitReachedError, "insufficient_permissions": InsufficientPermissionsError, "acs_system_disconnected": AcsSystemDisconnectedError, "account_disconnected": AccountDisconnectedError, diff --git a/seam/resources/action_attempt.py b/seam/resources/action_attempt.py index a745735c..87bd09f1 100644 --- a/seam/resources/action_attempt.py +++ b/seam/resources/action_attempt.py @@ -1772,7 +1772,7 @@ class Result(ResourceMapping): :ivar is_ready_for_assignment: Indicates whether the access method is ready for card assignment. This is true when the access method is in card mode, has not yet been issued, and the system supports credential assignment. - :ivar is_ready_for_encoding: Indicates whether the access method is ready to be encoded. This is true when the credential has been created and the card has not yet been issued. + :ivar is_ready_for_encoding: Indicates whether the access method is ready to be encoded. This is true when the card has not yet been issued and the access system has received all the access the card needs. While it is false, ``pending_mutations`` contains ``waiting_for_access_on_acs_system``. :ivar issued_at: Date and time at which the access method was issued. @@ -1797,7 +1797,7 @@ class Errors(ResourceMapping): """ created_at: str - error_code: Literal["failed_to_issue"] + error_code: Literal["failed_to_issue", "access_not_provisioned"] message: str @classmethod @@ -1818,7 +1818,7 @@ class PendingMutations(ResourceMapping): :ivar message: Detailed description of the mutation. - :ivar mutation_code: Mutation code to indicate that Seam is in the process of updating the access times for this access method. + :ivar mutation_code: Mutation code to indicate that the access system has not yet received all the access this card needs, so the card is not ready to be encoded. :ivar to: New access time configuration.""" @@ -1862,7 +1862,10 @@ def from_dict(cls, d: Any): from_: Optional[From] message: str mutation_code: Literal[ - "provisioning_access", "revoking_access", "updating_access_times" + "provisioning_access", + "revoking_access", + "updating_access_times", + "waiting_for_access_on_acs_system", ] to: Optional[To] @@ -1940,33 +1943,755 @@ def from_dict(cls, d: Any): @classmethod def from_dict(cls, d: Any): - return cls( - access_method_id=d.get("access_method_id", None), - client_session_token=d.get("client_session_token", None), - code=d.get("code", None), - created_at=d.get("created_at", None), - customization_profile_id=d.get("customization_profile_id", None), - display_name=d.get("display_name", None), - display_status=d.get("display_status", None), - errors=[cls.Errors.from_dict(i) for i in d.get("errors") or []], - instant_key_url=d.get("instant_key_url", None), - is_assignment_required=d.get("is_assignment_required", None), - is_encoding_required=d.get("is_encoding_required", None), - is_issued=d.get("is_issued", None), - is_ready_for_assignment=d.get("is_ready_for_assignment", None), - is_ready_for_encoding=d.get("is_ready_for_encoding", None), - issued_at=d.get("issued_at", None), - mode=d.get("mode", None), - pending_mutations=[ - cls.PendingMutations.from_dict(i) - for i in d.get("pending_mutations") or [] - ], - warnings=[cls.Warnings.from_dict(i) for i in d.get("warnings") or []], - workspace_id=d.get("workspace_id", None), - ) + return cls( + access_method_id=d.get("access_method_id", None), + client_session_token=d.get("client_session_token", None), + code=d.get("code", None), + created_at=d.get("created_at", None), + customization_profile_id=d.get("customization_profile_id", None), + display_name=d.get("display_name", None), + display_status=d.get("display_status", None), + errors=[cls.Errors.from_dict(i) for i in d.get("errors") or []], + instant_key_url=d.get("instant_key_url", None), + is_assignment_required=d.get("is_assignment_required", None), + is_encoding_required=d.get("is_encoding_required", None), + is_issued=d.get("is_issued", None), + is_ready_for_assignment=d.get("is_ready_for_assignment", None), + is_ready_for_encoding=d.get("is_ready_for_encoding", None), + issued_at=d.get("issued_at", None), + mode=d.get("mode", None), + pending_mutations=[ + cls.PendingMutations.from_dict(i) + for i in d.get("pending_mutations") or [] + ], + warnings=[cls.Warnings.from_dict(i) for i in d.get("warnings") or []], + workspace_id=d.get("workspace_id", None), + ) + + action_attempt_id: str + action_type: Literal["ASSIGN_CREDENTIAL"] + error: None + result: Result + status: Literal["success"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=cls.Result.from_dict(d.get("result") or {}), + status=d.get("status", None), + ) + + +@dataclass +class AssignCredentialPendingActionAttempt: + """Assigning a credential to an access method is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of assigning a pre-registered card credential to an access method. + + :ivar error: + + :ivar result: Result of assigning a credential. If successful, includes the updated access method with the assigned credential. + + :ivar status:""" + + action_attempt_id: str + action_type: Literal["ASSIGN_CREDENTIAL"] + error: None + result: None + status: Literal["pending"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class AssignCredentialErrorActionAttempt: + """Assigning a credential to an access method is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of assigning a pre-registered card credential to an access method. + + :ivar error: + + :ivar result: Result of assigning a credential. If successful, includes the updated access method with the assigned credential. + + :ivar status:""" + + @dataclass + class Error(ResourceMapping): + """ + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + + :ivar type: Error type to indicate that no matching credential was found.""" + + message: str + type: Literal[ + "uncategorized_error", "action_attempt_expired", "credential_not_found" + ] + + @classmethod + def from_dict(cls, d: Any): + return cls( + message=d.get("message", None), + type=d.get("type", None), + ) + + action_attempt_id: str + action_type: Literal["ASSIGN_CREDENTIAL"] + error: Error + result: None + status: Literal["error"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=cls.Error.from_dict(d.get("error") or {}), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class ResetSandboxWorkspaceSuccessActionAttempt: + """Resetting a sandbox workspace is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of resetting a sandbox workspace. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Result(ResourceMapping): + """Result of the action.""" + + @classmethod + def from_dict(cls, d: Any): + # pylint: disable=unused-argument + return cls() + + action_attempt_id: str + action_type: Literal["RESET_SANDBOX_WORKSPACE"] + error: None + result: Result + status: Literal["success"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=cls.Result.from_dict(d.get("result") or {}), + status=d.get("status", None), + ) + + +@dataclass +class ResetSandboxWorkspacePendingActionAttempt: + """Resetting a sandbox workspace is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of resetting a sandbox workspace. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + action_attempt_id: str + action_type: Literal["RESET_SANDBOX_WORKSPACE"] + error: None + result: None + status: Literal["pending"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class ResetSandboxWorkspaceErrorActionAttempt: + """Resetting a sandbox workspace is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of resetting a sandbox workspace. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Error(ResourceMapping): + """Error associated with the action. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + + :ivar type: Type of the error.""" + + message: str + type: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + message=d.get("message", None), + type=d.get("type", None), + ) + + action_attempt_id: str + action_type: Literal["RESET_SANDBOX_WORKSPACE"] + error: Error + result: None + status: Literal["error"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=cls.Error.from_dict(d.get("error") or {}), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class SetFanModeSuccessActionAttempt: + """Setting the fan mode is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of setting the fan mode on a thermostat. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Result(ResourceMapping): + """Result of the action.""" + + @classmethod + def from_dict(cls, d: Any): + # pylint: disable=unused-argument + return cls() + + action_attempt_id: str + action_type: Literal["SET_FAN_MODE"] + error: None + result: Result + status: Literal["success"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=cls.Result.from_dict(d.get("result") or {}), + status=d.get("status", None), + ) + + +@dataclass +class SetFanModePendingActionAttempt: + """Setting the fan mode is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of setting the fan mode on a thermostat. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + action_attempt_id: str + action_type: Literal["SET_FAN_MODE"] + error: None + result: None + status: Literal["pending"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class SetFanModeErrorActionAttempt: + """Setting the fan mode is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of setting the fan mode on a thermostat. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Error(ResourceMapping): + """Error associated with the action. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + + :ivar type: Type of the error.""" + + message: str + type: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + message=d.get("message", None), + type=d.get("type", None), + ) + + action_attempt_id: str + action_type: Literal["SET_FAN_MODE"] + error: Error + result: None + status: Literal["error"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=cls.Error.from_dict(d.get("error") or {}), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class SetHvacModeSuccessActionAttempt: + """Setting the HVAC mode is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of setting the HVAC mode on a thermostat. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Result(ResourceMapping): + """Result of the action.""" + + @classmethod + def from_dict(cls, d: Any): + # pylint: disable=unused-argument + return cls() + + action_attempt_id: str + action_type: Literal["SET_HVAC_MODE"] + error: None + result: Result + status: Literal["success"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=cls.Result.from_dict(d.get("result") or {}), + status=d.get("status", None), + ) + + +@dataclass +class SetHvacModePendingActionAttempt: + """Setting the HVAC mode is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of setting the HVAC mode on a thermostat. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + action_attempt_id: str + action_type: Literal["SET_HVAC_MODE"] + error: None + result: None + status: Literal["pending"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class SetHvacModeErrorActionAttempt: + """Setting the HVAC mode is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of setting the HVAC mode on a thermostat. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Error(ResourceMapping): + """Error associated with the action. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + + :ivar type: Type of the error.""" + + message: str + type: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + message=d.get("message", None), + type=d.get("type", None), + ) + + action_attempt_id: str + action_type: Literal["SET_HVAC_MODE"] + error: Error + result: None + status: Literal["error"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=cls.Error.from_dict(d.get("error") or {}), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class ActivateClimatePresetSuccessActionAttempt: + """Activating a climate preset is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of a climate preset activation. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Result(ResourceMapping): + """Result of the action.""" + + @classmethod + def from_dict(cls, d: Any): + # pylint: disable=unused-argument + return cls() + + action_attempt_id: str + action_type: Literal["ACTIVATE_CLIMATE_PRESET"] + error: None + result: Result + status: Literal["success"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=cls.Result.from_dict(d.get("result") or {}), + status=d.get("status", None), + ) + + +@dataclass +class ActivateClimatePresetPendingActionAttempt: + """Activating a climate preset is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of a climate preset activation. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + action_attempt_id: str + action_type: Literal["ACTIVATE_CLIMATE_PRESET"] + error: None + result: None + status: Literal["pending"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class ActivateClimatePresetErrorActionAttempt: + """Activating a climate preset is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of a climate preset activation. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Error(ResourceMapping): + """Error associated with the action. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + + :ivar type: Type of the error.""" + + message: str + type: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + message=d.get("message", None), + type=d.get("type", None), + ) + + action_attempt_id: str + action_type: Literal["ACTIVATE_CLIMATE_PRESET"] + error: Error + result: None + status: Literal["error"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=cls.Error.from_dict(d.get("error") or {}), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class ActivateWeeklyProgramSuccessActionAttempt: + """Activating the weekly program is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of returning a thermostat to its weekly program. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Result(ResourceMapping): + """Result of the action.""" + + @classmethod + def from_dict(cls, d: Any): + # pylint: disable=unused-argument + return cls() + + action_attempt_id: str + action_type: Literal["ACTIVATE_WEEKLY_PROGRAM"] + error: None + result: Result + status: Literal["success"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=cls.Result.from_dict(d.get("result") or {}), + status=d.get("status", None), + ) + + +@dataclass +class ActivateWeeklyProgramPendingActionAttempt: + """Activating the weekly program is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of returning a thermostat to its weekly program. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + action_attempt_id: str + action_type: Literal["ACTIVATE_WEEKLY_PROGRAM"] + error: None + result: None + status: Literal["pending"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=d.get("error", None), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class ActivateWeeklyProgramErrorActionAttempt: + """Activating the weekly program is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of returning a thermostat to its weekly program. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Error(ResourceMapping): + """Error associated with the action. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + + :ivar type: Type of the error.""" + + message: str + type: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + message=d.get("message", None), + type=d.get("type", None), + ) + + action_attempt_id: str + action_type: Literal["ACTIVATE_WEEKLY_PROGRAM"] + error: Error + result: None + status: Literal["error"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + action_attempt_id=d.get("action_attempt_id", None), + action_type=d.get("action_type", None), + error=cls.Error.from_dict(d.get("error") or {}), + result=d.get("result", None), + status=d.get("status", None), + ) + + +@dataclass +class SimulateKeypadCodeEntrySuccessActionAttempt: + """Simulating a keypad code entry is pending. + + :ivar action_attempt_id: ID of the action attempt. + + :ivar action_type: Action attempt to track the status of simulating a keypad code entry. + + :ivar error: Error associated with the action. + + :ivar result: Result of the action. + + :ivar status:""" + + @dataclass + class Result(ResourceMapping): + """Result of the action.""" + + @classmethod + def from_dict(cls, d: Any): + # pylint: disable=unused-argument + return cls() action_attempt_id: str - action_type: Literal["ASSIGN_CREDENTIAL"] + action_type: Literal["SIMULATE_KEYPAD_CODE_ENTRY"] error: None result: Result status: Literal["success"] @@ -1983,21 +2708,21 @@ def from_dict(cls, d: Any): @dataclass -class AssignCredentialPendingActionAttempt: - """Assigning a credential to an access method is pending. +class SimulateKeypadCodeEntryPendingActionAttempt: + """Simulating a keypad code entry is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of assigning a pre-registered card credential to an access method. + :ivar action_type: Action attempt to track the status of simulating a keypad code entry. - :ivar error: + :ivar error: Error associated with the action. - :ivar result: Result of assigning a credential. If successful, includes the updated access method with the assigned credential. + :ivar result: Result of the action. :ivar status:""" action_attempt_id: str - action_type: Literal["ASSIGN_CREDENTIAL"] + action_type: Literal["SIMULATE_KEYPAD_CODE_ENTRY"] error: None result: None status: Literal["pending"] @@ -2014,31 +2739,29 @@ def from_dict(cls, d: Any): @dataclass -class AssignCredentialErrorActionAttempt: - """Assigning a credential to an access method is pending. +class SimulateKeypadCodeEntryErrorActionAttempt: + """Simulating a keypad code entry is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of assigning a pre-registered card credential to an access method. + :ivar action_type: Action attempt to track the status of simulating a keypad code entry. - :ivar error: + :ivar error: Error associated with the action. - :ivar result: Result of assigning a credential. If successful, includes the updated access method with the assigned credential. + :ivar result: Result of the action. :ivar status:""" @dataclass class Error(ResourceMapping): - """ + """Error associated with the action. :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. - :ivar type: Error type to indicate that no matching credential was found.""" + :ivar type: Type of the error.""" message: str - type: Literal[ - "uncategorized_error", "action_attempt_expired", "credential_not_found" - ] + type: str @classmethod def from_dict(cls, d: Any): @@ -2048,7 +2771,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["ASSIGN_CREDENTIAL"] + action_type: Literal["SIMULATE_KEYPAD_CODE_ENTRY"] error: Error result: None status: Literal["error"] @@ -2065,12 +2788,12 @@ def from_dict(cls, d: Any): @dataclass -class ResetSandboxWorkspaceSuccessActionAttempt: - """Resetting a sandbox workspace is pending. +class SimulateManualLockViaKeypadSuccessActionAttempt: + """Simulating a manual lock action using a keypad is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of resetting a sandbox workspace. + :ivar action_type: Action attempt to track the status of simulating a manual lock action using a keypad. :ivar error: Error associated with the action. @@ -2088,7 +2811,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["RESET_SANDBOX_WORKSPACE"] + action_type: Literal["SIMULATE_MANUAL_LOCK_VIA_KEYPAD"] error: None result: Result status: Literal["success"] @@ -2105,12 +2828,12 @@ def from_dict(cls, d: Any): @dataclass -class ResetSandboxWorkspacePendingActionAttempt: - """Resetting a sandbox workspace is pending. +class SimulateManualLockViaKeypadPendingActionAttempt: + """Simulating a manual lock action using a keypad is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of resetting a sandbox workspace. + :ivar action_type: Action attempt to track the status of simulating a manual lock action using a keypad. :ivar error: Error associated with the action. @@ -2119,7 +2842,7 @@ class ResetSandboxWorkspacePendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["RESET_SANDBOX_WORKSPACE"] + action_type: Literal["SIMULATE_MANUAL_LOCK_VIA_KEYPAD"] error: None result: None status: Literal["pending"] @@ -2136,12 +2859,12 @@ def from_dict(cls, d: Any): @dataclass -class ResetSandboxWorkspaceErrorActionAttempt: - """Resetting a sandbox workspace is pending. +class SimulateManualLockViaKeypadErrorActionAttempt: + """Simulating a manual lock action using a keypad is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of resetting a sandbox workspace. + :ivar action_type: Action attempt to track the status of simulating a manual lock action using a keypad. :ivar error: Error associated with the action. @@ -2168,7 +2891,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["RESET_SANDBOX_WORKSPACE"] + action_type: Literal["SIMULATE_MANUAL_LOCK_VIA_KEYPAD"] error: Error result: None status: Literal["error"] @@ -2185,12 +2908,12 @@ def from_dict(cls, d: Any): @dataclass -class SetFanModeSuccessActionAttempt: - """Setting the fan mode is pending. +class PushThermostatProgramsSuccessActionAttempt: + """Pushing thermostat weekly programs is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of setting the fan mode on a thermostat. + :ivar action_type: Action attempt to track the status of pushing thermostat programs. :ivar error: Error associated with the action. @@ -2208,7 +2931,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["SET_FAN_MODE"] + action_type: Literal["PUSH_THERMOSTAT_PROGRAMS"] error: None result: Result status: Literal["success"] @@ -2225,12 +2948,12 @@ def from_dict(cls, d: Any): @dataclass -class SetFanModePendingActionAttempt: - """Setting the fan mode is pending. +class PushThermostatProgramsPendingActionAttempt: + """Pushing thermostat weekly programs is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of setting the fan mode on a thermostat. + :ivar action_type: Action attempt to track the status of pushing thermostat programs. :ivar error: Error associated with the action. @@ -2239,7 +2962,7 @@ class SetFanModePendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["SET_FAN_MODE"] + action_type: Literal["PUSH_THERMOSTAT_PROGRAMS"] error: None result: None status: Literal["pending"] @@ -2256,12 +2979,12 @@ def from_dict(cls, d: Any): @dataclass -class SetFanModeErrorActionAttempt: - """Setting the fan mode is pending. +class PushThermostatProgramsErrorActionAttempt: + """Pushing thermostat weekly programs is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of setting the fan mode on a thermostat. + :ivar action_type: Action attempt to track the status of pushing thermostat programs. :ivar error: Error associated with the action. @@ -2288,7 +3011,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["SET_FAN_MODE"] + action_type: Literal["PUSH_THERMOSTAT_PROGRAMS"] error: Error result: None status: Literal["error"] @@ -2305,12 +3028,12 @@ def from_dict(cls, d: Any): @dataclass -class SetHvacModeSuccessActionAttempt: - """Setting the HVAC mode is pending. +class ConfigureAutoLockSuccessActionAttempt: + """Configuring the auto-lock is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of setting the HVAC mode on a thermostat. + :ivar action_type: Action attempt to track the status of configuring the auto-lock on a lock. :ivar error: Error associated with the action. @@ -2328,7 +3051,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["SET_HVAC_MODE"] + action_type: Literal["CONFIGURE_AUTO_LOCK"] error: None result: Result status: Literal["success"] @@ -2345,12 +3068,12 @@ def from_dict(cls, d: Any): @dataclass -class SetHvacModePendingActionAttempt: - """Setting the HVAC mode is pending. +class ConfigureAutoLockPendingActionAttempt: + """Configuring the auto-lock is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of setting the HVAC mode on a thermostat. + :ivar action_type: Action attempt to track the status of configuring the auto-lock on a lock. :ivar error: Error associated with the action. @@ -2359,7 +3082,7 @@ class SetHvacModePendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["SET_HVAC_MODE"] + action_type: Literal["CONFIGURE_AUTO_LOCK"] error: None result: None status: Literal["pending"] @@ -2376,12 +3099,12 @@ def from_dict(cls, d: Any): @dataclass -class SetHvacModeErrorActionAttempt: - """Setting the HVAC mode is pending. +class ConfigureAutoLockErrorActionAttempt: + """Configuring the auto-lock is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of setting the HVAC mode on a thermostat. + :ivar action_type: Action attempt to track the status of configuring the auto-lock on a lock. :ivar error: Error associated with the action. @@ -2408,7 +3131,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["SET_HVAC_MODE"] + action_type: Literal["CONFIGURE_AUTO_LOCK"] error: Error result: None status: Literal["error"] @@ -2425,12 +3148,12 @@ def from_dict(cls, d: Any): @dataclass -class ActivateClimatePresetSuccessActionAttempt: - """Activating a climate preset is pending. +class ConvertAccessCodeToManagedSuccessActionAttempt: + """Converting an unmanaged access code to managed is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of a climate preset activation. + :ivar action_type: Action attempt to track the status of converting an unmanaged access code to a managed access code. :ivar error: Error associated with the action. @@ -2448,7 +3171,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["ACTIVATE_CLIMATE_PRESET"] + action_type: Literal["CONVERT_ACCESS_CODE_TO_MANAGED"] error: None result: Result status: Literal["success"] @@ -2465,12 +3188,12 @@ def from_dict(cls, d: Any): @dataclass -class ActivateClimatePresetPendingActionAttempt: - """Activating a climate preset is pending. +class ConvertAccessCodeToManagedPendingActionAttempt: + """Converting an unmanaged access code to managed is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of a climate preset activation. + :ivar action_type: Action attempt to track the status of converting an unmanaged access code to a managed access code. :ivar error: Error associated with the action. @@ -2479,7 +3202,7 @@ class ActivateClimatePresetPendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["ACTIVATE_CLIMATE_PRESET"] + action_type: Literal["CONVERT_ACCESS_CODE_TO_MANAGED"] error: None result: None status: Literal["pending"] @@ -2496,12 +3219,12 @@ def from_dict(cls, d: Any): @dataclass -class ActivateClimatePresetErrorActionAttempt: - """Activating a climate preset is pending. +class ConvertAccessCodeToManagedErrorActionAttempt: + """Converting an unmanaged access code to managed is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of a climate preset activation. + :ivar action_type: Action attempt to track the status of converting an unmanaged access code to a managed access code. :ivar error: Error associated with the action. @@ -2528,7 +3251,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["ACTIVATE_CLIMATE_PRESET"] + action_type: Literal["CONVERT_ACCESS_CODE_TO_MANAGED"] error: Error result: None status: Literal["error"] @@ -2545,12 +3268,12 @@ def from_dict(cls, d: Any): @dataclass -class ActivateWeeklyProgramSuccessActionAttempt: - """Activating the weekly program is pending. +class SetSpeakerVolumeSuccessActionAttempt: + """Setting the speaker volume is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of returning a thermostat to its weekly program. + :ivar action_type: Action attempt to track the status of setting the volume on a speaker. :ivar error: Error associated with the action. @@ -2568,7 +3291,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["ACTIVATE_WEEKLY_PROGRAM"] + action_type: Literal["SET_SPEAKER_VOLUME"] error: None result: Result status: Literal["success"] @@ -2585,12 +3308,12 @@ def from_dict(cls, d: Any): @dataclass -class ActivateWeeklyProgramPendingActionAttempt: - """Activating the weekly program is pending. +class SetSpeakerVolumePendingActionAttempt: + """Setting the speaker volume is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of returning a thermostat to its weekly program. + :ivar action_type: Action attempt to track the status of setting the volume on a speaker. :ivar error: Error associated with the action. @@ -2599,7 +3322,7 @@ class ActivateWeeklyProgramPendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["ACTIVATE_WEEKLY_PROGRAM"] + action_type: Literal["SET_SPEAKER_VOLUME"] error: None result: None status: Literal["pending"] @@ -2616,12 +3339,12 @@ def from_dict(cls, d: Any): @dataclass -class ActivateWeeklyProgramErrorActionAttempt: - """Activating the weekly program is pending. +class SetSpeakerVolumeErrorActionAttempt: + """Setting the speaker volume is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of returning a thermostat to its weekly program. + :ivar action_type: Action attempt to track the status of setting the volume on a speaker. :ivar error: Error associated with the action. @@ -2648,7 +3371,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["ACTIVATE_WEEKLY_PROGRAM"] + action_type: Literal["SET_SPEAKER_VOLUME"] error: Error result: None status: Literal["error"] @@ -2665,12 +3388,12 @@ def from_dict(cls, d: Any): @dataclass -class SimulateKeypadCodeEntrySuccessActionAttempt: - """Simulating a keypad code entry is pending. +class SetSpeakerMuteSuccessActionAttempt: + """Muting or unmuting the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of simulating a keypad code entry. + :ivar action_type: Action attempt to track the status of muting or unmuting a speaker. :ivar error: Error associated with the action. @@ -2688,7 +3411,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["SIMULATE_KEYPAD_CODE_ENTRY"] + action_type: Literal["SET_SPEAKER_MUTE"] error: None result: Result status: Literal["success"] @@ -2705,12 +3428,12 @@ def from_dict(cls, d: Any): @dataclass -class SimulateKeypadCodeEntryPendingActionAttempt: - """Simulating a keypad code entry is pending. +class SetSpeakerMutePendingActionAttempt: + """Muting or unmuting the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of simulating a keypad code entry. + :ivar action_type: Action attempt to track the status of muting or unmuting a speaker. :ivar error: Error associated with the action. @@ -2719,7 +3442,7 @@ class SimulateKeypadCodeEntryPendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["SIMULATE_KEYPAD_CODE_ENTRY"] + action_type: Literal["SET_SPEAKER_MUTE"] error: None result: None status: Literal["pending"] @@ -2736,12 +3459,12 @@ def from_dict(cls, d: Any): @dataclass -class SimulateKeypadCodeEntryErrorActionAttempt: - """Simulating a keypad code entry is pending. +class SetSpeakerMuteErrorActionAttempt: + """Muting or unmuting the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of simulating a keypad code entry. + :ivar action_type: Action attempt to track the status of muting or unmuting a speaker. :ivar error: Error associated with the action. @@ -2768,7 +3491,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["SIMULATE_KEYPAD_CODE_ENTRY"] + action_type: Literal["SET_SPEAKER_MUTE"] error: Error result: None status: Literal["error"] @@ -2785,12 +3508,12 @@ def from_dict(cls, d: Any): @dataclass -class SimulateManualLockViaKeypadSuccessActionAttempt: - """Simulating a manual lock action using a keypad is pending. +class PauseSpeakerPlaybackSuccessActionAttempt: + """Pausing playback on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of simulating a manual lock action using a keypad. + :ivar action_type: Action attempt to track the status of pausing playback on a speaker. :ivar error: Error associated with the action. @@ -2800,15 +3523,21 @@ class SimulateManualLockViaKeypadSuccessActionAttempt: @dataclass class Result(ResourceMapping): - """Result of the action.""" + """Result of the action. + + :ivar affected_device_ids: IDs of the speakers whose playback was paused, including speakers grouped with the requested speaker. + """ + + affected_device_ids: List[str] @classmethod def from_dict(cls, d: Any): - # pylint: disable=unused-argument - return cls() + return cls( + affected_device_ids=d.get("affected_device_ids", None), + ) action_attempt_id: str - action_type: Literal["SIMULATE_MANUAL_LOCK_VIA_KEYPAD"] + action_type: Literal["PAUSE_SPEAKER_PLAYBACK"] error: None result: Result status: Literal["success"] @@ -2825,12 +3554,12 @@ def from_dict(cls, d: Any): @dataclass -class SimulateManualLockViaKeypadPendingActionAttempt: - """Simulating a manual lock action using a keypad is pending. +class PauseSpeakerPlaybackPendingActionAttempt: + """Pausing playback on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of simulating a manual lock action using a keypad. + :ivar action_type: Action attempt to track the status of pausing playback on a speaker. :ivar error: Error associated with the action. @@ -2839,7 +3568,7 @@ class SimulateManualLockViaKeypadPendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["SIMULATE_MANUAL_LOCK_VIA_KEYPAD"] + action_type: Literal["PAUSE_SPEAKER_PLAYBACK"] error: None result: None status: Literal["pending"] @@ -2856,12 +3585,12 @@ def from_dict(cls, d: Any): @dataclass -class SimulateManualLockViaKeypadErrorActionAttempt: - """Simulating a manual lock action using a keypad is pending. +class PauseSpeakerPlaybackErrorActionAttempt: + """Pausing playback on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of simulating a manual lock action using a keypad. + :ivar action_type: Action attempt to track the status of pausing playback on a speaker. :ivar error: Error associated with the action. @@ -2888,7 +3617,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["SIMULATE_MANUAL_LOCK_VIA_KEYPAD"] + action_type: Literal["PAUSE_SPEAKER_PLAYBACK"] error: Error result: None status: Literal["error"] @@ -2905,12 +3634,12 @@ def from_dict(cls, d: Any): @dataclass -class PushThermostatProgramsSuccessActionAttempt: - """Pushing thermostat weekly programs is pending. +class ResumeSpeakerPlaybackSuccessActionAttempt: + """Resuming playback on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of pushing thermostat programs. + :ivar action_type: Action attempt to track the status of resuming playback on a speaker. :ivar error: Error associated with the action. @@ -2920,15 +3649,21 @@ class PushThermostatProgramsSuccessActionAttempt: @dataclass class Result(ResourceMapping): - """Result of the action.""" + """Result of the action. + + :ivar affected_device_ids: IDs of the speakers whose playback was resumed, including speakers grouped with the requested speaker. + """ + + affected_device_ids: List[str] @classmethod def from_dict(cls, d: Any): - # pylint: disable=unused-argument - return cls() + return cls( + affected_device_ids=d.get("affected_device_ids", None), + ) action_attempt_id: str - action_type: Literal["PUSH_THERMOSTAT_PROGRAMS"] + action_type: Literal["RESUME_SPEAKER_PLAYBACK"] error: None result: Result status: Literal["success"] @@ -2945,12 +3680,12 @@ def from_dict(cls, d: Any): @dataclass -class PushThermostatProgramsPendingActionAttempt: - """Pushing thermostat weekly programs is pending. +class ResumeSpeakerPlaybackPendingActionAttempt: + """Resuming playback on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of pushing thermostat programs. + :ivar action_type: Action attempt to track the status of resuming playback on a speaker. :ivar error: Error associated with the action. @@ -2959,7 +3694,7 @@ class PushThermostatProgramsPendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["PUSH_THERMOSTAT_PROGRAMS"] + action_type: Literal["RESUME_SPEAKER_PLAYBACK"] error: None result: None status: Literal["pending"] @@ -2976,12 +3711,12 @@ def from_dict(cls, d: Any): @dataclass -class PushThermostatProgramsErrorActionAttempt: - """Pushing thermostat weekly programs is pending. +class ResumeSpeakerPlaybackErrorActionAttempt: + """Resuming playback on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of pushing thermostat programs. + :ivar action_type: Action attempt to track the status of resuming playback on a speaker. :ivar error: Error associated with the action. @@ -3008,7 +3743,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["PUSH_THERMOSTAT_PROGRAMS"] + action_type: Literal["RESUME_SPEAKER_PLAYBACK"] error: Error result: None status: Literal["error"] @@ -3025,12 +3760,12 @@ def from_dict(cls, d: Any): @dataclass -class ConfigureAutoLockSuccessActionAttempt: - """Configuring the auto-lock is pending. +class PlaySpeakerChimeSuccessActionAttempt: + """Playing a chime on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of configuring the auto-lock on a lock. + :ivar action_type: Action attempt to track the status of playing a chime on a speaker. :ivar error: Error associated with the action. @@ -3048,7 +3783,7 @@ def from_dict(cls, d: Any): return cls() action_attempt_id: str - action_type: Literal["CONFIGURE_AUTO_LOCK"] + action_type: Literal["PLAY_SPEAKER_CHIME"] error: None result: Result status: Literal["success"] @@ -3065,12 +3800,12 @@ def from_dict(cls, d: Any): @dataclass -class ConfigureAutoLockPendingActionAttempt: - """Configuring the auto-lock is pending. +class PlaySpeakerChimePendingActionAttempt: + """Playing a chime on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of configuring the auto-lock on a lock. + :ivar action_type: Action attempt to track the status of playing a chime on a speaker. :ivar error: Error associated with the action. @@ -3079,7 +3814,7 @@ class ConfigureAutoLockPendingActionAttempt: :ivar status:""" action_attempt_id: str - action_type: Literal["CONFIGURE_AUTO_LOCK"] + action_type: Literal["PLAY_SPEAKER_CHIME"] error: None result: None status: Literal["pending"] @@ -3096,12 +3831,12 @@ def from_dict(cls, d: Any): @dataclass -class ConfigureAutoLockErrorActionAttempt: - """Configuring the auto-lock is pending. +class PlaySpeakerChimeErrorActionAttempt: + """Playing a chime on the speaker is pending. :ivar action_attempt_id: ID of the action attempt. - :ivar action_type: Action attempt to track the status of configuring the auto-lock on a lock. + :ivar action_type: Action attempt to track the status of playing a chime on a speaker. :ivar error: Error associated with the action. @@ -3128,7 +3863,7 @@ def from_dict(cls, d: Any): ) action_attempt_id: str - action_type: Literal["CONFIGURE_AUTO_LOCK"] + action_type: Literal["PLAY_SPEAKER_CHIME"] error: Error result: None status: Literal["error"] @@ -4050,6 +4785,24 @@ def from_dict(cls, d: Any): ConfigureAutoLockSuccessActionAttempt, ConfigureAutoLockPendingActionAttempt, ConfigureAutoLockErrorActionAttempt, + ConvertAccessCodeToManagedSuccessActionAttempt, + ConvertAccessCodeToManagedPendingActionAttempt, + ConvertAccessCodeToManagedErrorActionAttempt, + SetSpeakerVolumeSuccessActionAttempt, + SetSpeakerVolumePendingActionAttempt, + SetSpeakerVolumeErrorActionAttempt, + SetSpeakerMuteSuccessActionAttempt, + SetSpeakerMutePendingActionAttempt, + SetSpeakerMuteErrorActionAttempt, + PauseSpeakerPlaybackSuccessActionAttempt, + PauseSpeakerPlaybackPendingActionAttempt, + PauseSpeakerPlaybackErrorActionAttempt, + ResumeSpeakerPlaybackSuccessActionAttempt, + ResumeSpeakerPlaybackPendingActionAttempt, + ResumeSpeakerPlaybackErrorActionAttempt, + PlaySpeakerChimeSuccessActionAttempt, + PlaySpeakerChimePendingActionAttempt, + PlaySpeakerChimeErrorActionAttempt, SyncAccessCodesSuccessActionAttempt, SyncAccessCodesPendingActionAttempt, SyncAccessCodesErrorActionAttempt, @@ -4163,6 +4916,42 @@ def from_dict(cls, d: Any): ConfigureAutoLockErrorActionAttempt, ] +ConvertAccessCodeToManagedActionAttempt = Union[ + ConvertAccessCodeToManagedSuccessActionAttempt, + ConvertAccessCodeToManagedPendingActionAttempt, + ConvertAccessCodeToManagedErrorActionAttempt, +] + +SetSpeakerVolumeActionAttempt = Union[ + SetSpeakerVolumeSuccessActionAttempt, + SetSpeakerVolumePendingActionAttempt, + SetSpeakerVolumeErrorActionAttempt, +] + +SetSpeakerMuteActionAttempt = Union[ + SetSpeakerMuteSuccessActionAttempt, + SetSpeakerMutePendingActionAttempt, + SetSpeakerMuteErrorActionAttempt, +] + +PauseSpeakerPlaybackActionAttempt = Union[ + PauseSpeakerPlaybackSuccessActionAttempt, + PauseSpeakerPlaybackPendingActionAttempt, + PauseSpeakerPlaybackErrorActionAttempt, +] + +ResumeSpeakerPlaybackActionAttempt = Union[ + ResumeSpeakerPlaybackSuccessActionAttempt, + ResumeSpeakerPlaybackPendingActionAttempt, + ResumeSpeakerPlaybackErrorActionAttempt, +] + +PlaySpeakerChimeActionAttempt = Union[ + PlaySpeakerChimeSuccessActionAttempt, + PlaySpeakerChimePendingActionAttempt, + PlaySpeakerChimeErrorActionAttempt, +] + SyncAccessCodesActionAttempt = Union[ SyncAccessCodesSuccessActionAttempt, SyncAccessCodesPendingActionAttempt, @@ -4221,6 +5010,12 @@ def from_dict(cls, d: Any): SimulateManualLockViaKeypadSuccessActionAttempt, PushThermostatProgramsSuccessActionAttempt, ConfigureAutoLockSuccessActionAttempt, + ConvertAccessCodeToManagedSuccessActionAttempt, + SetSpeakerVolumeSuccessActionAttempt, + SetSpeakerMuteSuccessActionAttempt, + PauseSpeakerPlaybackSuccessActionAttempt, + ResumeSpeakerPlaybackSuccessActionAttempt, + PlaySpeakerChimeSuccessActionAttempt, SyncAccessCodesSuccessActionAttempt, CreateAccessCodeSuccessActionAttempt, DeleteAccessCodeSuccessActionAttempt, @@ -4246,6 +5041,12 @@ def from_dict(cls, d: Any): SimulateManualLockViaKeypadPendingActionAttempt, PushThermostatProgramsPendingActionAttempt, ConfigureAutoLockPendingActionAttempt, + ConvertAccessCodeToManagedPendingActionAttempt, + SetSpeakerVolumePendingActionAttempt, + SetSpeakerMutePendingActionAttempt, + PauseSpeakerPlaybackPendingActionAttempt, + ResumeSpeakerPlaybackPendingActionAttempt, + PlaySpeakerChimePendingActionAttempt, SyncAccessCodesPendingActionAttempt, CreateAccessCodePendingActionAttempt, DeleteAccessCodePendingActionAttempt, @@ -4271,6 +5072,12 @@ def from_dict(cls, d: Any): SimulateManualLockViaKeypadErrorActionAttempt, PushThermostatProgramsErrorActionAttempt, ConfigureAutoLockErrorActionAttempt, + ConvertAccessCodeToManagedErrorActionAttempt, + SetSpeakerVolumeErrorActionAttempt, + SetSpeakerMuteErrorActionAttempt, + PauseSpeakerPlaybackErrorActionAttempt, + ResumeSpeakerPlaybackErrorActionAttempt, + PlaySpeakerChimeErrorActionAttempt, SyncAccessCodesErrorActionAttempt, CreateAccessCodeErrorActionAttempt, DeleteAccessCodeErrorActionAttempt, @@ -4347,6 +5154,33 @@ def from_dict(cls, d: Any): ("CONFIGURE_AUTO_LOCK", "success"): ConfigureAutoLockSuccessActionAttempt, ("CONFIGURE_AUTO_LOCK", "pending"): ConfigureAutoLockPendingActionAttempt, ("CONFIGURE_AUTO_LOCK", "error"): ConfigureAutoLockErrorActionAttempt, + ( + "CONVERT_ACCESS_CODE_TO_MANAGED", + "success", + ): ConvertAccessCodeToManagedSuccessActionAttempt, + ( + "CONVERT_ACCESS_CODE_TO_MANAGED", + "pending", + ): ConvertAccessCodeToManagedPendingActionAttempt, + ( + "CONVERT_ACCESS_CODE_TO_MANAGED", + "error", + ): ConvertAccessCodeToManagedErrorActionAttempt, + ("SET_SPEAKER_VOLUME", "success"): SetSpeakerVolumeSuccessActionAttempt, + ("SET_SPEAKER_VOLUME", "pending"): SetSpeakerVolumePendingActionAttempt, + ("SET_SPEAKER_VOLUME", "error"): SetSpeakerVolumeErrorActionAttempt, + ("SET_SPEAKER_MUTE", "success"): SetSpeakerMuteSuccessActionAttempt, + ("SET_SPEAKER_MUTE", "pending"): SetSpeakerMutePendingActionAttempt, + ("SET_SPEAKER_MUTE", "error"): SetSpeakerMuteErrorActionAttempt, + ("PAUSE_SPEAKER_PLAYBACK", "success"): PauseSpeakerPlaybackSuccessActionAttempt, + ("PAUSE_SPEAKER_PLAYBACK", "pending"): PauseSpeakerPlaybackPendingActionAttempt, + ("PAUSE_SPEAKER_PLAYBACK", "error"): PauseSpeakerPlaybackErrorActionAttempt, + ("RESUME_SPEAKER_PLAYBACK", "success"): ResumeSpeakerPlaybackSuccessActionAttempt, + ("RESUME_SPEAKER_PLAYBACK", "pending"): ResumeSpeakerPlaybackPendingActionAttempt, + ("RESUME_SPEAKER_PLAYBACK", "error"): ResumeSpeakerPlaybackErrorActionAttempt, + ("PLAY_SPEAKER_CHIME", "success"): PlaySpeakerChimeSuccessActionAttempt, + ("PLAY_SPEAKER_CHIME", "pending"): PlaySpeakerChimePendingActionAttempt, + ("PLAY_SPEAKER_CHIME", "error"): PlaySpeakerChimeErrorActionAttempt, ("SYNC_ACCESS_CODES", "success"): SyncAccessCodesSuccessActionAttempt, ("SYNC_ACCESS_CODES", "pending"): SyncAccessCodesPendingActionAttempt, ("SYNC_ACCESS_CODES", "error"): SyncAccessCodesErrorActionAttempt, diff --git a/seam/resources/connect_webview.py b/seam/resources/connect_webview.py index 8935449b..49dc8d17 100644 --- a/seam/resources/connect_webview.py +++ b/seam/resources/connect_webview.py @@ -57,7 +57,9 @@ class ConnectWebview: :ivar workspace_id: ID of the workspace that contains the Connect Webview.""" accepted_capabilities: List[ - Literal["lock", "thermostat", "noise_sensor", "access_control", "camera"] + Literal[ + "lock", "thermostat", "noise_sensor", "access_control", "camera", "speaker" + ] ] accepted_providers: List[str] any_provider_allowed: bool diff --git a/seam/resources/connected_account.py b/seam/resources/connected_account.py index e7a5b531..d2243bb3 100644 --- a/seam/resources/connected_account.py +++ b/seam/resources/connected_account.py @@ -533,7 +533,9 @@ def from_dict(cls, d: Any): } accepted_capabilities: List[ - Literal["lock", "thermostat", "noise_sensor", "access_control", "camera"] + Literal[ + "lock", "thermostat", "noise_sensor", "access_control", "camera", "speaker" + ] ] account_type: Optional[str] account_type_display_name: str diff --git a/seam/resources/device.py b/seam/resources/device.py index 8bab72d3..0c0ecc34 100644 --- a/seam/resources/device.py +++ b/seam/resources/device.py @@ -25,6 +25,12 @@ class Device: :ivar can_hvac_heat_cool: Indicates whether the thermostat supports simultaneous heating and cooling. + :ivar can_mute_speaker: Indicates whether the speaker supports muting and unmuting. + + :ivar can_pause_speaker_playback: Indicates whether the speaker supports pausing and resuming playback. + + :ivar can_play_speaker_chime: Indicates whether the speaker supports playing a chime. + :ivar can_program_offline_access_codes: Indicates whether the device supports programming offline access codes. :ivar can_program_online_access_codes: Indicates whether the device supports programming online access codes. @@ -41,6 +47,8 @@ class Device: :ivar can_run_thermostat_programs: Indicates whether the thermostat supports running climate programs. + :ivar can_set_speaker_volume: Indicates whether the speaker supports setting its volume. + :ivar can_simulate_connection: Indicates whether the device supports simulating connection in a sandbox. :ivar can_simulate_disconnection: Indicates whether the device supports simulating disconnection in a sandbox. @@ -681,6 +689,8 @@ class Properties(ResourceMapping): :ivar smartthings_metadata: Metadata for a SmartThings device. + :ivar sonos_metadata: Metadata for a Sonos speaker. + :ivar tado_metadata: Metadata for a tado° device. :ivar tapo_metadata: Metadata for a Tapo camera. @@ -721,6 +731,8 @@ class Properties(ResourceMapping): :ivar online_time_frame_options: Time frames that may be requested when creating an online access code, expressed as a list of options. The caller picks one option (by matching the requested duration when the options' duration ranges do not overlap, or by ``display_name`` when they do) and satisfies that one option's rules. When ``undefined``, any time frame works. + :ivar speaker: Audio state and capabilities of the speaker. + :ivar supported_code_lengths: Supported code lengths for access codes. :ivar supports_backup_access_code_pool: Indicates whether the device supports a `backup access code pool `_. @@ -2225,6 +2237,44 @@ def from_dict(cls, d: Any): model=d.get("model", None), ) + @dataclass + class SonosMetadata(ResourceMapping): + """Metadata for a Sonos speaker. + + :ivar bonded_member_models: Models of the speakers bonded to this speaker, such as surrounds or a subwoofer. + + :ivar color: Color of the speaker, as reported by Sonos. + + :ivar household_id: ID of the Sonos household that the speaker belongs to. + + :ivar model_display_name: Model name of the speaker, as reported by Sonos. + + :ivar player_id: ID of the Sonos player for the speaker. + + :ivar player_name: Name of the speaker, as set in the Sonos app. + + :ivar software_version: Software version running on the speaker.""" + + bonded_member_models: Optional[List[str]] + color: Optional[str] + household_id: Optional[str] + model_display_name: Optional[str] + player_id: Optional[str] + player_name: Optional[str] + software_version: Optional[str] + + @classmethod + def from_dict(cls, d: Any): + return cls( + bonded_member_models=d.get("bonded_member_models", None), + color=d.get("color", None), + household_id=d.get("household_id", None), + model_display_name=d.get("model_display_name", None), + player_id=d.get("player_id", None), + player_name=d.get("player_name", None), + software_version=d.get("software_version", None), + ) + @dataclass class TadoMetadata(ResourceMapping): """Metadata for a tado° device. @@ -2724,6 +2774,87 @@ def from_dict(cls, d: Any): time_zone=d.get("time_zone", None), ) + @dataclass + class Speaker(ResourceMapping): + """Audio state and capabilities of the speaker. + + :ivar grouped_with_device_ids: IDs of the other speakers that are currently grouped with this speaker. Pausing or resuming playback on a speaker also affects the speakers in its group. + + :ivar has_fixed_volume: Indicates whether the speaker's volume is fixed, for example, because the speaker's line-out level is controlled by an external amplifier. A speaker with a fixed volume cannot have its volume set through Seam. + + :ivar is_muted: Indicates whether the speaker is muted. + + :ivar max_volume: Maximum volume that you can set on the speaker. This is the ceiling of the speaker's native volume scale, not a limit configured for guests. + + :ivar min_volume: Minimum volume that you can set on the speaker. + + :ivar now_playing: Content that is currently playing on the speaker. + + :ivar playback_state: Playback state of the speaker. + + :ivar supports_chime: Indicates whether the speaker can play a chime. + + :ivar volume: Current volume of the speaker, on the speaker's native volume scale from ``min_volume`` to ``max_volume``. This is the native volume setting, not a decibel level. + + :ivar volume_reported_at: Date and time at which the speaker first reported its current volume. + + :ivar volume_step: Increment between the volume values that you can set on the speaker. + """ + + @dataclass + class NowPlaying(ResourceMapping): + """Content that is currently playing on the speaker. + + :ivar album: Album of the content that is currently playing. + + :ivar artist: Artist of the content that is currently playing. + + :ivar title: Title of the content that is currently playing.""" + + album: Optional[str] + artist: Optional[str] + title: Optional[str] + + @classmethod + def from_dict(cls, d: Any): + return cls( + album=d.get("album", None), + artist=d.get("artist", None), + title=d.get("title", None), + ) + + grouped_with_device_ids: List[str] + has_fixed_volume: bool + is_muted: bool + max_volume: float + min_volume: float + now_playing: Optional[NowPlaying] + playback_state: Literal["playing", "paused", "idle", "buffering", "unknown"] + supports_chime: bool + volume: float + volume_reported_at: Optional[str] + volume_step: float + + @classmethod + def from_dict(cls, d: Any): + return cls( + grouped_with_device_ids=d.get("grouped_with_device_ids", None), + has_fixed_volume=d.get("has_fixed_volume", None), + is_muted=d.get("is_muted", None), + max_volume=d.get("max_volume", None), + min_volume=d.get("min_volume", None), + now_playing=( + cls.NowPlaying.from_dict(d.get("now_playing")) + if d.get("now_playing") is not None + else None + ), + playback_state=d.get("playback_state", None), + supports_chime=d.get("supports_chime", None), + volume=d.get("volume", None), + volume_reported_at=d.get("volume_reported_at", None), + volume_step=d.get("volume_step", None), + ) + @dataclass class ActiveThermostatSchedule(ResourceMapping): """Active `thermostat schedule `_. @@ -3312,6 +3443,7 @@ def from_dict(cls, d: Any): seam_bridge_metadata: Optional[SeamBridgeMetadata] sensi_metadata: Optional[SensiMetadata] smartthings_metadata: Optional[SmartthingsMetadata] + sonos_metadata: Optional[SonosMetadata] tado_metadata: Optional[TadoMetadata] tapo_metadata: Optional[TapoMetadata] tedee_metadata: Optional[TedeeMetadata] @@ -3332,6 +3464,7 @@ def from_dict(cls, d: Any): max_active_codes_supported: Optional[float] offline_time_frame_options: Optional[List[OfflineTimeFrameOptions]] online_time_frame_options: Optional[List[OnlineTimeFrameOptions]] + speaker: Optional[Speaker] supported_code_lengths: Optional[List[float]] supports_backup_access_code_pool: Optional[bool] active_thermostat_schedule: Optional[ActiveThermostatSchedule] @@ -3607,6 +3740,11 @@ def from_dict(cls, d: Any): if d.get("smartthings_metadata") is not None else None ), + sonos_metadata=( + cls.SonosMetadata.from_dict(d.get("sonos_metadata")) + if d.get("sonos_metadata") is not None + else None + ), tado_metadata=( cls.TadoMetadata.from_dict(d.get("tado_metadata")) if d.get("tado_metadata") is not None @@ -3678,6 +3816,11 @@ def from_dict(cls, d: Any): cls.OnlineTimeFrameOptions.from_dict(i) for i in d.get("online_time_frame_options") or [] ], + speaker=( + cls.Speaker.from_dict(d.get("speaker")) + if d.get("speaker") is not None + else None + ), supported_code_lengths=d.get("supported_code_lengths", None), supports_backup_access_code_pool=d.get( "supports_backup_access_code_pool", None @@ -4538,6 +4681,9 @@ def from_dict(cls, d: Any): can_hvac_cool: Optional[bool] can_hvac_heat: Optional[bool] can_hvac_heat_cool: Optional[bool] + can_mute_speaker: Optional[bool] + can_pause_speaker_playback: Optional[bool] + can_play_speaker_chime: Optional[bool] can_program_offline_access_codes: Optional[bool] can_program_online_access_codes: Optional[bool] can_program_thermostat_programs_as_different_each_day: Optional[bool] @@ -4546,6 +4692,7 @@ def from_dict(cls, d: Any): can_remotely_lock: Optional[bool] can_remotely_unlock: Optional[bool] can_run_thermostat_programs: Optional[bool] + can_set_speaker_volume: Optional[bool] can_simulate_connection: Optional[bool] can_simulate_disconnection: Optional[bool] can_simulate_hub_connection: Optional[bool] @@ -4613,6 +4760,7 @@ def from_dict(cls, d: Any): "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] display_name: str errors: List[Errors] @@ -4632,6 +4780,9 @@ def from_dict(cls, d: Any): can_hvac_cool=d.get("can_hvac_cool", None), can_hvac_heat=d.get("can_hvac_heat", None), can_hvac_heat_cool=d.get("can_hvac_heat_cool", None), + can_mute_speaker=d.get("can_mute_speaker", None), + can_pause_speaker_playback=d.get("can_pause_speaker_playback", None), + can_play_speaker_chime=d.get("can_play_speaker_chime", None), can_program_offline_access_codes=d.get( "can_program_offline_access_codes", None ), @@ -4650,6 +4801,7 @@ def from_dict(cls, d: Any): can_remotely_lock=d.get("can_remotely_lock", None), can_remotely_unlock=d.get("can_remotely_unlock", None), can_run_thermostat_programs=d.get("can_run_thermostat_programs", None), + can_set_speaker_volume=d.get("can_set_speaker_volume", None), can_simulate_connection=d.get("can_simulate_connection", None), can_simulate_disconnection=d.get("can_simulate_disconnection", None), can_simulate_hub_connection=d.get("can_simulate_hub_connection", None), diff --git a/seam/resources/device_provider.py b/seam/resources/device_provider.py index 627fca9f..dddc07d8 100644 --- a/seam/resources/device_provider.py +++ b/seam/resources/device_provider.py @@ -18,6 +18,12 @@ class DeviceProvider: :ivar can_hvac_heat_cool: Indicates whether the thermostat supports simultaneous heating and cooling. + :ivar can_mute_speaker: Indicates whether the speaker supports muting and unmuting. + + :ivar can_pause_speaker_playback: Indicates whether the speaker supports pausing and resuming playback. + + :ivar can_play_speaker_chime: Indicates whether the speaker supports playing a chime. + :ivar can_program_offline_access_codes: Indicates whether the device supports programming offline access codes. :ivar can_program_online_access_codes: Indicates whether the device supports programming online access codes. @@ -34,6 +40,8 @@ class DeviceProvider: :ivar can_run_thermostat_programs: Indicates whether the thermostat supports running climate programs. + :ivar can_set_speaker_volume: Indicates whether the speaker supports setting its volume. + :ivar can_simulate_connection: Indicates whether the device supports simulating connection in a sandbox. :ivar can_simulate_disconnection: Indicates whether the device supports simulating disconnection in a sandbox. @@ -66,6 +74,9 @@ class DeviceProvider: can_hvac_cool: Optional[bool] can_hvac_heat: Optional[bool] can_hvac_heat_cool: Optional[bool] + can_mute_speaker: Optional[bool] + can_pause_speaker_playback: Optional[bool] + can_play_speaker_chime: Optional[bool] can_program_offline_access_codes: Optional[bool] can_program_online_access_codes: Optional[bool] can_program_thermostat_programs_as_different_each_day: Optional[bool] @@ -74,6 +85,7 @@ class DeviceProvider: can_remotely_lock: Optional[bool] can_remotely_unlock: Optional[bool] can_run_thermostat_programs: Optional[bool] + can_set_speaker_volume: Optional[bool] can_simulate_connection: Optional[bool] can_simulate_disconnection: Optional[bool] can_simulate_hub_connection: Optional[bool] @@ -152,6 +164,7 @@ class DeviceProvider: "omnitec", "kisi", "aqara", + "sonos", ] display_name: str image_url: str @@ -176,6 +189,9 @@ def from_dict(cls, d: Any): can_hvac_cool=d.get("can_hvac_cool", None), can_hvac_heat=d.get("can_hvac_heat", None), can_hvac_heat_cool=d.get("can_hvac_heat_cool", None), + can_mute_speaker=d.get("can_mute_speaker", None), + can_pause_speaker_playback=d.get("can_pause_speaker_playback", None), + can_play_speaker_chime=d.get("can_play_speaker_chime", None), can_program_offline_access_codes=d.get( "can_program_offline_access_codes", None ), @@ -194,6 +210,7 @@ def from_dict(cls, d: Any): can_remotely_lock=d.get("can_remotely_lock", None), can_remotely_unlock=d.get("can_remotely_unlock", None), can_run_thermostat_programs=d.get("can_run_thermostat_programs", None), + can_set_speaker_volume=d.get("can_set_speaker_volume", None), can_simulate_connection=d.get("can_simulate_connection", None), can_simulate_disconnection=d.get("can_simulate_disconnection", None), can_simulate_hub_connection=d.get("can_simulate_hub_connection", None), diff --git a/seam/resources/phone.py b/seam/resources/phone.py index acc3a18d..dc532555 100644 --- a/seam/resources/phone.py +++ b/seam/resources/phone.py @@ -4,6 +4,13 @@ from ..resource_mapping import ResourceMapping +def _from_discriminated_dict( + d: Any, variants: Dict[str, Any], discriminator: str +) -> Any: + variant = variants.get(d.get(discriminator)) + return DeepAttrDict(d) if variant is None else variant.from_dict(d) + + @dataclass class Phone: """Represents an app user's mobile phone. @@ -18,28 +25,402 @@ class Phone: :ivar display_name: Display name of the phone. Defaults to ``nickname`` (if it is set) or ``properties.appearance.name``, otherwise. Enables administrators and users to identify the phone easily, especially when there are numerous phones. - :ivar errors: Errors associated with the phone. + :ivar errors: Array of errors associated with the device. Each error object within the array contains two fields: ``error_code`` and ``message``. ``error_code`` is a string that uniquely identifies the type of error, enabling quick recognition and categorization of the issue. ``message`` provides a more detailed description of the error, offering insights into the issue and potentially how to rectify it. :ivar nickname: Optional nickname to describe the phone, settable through Seam. :ivar properties: Properties of the phone. - :ivar warnings: Warnings associated with the phone. + :ivar warnings: Array of warnings associated with the device. Each warning object within the array contains two fields: ``warning_code`` and ``message``. ``warning_code`` is a string that uniquely identifies the type of warning, enabling quick recognition and categorization of the issue. ``message`` provides a more detailed description of the warning, offering insights into the issue and potentially how to rectify it. :ivar workspace_id: ID of the workspace that contains the phone.""" @dataclass - class Errors(ResourceMapping): - """Errors associated with the phone. + class AccountDisconnectedError(ResourceMapping): + """Indicates that the account is disconnected. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_connected_account_error: Indicates that the error is a `connected account `_ error. + + :ivar is_device_error: Indicates that the error is not a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["account_disconnected"] + is_connected_account_error: Literal[True] + is_device_error: Literal[False] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_connected_account_error=d.get("is_connected_account_error", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class SaltoKsSubscriptionLimitExceededError(ResourceMapping): + """Indicates that the Salto site user limit has been reached. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_connected_account_error: Indicates that the error is a `connected account `_ error. + + :ivar is_device_error: Indicates that the error is not a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["salto_ks_subscription_limit_exceeded"] + is_connected_account_error: Literal[True] + is_device_error: Literal[False] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_connected_account_error=d.get("is_connected_account_error", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class InsufficientPermissionsError(ResourceMapping): + """Indicates that the provider's system to which this device belongs is not letting Seam act on it, so Seam cannot manage access codes or unlock the device. The error message says which of three causes applies. Seam's integration user may not have sufficient permissions on the provider's system, or may have been suspended there: grant the integration user the required permissions in the provider's system, or reauthorize the connected account in Seam. The provider account or site may not have a valid subscription with the provider: set up or renew that subscription with the provider. Or the provider may have rejected the credential Seam uses to operate the device's hub: contact Seam support to re-activate it. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_connected_account_error: Indicates that the error is a `connected account `_ error. + + :ivar is_device_error: Indicates that the error is not a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["insufficient_permissions"] + is_connected_account_error: Literal[True] + is_device_error: Literal[False] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_connected_account_error=d.get("is_connected_account_error", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class DormakabaSitesDisconnectedError(ResourceMapping): + """Indicates that one or more dormakaba sites associated with the connected account could not be connected. Contact dormakaba support. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_connected_account_error: Indicates that the error is a `connected account `_ error. + + :ivar is_device_error: Indicates that the error is not a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["dormakaba_sites_disconnected"] + is_connected_account_error: Literal[True] + is_device_error: Literal[False] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_connected_account_error=d.get("is_connected_account_error", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class DeviceOfflineError(ResourceMapping): + """Indicates that the device is offline. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["device_offline"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class DeviceRemovedError(ResourceMapping): + """Indicates that the device has been removed. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["device_removed"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class HubDisconnectedError(ResourceMapping): + """Indicates that the hub is disconnected. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["hub_disconnected"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class DeviceDisconnectedError(ResourceMapping): + """Indicates that the device is disconnected. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["device_disconnected"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class EmptyBackupAccessCodePoolError(ResourceMapping): + """Indicates that the `backup access code pool `_ is empty. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["empty_backup_access_code_pool"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class AugustLockNotAuthorizedError(ResourceMapping): + """Indicates that the user is not authorized to use the August lock. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["august_lock_not_authorized"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class MissingDeviceCredentialsError(ResourceMapping): + """Indicates that device credentials are missing. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["missing_device_credentials"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class AuxiliaryHeatRunningError(ResourceMapping): + """Indicates that the auxiliary heat is running. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["auxiliary_heat_running"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class SubscriptionRequiredError(ResourceMapping): + """Indicates that a subscription is required to connect. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_device_error: Indicates that the error is a device error. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["subscription_required"] + is_device_error: Literal[True] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + is_device_error=d.get("is_device_error", None), + message=d.get("message", None), + ) + + @dataclass + class BridgeDisconnectedError(ResourceMapping): + """Indicates that the Seam API cannot communicate with `Seam Bridge `_, for example, if the Seam Bridge executable has stopped or if the computer running the Seam Bridge executable is offline. See also `Troubleshooting Your Access Control System `_. :ivar created_at: Date and time at which Seam created the error. - :ivar error_code: Unique identifier of the type of error. + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar is_bridge_error: Indicates whether the error is related to `Seam Bridge `_. - :ivar message: Detailed description of the error.""" + :ivar is_connected_account_error: Indicates whether the error is related specifically to the connected account. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ created_at: str - error_code: str + error_code: Literal["bridge_disconnected"] + is_bridge_error: Optional[bool] + is_connected_account_error: Optional[bool] message: str @classmethod @@ -47,6 +428,8 @@ def from_dict(cls, d: Any): return cls( created_at=d.get("created_at", None), error_code=d.get("error_code", None), + is_bridge_error=d.get("is_bridge_error", None), + is_connected_account_error=d.get("is_connected_account_error", None), message=d.get("message", None), ) @@ -140,18 +523,548 @@ def from_dict(cls, d: Any): ) @dataclass - class Warnings(ResourceMapping): - """Warnings associated with the phone. + class PartialBackupAccessCodePoolWarning(ResourceMapping): + """Indicates that the backup access code is unhealthy. :ivar created_at: Date and time at which Seam created the warning. - :ivar message: Detailed description of the warning. + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. - :ivar warning_code: Unique identifier of the type of warning.""" + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["partial_backup_access_code_pool"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class ManyActiveBackupCodesWarning(ResourceMapping): + """Indicates that there are too many backup codes. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["many_active_backup_codes"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class ThirdPartyIntegrationDetectedWarning(ResourceMapping): + """Indicates that a third-party integration has been detected. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["third_party_integration_detected"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class TtlockLockGatewayUnlockingNotEnabledWarning(ResourceMapping): + """Indicates that the Remote Unlock feature is not enabled in the settings." + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["ttlock_lock_gateway_unlocking_not_enabled"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class TtlockWeakGatewaySignalWarning(ResourceMapping): + """Indicates that the gateway signal is weak. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["ttlock_weak_gateway_signal"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class PowerSavingModeWarning(ResourceMapping): + """Indicates that the device is in power saving mode and may have limited functionality. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["power_saving_mode"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class TemperatureThresholdExceededWarning(ResourceMapping): + """Indicates that the temperature threshold has been exceeded. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["temperature_threshold_exceeded"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class DeviceCommunicationDegradedWarning(ResourceMapping): + """Indicates that the device appears to be unresponsive. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["device_communication_degraded"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class ScheduledMaintenanceWindowWarning(ResourceMapping): + """Indicates that a scheduled maintenance window has been detected. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["scheduled_maintenance_window"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class DeviceHasFlakyConnectionWarning(ResourceMapping): + """Indicates that the device has a flaky connection. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["device_has_flaky_connection"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class SaltoKsOfficeModeWarning(ResourceMapping): + """Indicates that the Salto KS lock is in Office Mode. Access Codes will not unlock doors. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["salto_ks_office_mode"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class SaltoKsPrivacyModeWarning(ResourceMapping): + """Indicates that the Salto KS lock is in Privacy Mode. Access Codes will not unlock doors. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["salto_ks_privacy_mode"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class PrivacyModeWarning(ResourceMapping): + """Indicates that the lock is in Privacy Mode. Access codes and remote unlock are blocked until Privacy Mode is disabled. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["privacy_mode"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class SaltoKsSubscriptionLimitAlmostReachedWarning(ResourceMapping): + """Indicates that the Salto KS site has exceeded 80% of the maximum number of allowed users. Increase your subscription limit or delete some users from your site. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["salto_ks_subscription_limit_almost_reached"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class SaltoKsLockAccessCodeSupportRemovedWarning(ResourceMapping): + """Indicates that a change in the reported device model has been detected for this Salto KS lock, which may occur after an IQ hub reset. Access code support may be affected. See https://help.getseam.com/articles/5098842588-salto-ks-lock-loses-access-code-support for troubleshooting steps. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["salto_ks_lock_access_code_support_removed"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class UnknownIssueWithPhoneWarning(ResourceMapping): + """Indicates that an unknown issue occurred while syncing the state of the phone with the provider. This issue may affect the proper functioning of the phone. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["unknown_issue_with_phone"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class LocklyTimeZoneNotConfiguredWarning(ResourceMapping): + """Indicates that Seam detected that the Lockly device does not have a time zone configured. Time-bound codes may not work as expected. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["lockly_time_zone_not_configured"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class UltraloqTimeZoneUnknownWarning(ResourceMapping): + """Indicates that Seam does not know the time zone of the Ultraloq device. Set a time zone to enable time-bound access codes. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["ultraloq_time_zone_unknown"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class TimeZoneUnknownWarning(ResourceMapping): + """Indicates that Seam does not know the device's time zone. Set a time zone to enable time-bound access codes. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["time_zone_unknown"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class TimeZoneMismatchWarning(ResourceMapping): + """Indicates that the device's configured time zone does not match its hardware UTC offset. Time-bound access codes may activate at the wrong local time. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["time_zone_mismatch"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class TwoNDeviceMissingTimezoneWarning(ResourceMapping): + """Indicates that the 2N device does not have a time zone configured. Configure a time zone on the device to enable access codes. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["two_n_device_missing_timezone"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class HubRequiredForAdditionalCapabilitiesWarning(ResourceMapping): + """Indicates that a hub or relay must be connected to unlock additional capabilities such as remote unlock. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["hub_required_for_additional_capabilities"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class ProviderIssueWarning(ResourceMapping): + """Indicates a provider-specific issue that may affect device functionality. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["provider_issue"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class KeynestUnsupportedLockerWarning(ResourceMapping): + """Indicates that the key is in a locker that does not support the access codes API. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ created_at: str message: str - warning_code: str + warning_code: Literal["keynest_unsupported_locker"] @classmethod def from_dict(cls, d: Any): @@ -161,6 +1074,202 @@ def from_dict(cls, d: Any): warning_code=d.get("warning_code", None), ) + @dataclass + class AccessoryKeypadSetupRequiredWarning(ResourceMapping): + """Indicates that the accessory keypad exists, but is not linked to the Igloohome Bridge. Online access code programming will fail until the keypad is linked to the Igloohome Bridge in the Igloohome app. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["accessory_keypad_setup_required"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class AccessoryKeypadLowBatteryWarning(ResourceMapping): + """Indicates that the accessory keypad paired with this lock has a low or critically low battery. Replace its batteries so guests can keep entering their access codes. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["accessory_keypad_low_battery"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class UnreliableOnlineStatusWarning(ResourceMapping): + """Indicates that the device may optimistically be reported as online because the provider does not reliably report its online status. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["unreliable_online_status"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + @dataclass + class MaxAccessCodesReachedWarning(ResourceMapping): + """Indicates that the device has reached its maximum number of active access codes. Delete existing codes before creating new ones. + + :ivar active_access_code_count: Number of active access codes on the device when the warning was set. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar max_active_access_code_count: Maximum number of active access codes supported by the device. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + active_access_code_count: int + created_at: str + max_active_access_code_count: int + message: str + warning_code: Literal["max_access_codes_reached"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + active_access_code_count=d.get("active_access_code_count", None), + created_at=d.get("created_at", None), + max_active_access_code_count=d.get( + "max_active_access_code_count", None + ), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + Errors = Union[ + AccountDisconnectedError, + SaltoKsSubscriptionLimitExceededError, + InsufficientPermissionsError, + DormakabaSitesDisconnectedError, + DeviceOfflineError, + DeviceRemovedError, + HubDisconnectedError, + DeviceDisconnectedError, + EmptyBackupAccessCodePoolError, + AugustLockNotAuthorizedError, + MissingDeviceCredentialsError, + AuxiliaryHeatRunningError, + SubscriptionRequiredError, + BridgeDisconnectedError, + ] + _ErrorsVariants = { + "account_disconnected": AccountDisconnectedError, + "salto_ks_subscription_limit_exceeded": SaltoKsSubscriptionLimitExceededError, + "insufficient_permissions": InsufficientPermissionsError, + "dormakaba_sites_disconnected": DormakabaSitesDisconnectedError, + "device_offline": DeviceOfflineError, + "device_removed": DeviceRemovedError, + "hub_disconnected": HubDisconnectedError, + "device_disconnected": DeviceDisconnectedError, + "empty_backup_access_code_pool": EmptyBackupAccessCodePoolError, + "august_lock_not_authorized": AugustLockNotAuthorizedError, + "missing_device_credentials": MissingDeviceCredentialsError, + "auxiliary_heat_running": AuxiliaryHeatRunningError, + "subscription_required": SubscriptionRequiredError, + "bridge_disconnected": BridgeDisconnectedError, + } + + Warnings = Union[ + PartialBackupAccessCodePoolWarning, + ManyActiveBackupCodesWarning, + ThirdPartyIntegrationDetectedWarning, + TtlockLockGatewayUnlockingNotEnabledWarning, + TtlockWeakGatewaySignalWarning, + PowerSavingModeWarning, + TemperatureThresholdExceededWarning, + DeviceCommunicationDegradedWarning, + ScheduledMaintenanceWindowWarning, + DeviceHasFlakyConnectionWarning, + SaltoKsOfficeModeWarning, + SaltoKsPrivacyModeWarning, + PrivacyModeWarning, + SaltoKsSubscriptionLimitAlmostReachedWarning, + SaltoKsLockAccessCodeSupportRemovedWarning, + UnknownIssueWithPhoneWarning, + LocklyTimeZoneNotConfiguredWarning, + UltraloqTimeZoneUnknownWarning, + TimeZoneUnknownWarning, + TimeZoneMismatchWarning, + TwoNDeviceMissingTimezoneWarning, + HubRequiredForAdditionalCapabilitiesWarning, + ProviderIssueWarning, + KeynestUnsupportedLockerWarning, + AccessoryKeypadSetupRequiredWarning, + AccessoryKeypadLowBatteryWarning, + UnreliableOnlineStatusWarning, + MaxAccessCodesReachedWarning, + ] + _WarningsVariants = { + "partial_backup_access_code_pool": PartialBackupAccessCodePoolWarning, + "many_active_backup_codes": ManyActiveBackupCodesWarning, + "third_party_integration_detected": ThirdPartyIntegrationDetectedWarning, + "ttlock_lock_gateway_unlocking_not_enabled": TtlockLockGatewayUnlockingNotEnabledWarning, + "ttlock_weak_gateway_signal": TtlockWeakGatewaySignalWarning, + "power_saving_mode": PowerSavingModeWarning, + "temperature_threshold_exceeded": TemperatureThresholdExceededWarning, + "device_communication_degraded": DeviceCommunicationDegradedWarning, + "scheduled_maintenance_window": ScheduledMaintenanceWindowWarning, + "device_has_flaky_connection": DeviceHasFlakyConnectionWarning, + "salto_ks_office_mode": SaltoKsOfficeModeWarning, + "salto_ks_privacy_mode": SaltoKsPrivacyModeWarning, + "privacy_mode": PrivacyModeWarning, + "salto_ks_subscription_limit_almost_reached": SaltoKsSubscriptionLimitAlmostReachedWarning, + "salto_ks_lock_access_code_support_removed": SaltoKsLockAccessCodeSupportRemovedWarning, + "unknown_issue_with_phone": UnknownIssueWithPhoneWarning, + "lockly_time_zone_not_configured": LocklyTimeZoneNotConfiguredWarning, + "ultraloq_time_zone_unknown": UltraloqTimeZoneUnknownWarning, + "time_zone_unknown": TimeZoneUnknownWarning, + "time_zone_mismatch": TimeZoneMismatchWarning, + "two_n_device_missing_timezone": TwoNDeviceMissingTimezoneWarning, + "hub_required_for_additional_capabilities": HubRequiredForAdditionalCapabilitiesWarning, + "provider_issue": ProviderIssueWarning, + "keynest_unsupported_locker": KeynestUnsupportedLockerWarning, + "accessory_keypad_setup_required": AccessoryKeypadSetupRequiredWarning, + "accessory_keypad_low_battery": AccessoryKeypadLowBatteryWarning, + "unreliable_online_status": UnreliableOnlineStatusWarning, + "max_access_codes_reached": MaxAccessCodesReachedWarning, + } + created_at: str custom_metadata: Dict[str, Union[str, bool]] device_id: str @@ -180,13 +1289,19 @@ def from_dict(cls, d: Any): device_id=d.get("device_id", None), device_type=d.get("device_type", None), display_name=d.get("display_name", None), - errors=[cls.Errors.from_dict(i) for i in d.get("errors") or []], + errors=[ + _from_discriminated_dict(i, cls._ErrorsVariants, "error_code") + for i in d.get("errors") or [] + ], nickname=d.get("nickname", None), properties=( cls.Properties.from_dict(d.get("properties")) if d.get("properties") is not None else None ), - warnings=[cls.Warnings.from_dict(i) for i in d.get("warnings") or []], + warnings=[ + _from_discriminated_dict(i, cls._WarningsVariants, "warning_code") + for i in d.get("warnings") or [] + ], workspace_id=d.get("workspace_id", None), ) diff --git a/seam/resources/space.py b/seam/resources/space.py index 5bb3ec7a..1279dadd 100644 --- a/seam/resources/space.py +++ b/seam/resources/space.py @@ -4,6 +4,13 @@ from ..resource_mapping import ResourceMapping +def _from_discriminated_dict( + d: Any, variants: Dict[str, Any], discriminator: str +) -> Any: + variant = variants.get(d.get(discriminator)) + return DeepAttrDict(d) if variant is None else variant.from_dict(d) + + @dataclass class Space: """Represents a space that is a logical grouping of devices and entrances. You can assign access to an entire space, thereby making granting access more efficient. @@ -28,6 +35,8 @@ class Space: :ivar space_key: Unique key for the space within the workspace. + :ivar warnings: Warnings associated with the space. + :ivar workspace_id: ID of the workspace associated with the space.""" @dataclass @@ -74,6 +83,34 @@ def from_dict(cls, d: Any): longitude=d.get("longitude", None), ) + @dataclass + class BeingDeletedWarning(ResourceMapping): + """Indicates that the space is being deleted. Seam removes it, revokes its access grants, and detaches its devices and entrances shortly. + + :ivar created_at: Date and time at which Seam created the warning. + + :ivar message: Detailed description of the warning. Provides insights into the issue and potentially how to rectify it. + + :ivar warning_code: Unique identifier of the type of warning. Enables quick recognition and categorization of the issue. + """ + + created_at: str + message: str + warning_code: Literal["being_deleted"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + warning_code=d.get("warning_code", None), + ) + + Warnings = Union[BeingDeletedWarning] + _WarningsVariants = { + "being_deleted": BeingDeletedWarning, + } + acs_entrance_count: float created_at: str customer_data: Optional[CustomerData] @@ -84,6 +121,7 @@ def from_dict(cls, d: Any): name: str space_id: str space_key: Optional[str] + warnings: List[Warnings] workspace_id: str @classmethod @@ -107,5 +145,9 @@ def from_dict(cls, d: Any): name=d.get("name", None), space_id=d.get("space_id", None), space_key=d.get("space_key", None), + warnings=[ + _from_discriminated_dict(i, cls._WarningsVariants, "warning_code") + for i in d.get("warnings") or [] + ], workspace_id=d.get("workspace_id", None), ) diff --git a/seam/resources/unmanaged_access_grant.py b/seam/resources/unmanaged_access_grant.py index 52fb3d68..f0b4124b 100644 --- a/seam/resources/unmanaged_access_grant.py +++ b/seam/resources/unmanaged_access_grant.py @@ -74,6 +74,29 @@ def from_dict(cls, d: Any): missing_device_ids=d.get("missing_device_ids", None), ) + @dataclass + class AccessNotProvisionedError(ResourceMapping): + """Indicates that the access system rejected the access that Seam tried to set up for this access grant, so its credentials cannot open the affected entrances. For example, a hotel room may already be reserved or checked in for another guest. The message contains the reason that the access system gave. Seam keeps retrying, and this error clears automatically once the access system accepts the access. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["access_not_provisioned"] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + message=d.get("message", None), + ) + @dataclass class UpdatingSpacesPendingMutation(ResourceMapping): """Seam is in the process of updating the devices/spaces associated with this access grant. @@ -314,12 +337,12 @@ class FailedDevices(ResourceMapping): :ivar device_id: Device whose access code could not be revoked. - :ivar error_code: Reason the access code could not be revoked (e.g. ``offline_access_code_not_revocable``). + :ivar error_code: Reason the access code could not be revoked. :ivar message: Human-readable description of why revocation failed.""" device_id: str - error_code: str + error_code: Literal["offline_access_code_not_revocable"] message: str @classmethod @@ -469,9 +492,10 @@ def from_dict(cls, d: Any): warning_code=d.get("warning_code", None), ) - Errors = Union[CannotCreateRequestedAccessMethodsError] + Errors = Union[CannotCreateRequestedAccessMethodsError, AccessNotProvisionedError] _ErrorsVariants = { "cannot_create_requested_access_methods": CannotCreateRequestedAccessMethodsError, + "access_not_provisioned": AccessNotProvisionedError, } PendingMutations = Union[ diff --git a/seam/resources/unmanaged_access_method.py b/seam/resources/unmanaged_access_method.py index fdc0d18a..3a267b2d 100644 --- a/seam/resources/unmanaged_access_method.py +++ b/seam/resources/unmanaged_access_method.py @@ -35,7 +35,7 @@ class UnmanagedAccessMethod: :ivar is_ready_for_assignment: Indicates whether the access method is ready for card assignment. This is true when the access method is in card mode, has not yet been issued, and the system supports credential assignment. - :ivar is_ready_for_encoding: Indicates whether the access method is ready to be encoded. This is true when the credential has been created and the card has not yet been issued. + :ivar is_ready_for_encoding: Indicates whether the access method is ready to be encoded. This is true when the card has not yet been issued and the access system has received all the access the card needs. While it is false, ``pending_mutations`` contains ``waiting_for_access_on_acs_system``. :ivar issued_at: Date and time at which the access method was issued. @@ -70,6 +70,29 @@ def from_dict(cls, d: Any): message=d.get("message", None), ) + @dataclass + class AccessNotProvisionedError(ResourceMapping): + """Indicates that the access system rejected the access that Seam tried to set up for this access method, so its credential cannot open the affected entrances, even after it is issued. For example, a hotel room may already be reserved or checked in for another guest. The message contains the reason that the access system gave. Seam keeps retrying, and this error clears automatically once the access system accepts the access. + + :ivar created_at: Date and time at which Seam created the error. + + :ivar error_code: Unique identifier of the type of error. Enables quick recognition and categorization of the issue. + + :ivar message: Detailed description of the error. Provides insights into the issue and potentially how to rectify it. + """ + + created_at: str + error_code: Literal["access_not_provisioned"] + message: str + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + error_code=d.get("error_code", None), + message=d.get("message", None), + ) + @dataclass class ProvisioningAccessPendingMutation(ResourceMapping): """Seam is in the process of provisioning access for this access method on new devices. @@ -264,6 +287,29 @@ def from_dict(cls, d: Any): to=cls.To.from_dict(d.get("to")) if d.get("to") is not None else None, ) + @dataclass + class WaitingForAccessOnAcsSystemPendingMutation(ResourceMapping): + """The access system has not yet received all the access this card needs. A card encoded now would carry only the access the system already has, so wait until this clears before encoding. + + :ivar created_at: Date and time at which the mutation was created. + + :ivar message: Detailed description of the mutation. + + :ivar mutation_code: Mutation code to indicate that the access system has not yet received all the access this card needs, so the card is not ready to be encoded. + """ + + created_at: str + message: str + mutation_code: Literal["waiting_for_access_on_acs_system"] + + @classmethod + def from_dict(cls, d: Any): + return cls( + created_at=d.get("created_at", None), + message=d.get("message", None), + mutation_code=d.get("mutation_code", None), + ) + @dataclass class BeingDeletedWarning(ResourceMapping): """Indicates that the `access method `_ is being deleted. @@ -406,20 +452,23 @@ def from_dict(cls, d: Any): warning_code=d.get("warning_code", None), ) - Errors = Union[FailedToIssueError] + Errors = Union[FailedToIssueError, AccessNotProvisionedError] _ErrorsVariants = { "failed_to_issue": FailedToIssueError, + "access_not_provisioned": AccessNotProvisionedError, } PendingMutations = Union[ ProvisioningAccessPendingMutation, RevokingAccessPendingMutation, UpdatingAccessTimesPendingMutation, + WaitingForAccessOnAcsSystemPendingMutation, ] _PendingMutationsVariants = { "provisioning_access": ProvisioningAccessPendingMutation, "revoking_access": RevokingAccessPendingMutation, "updating_access_times": UpdatingAccessTimesPendingMutation, + "waiting_for_access_on_acs_system": WaitingForAccessOnAcsSystemPendingMutation, } Warnings = Union[ diff --git a/seam/resources/unmanaged_device.py b/seam/resources/unmanaged_device.py index f41933f9..b6ba49a6 100644 --- a/seam/resources/unmanaged_device.py +++ b/seam/resources/unmanaged_device.py @@ -25,6 +25,12 @@ class UnmanagedDevice: :ivar can_hvac_heat_cool: Indicates whether the thermostat supports simultaneous heating and cooling. + :ivar can_mute_speaker: Indicates whether the speaker supports muting and unmuting. + + :ivar can_pause_speaker_playback: Indicates whether the speaker supports pausing and resuming playback. + + :ivar can_play_speaker_chime: Indicates whether the speaker supports playing a chime. + :ivar can_program_offline_access_codes: Indicates whether the device supports programming offline access codes. :ivar can_program_online_access_codes: Indicates whether the device supports programming online access codes. @@ -41,6 +47,8 @@ class UnmanagedDevice: :ivar can_run_thermostat_programs: Indicates whether the thermostat supports running climate programs. + :ivar can_set_speaker_volume: Indicates whether the speaker supports setting its volume. + :ivar can_simulate_connection: Indicates whether the device supports simulating connection in a sandbox. :ivar can_simulate_disconnection: Indicates whether the device supports simulating disconnection in a sandbox. @@ -1436,6 +1444,9 @@ def from_dict(cls, d: Any): can_hvac_cool: Optional[bool] can_hvac_heat: Optional[bool] can_hvac_heat_cool: Optional[bool] + can_mute_speaker: Optional[bool] + can_pause_speaker_playback: Optional[bool] + can_play_speaker_chime: Optional[bool] can_program_offline_access_codes: Optional[bool] can_program_online_access_codes: Optional[bool] can_program_thermostat_programs_as_different_each_day: Optional[bool] @@ -1444,6 +1455,7 @@ def from_dict(cls, d: Any): can_remotely_lock: Optional[bool] can_remotely_unlock: Optional[bool] can_run_thermostat_programs: Optional[bool] + can_set_speaker_volume: Optional[bool] can_simulate_connection: Optional[bool] can_simulate_disconnection: Optional[bool] can_simulate_hub_connection: Optional[bool] @@ -1509,6 +1521,7 @@ def from_dict(cls, d: Any): "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] display_name: str errors: List[Errors] @@ -1526,6 +1539,9 @@ def from_dict(cls, d: Any): can_hvac_cool=d.get("can_hvac_cool", None), can_hvac_heat=d.get("can_hvac_heat", None), can_hvac_heat_cool=d.get("can_hvac_heat_cool", None), + can_mute_speaker=d.get("can_mute_speaker", None), + can_pause_speaker_playback=d.get("can_pause_speaker_playback", None), + can_play_speaker_chime=d.get("can_play_speaker_chime", None), can_program_offline_access_codes=d.get( "can_program_offline_access_codes", None ), @@ -1544,6 +1560,7 @@ def from_dict(cls, d: Any): can_remotely_lock=d.get("can_remotely_lock", None), can_remotely_unlock=d.get("can_remotely_unlock", None), can_run_thermostat_programs=d.get("can_run_thermostat_programs", None), + can_set_speaker_volume=d.get("can_set_speaker_volume", None), can_simulate_connection=d.get("can_simulate_connection", None), can_simulate_disconnection=d.get("can_simulate_disconnection", None), can_simulate_hub_connection=d.get("can_simulate_hub_connection", None), diff --git a/seam/routes/connect_webviews.py b/seam/routes/connect_webviews.py index 15df1a12..6a16e689 100644 --- a/seam/routes/connect_webviews.py +++ b/seam/routes/connect_webviews.py @@ -18,7 +18,12 @@ def create( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -93,6 +98,7 @@ def create( "omnitec", "kisi", "aqara", + "sonos", "yale_access", "hid_cm", "google_nest", @@ -210,7 +216,12 @@ async def create( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -285,6 +296,7 @@ async def create( "omnitec", "kisi", "aqara", + "sonos", "yale_access", "hid_cm", "google_nest", @@ -409,7 +421,12 @@ def create( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -484,6 +501,7 @@ def create( "omnitec", "kisi", "aqara", + "sonos", "yale_access", "hid_cm", "google_nest", @@ -690,7 +708,12 @@ async def create( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -765,6 +788,7 @@ async def create( "omnitec", "kisi", "aqara", + "sonos", "yale_access", "hid_cm", "google_nest", diff --git a/seam/routes/connected_accounts.py b/seam/routes/connected_accounts.py index 242cd6ca..d3cda3aa 100644 --- a/seam/routes/connected_accounts.py +++ b/seam/routes/connected_accounts.py @@ -96,7 +96,12 @@ def update( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -203,7 +208,12 @@ async def update( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -399,7 +409,12 @@ def update( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, @@ -616,7 +631,12 @@ async def update( accepted_capabilities: Optional[ List[ Literal[ - "lock", "thermostat", "noise_sensor", "access_control", "camera" + "lock", + "thermostat", + "noise_sensor", + "access_control", + "camera", + "speaker", ] ] ] = None, diff --git a/seam/routes/customers.py b/seam/routes/customers.py index f1adf17b..17d59ee7 100644 --- a/seam/routes/customers.py +++ b/seam/routes/customers.py @@ -91,6 +91,7 @@ def delete_data( ) -> None: """Deletes customer data including resources like spaces, properties, rooms, users, etc. This will delete the partner resources and any related Seam resources (user identities, access grants, spaces). + Space keys also match spaces created directly with a ``space_key`` (for example, through ``/spaces/create``). :param access_grant_keys: List of access grant keys to delete. @@ -144,6 +145,7 @@ def push_data( facilities: Optional[List[Dict[str, Any]]] = None, guests: Optional[List[Dict[str, Any]]] = None, listings: Optional[List[Dict[str, Any]]] = None, + low_battery_alert_threshold: Optional[Union[float, Null]] = None, properties: Optional[List[Dict[str, Any]]] = None, property_listings: Optional[List[Dict[str, Any]]] = None, reservations: Optional[List[Dict[str, Any]]] = None, @@ -177,6 +179,8 @@ def push_data( :param listings: List of property listings. + :param low_battery_alert_threshold: Battery level, from 0 to 1, at or below which ``device.low_battery`` events fire for this customer's devices. Overrides the workspace and device defaults. Pass ``null`` to remove the customer's override. + :param properties: List of short-term rental properties. :param property_listings: List of property listings. @@ -287,6 +291,7 @@ async def delete_data( ) -> None: """Deletes customer data including resources like spaces, properties, rooms, users, etc. This will delete the partner resources and any related Seam resources (user identities, access grants, spaces). + Space keys also match spaces created directly with a ``space_key`` (for example, through ``/spaces/create``). :param access_grant_keys: List of access grant keys to delete. @@ -340,6 +345,7 @@ async def push_data( facilities: Optional[List[Dict[str, Any]]] = None, guests: Optional[List[Dict[str, Any]]] = None, listings: Optional[List[Dict[str, Any]]] = None, + low_battery_alert_threshold: Optional[Union[float, Null]] = None, properties: Optional[List[Dict[str, Any]]] = None, property_listings: Optional[List[Dict[str, Any]]] = None, reservations: Optional[List[Dict[str, Any]]] = None, @@ -373,6 +379,8 @@ async def push_data( :param listings: List of property listings. + :param low_battery_alert_threshold: Battery level, from 0 to 1, at or below which ``device.low_battery`` events fire for this customer's devices. Overrides the workspace and device defaults. Pass ``null`` to remove the customer's override. + :param properties: List of short-term rental properties. :param property_listings: List of property listings. @@ -523,6 +531,7 @@ def delete_data( ) -> None: """Deletes customer data including resources like spaces, properties, rooms, users, etc. This will delete the partner resources and any related Seam resources (user identities, access grants, spaces). + Space keys also match spaces created directly with a ``space_key`` (for example, through ``/spaces/create``). :param access_grant_keys: List of access grant keys to delete. @@ -623,6 +632,7 @@ def push_data( facilities: Optional[List[Dict[str, Any]]] = None, guests: Optional[List[Dict[str, Any]]] = None, listings: Optional[List[Dict[str, Any]]] = None, + low_battery_alert_threshold: Optional[Union[float, Null]] = None, properties: Optional[List[Dict[str, Any]]] = None, property_listings: Optional[List[Dict[str, Any]]] = None, reservations: Optional[List[Dict[str, Any]]] = None, @@ -656,6 +666,8 @@ def push_data( :param listings: List of property listings. + :param low_battery_alert_threshold: Battery level, from 0 to 1, at or below which ``device.low_battery`` events fire for this customer's devices. Overrides the workspace and device defaults. Pass ``null`` to remove the customer's override. + :param properties: List of short-term rental properties. :param property_listings: List of property listings. @@ -699,6 +711,8 @@ def push_data( json_payload["guests"] = guests if listings is not None: json_payload["listings"] = listings + if low_battery_alert_threshold is not None: + json_payload["low_battery_alert_threshold"] = low_battery_alert_threshold if properties is not None: json_payload["properties"] = properties if property_listings is not None: @@ -853,6 +867,7 @@ async def delete_data( ) -> None: """Deletes customer data including resources like spaces, properties, rooms, users, etc. This will delete the partner resources and any related Seam resources (user identities, access grants, spaces). + Space keys also match spaces created directly with a ``space_key`` (for example, through ``/spaces/create``). :param access_grant_keys: List of access grant keys to delete. @@ -953,6 +968,7 @@ async def push_data( facilities: Optional[List[Dict[str, Any]]] = None, guests: Optional[List[Dict[str, Any]]] = None, listings: Optional[List[Dict[str, Any]]] = None, + low_battery_alert_threshold: Optional[Union[float, Null]] = None, properties: Optional[List[Dict[str, Any]]] = None, property_listings: Optional[List[Dict[str, Any]]] = None, reservations: Optional[List[Dict[str, Any]]] = None, @@ -986,6 +1002,8 @@ async def push_data( :param listings: List of property listings. + :param low_battery_alert_threshold: Battery level, from 0 to 1, at or below which ``device.low_battery`` events fire for this customer's devices. Overrides the workspace and device defaults. Pass ``null`` to remove the customer's override. + :param properties: List of short-term rental properties. :param property_listings: List of property listings. @@ -1029,6 +1047,8 @@ async def push_data( json_payload["guests"] = guests if listings is not None: json_payload["listings"] = listings + if low_battery_alert_threshold is not None: + json_payload["low_battery_alert_threshold"] = low_battery_alert_threshold if properties is not None: json_payload["properties"] = properties if property_listings is not None: diff --git a/seam/routes/devices.py b/seam/routes/devices.py index 61b86de1..98bc869e 100644 --- a/seam/routes/devices.py +++ b/seam/routes/devices.py @@ -109,6 +109,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -160,6 +161,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -223,6 +225,7 @@ def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, @@ -420,6 +423,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -471,6 +475,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -534,6 +539,7 @@ async def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, @@ -761,6 +767,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -812,6 +819,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -875,6 +883,7 @@ def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, @@ -1193,6 +1202,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -1244,6 +1254,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -1307,6 +1318,7 @@ async def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, diff --git a/seam/routes/devices_unmanaged.py b/seam/routes/devices_unmanaged.py index 9b551602..93267125 100644 --- a/seam/routes/devices_unmanaged.py +++ b/seam/routes/devices_unmanaged.py @@ -88,6 +88,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -139,6 +140,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -202,6 +204,7 @@ def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, @@ -338,6 +341,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -389,6 +393,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -452,6 +457,7 @@ async def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, @@ -624,6 +630,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -675,6 +682,7 @@ def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -738,6 +746,7 @@ def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None, @@ -960,6 +969,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] = None, device_types: Optional[ @@ -1011,6 +1021,7 @@ async def list( "tapo_camera", "arlo_camera", "reolink_camera", + "sonos_speaker", ] ] ] = None, @@ -1074,6 +1085,7 @@ async def list( "kisi", "slack", "yacan", + "sonos", ] ] = None, page_cursor: Optional[Union[str, Null]] = None,