import type { EspHomeLogging, Nullable } from "./types.js";
import { EventEmitter } from "node:events";
/**
 * Represents one entity from the ESPHome device. An entity is any controllable or observable component on the device.
 *
 * @property key - The numeric key identifier for the entity.
 * @property name - The human-readable name of the entity.
 * @property type - The type of entity (e.g., "switch", "light", "cover").
 */
interface Entity {
    key: number;
    name: string;
    type: string;
}
/**
 * Device information to send when requested by the ESPHome device. This structure contains metadata about the connected ESPHome device.
 *
 * @property bluetoothProxyFeatureFlags - Bluetooth proxy feature flags.
 * @property compilationTime - When the client was compiled/started.
 * @property esphomeVersion - Version of ESPHome protocol being used.
 * @property hasDeepSleep - Whether the client supports deep sleep.
 * @property legacyBluetoothProxyVersion - Legacy Bluetooth proxy version.
 * @property macAddress - MAC address of the client (format: "AA:BB:CC:DD:EE:FF").
 * @property model - Model or type of the client.
 * @property name - Friendly name of the client.
 * @property projectName - Name of the project/plugin.
 * @property projectVersion - Version of the project/plugin.
 * @property usesPassword - Whether the client uses password authentication.
 * @property webserverPort - Port number of any web server.
 */
export interface DeviceInfo {
    bluetoothProxyFeatureFlags?: number;
    compilationTime?: string;
    esphomeVersion?: string;
    hasDeepSleep?: boolean;
    legacyBluetoothProxyVersion?: number;
    macAddress?: string;
    model?: string;
    name?: string;
    projectName?: string;
    projectVersion?: string;
    usesPassword?: boolean;
    webserverPort?: number;
}
/**
 * Configuration options for creating an ESPHome client instance. These options control how the client connects to and communicates with ESPHome devices.
 *
 * @property clientId - Optional client identifier to announce when connecting (default: "esphome-client").
 * @property host - The hostname or IP address of the ESPHome device.
 * @property logger - Optional logging interface for debug and error messages.
 * @property port - The port number for the ESPHome API (default: 6053).
 * @property psk - Optional base64 encoded pre-shared key for Noise encryption.
 * @property serverName - Optional expected server name for validation during encrypted connections.
 */
export interface EspHomeClientOptions {
    clientId?: Nullable<string>;
    host: string;
    logger?: EspHomeLogging;
    port?: number;
    psk?: Nullable<string>;
    serverName?: Nullable<string>;
}
/**
 * ESPHome API client for communicating with ESPHome devices.
 * Implements the ESPHome native API protocol over TCP with optional Noise encryption.
 *
 * This client automatically handles encryption based on the presence of a pre-shared key (PSK). When a PSK is provided, the client will attempt an encrypted connection
 * first and fall back to plaintext if the device doesn't support encryption. Without a PSK, only plaintext connections are attempted.
 *
 * @extends EventEmitter
 * @emits connect - Connected to device with encryption status (boolean).
 * @emits disconnect - Disconnected from device with optional reason string.
 * @emits message - Raw message received with type and payload in MessageEventData format.
 * @emits entities - List of discovered entities after enumeration completes.
 * @emits telemetry - Generic telemetry update for any entity with TelemetryData.
 * @emits heartbeat - Heartbeat response received (ping/pong).
 * @emits time - Time response received with epoch seconds as number.
 * @emits deviceInfo - Device information received with DeviceInfo and encryption status.
 * @emits {entityType} - Type-specific telemetry events (e.g., "cover", "light", "switch", "binary_sensor", "sensor", "text_sensor", "number", "lock").
 *
 * @example
 * ```typescript
 * // Create a client without encryption for devices that don't require it.
 * const client = new EspHomeClient({
 *   host: "192.168.1.100",
 *   logger: log
 * });
 * client.connect();
 *
 * // Create a client with encryption - will try encrypted first, then plaintext.
 * const encryptedClient = new EspHomeClient({
 *   host: "192.168.1.100",
 *   port: 6053,
 *   psk: "base64encodedkey",
 *   logger: log
 * });
 * encryptedClient.connect();
 *
 * // Create a client with custom client ID and server name validation.
 * const customClient = new EspHomeClient({
 *   host: "192.168.1.100",
 *   clientId: "my-custom-client",
 *   serverName: "garage-controller",
 *   psk: "base64encodedkey",
 *   logger: log
 * });
 * customClient.connect();
 *
 * // Listen for connection events to know when the device is ready.
 * client.on("connect", (usingEncryption) => {
 *   console.log(`Connected ${usingEncryption ? 'with' : 'without'} encryption`);
 * });
 *
 * // Listen for discovered entities to see what's available.
 * client.on("entities", (entities) => {
 *   // Log all available entity IDs for reference.
 *   client.logAllEntityIds();
 * });
 *
 * // Send commands using entity IDs once entities are discovered.
 * await client.sendSwitchCommand("switch-garagedoor", true);
 * await client.sendLightCommand("light-light", { state: true, brightness: 0.8 });
 * await client.sendCoverCommand("cover-door", { command: "open" });
 * ```
 */
