text: #ifndef __HOMEKIT_TYPES_H__
  #define __HOMEKIT_TYPES_H__
  
  #include <stdbool.h>
  #include <stdint.h>
  
  typedef enum {
      homekit_format_bool,
      homekit_format_uint8,
      homekit_format_uint16,
      homekit_format_uint32,
      homekit_format_uint64,
      homekit_format_int,
      homekit_format_float,
      homekit_format_string,
      homekit_format_tlv,
      homekit_format_data
  } homekit_format_t;
  
  typedef enum {
      homekit_unit_none,
      homekit_unit_celsius,
      homekit_unit_percentage,
      homekit_unit_arcdegrees,
      homekit_unit_lux,
      homekit_unit_seconds
  } homekit_unit_t;
  
  typedef enum {
      homekit_permissions_paired_read = 1,
      homekit_permissions_paired_write = 2,
      homekit_permissions_notify = 4,
      homekit_permissions_additional_authorization = 8,
      homekit_permissions_timed_write = 16,
      homekit_permissions_hidden = 32
  } homekit_permissions_t;
  
  typedef enum {
      homekit_accessory_category_other = 1,
      homekit_accessory_category_bridge = 2,
      homekit_accessory_category_fan = 3,
      homekit_accessory_category_garage = 4,
      homekit_accessory_category_lightbulb = 5,
      homekit_accessory_category_door_lock = 6,
      homekit_accessory_category_outlet = 7,
      homekit_accessory_category_switch = 8,
      homekit_accessory_category_thermostat = 9,
      homekit_accessory_category_sensor = 10,
      homekit_accessory_category_security_system = 11,
      homekit_accessory_category_door = 12,
      homekit_accessory_category_window = 13,
      homekit_accessory_category_window_covering = 14,
      homekit_accessory_category_programmable_switch = 15,
      homekit_accessory_category_range_extender = 16,
      homekit_accessory_category_ip_camera = 17,
      homekit_accessory_category_video_door_bell = 18,
      homekit_accessory_category_air_purifier = 19,
      homekit_accessory_category_air_heater = 20,
      homekit_accessory_category_air_conditioner = 21,
      homekit_accessory_category_air_humidifier = 22,
      homekit_accessory_category_air_dehumidifier = 23,
      homekit_accessory_category_speaker = 26,
      homekit_accessory_category_sprinkler = 28,
      homekit_accessory_category_faucet = 29,
      homekit_accessory_category_shower_head = 30,
  } homekit_accessory_category_t;
  
  struct _homekit_accessory;
  struct _homekit_service;
  struct _homekit_characteristic;
  typedef struct _homekit_accessory homekit_accessory_t;
  typedef struct _homekit_service homekit_service_t;
  typedef struct _homekit_characteristic homekit_characteristic_t;
  
  
  typedef struct {
      bool is_null : 1;
      bool is_static : 1;
      homekit_format_t format : 6;
      union {
          bool bool_value;
          int int_value;
          float float_value;
          char *string_value;
          // tlv
          // data
      };
  } homekit_value_t;
  
  bool homekit_value_equal(homekit_value_t *a, homekit_value_t *b);
  void homekit_value_copy(homekit_value_t *dst, homekit_value_t *src);
  homekit_value_t *homekit_value_clone(homekit_value_t *value);
  void homekit_value_destruct(homekit_value_t *value);
  void homekit_value_free(homekit_value_t *value);
  
  
  #define HOMEKIT_NULL_(...) \
      {.format=homekit_format_bool, .is_null=true, ##__VA_ARGS__}
  #define HOMEKIT_NULL(...) (homekit_value_t) HOMEKIT_NULL_( __VA_ARGS__ )
  
  #define HOMEKIT_BOOL_(value, ...) \
      {.format=homekit_format_bool, .bool_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_BOOL(value, ...) (homekit_value_t) HOMEKIT_BOOL_(value, __VA_ARGS__)
  
  #define HOMEKIT_INT_(value, ...) \
      {.format=homekit_format_int, .int_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_INT(value, ...) (homekit_value_t) HOMEKIT_INT_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_UINT8_(value, ...) \
      {.format=homekit_format_uint8, .int_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_UINT8(value, ...) (homekit_value_t) HOMEKIT_UINT8_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_UINT16_(value, ...) \
      {.format=homekit_format_uint16, .int_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_UINT16(value, ...) (homekit_value_t) HOMEKIT_UINT16_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_UINT32_(value, ...) \
      {.format=homekit_format_uint32, .int_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_UINT32(value, ...) (homekit_value_t) HOMEKIT_UINT32_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_UINT64_(value, ...) \
      {.format=homekit_format_uint64, .int_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_UINT64(value, ...) (homekit_value_t) HOMEKIT_UINT64_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_FLOAT_(value, ...) \
      {.format=homekit_format_float, .float_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_FLOAT(value, ...) (homekit_value_t) HOMEKIT_FLOAT_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_STRING_(value, ...) \
      {.format=homekit_format_string, .string_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_STRING(value, ...) (homekit_value_t) HOMEKIT_STRING_(value, ##__VA_ARGS__)
  /*
  #define HOMEKIT_TLV_(value, ...) \
      {.format=homekit_format_tlv, .tlv_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_TLV(value, ...) (homekit_value_t) HOMEKIT_TLV_(value, ##__VA_ARGS__)
  
  #define HOMEKIT_DATA_(value, ...) \
      {.format=homekit_format_data, .data_value=(value), ##__VA_ARGS__}
  #define HOMEKIT_DATA(value, ...) (homekit_value_t) HOMEKIT_DATA_(value, ##__VA_ARGS__)
  */
  
  
  typedef struct {
      int count;
      uint8_t *values;
  } homekit_valid_values_t;
  
  
  typedef struct {
      uint8_t start;
      uint8_t end;
  } homekit_valid_values_range_t;
  
  
  typedef struct {
      int count;
      homekit_valid_values_range_t *ranges;
  } homekit_valid_values_ranges_t;
  
  
  typedef void (*homekit_characteristic_change_callback_fn)(homekit_characteristic_t *ch, homekit_value_t value, void *context);
  
  typedef struct _homekit_characteristic_change_callback {
      homekit_characteristic_change_callback_fn function;
      void *context;
      struct _homekit_characteristic_change_callback *next;
  } homekit_characteristic_change_callback_t;
  
  
  #define HOMEKIT_CHARACTERISTIC_CALLBACK(f) &(homekit_characteristic_change_callback_t) { .function = f }
  
  
  struct _homekit_characteristic {
      homekit_service_t *service;
  
      unsigned int id;
      const char *type;
      const char *description;
      homekit_format_t format;
      homekit_unit_t unit;
      homekit_permissions_t permissions;
      homekit_value_t value;
  
      float *min_value;
      float *max_value;
      float *min_step;
      int *max_len;
      int *max_data_len;
  
      homekit_valid_values_t valid_values;
      homekit_valid_values_ranges_t valid_values_ranges;
  
      homekit_value_t (*getter)();
      void (*setter)(const homekit_value_t);
  
      homekit_characteristic_change_callback_t *callback;
  };
  
  struct _homekit_service {
      homekit_accessory_t *accessory;
  
      unsigned int id;
      const char *type;
      bool hidden;
      bool primary;
      // linked
      homekit_characteristic_t **characteristics;
  };
  
  struct _homekit_accessory {
      unsigned int id;
  
      homekit_accessory_category_t category;
      int config_number;
  
      homekit_service_t **services;
  };
  
  #define HOMEKIT_ACCESSORY(...) \
      &(homekit_accessory_t) { \
          .config_number=1, \
          .category=homekit_accessory_category_other, \
          ##__VA_ARGS__ \
      }
  
  #define HOMEKIT_SERVICE(_type, ...) \
      &(homekit_service_t) { .type=HOMEKIT_SERVICE_ ## _type, ##__VA_ARGS__ }
  
  #define HOMEKIT_CHARACTERISTIC(name, ...) \
      &(homekit_characteristic_t) { \
          HOMEKIT_DECLARE_CHARACTERISTIC_ ## name( __VA_ARGS__ ) \
      }
  
  #define HOMEKIT_CHARACTERISTIC_(name, ...) \
      { \
          HOMEKIT_DECLARE_CHARACTERISTIC_ ## name( __VA_ARGS__ ) \
      }
  
  
  #define HOMEKIT_DECLARE_CHARACTERISTIC_CUSTOM(...) \
      .format = homekit_format_uint8, \
      .unit = homekit_unit_none, \
      .permissions = homekit_permissions_paired_read, \
      ##__VA_ARGS__
  
  
  
  void homekit_accessories_init(homekit_accessory_t **accessories);
  homekit_accessory_t *homekit_accessory_by_id(homekit_accessory_t **accessories, int aid);
  homekit_service_t *homekit_service_by_type(homekit_accessory_t *accessory, const char *type);
  homekit_characteristic_t *homekit_service_characteristic_by_type(homekit_service_t *service, const char *type);
  homekit_characteristic_t *homekit_characteristic_by_aid_and_iid(homekit_accessory_t **accessories, int aid, int iid);
  
  void homekit_characteristic_notify(homekit_characteristic_t *ch, const homekit_value_t value);
  void homekit_characteristic_add_notify_callback(
      homekit_characteristic_t *ch,
      homekit_characteristic_change_callback_fn callback,
      void *context
  );
  void homekit_characteristic_remove_notify_callback(
      homekit_characteristic_t *ch,
      homekit_characteristic_change_callback_fn callback,
      void *context
  );
  void homekit_accessories_clear_notify_callbacks(
      homekit_accessory_t **accessories,
      homekit_characteristic_change_callback_fn callback,
      void *context
  );
  bool homekit_characteristic_has_notify_callback(
      const homekit_characteristic_t *ch,
      homekit_characteristic_change_callback_fn callback,
      void *context
  );
  
  
  #endif // __HOMEKIT_TYPES_H__
  