import { EventEmitter } from "events";
import { ConstructorArgs, HAPPincode, InterfaceName, IPAddress, MacAddress, Nullable, VoidCallback, WithUUID } from "../types";
import { Advertiser } from "./Advertiser";
import { Characteristic } from "./Characteristic";
import { Controller, ControllerConstructor, ControllerIdentifier, ControllerServiceMap } from "./controller";
import { HAPServer } from "./HAPServer";
import { AccessoryInfo } from "./model/AccessoryInfo";
import { ControllerStorage } from "./model/ControllerStorage";
import { IdentifierCache } from "./model/IdentifierCache";
import { SerializedService, Service, ServiceCharacteristicChange, ServiceId } from "./Service";
/**
 * Known category values. Category is a hint to iOS clients about what "type" of Accessory this represents, for UI only.
 *
 * @group Accessory
 */
export declare const enum Categories {
    OTHER = 1,
    BRIDGE = 2,
    FAN = 3,
    GARAGE_DOOR_OPENER = 4,
    LIGHTBULB = 5,
    DOOR_LOCK = 6,
    OUTLET = 7,
    SWITCH = 8,
    THERMOSTAT = 9,
    SENSOR = 10,
    ALARM_SYSTEM = 11,
    SECURITY_SYSTEM = 11,//Added to conform to HAP naming
    DOOR = 12,
    WINDOW = 13,
    WINDOW_COVERING = 14,
    PROGRAMMABLE_SWITCH = 15,
    RANGE_EXTENDER = 16,
    CAMERA = 17,
    IP_CAMERA = 17,//Added to conform to HAP naming
    VIDEO_DOORBELL = 18,
    AIR_PURIFIER = 19,
    AIR_HEATER = 20,
    AIR_CONDITIONER = 21,
    AIR_HUMIDIFIER = 22,
    AIR_DEHUMIDIFIER = 23,
    APPLE_TV = 24,
    HOMEPOD = 25,
    SPEAKER = 26,
    AIRPORT = 27,
    SPRINKLER = 28,
    FAUCET = 29,
    SHOWER_HEAD = 30,
    TELEVISION = 31,
    TARGET_CONTROLLER = 32,// Remote Control
    ROUTER = 33,
    AUDIO_RECEIVER = 34,
    TV_SET_TOP_BOX = 35,
    TV_STREAMING_STICK = 36
}
/**
 * @group Accessory
 */
export interface SerializedAccessory {
    displayName: string;
    UUID: string;
    lastKnownUsername?: MacAddress;
    category: Categories;
    services: SerializedService[];
    linkedServices?: Record<ServiceId, ServiceId[]>;
    controllers?: SerializedControllerContext[];
}
/**
 * @group Controller API
 */
export interface SerializedControllerContext {
    type: ControllerIdentifier;
    services: SerializedServiceMap;
}
/**
 * @group Controller API
 */
export type SerializedServiceMap = Record<string, ServiceId>;
/**
 * @group Controller API
 */
export interface ControllerContext {
    controller: Controller;
    serviceMap: ControllerServiceMap;
}
/**
 * @group Accessory
 */
export declare const enum CharacteristicWarningType {
    SLOW_WRITE = "slow-write",
    TIMEOUT_WRITE = "timeout-write",
    SLOW_READ = "slow-read",
    TIMEOUT_READ = "timeout-read",
    WARN_MESSAGE = "warn-message",
    ERROR_MESSAGE = "error-message",
    DEBUG_MESSAGE = "debug-message"
}
/**
 * @group Accessory
 */
export interface CharacteristicWarning {
    characteristic: Characteristic;
    type: CharacteristicWarningType;
    message: string;
    originatorChain: string[];
    stack?: string;
}
/**
 * @group Accessory
 */
