Bluetooth Low Energy Device Model
WHAD uses a specific device model to create BLE peripherals. This device model
is implemented in whad.ble.profile.GenericProfile
and allows dynamic
modification of services and characteristics but also provides a convenient
way to define a device services and characteristics.
Creating a device model of a BLE peripheral
Here is an example of a BLE peripheral implemented with WHAD:
from whad.ble import UUID
from whad.ble.profile import GenericProfile, PrimaryService, \
Characteristic
class MyPeripheral(GenericProfile):
generic_access = PrimaryService(
uuid=UUID(0x1800),
device_name = Characteristic(
uuid=UUID(0x2A00),
permissions=['read', 'notify'],
notify=True,
value=b'My device name'
)
)
whad.ble.profile.GenericProfile
performs an introspection on its properties
to find every instance of whad.ble.profile.PrimaryService
, finds every
instance of whad.ble.profile.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:
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.
Hooking GATT events on characteristics
WHAD BLE device model provides a set of method decorators that must be used to attach a method to a specific event and a specific characteristic:
whad.ble.profile.read
declares a characteristic read event handlerwhad.ble.profile.write
declares a characteristic before-write event handlerwhad.ble.profile.written
declares a characteristic after-write event handlerwhad.ble.profile.subscribed
declares a characteristic subscribe event handlerwhad.ble.profile.unsubscribed
declares a characteristic unsubscribe event handler
A characteristic event handler may raise one of the following exception to cause the GATT stack to react accordingly:
whad.ble.exceptions.HookReturnValue
: force a characteristic value to be returned to a GATT client on a read eventwhad.ble.exceptions.HookReturnGattError
: generates a GATT error that will be sent back to the connected GATT clientwhad.ble.exceptions.HookReturnNotFound
: tells a GATT client the characteristic does not existwhad.ble.exceptions.HookReturnAccesDenied
: tells a GATT client that authentication is required to access this characteristic
If no exception is raised in the event handler, the GATT operation continues as expected. As an example, here follows a peripheral model declaration that uses a characteristic event handler:
class MyPeripheral(GattProfile):
generic_access = PrimaryService(
uuid=UUID(0x1800),
device_name = Characteristic(
uuid=UUID(0x2A00),
permissions=['read', 'write', 'notify'],
notify=True,
value=b'My device name'
)
)
@read(generic_access.device_name)
def on_device_name_read(self, offset, mtu):
"""Return the content of the device name characteristic prefixed with 'FOO'
"""
raise HookReturnValue(b'FOO'+ self.generic_access.device_name.value)
@written(generic_access.device_name)
def on_device_name_changed(self, value, without_response):
"""Called every time the device name characteristic has been changed by client.
"""
print('Device name has been changed to: %s' % value)
GATT Generic Profile
- class whad.ble.profile.GenericProfile(start_handle=0, from_json=None)[source]
Generic Profile
- __init__(start_handle=0, from_json=None)[source]
Parse the device model, instanciate all the services, characteristics and descriptors, compute all handle values and registers everything inside this instance for further use.
- Parameters:
start_handle (int) – Start handle value to use (default: 0)
from_json (str) – JSON data describing a GATT profile
- add_service(service, handles_only=False)[source]
Add a service to the current device
- Parameters:
service (
whad.ble.profile.service.Service
) – Service to add to the devicehandles_only (bool) – Add only service handles if set to
True
- attr_by_type_uuid(uuid, start=1, end=65535) Iterator[Attribute] [source]
Enumerate attributes that have a specific type UUID.
- Parameters:
uuid (
whad.ble.profile.attribute.UUID
) – Type UUIDstart (int) – Start handle
end (int) – End handle
- export_json()[source]
Export profile as JSON data, including services, characteristics and descriptors definition.
- Returns:
JSON data corresponding to this profile
- Return type:
str
- find_characteristic_by_value_handle(value_handle) Characteristic [source]
Find characteristic object by its value handle.
- Parameters:
value_handle (int) – Characteristic value handle
- Returns:
Corresponding characteristic object or
None
if not found.- Return type:
whad.ble.profile.characteristic.Characteristic
- find_characteristic_end_handle(handle) int [source]
Find characteristic end handle based on its handle.
- Parameters:
handle (int) – Characteristic handle
- Return type:
int
- Returns:
Characteristic value handle
- Raises:
whad.ble.exceptions.InvalidHandleValueException
- find_hook(service, characteristic, operation) callable [source]
Find a registered hook for a specific service, characteristic and operation.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service objectcharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectoperation (str) – GATT operation
- Returns:
Hook callback
- Return type:
callable
- find_object_by_handle(handle) Attribute [source]
Find an object by its handle value
- Parameters:
handle (int) – Object handle
- Returns:
Object if handle is valid, or raise an IndexError exception otherwise
- Return type:
whad.ble.profile.attribute.Attribute
- Raises:
IndexError
- find_objects_by_range(start, end) List[Attribute] [source]
Find attributes with handles belonging in the [start, end+1] interval.
- Parameters:
start (int) – Start handle value
end (int) – End handle value
- Returns:
List of objects with handles between start and end values
- Return type:
list
- find_service_by_characteristic_handle(handle) Service [source]
Find a service object given a characteristic handle that belongs to this service.
- Parameters:
handle (int) – Characteristic handle belonging to the searched service
- Return type:
whad.ble.profile.service.Service
- Returns:
Service object containing the specified characteristic
- Raises:
whad.ble.exceptions.InvalidHandleValueException
- get_characteristic_by_UUID(charac_uuid: UUID)[source]
Get characteristic by its UUID.
- Parameters:
charac_uuid (
whad.ble.profile.attribute.UUID
) – Characteristic UUID to look for- Returns:
Characteristic if found,
None
otherwise- Return type:
whad.ble.profile.characteristic.Characteristic
- get_service_by_UUID(service_uuid: UUID)[source]
Get a service by its UUID.
- Parameters:
service_uuid (
whad.ble.profile.attribute.UUID
) – Service UUID to look for- Returns:
Service if found,
None
otherwise- Return type:
whad.ble.profile.service.Service
- on_characteristic_read(service, characteristic, offset=0, length=0)[source]
Characteristic read hook.
This hook is called whenever a characteristic is about to be read by a GATT client. If this method returns a byte array, this byte array will be sent back to the GATT client. If this method returns None, then the read operation will return an error (not allowed to read characteristic value).
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectoffset (int) – Read offset (default: 0)
length (int) – Max read length
- Returns:
Value to return to the GATT client
- Return type:
bytes
- on_characteristic_subscribed(service, characteristic, notification=False, indication=False)[source]
Characteristic subscribed hook
This hook is called whenever a characteristic has been subscribed to.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectnotification (bool) – Set to
True
if subscribed to notificationindication (bool) – Set to
True
if subscribed to notification
- on_characteristic_unsubscribed(service, characteristic)[source]
Characteristic unsubscribed hook
This hook is called whenever a characteristic has been unsubscribed.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic object
- on_characteristic_write(service, characteristic, offset=0, value=b'', without_response=False)[source]
Characteristic write hook
This hook is called whenever a charactertistic is about to be written by a GATT client.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectoffset (int) – Read offset (default: 0)
value (bytes) – Value about to be written into the characteristic
without_response (bool) – Set to
True
if no response is required
- on_characteristic_written(service, characteristic, offset=0, value=b'', without_response=False)[source]
Characteristic written hook
This hook is called whenever a charactertistic has been written by a GATT client.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectoffset (int) – Read offset (default: 0)
value (bytes) – Value about to be written into the characteristic
without_response (bool) – Set to
True
if no response is required
- on_connect(conn_handle)[source]
Connection hook.
This hook is only used to notify the connection of a device.
- Parameters:
conn_handle (int) – Connection handle
- on_disconnect(conn_handle)[source]
Disconnection hook.
This hook is only used to notify the disconnection of a device.
- Parameters:
conn_handle (int) – Connection handle
- on_indication(service, characteristic, value)[source]
Characteristic indication hook.
This hook is called when a indication is sent to a characteristic.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectvalue (bytes) – Characteristic value
- on_notification(service, characteristic, value)[source]
Characteristic notification hook.
This hook is called when a notification is sent to a characteristic.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service owning the characteristiccharacteristic (
whad.ble.profile.characteristic.Characteristic
) – Characteristic objectvalue (bytes) – Characteristic value
- register_attribute(attribute)[source]
Register a GATT attribute
- Parameters:
attribute (
whad.ble.profile.attribute.Attribute
) – Attribute to register
- remove_service(service, handles_only=False)[source]
Remove service
- Parameters:
service (
whad.ble.profile.service.Service
) – Service object or UUIDhandles_only (bool) – Remove only handles if set to
True
- services() Iterator[Service] [source]
Enumerate service objects.
This method is a generator and will yield service objects registered into the profile.
- update_service(service) bool [source]
Update service in profile.
Keep service in place in the service list, but update all the services declared after this one.
- Parameters:
service (
whad.ble.profile.service.Service
) – Service object to update.- Returns:
True
if service has been updated,False
otherwise.- Return type:
bool
GATT Primary service
- class whad.ble.profile.PrimaryService(uuid=None, start_handle=0, end_handle=0, name=None, **kwargs)[source]
- __init__(uuid=None, start_handle=0, end_handle=0, name=None, **kwargs)[source]
Declares a GATT primary service.
Other named arguments are used to add service’s characteristics.
- Parameters:
uuid (
whad.ble.profile.attribute.UUID
) – Primary service UUIDstart_handle (int, optional) – Service start handle
end_handle (int, optional) – Service end handle
name (str) – Service name
GATT Characteristic
- class whad.ble.profile.Characteristic(name=None, uuid=None, value=b'', permissions=None, notify=False, indicate=False, description=None, security=[], **kwargs)[source]
GATT characteristic.
- __init__(name=None, uuid=None, value=b'', permissions=None, notify=False, indicate=False, description=None, security=[], **kwargs)[source]
Declares a GATT characteristic.
Other named arguments are used to declare characteristic’s descriptors.
- Parameters:
name (str) – Characteristic name used in GATT model
uuid (
whad.ble.profile.attribute.UUID
) – Characteristic UUIDpermissions (list) – List of permissions for this characteristic (read, write, notify, indicate)
notify (bool) – Enable notifications
indicate (bool) – Enable indications
description (str) – Textual description for this characteristic
security (SecurityAccess) – Indicate the security property associated to this characteristic
- add_descriptor(descriptor)[source]
Add descriptor to our descriptor list
- Parameters:
descriptor (
whad.ble.profile.characteristic.CharacteristicDescriptor
) – Descriptor to add to the characteristic’s descriptor list
- attach(service)[source]
Attach this characteristic to the corresponding service.
- Parameters:
service (:class:̀ whad.ble.profile.service.Service`) – Service
- property description: str
Return characteristic textual description, if any
- descriptors() Iterator[CharacteristicDescriptor] [source]
Enumerate descriptors attached to this characteristic
This method will yield every descriptor attached to the characteristic.
- property end_handle: int
Characteristic end handle (including characteristic value and descriptors).
- get_required_handles() int [source]
Compute the number of handles this characteristic will consume
- Returns:
Number of handles
- Return type:
int
- property handle: int
Characteristic handle
- property must_indicate: bool
Check if indication has to be sent on value change.
- property must_notify: bool
Check if notification has to be sent on value change.
- property name: str
Name
- property permissions: List[str]
Characteristics permissions
- property security: SecurityAccess
Returns security access property
- property service: Service
Related service.
- property value: UUID
Characteristic UUID