export declare class EspHomeClient extends EventEmitter {
    private clientId;
    private clientSocket;
    private dataListener;
    private host;
    private log;
    private port;
    private recvBuffer;
    private remoteDeviceInfo;
    private discoveredEntities;
    private entityKeys;
    private entityNames;
    private entityTypes;
    private encryptionKey;
    private expectedServerName;
    private noiseClient;
    private handshakeState;
    private connectionState;
    private connectionTimer;
    private usingEncryption;
    /**
     * Creates a new ESPHome client instance. The client can be configured for both encrypted and unencrypted connections depending on the provided options. When a PSK
     * is provided, the client will automatically attempt encryption first and fall back to plaintext if the device doesn't support it.
     *
     * @param options - Configuration options for the client connection.
     * @param options.clientId - Optional client identifier to announce when connecting (default: "esphome-client").
     * @param options.host - The hostname or IP address of the ESPHome device.
     * @param options.logger - Optional logging interface for debug and error messages. If not provided, defaults to console methods.
     * @param options.port - The port number for the ESPHome API (default: 6053).
     * @param options.psk - Optional base64 encoded pre-shared key for Noise encryption. Must be exactly 32 bytes when decoded.
     * @param options.serverName - Optional expected server name for validation during encrypted connections.
     *
     * @example
     * ```typescript
     * // Minimal configuration for unencrypted connection.
     * const client = new EspHomeClient({ host: "192.168.1.100" });
     *
     * // Full configuration with all options except serverName.
     * const client = new EspHomeClient({
     *   host: "192.168.1.100",
     *   port: 6053,
     *   clientId: "homebridge-ratgdo",
     *   psk: "base64encodedkey",
     *   logger: myLogger
     * });
     * ```
     */
    constructor(options: EspHomeClientOptions);
    /**
     * Connect to the ESPHome device and start communication. This method initializes a new connection. If an encryption key is provided, it will attempt an encrypted
     * connection first and fall back to plaintext if the device doesn't support encryption. Without an encryption key, only plaintext connections are attempted.
     */
    connect(): void;
    /**
     * Create a new TCP connection to the ESPHome device. This is a separate method to allow reconnection with different protocols when falling back from encrypted to
     * plaintext connections.
     */
    private createConnection;
    /**
     * Internal disconnect method that cleans up resources and emits the disconnect event.
     *
     * @param reason - Optional reason for the disconnection.
     */
    private _disconnect;
    /**
     * Disconnect from the ESPHome device and cleanup resources. This method should be called when you're done communicating with the device.
     */
    disconnect(): void;
    /**
     * Clean up Noise encryption resources. This ensures we don't leak memory from the WebAssembly Noise library.
     */
    private cleanupNoiseResources;
    /**
     * Clear the connection timer if it exists. This prevents timeout callbacks from firing after they're no longer needed.
     */
    private clearConnectionTimer;
    /**
     * Set a connection timer for timeout detection. This helps detect when a connection attempt has stalled.
     *
     * @param timeout - Timeout duration in milliseconds (default: 5000).
     */
    private setConnectionTimer;
    /**
     * Handle connection timeout based on the current connection state. This method determines what to do when a connection attempt times out.
     */
    private handleConnectionTimeout;
    /**
     * Handle a newly connected socket. This method is called when the TCP connection is established.
     */
    private handleConnect;
    /**
     * Initialize the Noise handshake for encrypted connections. This sets up the Noise protocol state and sends the initial handshake message.
     */
    private initializeNoiseHandshake;
    /**
     * Send a hello request to let ESPHome know who we are. This is the initial message sent to establish communication when unencrypted. When encrypted, this is sent
     * after we've established a secure connection.
     */
    private sendHello;
    /**
     * Handle socket errors by logging appropriate messages and disconnecting.
     *
     * @param err - The socket error that occurred.
     */
    private handleSocketError;
    /**
     * Handle socket closure. If we were trying encryption and the socket closed, it might be because the device doesn't support encryption.
     */
    private handleSocketClose;
    /**
     * Clean up the data listener if it exists.
     */
    private cleanupDataListener;
    /**
     * Handle incoming raw data, frame messages, and dispatch. This method accumulates data and processes complete frames.
     *
     * @param chunk - The incoming data chunk from the socket.
     */
    private handleData;
    /**
     * Process Noise protocol frames. This handles the Noise handshake and encrypted message processing.
     */
    private processNoiseFrames;
    /**
     * Extract a Noise frame from the receive buffer. Noise frames have a specific format: [0x01][size_high][size_low][data...].
     *
     * @returns The frame data or null if incomplete.
     */
    private extractNoiseFrame;
    /**
     * Handle the Noise hello response. This processes the server's protocol selection and validates the server name if configured.
     *
     * @param serverHello - The server hello data.
     */
    private handleNoiseHello;
    /**
     * Handle the Noise handshake response. This completes the Noise handshake and establishes the encrypted channel.
     *
     * @param serverHandshake - The server handshake data.
     */
    private handleNoiseHandshake;
    /**
     * Write a Noise protocol frame. Frames are sent with a specific header format for the Noise protocol.
     *
     * @param frame - The frame data to send.
     */
    private writeNoiseFrame;
    /**
     * Serialize a message for Noise protocol. This creates the message format used within encrypted frames.
     *
     * @param type - The message type.
     * @param payload - The message payload.
     *
     * @returns The serialized message buffer.
     */
    private serializeNoiseMessage;
    /**
     * Deserialize a Noise protocol message. This extracts the message type and payload from the decrypted data.
     *
     * @param buffer - The buffer to deserialize.
     *
     * @returns The message type and payload, or null if invalid.
     */
    private deserializeNoiseMessage;
    /**
     * Process plaintext frames during the handshake phase. This handles unencrypted message processing for devices that don't require encryption.
     */
    private processPlaintextFrames;
    /**
     * Dispatch based on message type. This is the main message router that handles all protocol messages.
     *
     * @param type - The message type identifier.
     * @param payload - The message payload data.
     */
    private handleMessage;
    /**
     * Handle device info response from the ESPHome device. This extracts all the device metadata from the response message.
     *
     * @param payload - The device info response payload.
     */
    private handleDeviceInfoResponse;
    /**
     * Return the device information of the connected ESPHome device if available.
     *
     * @returns The device information if available, or `null`.
     */
    deviceInfo(): Nullable<DeviceInfo>;
    /**
     * Check if a message type is a list entities response. These messages contain entity discovery information.
     *
     * @param type - The message type to check.
     * @returns `true` if this is a list entities response, `false` otherwise.
     */
    private isListEntitiesResponse;
    /**
     * Check if a message type is a state update. These messages contain current state information for entities.
     *
     * @param type - The message type to check.
     * @returns `true` if this is a state update message, `false` otherwise.
     */
    private isStateUpdate;
    /**
     * Extract entity type label from message type. This converts the message type enum to a lowercase string identifier.
     *
     * @param type - The message type enum value.
     * @returns The entity type label string.
     */
    private getEntityTypeLabel;
    /**
     * Parses a single ListEntities*Response, logs it, and stores it. This registers a discovered entity in our internal maps for later reference.
     *
     * @param type - The message type indicating the entity type.
     * @param payload - The entity description payload.
     */
    private handleListEntity;
    /**
     * Decodes a state update, looks up entity info, and emits events. This processes telemetry data from entities and emits appropriate events.
     *
     * @param type - The message type indicating the entity type.
     * @param payload - The state update payload.
     */
    private handleTelemetry;
    /**
     * Decode cover state telemetry. Cover entities have complex state with position, tilt, and operation status.
     *
     * @param fields - The decoded protobuf fields.
     * @param eventType - The event type string.
     * @param name - The entity name.
     */
    private decodeCoverState;
    /**
     * Extract entity key from protobuf fields. Entity keys can be encoded as either Buffer or number types.
     *
     * @param fields - The decoded protobuf fields.
     * @param fieldNum - The field number to extract.
     * @returns The entity key or undefined if not found.
     */
    private extractEntityKey;
    /**
     * Extract fixed32 field from protobuf fields. Fixed32 fields are always 4 bytes and represent 32-bit values.
     *
     * @param fields - The decoded protobuf fields.
     * @param fieldNum - The field number to extract.
     * @returns The numeric value or undefined if not found.
     */
    private extractFixed32Field;
    /**
     * Extract string field from protobuf fields. String fields are encoded as UTF-8 bytes.
     *
     * @param fields - The decoded protobuf fields.
     * @param fieldNum - The field number to extract.
     * @returns The string value or undefined if not found.
     */
    private extractStringField;
    /**
     * Extract number field from protobuf fields. Number fields are encoded as varints.
     *
     * @param fields - The decoded protobuf fields.
     * @param fieldNum - The field number to extract.
     * @returns The numeric value or undefined if not found.
     */
    private extractNumberField;
    /**
     * Extract telemetry value from protobuf fields. Telemetry values can be numbers, floats, or strings depending on the entity type.
     *
     * @param fields - The decoded protobuf fields.
     * @param fieldNum - The field number to extract.
     * @returns The telemetry value or undefined if not found.
     */
    private extractTelemetryValue;
    /**
     * Frames a raw protobuf payload with the appropriate framing based on encryption state. This method automatically chooses between encrypted and plaintext framing.
     *
     * @param type - The message type.
     * @param payload - The message payload.
     */
    private frameAndSend;
    /**
     * Send a plaintext message with standard framing. Plaintext messages use a simple length-prefixed format.
     *
     * @param type - The message type.
     * @param payload - The message payload.
     */
    private sendPlaintextMessage;
    /**
     * Encode protobuf fields into a buffer. This creates a protobuf message from field definitions.
     *
     * @param fields - The fields to encode.
     * @returns The encoded protobuf message.
     */
    private encodeProtoFields;
    /**
     * Build key field as fixed32 for command requests. Entity keys are always sent as fixed32 fields in command messages.
     *
     * @param key - The entity key.
     * @returns The field definition.
     */
    private buildKeyField;
    /**
     * Get entity key by ID. This looks up the numeric key for an entity given its string ID.
     *
     * @param id - The entity ID to look up.
     *
     * @returns The entity key or `null` if not found.
     */
    getEntityKey(id: string): Nullable<number>;
    /**
     * Log all registered entity IDs for debugging. Logs entities grouped by type with their names and keys. This is primarily a debugging and development tool.
     */
    logAllEntityIds(): void;
    /**
     * Get entity information by ID. This retrieves full entity details given its string ID.
     *
     * @param id - The entity ID to look up.
     *
     * @returns The entity information or `null` if not found.
     */
    getEntityById(id: string): Nullable<Entity>;
    /**
     * Check if an entity ID exists. This is useful for validating entity IDs before sending commands.
     *
     * @param id - The entity ID to check.
     *
     * @returns `true` if the entity exists, `false` otherwise.
     */
    hasEntity(id: string): boolean;
    /**
     * Get all available entity IDs grouped by type. This provides a structured view of all discovered entities.
     *
     * @returns Object with entity types as keys and arrays of IDs as values.
     */
    getAvailableEntityIds(): Record<string, string[]>;
    /**
     * Get all entities with their IDs. This returns the complete list of entities with their string IDs included.
     *
     * @returns Array of entities with their corresponding IDs.
     */
    getEntitiesWithIds(): Array<Entity & {
        id: string;
    }>;
    /**
     * Send a ping request to the device to heartbeat the connection. This can be used to keep the connection alive and verify connectivity.
     */
    sendPing(): void;
    /**
     * Sends a SwitchCommandRequest for the given entity ID and on/off state. This controls binary switch entities like garage door openers.
     *
     * @param id - The entity ID (format: "switch-entityname").
     * @param state - `true` for on, `false` for off.
     */
    sendSwitchCommand(id: string, state: boolean): void;
    /**
     * Sends a ButtonCommandRequest to press a button entity. Button entities trigger one-time actions when pressed.
     *
     * @param id - The entity ID (format: "button-entityname").
     */
    sendButtonCommand(id: string): void;
    /**
     * Sends a CoverCommandRequest for the given entity ID. Cover entities represent things like garage doors, blinds, or shades.
     *
     * @param id - The entity ID (format: "cover-entityname").
     * @param options - Command options (at least one option must be provided).
     * @param options.command - The command: "open", "close", or "stop" (optional).
     * @param options.position - Target position 0.0-1.0 where 0 is closed, 1 is open (optional).
     * @param options.tilt - Target tilt 0.0-1.0 where 0 is closed, 1 is open (optional).
     *
     * @example
     * ```typescript
     * // Send a simple command
     * await client.sendCoverCommand("cover-garagedoor", { command: "open" });
     *
     * // Set to specific position
     * await client.sendCoverCommand("cover-garagedoor", { position: 0.5 }); // 50% open
     *
     * // Set position and tilt for blinds
     * await client.sendCoverCommand("cover-blinds", { position: 1.0, tilt: 0.25 });
     * ```
     */
    sendCoverCommand(id: string, options: {
        command?: "open" | "close" | "stop";
        position?: number;
        tilt?: number;
    }): void;
    /**
     * Sends a LightCommandRequest to turn on/off and optionally set brightness. Light entities represent controllable lights with optional dimming.
     *
     * @param id - The entity ID (format: "light-entityname").
     * @param options - Command options.
     * @param options.state - `true` for on, `false` for off (optional).
     * @param options.brightness - Brightness level 0.0-1.0 (optional).
     */
    sendLightCommand(id: string, options: {
        state?: boolean;
        brightness?: number;
    }): void;
    /**
     * Sends a LockCommandRequest to lock or unlock the given entity ID. Lock entities represent controllable locks with optional code support.
     *
     * @param id - The entity ID (format: "lock-entityname").
     * @param command - The command to send: "lock" or "unlock".
     * @param code - Optional unlock code.
     */
    sendLockCommand(id: string, command: "lock" | "unlock", code?: string): void;
    /**
     * Encode an integer as a VarInt (protobuf-style). VarInts use 7 bits per byte with a continuation bit in the MSB.
     *
     * @param value - The value to encode.
     * @returns The encoded varint as a Buffer.
     */
    private encodeVarint;
    /**
     * Read a VarInt from buffer at offset; returns [value, bytesRead]. This decodes protobuf-style variable-length integers.
     *
     * @param buffer - The buffer to read from.
     * @param offset - The offset to start reading at.
     * @returns A tuple of [decoded value, number of bytes consumed].
     */
    private readVarint;
    /**
     * Decode a simple protobuf message into a map of field numbers to values. This implements basic protobuf decoding for the ESPHome protocol.
     *
     * @param buffer - The protobuf message to decode.
     * @returns A map from field numbers to arrays of decoded values.
     */
    private decodeProtobuf;
    /**
     * Return whether we are on an encrypted connection or not.
     *
     * @returns `true` if we are on an encrypted connection, `false` otherwise.
     */
    get isEncrypted(): boolean;
}
export {};