export interface PublishInfo {
    username: MacAddress;
    pincode: HAPPincode;
    /**
     * Specify the category for the HomeKit accessory.
     * The category is used only in the mdns advertisement and specifies the devices type
     * for the HomeKit controller.
     * Currently, this only affects the icon shown in the pairing screen.
     * For the Television and Smart Speaker service it also affects the icon shown in
     * the Home app when paired.
     */
    category?: Categories;
    setupID?: string;
    /**
     * Defines the host where the HAP server will be bound to.
     * When undefined the HAP server will bind to all available interfaces
     * (see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback).
     *
     * This property accepts a mixture of IPAddresses and network interface names.
     * Depending on the mixture of supplied addresses/names hap-nodejs will bind differently.
     *
     * It is advised to not just bind to a specific address, but specifying the interface name
     * in oder to bind on all address records (and ip version) available.
     *
     * HAP-NodeJS (or the underlying ciao library) will not report about misspelled interface names,
     * as it could be that the interface is currently just down and will come up later.
     *
     * Here are a few examples:
     *  - bind: "::"
     *      Pretty much identical to not specifying anything, as most systems (with ipv6 support)
     *      will default to the unspecified ipv6 address (with dual stack support).
     *
     *  - bind: "0.0.0.0"
     *      Binding TCP socket to the unspecified ipv4 address.
     *      The mdns advertisement will exclude any ipv6 address records.
     *
     *  - bind: ["en0", "lo0"]
     *      The mdns advertising will advertise all records of the en0 and loopback interface (if available) and
     *      will also react to address changes on those interfaces.
     *      In order for the HAP server to accept all those address records (which may contain ipv6 records)
     *      it will bind on the unspecified ipv6 address "::" (assuming dual stack is supported).
     *
     *  - bind: ["en0", "lo0", "0.0.0.0"]
     *      Same as above, only that the HAP server will bind on the unspecified ipv4 address "0.0.0.0".
     *      The mdns advertisement will not advertise any ipv6 records.
     *
     *  - bind: "169.254.104.90"
     *      This will bind the HAP server to the address 0.0.0.0.
     *      The mdns advertisement will only advertise the A record 169.254.104.90.
     *      If the given network interface of that address encounters an ip address change (to a different address),
     *      the mdns advertisement will result in not advertising an address at all.
     *      So it is advised to specify an interface name instead of a specific address.
     *      This is identical with ipv6 addresses.
     *
     *  - bind: ["169.254.104.90", "192.168.1.4"]
     *      As the HAP TCP socket can only bind to a single address, when specifying multiple ip addresses
     *      the HAP server will bind to the unspecified ip address (0.0.0.0 if only ipv4 addresses are supplied,
     *      :: if a mixture or only ipv6 addresses are supplied).
     *      The mdns advertisement will only advertise the specified ip addresses.
     *      If the given network interface of that address encounters an ip address change (to different addresses),
     *      the mdns advertisement will result in not advertising an address at all.
     *      So it is advised to specify an interface name instead of a specific address.
     *
     */
    bind?: (InterfaceName | IPAddress) | (InterfaceName | IPAddress)[];
    /**
     * Defines the port where the HAP server will be bound to.
     * When undefined port 0 will be used resulting in a random port.
     */
    port?: number;
    /**
     * If this option is set to true, HAP-NodeJS will add identifying material (based on {@link username})
     * to the end of the accessory display name (and bonjour instance name).
     * Default: true
     */
    addIdentifyingMaterial?: boolean;
    /**
     * Defines the advertiser used with the published Accessory.
     */
    advertiser?: MDNSAdvertiser;
}
/**
 * @group Accessory
 */
