Device Attribute Message Protocol

The Afero architecture uses a messaging protocol that is independent of the wireless technology used. This protocol provides a simple way for the client application to Set or Get attributes on the ASR module.

You will need the information on this page only if you are implementing the protocol yourself, not using afLib or afLib3 API. If you are using the API to communicate with ASR, the information below will be implemented for you.

Message Format

The format of the messages is defined below:

Message uint16_t Message length including header
Header uint8_t

Message type:

0x0B = Set

0x0C = Get

0x0D = Update


Request ID:

  0 = Transaction initiated from peripheral

>0 = Transaction initiated from authenticator

Set uint16_t Attribute ID
uint16_t Value length
n bytes Variable-length attribute value
Get uint16_t Attribute ID
Update uint16_t Attribute ID

Update state:

0x00 = UPDATED

0x01 = INTERRUPTED; Device-side Update in progress or preempted by device-side Update



0x04 = CONFLICT; Previous Set in progress

0x05 = TIMEOUT; Set operation timed out

0x06 = FORBIDDEN; Set not allowed

0x07 = Q_FULL; Queued attribute queue full failure

0xAA = INVALID_STATE; Cloud received unrecognized state value


Update reason:

0x00 = UNKNOWN

0x01 = MODULE; Unsolicited Afero module-initiated or MCU-initiated Update; e.g., button press

0x02 = SERVICE; Response to Cloud-initiated Set

0x03 = MCU; Response to MCU-initiated Set

0x04 = LINK; Linking completed

0x05 = BOUND; A bound attribute was changed

0x06 = FORBIDDEN; Set not allowed

0x07 = NOTIFY_MCU_WE_REBOOTED; Notify MCU that ASR rebooted; not sent to Cloud

0x08 = LOCAL_SET; Response to local Set; e.g., when a scheduled event fires

0x09 = REBOOT

0x0A = CRC_FAILURE; Cyclic redundancy check (CRC) failure; used to sync state between device and Cloud when attribute values no longer match

0x0B = GET_RESPONSE; Response to Get (Cloud or MCU-initiated)

0xAA = Invalid reason; Set when the Cloud receives an Update with either no reason or an invalid reason

uint16_t Value length
n bytes Variable-length attribute value
Update Rejected uint16_t Attribute ID
uint8_t Update state: See state codes above.
uint8_t Update reason: See reason codes above.

Protocol Rules

  • A Set for a specific attribute can only be sent by a non-owner of the attribute.
  • A Get for a specific attribute can only be sent by a non-owner of the attribute with the exception that an MCU can send a Get message to retrieve the value of its own attribute.
  • An Update for a specific attribute can only be sent by the owner of the attribute, except in the following cases:
    • ASR is notifying the MCU of the default values of the MCU's attributes immediately following a reboot.
    • ASR is sending back the result of an MCU get message for its own attribute.
  • Request IDs are always zero unless the transaction is a Get or a Set originally from the service, or the transaction is an Update for a Set or a Get originally from the service.
  • For every Set or Get message the owner of a specific attribute receives, it must send a corresponding Update. The owner must parrot back the request ID from the incoming Set or Get message.
  • Updates can also occur if the attribute change was initiated locally; for example, if the MCU changes one of its own attributes. In this case there is no corresponding Set or Get transaction.
  • The receiver of an Update message never sends a response to the message with one exception: ASR can send an unsolicited Update Rejected message if the Update message is bad in one of the following ways:

    • Attribute ID is not owned by the sender (MCU is the only possible sender in this case).
    • Attribute ID is not in the profile.
    • The value length is larger than the length of the attribute in the profile.
  • Only one Set or Get transaction for a given attribute can be in flight at a time. If a Set or Get transaction for an attribute has occurred and the corresponding Update transaction has not yet occurred, further Sets or Gets for that attribute are rejected.
  • Get transactions never originate from the service during normal use. However this could change in the future.
  • All transports are half duplex. There is collision control if both sides try to send at the same time (the MCU always wins); but once the winner has been chosen, the winner is guaranteed to send the entire message.
  • Updates sent in either direction must only happen one at a time; specifically:

    • For the SPI transport, because ASR is the slave, it uses flow control to enforce this Update rule.
    • For the SPI transport, because the MCU is the master, it can enforce this rule by delaying the start of the transaction. This is natural in a single-threaded event loop type of environment.
    • For the UART transport, both ASR and the MCU must be ready for a transaction to occur, making this rule easy to enforce.
  • Updates are allowed to interrupt Set and Get operations according to the design of the attribute store.
  • afLib uses the a single transmit queue for Set, Get, and Update operations. Each operation must finish before the next one is initiated. Therefore, only one Set, Get, or Update operation from the MCU can occur at any one time. ASR has no such limitations.

Protocol Corollaries

  • An Update message from ASR must have a request ID of zero because:

    • The service owns no attributes, therefore it cannot initiate an Update message.
    • When the MCU performs a Set or Get, it uses a request ID of zero.
  • If the MCU forgets to send an Update for a Set initiated from the service for a specific attribute, that attribute cannot be Set by the service again. The attribute will remain stuck until ASR reboots and forgets that the Set is still pending.