@startuml

package homekit {
    class AccessoryServer {
        + __init__(self, config_file, logger)
        + publish_device()
        + unpublish_device()
        + shutdown()
        + add_accessory()
        + serve_forever()
        + set_identify_callback(func)
    }
    package model {
        class FeatureFlags

        class Categories

        package services {
            note as n1
                This package contains all
                services as defined in the
                spec chapter 9.
            end note
            class AbstractService {
                + iid
                + append_characteristic()
            }


            class AccessoryInformationService {
            }

            class LightBulbService {
            }

            AccessoryInformationService -up-|> AbstractService
            LightBulbService -up-|> AbstractService
            GenericService -up-|> AbstractService
        }
        package characteristics {
            note as n2
                This package contains all
                characteristics as defined in the
                spec chapter 8.
            end note

            class CharacteristicsTypes {
                + __get_item__(item)
                + get_short(uuid)
                + get_short_uuid(item)
                + get_uuid(item)
            }

            class AbstractCharacteristic {
                + iid
                + type
                + perms
                + format
                + value
                + ev
                + description
                + unit
                + minValue
                + maxValue
                + minStep
                + maxLen
                + maxDataLen
                + valid_values
                + valid_values_range
                - _set_value_callback
                - _get_value_callback
                + set_set_value_callback(callback)
                + set_get_value_callback(callback)
                + set_events(value)
                + set_value(value)
                + get_value(value)
                + get_meta()
            }

            class OnCharacteristicMixin {
                + set_on_set_callback()
                + set_on_get_callback()
            }

            OnCharacteristic -up-|> AbstractCharacteristic

            OnCharacteristicMixin -up-> OnCharacteristic : _onCharacteristic

            GenericCharacteristic -up-|> AbstractCharacteristic
            NameCharacteristic -up-|> AbstractCharacteristic
        }

        AccessoryInformationService --> NameCharacteristic
        LightBulbService -up-|> OnCharacteristicMixin

        class Accessory {
            + aid
            + add_service(service)
            + set_identify_callback(func)
        }
    }

    AccessoryServer --> "*" Accessory : accessories
    AbstractService -right-> "1..*" AbstractCharacteristic : characteristics
    Accessory -down-> "*" AbstractService: services

    package exceptions {
        class HomeKitException
        ProtocolError -up-|> HomeKitException
        BusyError -up-|> ProtocolError
        UnknownError -up-|> ProtocolError
        MaxTriesError -up-|> ProtocolError
        UnavailableError -up-|> ProtocolError
        MaxPeersError -up-|> ProtocolError
        BackoffError -up-|> ProtocolError
        AuthenticationError -up-|> ProtocolError
        InvalidError -up-|> ProtocolError
        InvalidSignatureError -up-|> ProtocolError
        IncorrectPairingIdError -up-|> ProtocolError
        InvalidAuthTagError -up-|> ProtocolError

        HttpException -up-|> HomeKitException

        ConfigurationError -up-|> HomeKitException
        FormatError -up-|> HomeKitException
        CharacteristicPermissionError -up-|> HomeKitException
        AccessoryNotFoundError -up-|> HomeKitException
        ConfigSavingError -up-|> HomeKitException
        ConfigLoadingError -up-|> HomeKitException
        UnpairedError -up-|> HomeKitException
        AlreadyPairedError -up-|> HomeKitException
    }
}

class homekit.Pairing {
    + list_accessories_and_characteristics()
    + get_characteristics(characteristics[], include_meta, include_perms, include_type, include_events)
    + get_events(characteristics[], callback_fun, max_events=-1, max_seconds=-1)
    + list_pairings()
    + put_characteristics(characteristics_and_values[], do_conversion)
    + identify()
}

class homekit.Controller {
    + __init__(self, data)
    + {static}discover(max_seconds=10)
    + {static}identify(accessory_id)
    + load_data(filename)
    + save_data(filename)
    + get_pairings()
    + perform_pairing(alias, accessory_id, pin)
    + remove_pairing(alias)
}



homekit.Pairing "*" <-down- "1" homekit.Controller : pairings


class homekit.discover <<(E,#FF7700) executable>> {
    + timeout
}

homekit.discover --> homekit.Controller

class homekit.get_accessories <<(E,#FF7700) executable>> {
    + pairing_data_file
    + alias
    + output_format
}

homekit.get_accessories --> homekit.Controller

class homekit.get_characteristics <<(E,#FF7700) executable>> {
    + pairing_data_file
    + alias
    + characteristics[]
    + meta
    + permissions
    + type
    + events
}

homekit.get_characteristics --> homekit.Controller

class homekit.get_events <<(E,#FF7700) executable>> {
    + pairing_data_file
    + alias
    + characteristics[]
}

homekit.get_events --> homekit.Controller

class homekit.list_pairings <<(E,#FF7700) executable>> {
    + pairing_data_file
    + alias
}

homekit.list_pairings--> homekit.Controller

class homekit.pair <<(E,#FF7700) executable>> {
    + pairing_data_file
    + alias
    + accessory_id
    + pin
}

homekit.pair--> homekit.Controller

class homekit.put_characteristics <<(E,#FF7700) executable>> {
}

homekit.put_characteristics--> homekit.Controller

class homekit.unpair <<(E,#FF7700) executable>> {
    + pairing_data_file
    + alias
}

homekit.unpair --> homekit.Controller


hide <<executable>> methods
hide <<executable>> circle

@enduml


class homekit.Session {
    + {static} create_from_pairing_data(data)
    + {static} create_from_file(file)
    + get(self, url)
    + put(self, url, body, content_type=HttpContentTypes.JSON)
    + post(self, url, body, content_type=HttpContentTypes.JSON)
    + get_from_pairing_data(self, key)
    + set_in_pairing_data(self, key, value)
}

    package exceptions {
        class AuthenticationError
        class HomeKitTypeException
        class AccessoryNotFoundError
        class UnknownError
        class ConfigSavingError
        class AlreadyPairedError
        class HomeKitConfigurationException
    }


    Note "Table 5-12 page 80" as N1
    homekit.HapStatusCodes .. N1

class homekit.TLV {
    + {static} encode_dict(data)
    + {static} decode_bytes(data)
}

class homekit.CharacteristicsTypes {
    + __getitem__(self, item)
    + get_short(self, uuid)
    + get_uuid(self, item_name)
}

class homekit.HapStatusCodes {
}

class homekit.Categories {
}