export declare const enum MDNSAdvertiser {
    /**
     * Use the `@homebridge/ciao` module as advertiser.
     */
    CIAO = "ciao",
    /**
     * Use the `bonjour-hap` module as advertiser.
     */
    BONJOUR = "bonjour-hap",
    /**
     * Use Avahi/D-Bus as advertiser.
     */
    AVAHI = "avahi",
    /**
     * Use systemd-resolved/D-Bus as advertiser.
     *
     * Note: The systemd-resolved D-Bus interface doesn't provide means to detect restarts of the service.
     * Therefore, we can't detect if our advertisement might be lost due to a restart of the systemd-resolved daemon restart.
     * Consequentially, treat this feature as an experimental feature.
     */
    RESOLVED = "resolved"
}
/**
 * @group Accessory
 */
export type AccessoryCharacteristicChange = ServiceCharacteristicChange & {
    service: Service;
};
/**
 * @group Service
 */
export interface ServiceConfigurationChange {
    service: Service;
}
/**
 * @group Accessory
 */
export declare const enum AccessoryEventTypes {
    /**
     * Emitted when an iOS device wishes for this Accessory to identify itself. If `paired` is false, then
     * this device is currently browsing for Accessories in the system-provided "Add Accessory" screen. If
     * `paired` is true, then this is a device that has already paired with us. Note that if `paired` is true,
     * listening for this event is a shortcut for the underlying mechanism of setting the `Identify` Characteristic:
     * `getService(Service.AccessoryInformation).getCharacteristic(Characteristic.Identify).on('set', ...)`
     * You must call the callback for identification to be successful.
     */
    IDENTIFY = "identify",
    /**
     * This event is emitted once the HAP TCP socket is bound.
     * At this point the mdns advertisement isn't yet available. Use the {@link ADVERTISED} if you require the accessory to be discoverable.
     */
    LISTENING = "listening",
    /**
     * This event is emitted once the mDNS suite has fully advertised the presence of the accessory.
     * This event is guaranteed to be called after {@link LISTENING}.
     */
    ADVERTISED = "advertised",
    SERVICE_CONFIGURATION_CHANGE = "service-configurationChange",
    /**
     * Emitted after a change in the value of one of the provided Service's Characteristics.
     */
    SERVICE_CHARACTERISTIC_CHANGE = "service-characteristic-change",
    PAIRED = "paired",
    UNPAIRED = "unpaired",
    CHARACTERISTIC_WARNING = "characteristic-warning"
}
export declare interface Accessory {
    on(event: "identify", listener: (paired: boolean, callback: VoidCallback) => void): this;
    on(event: "listening", listener: (port: number, address: string) => void): this;
    on(event: "advertised", listener: () => void): this;
    on(event: "service-configurationChange", listener: (change: ServiceConfigurationChange) => void): this;
    on(event: "service-characteristic-change", listener: (change: AccessoryCharacteristicChange) => void): this;
    on(event: "paired", listener: () => void): this;
    on(event: "unpaired", listener: () => void): this;
    on(event: "characteristic-warning", listener: (warning: CharacteristicWarning) => void): this;
    emit(event: "identify", paired: boolean, callback: VoidCallback): boolean;
    emit(event: "listening", port: number, address: string): boolean;
    emit(event: "advertised"): boolean;
    emit(event: "service-configurationChange", change: ServiceConfigurationChange): boolean;
    emit(event: "service-characteristic-change", change: AccessoryCharacteristicChange): boolean;
    emit(event: "paired"): boolean;
    emit(event: "unpaired"): boolean;
    emit(event: "characteristic-warning", warning: CharacteristicWarning): boolean;
}
/**
 * Accessory is a virtual HomeKit device. It can publish an associated HAP server for iOS devices to communicate
 * with - or it can run behind another "Bridge" Accessory server.
 *
 * Bridged Accessories in this implementation must have a UUID that is unique among all other Accessories that
 * are hosted by the Bridge. This UUID must be "stable" and unchanging, even when the server is restarted. This
 * is required so that the Bridge can provide consistent "Accessory IDs" (aid) and "Instance IDs" (iid) for all
 * Accessories, Services, and Characteristics for iOS clients to reference later.
 *
 * @group Accessory
 */
