TTlockClient (TTlockClient v2.1.0)
TTLock client library for Elixir.
This library provides a clean, centralized interface to the TTLock Open Platform API with automatic OAuth 2.0 token management and refresh capabilities.
Getting Started
First, configure your client credentials:
TTlockClient.configure("your_client_id", "your_client_secret")Then authenticate with your TTLock app credentials:
TTlockClient.authenticate("your_username", "your_password")Now you can get valid tokens for API requests:
{:ok, token} = TTlockClient.get_valid_token()Configuration
The library supports configuration through application config:
config :ex_ttlock,
client_id: "your_client_id",
client_secret: "your_client_secret",
base_url: "https://euapi.ttlock.com" # optionalArchitecture
This library implements a centralized authentication state manager using GenServer that handles all token lifecycle management. This eliminates the need for module-specific authentication logic and provides thread-safe access to tokens across your application.
Key features:
- Automatic token refresh before expiry
- Thread-safe token access
- Centralized authentication state
- Error handling and recovery
- Proper OTP supervision
Summary
Functions
Adds a custom passcode with full control over parameters.
Adds a permanent passcode to a lock via gateway.
Adds a temporary passcode to a lock via gateway.
Authenticates with TTLock using your app credentials.
Changes a passcode's name, value, or validity period.
Changes only a passcode's name.
Changes only a passcode's validity period.
Changes only a passcode's value.
Configures the TTLock client with your application credentials.
Deletes a passcode from a lock via gateway.
Convenience function to delete a passcode via gateway.
Gets all locks for the authenticated user (handles pagination automatically).
Gets the list of locks for a specified gateway.
Gets the list of gateways for the authenticated user account.
Gets detailed information about a specific lock.
Gets all passcodes for a lock (convenience function).
Gets the list of locks for the authenticated user.
Gets all passcodes for a lock.
Gets the user ID of the currently authenticated user.
Gets a valid access token for API requests.
Helper function to check if the client is ready for API calls.
Manually refreshes the current access token.
Resets all authentication state.
Searches passcodes by name or passcode value.
Convenience function to configure and authenticate in one call.
Convenience function to start with environment variables.
Gets the current authentication status.
Functions
add_passcode(lock_id, passcode, name \\ nil, passcode_type \\ 3, start_date \\ nil, end_date \\ nil, add_type \\ 2)
@spec add_passcode( integer(), integer(), String.t() | nil, integer(), integer() | nil, integer() | nil, integer() ) :: {:ok, map()} | {:error, term()}
Adds a custom passcode with full control over parameters.
Parameters
lock_id- The lock ID to add the passcode topasscode- The 4-9 digit passcodename- Optional name/alias for the passcodepasscode_type- 2 = permanent, 3 = periodstart_date- Start time in milliseconds (required for period type)end_date- End time in milliseconds (required for period type)add_type- 2 = Gateway/WiFi
Examples
# Permanent passcode via gateway
{:ok, result} = TTlockClient.add_passcode(12345, 123456, "Guest", 2, nil, nil, 2)Returns
{:ok, response}- Contains keyboardPwdId{:error, reason}- Request failed
@spec add_permanent_passcode(integer(), integer(), String.t() | nil) :: {:ok, map()} | {:error, term()}
Adds a permanent passcode to a lock via gateway.
Parameters
lock_id- The lock ID to add the passcode topasscode- The 4-9 digit passcodename- Optional name/alias for the passcode
Examples
{:ok, %{keyboardPwdId: passcode_id}} = TTlockClient.add_permanent_passcode(12345, 123456, "Guest")Returns
{:ok, response}- Contains keyboardPwdId{:error, reason}- Request failed
@spec add_temporary_passcode( integer(), integer(), DateTime.t() | integer(), DateTime.t() | integer(), String.t() | nil ) :: {:ok, map()} | {:error, term()}
Adds a temporary passcode to a lock via gateway.
Parameters
lock_id- The lock ID to add the passcode topasscode- The 4-9 digit passcodestart_date- Start time (DateTime or milliseconds)end_date- End time (DateTime or milliseconds)name- Optional name/alias for the passcode
Examples
start_time = DateTime.utc_now()
end_time = DateTime.add(start_time, 7, :day)
{:ok, result} = TTlockClient.add_temporary_passcode(12345, 987654, start_time, end_time, "Week Access")Returns
{:ok, response}- Contains keyboardPwdId{:error, reason}- Request failed
Authenticates with TTLock using your app credentials.
Important: Use your TTLock mobile app credentials here, not your developer portal credentials. The username should be the same one you use to log into the TTLock mobile application.
Parameters
username- Your TTLock app username (often a phone number like "+8618966498228")password- Your TTLock app password (will be MD5 hashed automatically)
Examples
TTlockClient.authenticate("+8618966498228", "your_password")
TTlockClient.authenticate("your_email@example.com", "your_password")Returns
:ok- Authentication successful, tokens stored{:error, reason}- Authentication failed
Common error reasons:
:not_configured- Need to callconfigure/2first%{error_code: code, description: msg}- TTLock API error- Network/HTTP errors
change_passcode(lock_id, passcode_id, new_name \\ nil, new_passcode \\ nil, start_date \\ nil, end_date \\ nil)
@spec change_passcode( integer(), integer(), String.t() | nil, integer() | nil, DateTime.t() | integer() | nil, DateTime.t() | integer() | nil ) :: {:ok, map()} | {:error, term()}
Changes a passcode's name, value, or validity period.
Can change any combination of passcode properties. At least one of the optional parameters must be provided to perform a change.
Parameters
lock_id- The lock ID containing the passcodepasscode_id- The passcode ID to changenew_name- Optional new name for the passcodenew_passcode- Optional new passcode value (4-9 digits)start_date- Optional new start time (DateTime or milliseconds)end_date- Optional new end time (DateTime or milliseconds)
Examples
# Change name only
{:ok, result} = TTlockClient.change_passcode(12345, 67890, "New Name")
# Change passcode value only
{:ok, result} = TTlockClient.change_passcode(12345, 67890, nil, 999888)
# Change validity period only
start_time = DateTime.utc_now()
end_time = DateTime.add(start_time, 30, :day)
{:ok, result} = TTlockClient.change_passcode(12345, 67890, nil, nil, start_time, end_time)
# Change multiple properties
{:ok, result} = TTlockClient.change_passcode(12345, 67890, "Updated", 888999, start_time, end_time)Returns
{:ok, response}- Success with status information{:error, reason}- Request failed
Changes only a passcode's name.
Parameters
lock_id- The lock ID containing the passcodepasscode_id- The passcode ID to changenew_name- The new name for the passcode
Examples
{:ok, result} = TTlockClient.change_passcode_name(12345, 67890, "Updated Guest Access")Returns
{:ok, response}- Success with status information{:error, reason}- Request failed
@spec change_passcode_period( integer(), integer(), DateTime.t() | integer(), DateTime.t() | integer() ) :: {:ok, map()} | {:error, term()}
Changes only a passcode's validity period.
Parameters
lock_id- The lock ID containing the passcodepasscode_id- The passcode ID to changestart_date- New start time (DateTime or milliseconds)end_date- New end time (DateTime or milliseconds)
Examples
start_time = DateTime.utc_now()
end_time = DateTime.add(start_time, 30, :day)
{:ok, result} = TTlockClient.change_passcode_period(12345, 67890, start_time, end_time)Returns
{:ok, response}- Success with status information{:error, reason}- Request failed
Changes only a passcode's value.
Parameters
lock_id- The lock ID containing the passcodepasscode_id- The passcode ID to changenew_passcode- The new passcode value (4-9 digits)
Examples
{:ok, result} = TTlockClient.change_passcode_value(12345, 67890, 999888)Returns
{:ok, response}- Success with status information{:error, reason}- Request failed
Configures the TTLock client with your application credentials.
Parameters
client_id- Your application's client ID from the TTLock developer portalclient_secret- Your application's client secret from the TTLock developer portalbase_url- Optional API base URL (defaults to EU endpoint)
Examples
TTlockClient.configure("your_client_id", "your_client_secret")
# For different regions
TTlockClient.configure("client_id", "client_secret", "https://usapi.ttlock.com")Returns
:ok- Configuration successful{:error, reason}- Configuration failed
Deletes a passcode from a lock via gateway.
The passcode will be deleted directly via the cloud API for WiFi locks or locks connected to a gateway.
Parameters
lock_id- The lock ID containing the passcodepasscode_id- The passcode ID to delete
Examples
{:ok, result} = TTlockClient.delete_passcode(12345, 67890)Returns
{:ok, response}- Success with status information{:error, reason}- Request failed
Convenience function to delete a passcode via gateway.
This is an alias for delete_passcode/2 for clarity.
Parameters
lock_id- The lock ID containing the passcodepasscode_id- The passcode ID to delete
Examples
{:ok, result} = TTlockClient.delete_passcode_via_gateway(12345, 67890)Returns
{:ok, response}- Success with status information{:error, reason}- Request failed
Gets all locks for the authenticated user (handles pagination automatically).
Parameters
lock_alias- Optional filter by lock aliasgroup_id- Optional filter by group ID
Examples
{:ok, all_locks} = TTlockClient.get_all_locks()
{:ok, filtered_locks} = TTlockClient.get_all_locks("Front Door")Returns
{:ok, [lock_records]}- List of all locks{:error, reason}- Request failed
Gets the list of locks for a specified gateway.
Parameters
gateway_id- Gateway ID
Examples
{:ok, locks} = TTlockClient.get_gateway_locks(12345)Returns
{:ok, %{list: [lock_info]}}- List of locks with their information{:error, reason}- Request failed
Gets the list of gateways for the authenticated user account.
Parameters
page_no- Page number (starting from 1, default 1)page_size- Number of items per page (max 200, default 20)order_by- Sort order: 0 = by name, 1 = reverse by time, 2 = reverse by name (default 1)
Examples
{:ok, response} = TTlockClient.get_gateways()
{:ok, response} = TTlockClient.get_gateways(2, 50, 0)Returns
{:ok, response}- List of gateways with pagination info{:error, reason}- Request failed
Gets detailed information about a specific lock.
Parameters
lock_id- The ID of the lock to retrieve
Examples
{:ok, lock_detail} = TTlockClient.get_lock(12345)Returns
{:ok, lock_detail}- Detailed lock information{:error, reason}- Request failed or lock not found
Gets all passcodes for a lock (convenience function).
Parameters
lock_id- The lock ID to get passcodes forsearch_str- Optional search string
Examples
{:ok, %{list: passcodes}} = TTlockClient.get_lock_passcodes(12345)
{:ok, results} = TTlockClient.get_lock_passcodes(12345, "Guest")Returns
{:ok, response}- Contains list of passcodes{:error, reason}- Request failed
@spec get_locks(integer(), integer(), String.t() | nil, integer() | nil) :: {:ok, map()} | {:error, term()}
Gets the list of locks for the authenticated user.
Parameters
page_no- Page number (default 1)page_size- Items per page (default 20, max 1000)lock_alias- Optional filter by lock aliasgroup_id- Optional filter by group ID
Examples
# Get first page with defaults
{:ok, locks} = TTlockClient.get_locks()
# Get specific page
{:ok, locks} = TTlockClient.get_locks(2, 50)
# Filter by lock alias
{:ok, locks} = TTlockClient.get_locks(1, 20, "Front Door")Returns
{:ok, response}- Contains list, pagination info{:error, reason}- Request failed
@spec get_passcodes(integer(), String.t() | nil, integer(), integer(), integer()) :: {:ok, map()} | {:error, term()}
Gets all passcodes for a lock.
Parameters
lock_id- The lock ID to get passcodes forsearch_str- Optional search keyword (fuzzy search by name or exact match by passcode)page_no- Page number (default 1)page_size- Items per page (default 20, max 200)order_by- Sorting: 0 = by name, 1 = reverse by time, 2 = reverse by name (default 1)
Examples
# Get all passcodes for a lock
{:ok, %{list: passcodes, total: count}} = TTlockClient.get_passcodes(12345)
# Search for specific passcodes
{:ok, response} = TTlockClient.get_passcodes(12345, "Guest")
# Get specific page
{:ok, response} = TTlockClient.get_passcodes(12345, nil, 2, 50, 1)Returns
{:ok, response}- Contains list, pagination info{:error, reason}- Request failed
@spec get_user_id() :: {:ok, integer()} | {:error, :not_authenticated}
Gets the user ID of the currently authenticated user.
Examples
{:ok, user_id} = TTlockClient.get_user_id()Returns
{:ok, user_id}- Current user's ID{:error, :not_authenticated}- No user currently authenticated
Gets a valid access token for API requests.
This function will automatically refresh the token if it's expired or near expiry. The returned token can be used immediately for TTLock API requests.
Examples
case TTlockClient.get_valid_token() do
{:ok, token} ->
# Use token in your API requests
headers = [{"Authorization", "Bearer " <> token}]
{:error, :not_authenticated} ->
# Need to authenticate first
TTlockClient.authenticate("username", "password")
{:error, reason} ->
# Handle other errors
Logger.error("Token error: " <> inspect(reason))
endReturns
{:ok, access_token}- Valid token ready for use{:error, :not_authenticated}- Need to authenticate first{:error, reason}- Token refresh or other error
@spec ready?() :: boolean()
Helper function to check if the client is ready for API calls.
Examples
if TTlockClient.ready?() do
{:ok, token} = TTlockClient.get_valid_token()
# Make API calls
else
# Need to configure/authenticate
endReturns
true- Client is authenticated and readyfalse- Client needs configuration or authentication
@spec refresh_token() :: :ok | {:error, term()}
Manually refreshes the current access token.
Normally you don't need to call this as tokens are refreshed automatically, but this can be useful for testing or if you need to force a refresh.
Examples
TTlockClient.refresh_token()Returns
:ok- Token refreshed successfully{:error, reason}- Refresh failed
@spec reset() :: :ok
Resets all authentication state.
This clears stored tokens and credentials. You'll need to configure and authenticate again after calling this.
Examples
TTlockClient.reset()
TTlockClient.configure("new_client_id", "new_client_secret")
TTlockClient.authenticate("username", "password")Returns
:ok- State cleared successfully
Searches passcodes by name or passcode value.
Parameters
lock_id- The lock ID to search insearch_term- Search term (name or exact passcode match)
Examples
{:ok, results} = TTlockClient.search_passcodes(12345, "Guest")
{:ok, results} = TTlockClient.search_passcodes(12345, "123456")Returns
{:ok, response}- Contains matching passcodes{:error, reason}- Request failed
Convenience function to configure and authenticate in one call.
Parameters
client_id- Application client IDclient_secret- Application client secretusername- TTLock app usernamepassword- TTLock app passwordbase_url- Optional API base URL
Examples
TTlockClient.start("client_id", "client_secret", "username", "password")Returns
:ok- Configuration and authentication successful{:error, reason}- Setup failed
@spec start_with_env() :: :ok | {:error, term()}
Convenience function to start with environment variables.
Reads TTLOCK_CLIENT_ID, TTLOCK_CLIENT_SECRET, TTLOCK_USERNAME, and TTLOCK_PASSWORD from environment variables and configures/authenticates.
Examples
# Ensure your .env file has the required variables
TTlockClient.start_with_env()Returns
:ok- Configuration and authentication successful{:error, :missing_env_vars}- Required environment variables not set{:error, reason}- Setup failed
@spec status() :: :not_configured | :configured | :authenticated
Gets the current authentication status.
Examples
case TTlockClient.status() do
:not_configured ->
# Need to call configure/2
:configured ->
# Configured but not authenticated
:authenticated ->
# Ready to make API calls
endReturns
:not_configured- Client credentials not set:configured- Client configured but not authenticated:authenticated- Ready for API requests