Currently ADK requires you to define a number of (boilerplate) services and characteristics just to start writing the actual accessory logic which results in huge copy pasted declarations. For particular characteristic (let's say FirmwareRevision) all settings are the same every time, with exception of callbacks and maybe custom ranges (e.g. for TargetTemperature characteristic). It would make sense to automate filling most characteristic fields by using a set of macros: it's convenient, short and yet allows for customization. Here is an example of how this could be done (from my prototype):
#define HOMEKIT_SERVICE(iid_, name, ...) \
{ DEFINE_HOMEKIT_SERVICE_ ## name, .iid = iid_, ## __VA_ARGS__ }
#define HOMEKIT_CONCAT3(a, b, c) HOMEKIT_CONCAT3_(a, b, c)
#define HOMEKIT_CONCAT3_(a, b, c) a ## b ## c
#define HOMEKIT_CHARACTERISTIC_TYPE(name) HOMEKIT_CONCAT3(HAP, TYPEOF_HOMEKIT_CHARACTERISTIC_ ## name, Characteristic)
#define HOMEKIT_CHARACTERISTIC_(iid_, name, ...) \
{ DEFINE_HOMEKIT_CHARACTERISTIC_ ## name, .iid = iid_, ## __VA_ARGS__ }
#define HOMEKIT_CHARACTERISTIC(iid_, name, ...) \
&(HOMEKIT_CHARACTERISTIC_TYPE(name)) HOMEKIT_CHARACTERISTIC_(iid_, name, ## __VA_ARGS__)
#define DEFINE_HOMEKIT_SERVICE_ACCESSORY_INFORMATION \
.serviceType = &kHAPServiceType_AccessoryInformation, \
.debugDescription = kHAPServiceDebugDescription_AccessoryInformation \
#define TYPEOF_HOMEKIT_CHARACTERISTIC_MANUFACTURER String
#define DEFINE_HOMEKIT_CHARACTERISTIC_MANUFACTURER \
.format = kHAPCharacteristicFormat_String, \
.characteristicType = &kHAPCharacteristicType_Manufacturer, \
.debugDescription = kHAPCharacteristicDebugDescription_Manufacturer, \
.properties = { \
.readable = true, \
}, \
.constraints = { .maxLength = 64 }, \
.callbacks = { .handleRead = HAPHandleAccessoryInformationManufacturerRead, }
const HAPService accessoryInformationService = HOMEKIT_SERVICE(0x01, ACCESSORY_INFORMATION,
.characteristics = (const HAPCharacteristic* const[]) {
HOMEKIT_CHARACTERISTIC(0x02, IDENTIFY),
HOMEKIT_CHARACTERISTIC(0x03, MANUFACTURER),
HOMEKIT_CHARACTERISTIC(0x04, MODEL),
HOMEKIT_CHARACTERISTIC(0x05, ACCESSORY_NAME),
HOMEKIT_CHARACTERISTIC(0x06, SERIAL_NUMBER),
HOMEKIT_CHARACTERISTIC(0x07, FIRMWARE_REVISION),
HOMEKIT_CHARACTERISTIC(0x08, HARDWARE_REVISION),
HOMEKIT_CHARACTERISTIC(0x09, ADK_VERSION),
NULL
},
);
Here is example of more interesting service - a fan:
const HAPUInt8Characteristic fanActiveCharacteristic =
HOMEKIT_CHARACTERISTIC_(0x42, ACTIVE,
.callbacks.handleRead=HandleFanActiveRead,
.callbacks.handleWrite=HandleFanActiveWrite,
);
const HAPFloatCharacteristic fanRotationSpeedCharacteristic =
HOMEKIT_CHARACTERISTIC_(0x43, ROTATION_SPEED,
.callbacks.handleRead=HandleFanRotationSpeedRead,
.callbacks.handleWrite=HandleFanRotationSpeedWrite,
);
const HAPUInt8Characteristic fanSwingModeCharaceristic =
HOMEKIT_CHARACTERISTIC_(0x44, SWING_MODE,
.callbacks.handleRead=HandleFanSwingModeRead,
.callbacks.handleWrite=HandleFanSwingModeWrite,
);
const HAPService fanService = HOMEKIT_SERVICE(0x40, FAN,
.name = "Fan",
.characteristics = (const HAPCharacteristic* const[]) {
HOMEKIT_CHARACTERISTIC(0x41, NAME),
&fanActiveCharacteristic,
&fanRotationSpeedCharacteristic,
&fanSwingModeCharacteristic,
NULL
},
);
The above could be defined with all characteristics in-place right inside service declaration, but I think sometimes you need to raise an event on some characteristic outside it's read/write handler, so thus you need to have a pointer/reference to it.
So, ADK could have a library of field definitions for standard Apple services / characteristics. Plus, it is easy to create your own (just need to declare a bunch of defines).