esphome-client
Version:
A nearly complete implementation of the ESPHome client protocol with encryption support.
254 lines (193 loc) • 11.9 kB
Markdown
<SPAN ALIGN="CENTER" STYLE="text-align:center">
<DIV ALIGN="CENTER" STYLE="text-align:center">
[](https://github.com/hjdhjd/esphome-client)
# ESPHome Client API
[](https://www.npmjs.com/package/esphome-client)
[](https://www.npmjs.com/package/esphome-client)
## A complete Node-native ESPHome API client implementation.
</DIV>
</SPAN>
`esphome-client` is a library that enables you to connect to and communicate with ESPHome devices using their native API protocol. [ESPHome](https://esphome.io) is an open-source system for controlling ESP8266/ESP32 microcontrollers using simple yet powerful configuration files and control them remotely through home automation systems.
## Why use this library for ESPHome support?
In short - because I use it every day to support a very popular [Homebridge](https://homebridge.io) plugin named [homebridge-ratgdo](https://www.npmjs.com/package/homebridge-ratgdo) that I maintain. This library has been extracted and refined from real-world usage to provide a robust foundation for ESPHome communication.
What makes this implementation unique is that it's **completely Node-native** - there are no external dependencies, no WebAssembly modules, and no native code compilation required. All encryption support is provided by Node.js's built-in crypto module, making installation and deployment straightforward and reliable across all platforms.
The library implements the complete Noise Protocol Framework (specifically Noise_NNpsk0_25519_ChaChaPoly_SHA256) for secure communication with ESPHome devices, with automatic fallback to plaintext connections when encryption is not required or available.
Finally - the most significant reason that you should use this library: it's well-tested in production, it is modern TypeScript, and most importantly, *it just works*. The library handles all the complexity of the ESPHome native API protocol, including automatic encryption negotiation, entity discovery, and real-time state updates.
### <A NAME="esphome-contribute"></A>How you can contribute and make this library even better
This implementation is feature-complete for the core functionality but doesn't yet support every ESPHome message type. The most commonly used entity types and commands are fully implemented and tested. I welcome contributions to add support for additional message types and entity types.
The ESPHome native API is a binary protocol based on Protocol Buffers, and implementing a library like this one is the result of careful protocol analysis and real-world testing.
### Features
- **Zero external dependencies** - Uses only Node.js built-in modules
- **Complete Noise Protocol implementation** - Secure encryption using Node's native crypto
- **Automatic encryption negotiation** - Seamlessly handles both encrypted and plaintext connections
- **Entity discovery** - Automatically discovers all entities exposed by the ESPHome device
- **Real-time updates** - Receive instant telemetry updates for all entity states
- **Type-safe API** - Full TypeScript support with comprehensive type definitions
- **Production tested** - Battle-tested in the popular homebridge-ratgdo plugin
## Supported Message Types
### ✅ Fully Implemented
The following message types are fully implemented and tested:
#### Core Protocol
- `HELLO_REQUEST` / `HELLO_RESPONSE` - Initial handshake
- `CONNECT_REQUEST` / `CONNECT_RESPONSE` - Connection establishment
- `DISCONNECT_REQUEST` / `DISCONNECT_RESPONSE` - Clean disconnection
- `PING_REQUEST` / `PING_RESPONSE` - Keep-alive and latency monitoring
- `DEVICE_INFO_REQUEST` / `DEVICE_INFO_RESPONSE` - Device metadata retrieval
#### Entity Discovery
- `LIST_ENTITIES_REQUEST` - Request entity enumeration
- `LIST_ENTITIES_BINARY_SENSOR_RESPONSE` - Binary sensor discovery
- `LIST_ENTITIES_COVER_RESPONSE` - Cover (garage door, blind, etc.) discovery
- `LIST_ENTITIES_LIGHT_RESPONSE` - Light discovery
- `LIST_ENTITIES_SENSOR_RESPONSE` - Sensor discovery
- `LIST_ENTITIES_SWITCH_RESPONSE` - Switch discovery
- `LIST_ENTITIES_TEXT_SENSOR_RESPONSE` - Text sensor discovery
- `LIST_ENTITIES_NUMBER_RESPONSE` - Number entity discovery
- `LIST_ENTITIES_LOCK_RESPONSE` - Lock discovery
- `LIST_ENTITIES_BUTTON_RESPONSE` - Button discovery
- `LIST_ENTITIES_SERVICES_RESPONSE` - Service discovery
- `LIST_ENTITIES_DONE_RESPONSE` - Entity enumeration complete
#### State Updates
- `SUBSCRIBE_STATES_REQUEST` - Subscribe to state changes
- `BINARY_SENSOR_STATE` - Binary sensor state updates
- `COVER_STATE` - Cover state updates (position, tilt, operation)
- `LIGHT_STATE` - Light state updates
- `SENSOR_STATE` - Sensor value updates
- `SWITCH_STATE` - Switch state updates
- `TEXT_SENSOR_STATE` - Text sensor updates
- `NUMBER_STATE` - Number value updates
- `LOCK_STATE` - Lock state updates
#### Commands
- `SWITCH_COMMAND_REQUEST` - Control switches
- `LIGHT_COMMAND_REQUEST` - Control lights (on/off, brightness)
- `COVER_COMMAND_REQUEST` - Control covers (open/close/stop, position, tilt)
- `LOCK_COMMAND_REQUEST` - Control locks (lock/unlock, optional code)
- `BUTTON_COMMAND_REQUEST` - Trigger button actions
#### Time Synchronization
- `GET_TIME_REQUEST` / `GET_TIME_RESPONSE` - Time sync with device
### 🚧 Not Yet Implemented
Contributions are welcome to add support for these message types:
- `FAN_COMMAND_REQUEST` - Fan control
- `CLIMATE_*` - Climate/HVAC entities and commands
- `MEDIA_PLAYER_*` - Media player entities and commands
- `CAMERA_*` - Camera image requests
- `ALARM_CONTROL_PANEL_*` - Alarm panel entities and commands
- `SELECT_*` - Select/dropdown entities
- `DATE_*`, `TIME_*`, `DATETIME_*` - Date/time entities
- `UPDATE_*` - Update entities for OTA updates
- `BLUETOOTH_*` - Bluetooth proxy functionality
- `VOICE_ASSISTANT_*` - Voice assistant support
## Installation
To use this library in Node, install it from the command line:
```sh
npm install esphome-client
```
## Quick Start
### Basic Connection (No Encryption)
```typescript
import { EspHomeClient } from 'esphome-client';
// Create a client without encryption
const client = new EspHomeClient({
host: '192.168.1.100',
port: 6053 // Default ESPHome API port
});
// Listen for connection events
client.on('connect', (usingEncryption) => {
console.log(`Connected ${usingEncryption ? 'with' : 'without'} encryption`);
});
// Listen for discovered entities
client.on('entities', (entities) => {
console.log('Discovered entities:', entities);
// Log all entity IDs for reference
client.logAllEntityIds();
});
// Listen for telemetry updates
client.on('telemetry', (data) => {
console.log(`${data.entity}: ${data.value}`);
});
// Connect to the device
client.connect();
```
### Encrypted Connection
```typescript
import { EspHomeClient } from 'esphome-client';
// Create a client with encryption
const client = new EspHomeClient({
host: '192.168.1.100',
port: 6053,
psk: 'your-base64-encoded-psk', // From your ESPHome YAML api.encryption.key
clientId: 'my-app-name'
});
client.connect();
```
### Controlling Entities
```typescript
// After entities are discovered...
// Control a switch
await client.sendSwitchCommand('switch-garage_door', true);
// Control a light with brightness
await client.sendLightCommand('light-ceiling', {
state: true,
brightness: 0.8 // 80% brightness
});
// Control a cover (garage door, blind, etc.)
await client.sendCoverCommand('cover-garage', { command: 'open' });
await client.sendCoverCommand('cover-blind', { position: 0.5 }); // 50% open
// Control a lock
await client.sendLockCommand('lock-front_door', 'lock');
await client.sendLockCommand('lock-front_door', 'unlock', '1234'); // With code
// Press a button
await client.sendButtonCommand('button-restart');
```
## Noise Protocol Encryption
This library includes a complete, Node-native implementation of the Noise Protocol Framework, specifically the `Noise_NNpsk0_25519_ChaChaPoly_SHA256` handshake pattern used by ESPHome. The implementation:
- Uses only Node.js built-in crypto functions
- Supports X25519 key exchange
- Implements ChaCha20-Poly1305 AEAD encryption
- Handles the complete handshake and transport encryption
- Automatically falls back to plaintext when encryption is not available
### Using the Noise Protocol Directly
```typescript
import { createESPHomeHandshake } from 'esphome-client';
// Create a handshake for ESPHome communication
const handshake = createESPHomeHandshake({
role: 'initiator', // Clients are always initiators
psk: Buffer.from('your-32-byte-psk', 'base64')
});
// Perform the handshake...
const msg1 = handshake.writeMessage();
// Send msg1 to device, receive response...
handshake.readMessage(deviceResponse);
// After handshake completion, use cipher states for encryption
const encrypted = handshake.sendCipher.EncryptWithAd(Buffer.alloc(0), plaintext);
const decrypted = handshake.receiveCipher.DecryptWithAd(Buffer.alloc(0), encrypted);
```
## Documentation
Complete API documentation is available in the TypeDoc documentation. Key classes:
- `EspHomeClient` - Main client class for device communication
- `HandshakeState` - Noise protocol handshake implementation
- `createESPHomeHandshake` - Factory for ESPHome-specific Noise handshakes
For a real-world example of this library in action, check out [homebridge-ratgdo](https://github.com/hjdhjd/homebridge-ratgdo), which uses this library to provide HomeKit integration for ratgdo garage door controllers.
## Protocol Details
The ESPHome native API uses a binary protocol based on Protocol Buffers over TCP (default port 6053). Messages are framed with either:
- **Plaintext**: `[0x00][length_varint][type_varint][payload]`
- **Encrypted**: `[0x01][size_high][size_low][encrypted_payload]`
The library handles all protocol details automatically, including:
- Message framing and parsing
- Varint encoding/decoding
- Protocol buffer field encoding
- Automatic encryption negotiation
- Connection state management
- Entity discovery and caching
## Contributing
Contributions are welcome! Areas where help would be especially appreciated:
1. **Additional message types** - Implement support for climate, media player, and other entity types
2. **Testing** - Add unit tests and integration tests
3. **Documentation** - Improve examples and API documentation
4. **Bug fixes** - Report and fix any issues you encounter
Please ensure all code follows the existing style and includes appropriate TypeScript types.
## Library Development Dashboard
This is mostly of interest to the true developer nerds amongst us.
[](https://github.com/hjdhjd/esphome-client/blob/main/LICENSE.md)
[](https://github.com/hjdhjd/esphome-client/actions?query=workflow%3A%22Continuous+Integration%22)
[](https://libraries.io/npm/esphome-client)
[](https://github.com/hjdhjd/esphome-client/commits/main)