.. _whad-ble-device-model: .. py:currentmodule:: whad.ble Device Model ============ WHAD uses a specific device model to create BLE peripherals. This device model is implemented in :class:`~whad.ble.Profile` and allows dynamic modification of services and characteristics but also provides a convenient way to define a device's services, characteristics and descriptors. .. contents:: Table of Contents :local: Creating a device model of a BLE peripheral ------------------------------------------- Here is an example of a BLE peripheral implemented with WHAD: .. code-block:: python from whad.ble import UUID, Profile, PrimaryService, Characteristic class MyPeripheral(Profile): generic_access = PrimaryService( UUID(0x1800), device_name = Characteristic( UUID(0x2A00), permissions=['read', 'notify'], value=b'My device name' ) ) :class:`~.Profile` performs an introspection on its properties to find every instance of :class:`~.PrimaryService`, finds every instance of :class:`~.Characteristic` declared into each service and populates its attribute database based on the discovered information. But this mechanism also allows dynamic modification of any characteristic, for instance the device name characteristic: .. code-block:: python periph_inst = MyPeripheral() periph_inst.generic_access.device_name = b'Another name' Of course, this can also be done when the peripheral is running and will cause the BLE stack to send notifications or indications based on the characteristics properties. .. _ble-profile-standard-service: Defining and using a standard service ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ WHAD provides a :class:`~.service.StandardService` class used to define *standard* services in a custom profile. This class is a wrapper around the generic :class:`~.PrimaryService` that automatically retrieves the service's UUID from a special class property and equip the service class with additional methods allowing to provide an abstraction level from its characteristics. A standard service shall be defined as follows: .. code-block:: python from struct import pack, unpack from whad.ble import UUID, Characteristic from whad.ble.service import StandardService class CustomService(StandardService): """An example of a standard service. This service exposes a single read-only characteristic that contains some version number stored on 3 bytes. It defines a property named `version` that parses the characteristic's value and return a tuple with the version's major, minor and revision numbers. When this property is set, the provided version numbers are packed into a byte array and written into the corresponding characteristic's value. """ # Service UUID is expected in `_uuid`: _uuid = UUID(0x1337) # Characteristics are defined as class properties version = Characteristic( UUID(0x1338), properties=Characteristic.READ, value=b'\x01\x00\x00', required=True, # Characteristic MUST be present ) @property def version(self) -> (int, int, int): return unpack("