device package
Submodules
device.crypto module
- device.crypto.certificate_is_valid(crypto_store_dir: str) bool
Utility function that checks the certificate validity
- Parameters:
crypto_store_dir (str) – Path to the folder where crypto information are stored
- Returns:
True if the certificate is valid, False otherwise.
- Return type:
bool
- device.crypto.device_has_certificate(crypto_store_dir: str) bool
Utility function that checks if a certificate is present for the device
- Parameters:
crypto_store_dir (str) – Path to the folder where crypto information is stored
- Returns:
True if the certificate is present, False otherwise
- Return type:
bool
- device.crypto.generate_csr(realm: str, device_id: str, crypto_store_dir: str) bytes
Utility function that generate the csr for the device
- Parameters:
realm (str) – The Astarte realm where the device will be registered
device_id (str) – The device ID
crypto_store_dir (str) – Path to the folder where crypto information is stored
- Returns:
The device certificate signing request file
- Return type:
bytes
- device.crypto.import_device_certificate(client_crt: str, crypto_store_dir: str) None
Deserialize a client certificate and store the public information permanently in the file system
- Parameters:
client_crt (str) – Serialized client certificate
crypto_store_dir (str) – Directory where to store the public bytes of the certificate
device.database module
API for an SQLite database to be used for Astarte properties persistency.
- class device.database.AstarteDatabase
Bases:
ABC
Abstract class for a database that can be used to provide persistency to the properties.
- abstract clear() None
Fully clear the database of all the properties.
- abstract delete_prop(interface: str, path: str) None
Delete a property from the database.
- Parameters:
interface (str) – The interface name.
path (str) – The path to the property endpoint.
- abstract load_all_props() list[tuple[str, int, str, object]]
Load all the properties stored in the database.
- Returns:
A list containing all the propeties stored in the database. Each element of the list is a tuple in the format: (interface, interface major version, path, value)
- Return type:
list[tuple[str, int, str, object]]
- abstract load_prop(interface: str, major: int, path: str) object | None
Load a property from the database. If a property is found but the major version does not match, the property in the database will be deleted and None will be returned.
- Parameters:
interface (str) – The interface name.
major (int) – The major version for the interface.
path (str) – The path to the property endpoint.
- Returns:
The property value if the property is present and the provided interface major version matches the interface version stored in the database. None otherwise.
- Return type:
object | None
- abstract store_prop(interface: str, major: int, path: str, value: object) None
Store a property value in the database. It will overwrite the previous value where present.
- Parameters:
interface (str) – The interface name.
major (int) – The major version for the interface.
path (str) – The path to the property endpoint.
value (object) – The new value for the property.
- class device.database.AstarteDatabaseSQLite(database_path: Path)
Bases:
AstarteDatabase
An implementation for the abstract AstarteDatabase class. This implementation uses the standard SQLite library of python to implement property persistency.
- clear() None
Fully clear the database of all the properties.
- delete_prop(interface: str, path: str) None
Delete a property from the database.
- Parameters:
interface (str) – See documentation in AstarteDatabase.
path (str) – See documentation in AstarteDatabase.
- load_all_props() list[tuple[str, int, str, object]]
Load all the properties stored in the database.
- Returns:
See documentation in AstarteDatabase.
- Return type:
list[tuple[str, int, str, object]]
- load_prop(interface: str, major: int, path: str) object | None
Load a property from the database. If a property is found but the major version does not match, the property in the database will be deleted and None will be returned.
- Parameters:
interface (str) – See documentation in AstarteDatabase.
major (int) – See documentation in AstarteDatabase.
path (str) – See documentation in AstarteDatabase.
- Returns:
See documentation in AstarteDatabase.
- Return type:
object | None
- store_prop(interface: str, major: int, path: str, value: object | None) None
Store a property value in the database. It will overwrite the previous value where present.
- Parameters:
interface (str) – See documentation in AstarteDatabase.
major (int) – See documentation in AstarteDatabase.
path (str) – See documentation in AstarteDatabase.
value (object) – See documentation in AstarteDatabase.
device.device module
- class device.device.Device(device_id: str, realm: str, credentials_secret: str, pairing_base_url: str, persistency_dir: str, database: AstarteDatabase | None = None, loop: AbstractEventLoop | None = None, ignore_ssl_errors: bool = False)
Bases:
object
Basic class to define an Astarte Device.
Device represents an Astarte Device. It is the base class used for managing the Device lifecycle and data. Users should instantiate a Device with the right credentials and connect it to the configured instance to start working with it.
Threading and Concurrency
This SDK uses paho-mqtt under the hood to provide Transport connectivity. As such, it is bound by paho-mqtt’s behaviors in terms of threading. When a Device connects, a new thread is spawned and an event loop is run there to manage all the connection events.
This SDK spares the user from this detail - on the other hand, when configuring callbacks, threading has to be taken into account. When creating a Device, it is possible to specify an asyncio.loop() to automatically manage this detail. When a loop is specified, all callbacks will be called in the context of that loop, guaranteeing thread-safety and making sure that the user does not have to take any further action beyond consuming the callback.
When a loop is not specified, callbacks are invoked just as standard Python functions. This inevitably means that the user will have to take into account the fact that the callback will be invoked in the Thread of the MQTT connection. In particular, blocking the execution of that thread might cause deadlocks and, in general, malfunctions in the SDK. For this reason, the usage of asyncio is strongly recommended.
- on_connected
A function that will be invoked everytime the device successfully connects.
- Type:
Callable[[Device], None]
- on_disconnected
A function that will be invoked everytime the device disconnects. The int parameter bears the disconnect reason.
- Type:
Callable[[Device, int], None]
- on_data_received
A function that will be invoked everytime data is received from Astarte. Parameters are the Device itself, the Interface name, the Interface path, and the payload. The payload will reflect the type defined in the Interface.
- Type:
Callable[[Device, string, string, object], None]
- add_interface(interface_definition: dict) None
Adds an Interface to the Device
This will add an Interface definition to the Device. It has to be called before
connect()
, as it will be used for building the Device Introspection.- Parameters:
interface_definition (dict) – An Astarte Interface definition in the form of a Python dictionary. Usually obtained by using json.loads() on an Interface file.
- add_interface_from_file(interface_file: Path)
Adds an interface to the device
This will add an interface definition to the device. It has to be called before
connect()
, as it will be used for building the device introspection.- Parameters:
interface_file (Path) – An absolute path to an Astarte interface json file.
- Raises:
InterfaceFileNotFoundError – If the provided interface file does not exists.
InterfaceFileDecodeError – If speficied file is not a parsable .json file.
- add_interfaces_from_dir(interfaces_dir: Path)
Adds a series of interfaces to the device
This will add all the interfaces contained in the provided folder to the device. It has to be called before
connect()
, as it will be used for building the device introspection.- Parameters:
interfaces_dir (Path) – An absolute path to an a folder containing some Astarte interface .json files.
- Raises:
InterfaceFileNotFoundError – If specified directory does not exists.
- connect() None
Connects the Device asynchronously.
When calling connect, a new connection thread is spawned and the Device will start a connection routine. The function might return before the Device connects: you want to use the on_connected callback to ensure you are notified upon connection.
In case the Device gets disconnected unexpectedly, it will try to reconnect indefinitely until disconnect() is called.
- disconnect() None
Disconnects the Device asynchronously.
When calling disconnect, the connection thread is requested to terminate the disconnection, and the thread is stopped when the disconnection happens. The function might return before the Device connects: you want to use the on_disconnected callback to ensure you are notified upon connection. When doing so, check the return code parameter: if it is 0, it means the disconnection happened following an explicit disconnection request.
- get_device_id() str
Returns the Device ID of the Device.
- Returns:
The Id of the device
- Return type:
str
- is_connected() bool
Returns whether the Device is currently connected.
- Returns:
The device connection status.
- Return type:
bool
- remove_interface(interface_name: str) None
Removes an Interface from the Device
Removes an Interface definition from the Device. It has to be called before
connect()
, as it will be used for building the Device Introspection.- Parameters:
interface_name (str) – The name of an Interface previously added with
add_interface()
.
- send(interface_name: str, interface_path: str, payload: object, timestamp: datetime | None = None) None
Sends an individual message to an interface.
- Parameters:
interface_name (str) – The name of an the Interface to send data to.
interface_path (str) – The path on the Interface to send data to.
payload (object) – The value to be sent. The type should be compatible to the one specified in the interface path.
timestamp (datetime, optional) – If sending a Datastream with explicit_timestamp, you can specify a datetime object which will be registered as the timestamp for the value.
- Raises:
InterfaceNotFoundError – If the interface is not declared in the introspection
ValidationError – If the interface or the payload are not compatible.
- send_aggregate(interface_name: str, interface_path: str, payload: Mapping, timestamp: datetime | None = None) None
Sends an aggregate message to an interface
- Parameters:
interface_name (str) – The name of the Interface to send data to.
interface_path (str) – The endpoint to send the data to
payload (dict) – A dictionary containing the path:value map for the aggregate.
timestamp (datetime, optional) – If the Datastream has explicit_timestamp, you can specify a datetime object which will be registered as the timestamp for the value.
- Raises:
InterfaceNotFoundError – If the interface is not declared in the introspection
ValidationError – If the interface or the payload are not compatible.
- unset_property(interface_name: str, interface_path: str) None
Unset the specified property on an interface.
- Parameters:
interface_name (str) – The name of the Interface where the property to unset is located.
interface_path (str) – The path on the Interface to unset.
- Raises:
InterfaceNotFoundError – If the interface is not declared in the introspection
ValidationError – If the interface is of type datastream.
device.exceptions module
- exception device.exceptions.APIError(body)
Bases:
AstarteError
Exception raised when Astarte APIs throw unhandled errors.
- body -- the body of the API reply, which may carry further details
- exception device.exceptions.AstarteError
Bases:
Exception
Base class for Astarte Errors.
- exception device.exceptions.AuthorizationError(body)
Bases:
AstarteError
Exception raised when Astarte APIs refuse authentication.
- body -- the body of the API reply, which may carry further details
- exception device.exceptions.DeviceAlreadyRegisteredError
Bases:
AstarteError
Exception raised in case a Device being registered has already been registered.
- exception device.exceptions.InterfaceFileDecodeError(msg)
Bases:
AstarteError
Exception raised when an interface .json file is not correctly formatted.
- msg -- A message error carrying further details
- exception device.exceptions.InterfaceFileNotFoundError(msg)
Bases:
AstarteError
Exception raised when a file containing an interface definition does not exists.
- msg -- A message error carrying further details
- exception device.exceptions.InterfaceNotFoundError(msg)
Bases:
AstarteError
Exception raised when an interface is not found in the device introspection.
- msg -- A message error carrying further details
- exception device.exceptions.JWTGenerationError(msg)
Bases:
AstarteError
Exception raised when the generation of a Jason Web Token has failed.
- msg -- A message error carrying further details
- exception device.exceptions.PersistencyDirectoryNotFoundError(body)
Bases:
AstarteError
Exception raised when the provided persistency directory is not found.
- body -- the body of the API reply, which may carry further details
- exception device.exceptions.ValidationError(msg)
Bases:
AstarteError
Exception raised when validation has failed.
- msg -- A message error carrying further details
device.interface module
- class device.interface.Interface(interface_definition: dict)
Bases:
object
Class that represent an Interface definition
Interfaces are a core concept of Astarte which defines how data is exchanged between Astarte and its peers. They are not to be intended as OOP interfaces, but rather as the following definition:
In Astarte each interface has an owner, can represent either a continuous data stream or a snapshot of a set of properties, and can be either aggregated into an object or be an independent set of individual members.
- name
Interface name
- Type:
str
- version_major
Interface version major number
- Type:
int
- version_minor
Interface version minor number
- Type:
int
- type
Interface type
- Type:
str
- ownership
Interface ownership
- Type:
str
- aggregation
Interface aggregation policy
- Type:
str
- get_mapping(endpoint) Mapping | None
Retrieve the Mapping with the given endpoint from the Interface :param endpoint: The Mapping endpoint :type endpoint: str
- Returns:
The Mapping if found, None otherwise
- Return type:
Mapping or None
- get_reliability(endpoint: str) int
Get the reliability for the mapping corresponding to the provided endpoint.
- Parameters:
endpoint (str) – The Mapping endpoint to deduce reliability from.
- Returns:
The deduced reliability, one of [0,1,2].
- Return type:
int
- Raises:
InterfaceNotFoundError – If the interface is not declared in the introspection.
- is_aggregation_object() bool
Check if the current Interface is a datastream with aggregation object :returns: True if aggregation: object :rtype: bool
- is_property_endpoint_resettable(endpoint)
Check the resettability of an endpoint. :param endpoint: The Mapping endpoint :type endpoint: str
- Returns:
True if type is properties, endpoint is valid and resettable
- Return type:
bool
- is_server_owned() bool
Check the Interface ownership :returns: True if ownership: server :rtype: bool
- is_type_properties()
Check the Interface type :returns: True if type: properties :rtype: bool
- validate(path: str, payload, timestamp: datetime | None) ValidationError | None
Interface Data validation.
- Parameters:
path (str) – Data endpoint in interface
payload (object) – Data to validate
timestamp (datetime or None) – Timestamp associated to the payload
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
- validate_object_complete(path: str, payload)
Validate that the payload contains all the endpoints for an aggregated interface. Shall only be used on device owned interfaces, as server interfaces could be sent incomplete.
- Parameters:
path (str) – Path on which the payload has been received. This is assumed to correspond to a valid partial mapping.
payload (object) – Data to validate
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
- validate_path(path: str, payload) ValidationError | None
Validate that the provided path conforms to the interface.
- Parameters:
path (str) – Path to validate. In case of an individual interface it should correspond to the full endpoint, while in case of aggregated interfaces it should correspond to the common part to all the endpoints.
payload (object) – Payload used to extrapolate the remaining endpoints for aggregated interfaces.
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
- validate_payload(path: str, payload) ValidationError | None
Validate that the payload conforms to the interface.
- Parameters:
path (str) – Path on which the payload has been received. This is assumed to correspond to a valid mapping (or partial mapping in case of aggregate interface). Should be first checked with validate_path().
payload (object) – Data to validate
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
device.introspection module
- class device.introspection.Introspection
Bases:
object
Class that represent the introspection of a device.
The introspection is the list od interfaces that the device declares to the server it is compatible with.
In any given time a device can have a single interface with a given name, multiple interfaces with the same name but different major/minor are not supported.
- add_interface(interface_definition: dict) None
Adds an Interface to the Introspection
This will add an Interface definition to the Device. It has to be called before
connect()
, as it will be used for building the Device Introspection.- Parameters:
interface_definition (dict) – An Astarte Interface definition in the form of a Python dictionary. Usually obtained by using json.loads() on an Interface file.
- get_all_interfaces() list[astarte.device.interface.Interface]
Retrieve all the list of all Interfaces in Device’s Introspection
- Returns:
The list of all Interfaces in the Introspection
- Return type:
list
- get_all_server_owned_interfaces() list[astarte.device.interface.Interface]
Retrieve all the list of all Interfaces in Device’s Introspection with server ownership
- Returns:
The list of all Interfaces in the Introspection that have ownership “server”
- Return type:
list
- get_interface(interface_name: str) Interface | None
Retrieve an Interface definition from the Introspection
- Parameters:
interface_name (str) – The name of an Interface previously added with
add_interface()
.- Returns:
the Interface definition if found in the Introspection, None otherwise
- Return type:
Interface or None
- remove_interface(interface_name: str) None
Removes an Interface from the Introspection
Removes an Interface definition from the Device. It has to be called before
connect()
, as it will be used for building the Device Introspection.- Parameters:
interface_name (str) – The name of an Interface previously added with
add_interface()
.
device.mapping module
- device.mapping.MapType
Mapping type to python type mapping
alias of
Union
[int
,float
,str
,bytes
,bool
,datetime
,List
[int
],List
[float
],List
[str
],List
[bytes
],List
[bool
],List
[datetime
]]
- class device.mapping.Mapping(mapping_definition: dict, interface_type: str)
Bases:
object
Class that represent a data Mapping Mappings are designed around REST controller semantics: each mapping describes an endpoint which is resolved to a path, it is strongly typed, and can have additional options. Just like in REST controllers, Endpoints can be parametrized to build REST-like collection and trees. Parameters are identified by %{parameterName}, with each endpoint supporting any number of parameters (see Limitations).
- endpoint
Path of the Mapping
- Type:
str
- type
Type of the Mapping (see notes)
- Type:
str
- explicit_timestamp
Flag that defines if the Mapping requires a timestamp associated to the Payload before send.
- Type:
bool
- reliability
Reliability level of the Mapping (see notes)
Notes
Supported data types
The following types are supported:
- double: A double-precision floating-point number as specified by binary64, by the IEEE
754 standard (NaNs and other non-numerical values are not supported).
integer: A signed 32 bit integer.
boolean: Either true or false, adhering to JSON boolean type.
- longinteger: A signed 64-bit integer (please note that longinteger is represented as a
string by default in JSON-based APIs.).
string: An UTF-8 string, at most 65536 bytes long.
- binaryblob: An arbitrary sequence of any byte that should be shorter than 64 KiB. (
binaryblob is represented as a base64 string by default in JSON-based APIs.).
- datetime: A UTC timestamp, internally represented as milliseconds since 1st Jan 1970
using a signed 64 bits integer. (datetime is represented as an ISO 8601 string by default in JSON based APIs.)
- doublearray, integerarray, booleanarray, longintegerarray, stringarray,
binaryblobarray, datetimearray: A list of values, represented as a JSON Array. Arrays can have up to 1024 items and each item must respect the limits of its scalar type (i.e. each string in a stringarray must be at most 65535 bytes long, each binary blob in a binaryblobarray must be shorter than 64 KiB.)
Quality of Service
Data messages QoS is chosen according to mapping settings, such as reliability. Properties are always published using QoS 2.
INTERFACE TYPE
RELIABILITY
QOS
properties
always unique
2
datastream
unreliable
0
datastream
guaranteed
1
datastream
unique
2
- validate_path(path: str) ValidationError | None
Mapping data validation
- Parameters:
path (Str) – Path to validate.
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
- validate_payload(payload: int | float | str | bytes | bool | datetime | List[int] | List[float] | List[str] | List[bytes] | List[bool] | List[datetime]) ValidationError | None
Mapping data validation
- Parameters:
payload (MapType) – Data to validate
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
- validate_timestamp(timestamp: datetime | None) ValidationError | None
Mapping timestamp validation
- Parameters:
timestamp (datetime or None) – Timestamp associated to the payload
- Returns:
None in case of successful validation, ValidationError otherwise
- Return type:
ValidationError or None
device.pairing_handler module
- device.pairing_handler.generate_device_id(namespace: UUID, unique_data: str) str
Deterministically generate a device Id based on UUID namespace identifier and unique data.
- Parameters:
namespace (UUID) – UUID namespace of the device_id
unique_data (str) – device unique data used to generate the device_id
- Returns:
the generated device Id, using the standard Astarte Device ID encoding (base64 urlencoding without padding).
- Return type:
str
- device.pairing_handler.generate_random_device_id() str
Quick way to generate a device Id. Pay attention that each time this value is different and the use in production is discouraged.
- Returns:
the generated device Id, using the standard Astarte Device ID encoding (base64 urlencoding without padding).
- Return type:
str
- device.pairing_handler.obtain_device_certificate(device_id: str, realm: str, credentials_secret: str, pairing_base_url: str, crypto_store_dir: str, ignore_ssl_errors: bool) None
Utility function that gets a device certificate from Astarte based on a locally generated csr
- Parameters:
device_id (str) – The device ID
realm (str) – The Astarte realm where the device is registered
credentials_secret (str) – The credentials secret for the device in the given realm
pairing_base_url (str) – The base URL for the Astarte pairing APIs
crypto_store_dir (str) – Path to the folder where crypto information are stored
ignore_ssl_errors (str) – Set to True to ignore SSL errors
- Raises:
AuthorizationError – If the authentication provided was not correct
APIError – If a generic Error was returned by the APIs
- device.pairing_handler.obtain_device_transport_information(device_id: str, realm: str, credentials_secret: str, pairing_base_url: str, ignore_ssl_errors: bool) dict
Utility function that requests the device transport information to Astarte
- Parameters:
device_id (str) – The device ID
realm (str) – The Astarte realm where the device is registered
credentials_secret (str) – The credentials secret for the device in the given realm
pairing_base_url (str) – The base URL for the Astarte pairing APIs
ignore_ssl_errors (str) – Set to True to ignore SSL errors
- Returns:
The device transport information
- Return type:
dict
- Raises:
AuthorizationError – If the authentication provided was not correct
APIError – If a generic Error was returned by the APIs
- device.pairing_handler.register_device_with_jwt_token(device_id: str, realm: str, jwt_token: str, pairing_base_url: str, ignore_ssl_errors: bool = False) str
Registers a Device against an Astarte instance/realm with a JWT Token
Returns the Credentials secret for the Device
- Parameters:
device_id (str) – The Device ID to register.
realm (str) – The Realm in which to register the Device.
jwt_token (str) – A JWT Token to Authenticate against Pairing API. The token must have access to Pairing API and to the agent API paths.
pairing_base_url (str) – The Base URL of Pairing API of the Astarte Instance the Device will be registered in.
ignore_ssl_errors (bool) – Useful if you’re registering a device into a test instance of Astarte with self-signed certificates. It is not recommended to leave this true in production. Defaults to false, if true SSL errors will be ignored when registering a device.
- Returns:
The credentials secret obtained after the registration
- Return type:
str
- device.pairing_handler.register_device_with_private_key(device_id: str, realm: str, private_key_file: str, pairing_base_url: str, ignore_ssl_errors: bool) str
Registers a Device against an Astarte instance/realm with a Private Key
Returns the Credentials secret for the Device
- Parameters:
device_id (str) – The Device ID to register.
realm (str) – The Realm in which to register the Device.
private_key_file (str) – Path to the Private Key file for the Realm. It will be used to Authenticate against Pairing API.
pairing_base_url (str) – The Base URL of Pairing API of the Astarte Instance the Device will be registered in.
ignore_ssl_errors (str) – Set to True to ignore SSL errors
- Returns:
The credentials secret obtained after the registration
- Return type:
str