export declare class Accessory extends EventEmitter {
    displayName: string;
    UUID: string;
    private static readonly TIMEOUT_WARNING;
    private static readonly TIMEOUT_AFTER_WARNING;
    aid: Nullable<number>;
    _isBridge: boolean;
    bridged: boolean;
    bridge?: Accessory;
    bridgedAccessories: Accessory[];
    reachable: boolean;
    lastKnownUsername?: MacAddress;
    category: Categories;
    services: Service[];
    private primaryService?;
    shouldPurgeUnusedIDs: boolean;
    /**
     * Captures if initialization steps inside {@link publish} have been called.
     * This is important when calling {@link publish} multiple times (e.g. after calling {@link unpublish}).
     * @private Private API
     */
    private initialized;
    private controllers;
    private serializedControllers?;
    private activeCameraController?;
    /**
     * @private Private API.
     */
    _accessoryInfo?: Nullable<AccessoryInfo>;
    /**
     * @private Private API.
     */
    _setupID: Nullable<string>;
    /**
     * @private Private API.
     */
    _identifierCache?: Nullable<IdentifierCache>;
    /**
     * @private Private API.
     */
    controllerStorage: ControllerStorage;
    /**
     * @private Private API.
     */
    _advertiser?: Advertiser;
    /**
     * @private Private API.
     */
    _server?: HAPServer;
    /**
     * @private Private API.
     */
    _setupURI?: string;
    private configurationChangeDebounceTimeout?;
    /**
     * This property captures the time when we last served a /accessories request.
     * For multiple bursts of /accessories request we don't want to always contact GET handlers
     */
    private lastAccessoriesRequest;
    constructor(displayName: string, UUID: string);
    private identificationRequest;
    /**
     * Add the given service instance to the Accessory.
     *
     * @param service - A {@link Service} instance.
     * @returns Returns the service instance passed to the method call.
     */
    addService(service: Service): Service;
    /**
     * Adds a given service by calling the provided {@link Service} constructor with the provided constructor arguments.
     * @param serviceConstructor - A {@link Service} service constructor (e.g. {@link Service.Switch}).
     * @param constructorArgs - The arguments passed to the given constructor.
     * @returns Returns the constructed service instance.
     */
    addService<S extends typeof Service>(serviceConstructor: S, ...constructorArgs: ConstructorArgs<S>): Service;
    removeService(service: Service): void;
    private removeLinkedService;
    getService<T extends WithUUID<typeof Service>>(name: string | T): Service | undefined;
    getServiceById<T extends WithUUID<typeof Service>>(uuid: string | T, subType: string): Service | undefined;
    /**
     * Returns the bridging accessory if this accessory is bridged.
     * Otherwise, returns itself.
     *
     * @returns the primary accessory
     */
    getPrimaryAccessory: () => Accessory;
    addBridgedAccessory(accessory: Accessory, deferUpdate?: boolean): Accessory;
    addBridgedAccessories(accessories: Accessory[]): void;
    removeBridgedAccessory(accessory: Accessory, deferUpdate?: boolean): void;
    removeBridgedAccessories(accessories: Accessory[]): void;
    removeAllBridgedAccessories(): void;
    private getCharacteristicByIID;
    protected getAccessoryByAID(aid: number): Accessory | undefined;
    protected findCharacteristic(aid: number, iid: number): Characteristic | undefined;
    /**
     * This method is used to set up a new Controller for this accessory. See {@link Controller} for a more detailed
     * explanation what a Controller is and what it is capable of.
     *
     * The controller can be passed as an instance of the class or as a constructor (without any necessary parameters)
     * for a new Controller.
     * Only one Controller of a given {@link ControllerIdentifier} can be configured for a given Accessory.
     *
     * When called, it will be checked if there are any services and persistent data the Controller (for the given
     * {@link ControllerIdentifier}) can be restored from. Otherwise, the Controller will be created with new services.
     *
     *
     * @param controllerConstructor - The Controller instance or constructor to the Controller with no required arguments.
     */
    configureController(controllerConstructor: Controller | ControllerConstructor): void;
    /**
     * This method will remove a given Controller from this accessory.
     * The controller object will be restored to its initial state.
     * This also means that any event handlers setup for the controller will be removed.
     *
     * @param controller - The controller which should be removed from the accessory.
     */
    removeController(controller: Controller): void;
    private handleAccessoryUnpairedForControllers;
    private handleUpdatedControllerServiceMap;
    setupURI(): string;
    /**
     * This method is called right before the accessory is published. It should be used to check for common
     * mistakes in Accessory structured, which may lead to HomeKit rejecting the accessory when pairing.
     * If it is called on a bridge it will call this method for all bridged accessories.
     */
    private validateAccessory;
    /**
     * Assigns aid/iid to ourselves, any Accessories we are bridging, and all associated Services+Characteristics. Uses
     * the provided identifierCache to keep IDs stable.
     * @private Private API
     */
    _assignIDs(identifierCache: IdentifierCache): void;
    disableUnusedIDPurge(): void;
    enableUnusedIDPurge(): void;
    /**
     * Manually purge the unused ids if you like, comes handy
     * when you have disabled auto purge, so you can do it manually
     */
    purgeUnusedIDs(): void;
    /**
     * Returns a JSON representation of this accessory suitable for delivering to HAP clients.
     */
    private toHAP;
    /**
     * Returns a JSON representation of this accessory without characteristic values.
     */
    private internalHAPRepresentation;
    /**
     * Publishes this accessory on the local network for iOS clients to communicate with.
     * - `info.username` - formatted as a MAC address, like `CC:22:3D:E3:CE:F6`, of this accessory.
     *   Must be globally unique from all Accessories on your local network.
     * - `info.pincode` - the 8-digit pin code for clients to use when pairing this Accessory.
     *   Must be formatted as a string like `031-45-154`.
     * - `info.category` - one of the values of the `Accessory.Category` enum, like `Accessory.Category.SWITCH`.
     *   This is a hint to iOS clients about what "type" of Accessory this represents, so
     *   that for instance an appropriate icon can be drawn for the user while adding a
     *   new Accessory.
     * @param {{
     *   username: string;
     *   pincode: string;
     *   category: Accessory.Categories;
     * }} info - Required info for publishing.
     * @param {boolean} allowInsecureRequest - Will allow unencrypted and unauthenticated access to the http server
     */
    publish(info: PublishInfo, allowInsecureRequest?: boolean): Promise<void>;
    /**
     * Removes this Accessory from the local network
     * Accessory object will no longer valid after invoking this method
     * Trying to invoke publish() on the object will result undefined behavior
     */
    destroy(): Promise<void>;
    unpublish(): Promise<void>;
    private enqueueConfigurationUpdate;
    private onListening;
    private handleInitialPairSetupFinished;
    private handleAddPairing;
    private handleRemovePairing;
    private handleListPairings;
    private handleAccessories;
    private handleGetCharacteristics;
    private handleCharacteristicRead;
    private handleSetCharacteristics;
    private handleCharacteristicWrite;
    private handleResource;
    private handleHAPConnectionClosed;
    private handleServiceConfigurationChangeEvent;
    private handleCharacteristicChangeEvent;
    private sendCharacteristicWarning;
    private handleCharacteristicWarning;
    private setupServiceEventHandlers;
    private _sideloadServices;
    private static _generateSetupID;
    static serialize(accessory: Accessory): SerializedAccessory;
    static deserialize(json: SerializedAccessory): Accessory;
    static cleanupAccessoryData(username: MacAddress): void;
    private static serializeServiceMap;
    private static deserializeServiceMap;
    private static parseBindOption;
}
//# sourceMappingURL=Accessory.d.ts.map