Add Server-Sent Events (SSE) API documentation and README updates
- Created comprehensive SSE API documentation in `docs/SSE_API.md` - Updated README.md with new features section highlighting SSE capabilities - Added `.cursornotes` file for SSE subscription flow - Provided detailed examples and usage guidelines for SSE integration - Documented event types, authentication, and best practices for real-time updates
This commit is contained in:
14
.cursornotes
Normal file
14
.cursornotes
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "MCP SSE Subscribe Flow",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "sse_subscribe",
|
||||||
|
"type": "http request",
|
||||||
|
"method": "GET",
|
||||||
|
"url": "http://localhost:3000/sse",
|
||||||
|
"ret": "txt",
|
||||||
|
"persist": true,
|
||||||
|
"name": "SSE Subscription"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
33
README.md
33
README.md
@@ -11,6 +11,39 @@ A powerful bridge between your Home Assistant instance and Language Learning Mod
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🎮 **Device Control**: Control any Home Assistant device through natural language
|
||||||
|
- 🔄 **Real-time Updates**: Get instant updates through Server-Sent Events (SSE)
|
||||||
|
- 🤖 **Automation Management**: Create, update, and manage automations
|
||||||
|
- 📊 **State Monitoring**: Track and query device states
|
||||||
|
- 🔐 **Secure**: Token-based authentication and rate limiting
|
||||||
|
- 📱 **Mobile Ready**: Works with any HTTP-capable client
|
||||||
|
|
||||||
|
## Real-time Updates with SSE
|
||||||
|
|
||||||
|
The server includes a powerful Server-Sent Events (SSE) system that provides real-time updates from your Home Assistant instance. This allows you to:
|
||||||
|
|
||||||
|
- 🔄 Get instant state changes for any device
|
||||||
|
- 📡 Monitor automation triggers and executions
|
||||||
|
- 🎯 Subscribe to specific domains or entities
|
||||||
|
- 📊 Track service calls and script executions
|
||||||
|
|
||||||
|
### Quick SSE Example
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const eventSource = new EventSource(
|
||||||
|
'http://localhost:3000/subscribe_events?token=YOUR_TOKEN&domain=light'
|
||||||
|
);
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Update received:', data);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
See [SSE_API.md](docs/SSE_API.md) for complete documentation of the SSE system.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Key Features](#key-features)
|
- [Key Features](#key-features)
|
||||||
|
|||||||
364
docs/SSE_API.md
Normal file
364
docs/SSE_API.md
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
# Home Assistant MCP Server-Sent Events (SSE) API Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The SSE API provides real-time updates from Home Assistant through a persistent connection. This allows clients to receive instant notifications about state changes, events, and other activities without polling.
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
### Available Endpoints
|
||||||
|
|
||||||
|
| Endpoint | Method | Description | Authentication |
|
||||||
|
|----------|---------|-------------|----------------|
|
||||||
|
| `/subscribe_events` | POST | Subscribe to real-time events and state changes | Required |
|
||||||
|
| `/get_sse_stats` | POST | Get statistics about current SSE connections | Required |
|
||||||
|
|
||||||
|
### Event Types Available
|
||||||
|
|
||||||
|
| Event Type | Description | Example Subscription |
|
||||||
|
|------------|-------------|---------------------|
|
||||||
|
| `state_changed` | Entity state changes | `events=state_changed` |
|
||||||
|
| `service_called` | Service call events | `events=service_called` |
|
||||||
|
| `automation_triggered` | Automation trigger events | `events=automation_triggered` |
|
||||||
|
| `script_executed` | Script execution events | `events=script_executed` |
|
||||||
|
| `ping` | Connection keepalive (system) | Automatic |
|
||||||
|
| `error` | Error notifications (system) | Automatic |
|
||||||
|
|
||||||
|
### Subscription Options
|
||||||
|
|
||||||
|
| Option | Description | Example |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| `entity_id` | Subscribe to specific entity | `entity_id=light.living_room` |
|
||||||
|
| `domain` | Subscribe to entire domain | `domain=light` |
|
||||||
|
| `events` | Subscribe to event types | `events=state_changed,automation_triggered` |
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
All SSE connections require authentication using your Home Assistant token.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const token = 'YOUR_HASS_TOKEN';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### Subscribe to Events
|
||||||
|
|
||||||
|
`POST /subscribe_events`
|
||||||
|
|
||||||
|
Subscribe to Home Assistant events and state changes.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
|------------|----------|----------|-------------|
|
||||||
|
| token | string | Yes | Your Home Assistant authentication token |
|
||||||
|
| events | string[] | No | Array of event types to subscribe to |
|
||||||
|
| entity_id | string | No | Specific entity ID to monitor |
|
||||||
|
| domain | string | No | Domain to monitor (e.g., "light", "switch") |
|
||||||
|
|
||||||
|
#### Example Request
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const eventSource = new EventSource(`http://localhost:3000/subscribe_events?token=${token}&entity_id=light.living_room&domain=switch&events=state_changed,automation_triggered`);
|
||||||
|
|
||||||
|
eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('Received:', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
eventSource.onerror = (error) => {
|
||||||
|
console.error('SSE Error:', error);
|
||||||
|
eventSource.close();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get SSE Statistics
|
||||||
|
|
||||||
|
`POST /get_sse_stats`
|
||||||
|
|
||||||
|
Get current statistics about SSE connections and subscriptions.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
|-----------|--------|----------|-------------|
|
||||||
|
| token | string | Yes | Your Home Assistant authentication token |
|
||||||
|
|
||||||
|
#### Example Request
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:3000/get_sse_stats \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"token": "YOUR_HASS_TOKEN"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Event Types
|
||||||
|
|
||||||
|
### Standard Events
|
||||||
|
|
||||||
|
1. **connection**
|
||||||
|
- Sent when a client connects successfully
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "connection",
|
||||||
|
"status": "connected",
|
||||||
|
"id": "client_uuid",
|
||||||
|
"authenticated": true,
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **state_changed**
|
||||||
|
- Sent when an entity's state changes
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "state_changed",
|
||||||
|
"data": {
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"state": "on",
|
||||||
|
"attributes": {
|
||||||
|
"brightness": 255,
|
||||||
|
"color_temp": 370
|
||||||
|
},
|
||||||
|
"last_changed": "2024-02-10T12:00:00.000Z",
|
||||||
|
"last_updated": "2024-02-10T12:00:00.000Z"
|
||||||
|
},
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **service_called**
|
||||||
|
- Sent when a Home Assistant service is called
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "service_called",
|
||||||
|
"data": {
|
||||||
|
"domain": "light",
|
||||||
|
"service": "turn_on",
|
||||||
|
"service_data": {
|
||||||
|
"entity_id": "light.living_room",
|
||||||
|
"brightness": 255
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **automation_triggered**
|
||||||
|
- Sent when an automation is triggered
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "automation_triggered",
|
||||||
|
"data": {
|
||||||
|
"automation_id": "automation.morning_routine",
|
||||||
|
"trigger": {
|
||||||
|
"platform": "time",
|
||||||
|
"at": "07:00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
5. **script_executed**
|
||||||
|
- Sent when a script is executed
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "script_executed",
|
||||||
|
"data": {
|
||||||
|
"script_id": "script.welcome_home",
|
||||||
|
"execution_data": {
|
||||||
|
"status": "completed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### System Events
|
||||||
|
|
||||||
|
1. **ping**
|
||||||
|
- Sent every 30 seconds to keep the connection alive
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "ping",
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **error**
|
||||||
|
- Sent when an error occurs
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "error",
|
||||||
|
"error": "rate_limit_exceeded",
|
||||||
|
"message": "Too many requests, please try again later",
|
||||||
|
"timestamp": "2024-02-10T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
- Maximum 1000 requests per minute per client
|
||||||
|
- Rate limits are reset every minute
|
||||||
|
- Exceeding the rate limit will result in an error event
|
||||||
|
|
||||||
|
## Connection Management
|
||||||
|
|
||||||
|
- Maximum 100 concurrent clients
|
||||||
|
- Connections timeout after 5 minutes of inactivity
|
||||||
|
- Ping messages are sent every 30 seconds
|
||||||
|
- Clients should handle reconnection on connection loss
|
||||||
|
|
||||||
|
## Example Implementation
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class HomeAssistantSSE {
|
||||||
|
constructor(baseUrl, token) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
this.token = token;
|
||||||
|
this.eventSource = null;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
this.maxReconnectAttempts = 5;
|
||||||
|
this.reconnectDelay = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(options = {}) {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
token: this.token,
|
||||||
|
...(options.events && { events: options.events.join(',') }),
|
||||||
|
...(options.entity_id && { entity_id: options.entity_id }),
|
||||||
|
...(options.domain && { domain: options.domain })
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventSource = new EventSource(`${this.baseUrl}/subscribe_events?${params}`);
|
||||||
|
|
||||||
|
this.eventSource.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
this.handleEvent(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.eventSource.onerror = (error) => {
|
||||||
|
console.error('SSE Error:', error);
|
||||||
|
this.handleError(error);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent(data) {
|
||||||
|
switch (data.type) {
|
||||||
|
case 'connection':
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
console.log('Connected:', data);
|
||||||
|
break;
|
||||||
|
case 'ping':
|
||||||
|
// Connection is alive
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
console.error('Server Error:', data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Handle other event types
|
||||||
|
console.log('Event:', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error) {
|
||||||
|
this.eventSource?.close();
|
||||||
|
|
||||||
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
|
||||||
|
console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
||||||
|
setTimeout(() => this.connect(), delay);
|
||||||
|
} else {
|
||||||
|
console.error('Max reconnection attempts reached');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.eventSource?.close();
|
||||||
|
this.eventSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage example
|
||||||
|
const client = new HomeAssistantSSE('http://localhost:3000', 'YOUR_HASS_TOKEN');
|
||||||
|
client.connect({
|
||||||
|
events: ['state_changed', 'automation_triggered'],
|
||||||
|
domain: 'light'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Error Handling**
|
||||||
|
- Implement exponential backoff for reconnection attempts
|
||||||
|
- Handle connection timeouts gracefully
|
||||||
|
- Monitor for rate limit errors
|
||||||
|
|
||||||
|
2. **Resource Management**
|
||||||
|
- Close EventSource when no longer needed
|
||||||
|
- Limit subscriptions to necessary events/entities
|
||||||
|
- Handle cleanup on page unload
|
||||||
|
|
||||||
|
3. **Security**
|
||||||
|
- Never expose the authentication token in client-side code
|
||||||
|
- Use HTTPS in production
|
||||||
|
- Validate all incoming data
|
||||||
|
|
||||||
|
4. **Performance**
|
||||||
|
- Subscribe only to needed events
|
||||||
|
- Implement client-side event filtering
|
||||||
|
- Monitor memory usage for long-running connections
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Connection Failures**
|
||||||
|
- Verify your authentication token is valid
|
||||||
|
- Check server URL is accessible
|
||||||
|
- Ensure proper network connectivity
|
||||||
|
- Verify SSL/TLS configuration if using HTTPS
|
||||||
|
|
||||||
|
2. **Missing Events**
|
||||||
|
- Confirm subscription parameters are correct
|
||||||
|
- Check rate limiting status
|
||||||
|
- Verify entity/domain exists
|
||||||
|
- Monitor client-side event handlers
|
||||||
|
|
||||||
|
3. **Performance Issues**
|
||||||
|
- Reduce number of subscriptions
|
||||||
|
- Implement client-side filtering
|
||||||
|
- Monitor memory usage
|
||||||
|
- Check network latency
|
||||||
|
|
||||||
|
### Debugging Tips
|
||||||
|
|
||||||
|
1. Enable console logging:
|
||||||
|
```javascript
|
||||||
|
const client = new HomeAssistantSSE('http://localhost:3000', 'YOUR_HASS_TOKEN');
|
||||||
|
client.debug = true; // Enables detailed logging
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Monitor network traffic:
|
||||||
|
```javascript
|
||||||
|
// Add event listeners for connection states
|
||||||
|
eventSource.addEventListener('open', () => {
|
||||||
|
console.log('Connection opened');
|
||||||
|
});
|
||||||
|
|
||||||
|
eventSource.addEventListener('error', (e) => {
|
||||||
|
console.log('Connection error:', e);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Track subscription status:
|
||||||
|
```javascript
|
||||||
|
// Get current subscriptions
|
||||||
|
const stats = await fetch('/get_sse_stats', {
|
||||||
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
|
}).then(r => r.json());
|
||||||
|
|
||||||
|
console.log('Current subscriptions:', stats);
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user