302 lines
7.4 KiB
Markdown
302 lines
7.4 KiB
Markdown
# Home Automation API Client
|
|
|
|
Wiederverwendbare JavaScript-API-Client-Bibliothek für das Home Automation UI.
|
|
|
|
## Installation
|
|
|
|
Füge die folgenden Script-Tags in deine HTML-Seiten ein:
|
|
|
|
```html
|
|
<script src="/static/types.js"></script>
|
|
<script src="/static/api-client.js"></script>
|
|
```
|
|
|
|
## Konfiguration
|
|
|
|
Der API-Client nutzt `window.API_BASE`, das vom Backend gesetzt wird:
|
|
|
|
```javascript
|
|
window.API_BASE = '{{ api_base }}'; // Jinja2 template
|
|
```
|
|
|
|
## Verwendung
|
|
|
|
### Globale Instanz
|
|
|
|
Der API-Client erstellt automatisch eine globale Instanz `window.apiClient`:
|
|
|
|
```javascript
|
|
// Layout abrufen
|
|
const layout = await window.apiClient.getLayout();
|
|
|
|
// Geräte abrufen
|
|
const devices = await window.apiClient.getDevices();
|
|
|
|
// Gerätestatus abrufen
|
|
const state = await window.apiClient.getDeviceState('kitchen_light');
|
|
|
|
// Gerätesteuerung
|
|
await window.apiClient.setDeviceState('kitchen_light', 'light', {
|
|
power: true,
|
|
brightness: 80
|
|
});
|
|
```
|
|
|
|
### Verfügbare Methoden
|
|
|
|
#### `getLayout(): Promise<Layout>`
|
|
Lädt die Layout-Daten (Räume und ihre Geräte).
|
|
|
|
```javascript
|
|
const layout = await window.apiClient.getLayout();
|
|
// { rooms: [{name: "Küche", devices: ["kitchen_light", ...]}, ...] }
|
|
```
|
|
|
|
#### `getDevices(): Promise<Device[]>`
|
|
Lädt alle Geräte mit ihren Features.
|
|
|
|
```javascript
|
|
const devices = await window.apiClient.getDevices();
|
|
// [{device_id: "...", name: "...", type: "light", features: {...}}, ...]
|
|
```
|
|
|
|
#### `getDeviceState(deviceId): Promise<DeviceState>`
|
|
Lädt den aktuellen Status eines Geräts.
|
|
|
|
```javascript
|
|
const state = await window.apiClient.getDeviceState('kitchen_light');
|
|
// {power: true, brightness: 80, ...}
|
|
```
|
|
|
|
#### `getAllStates(): Promise<Object>`
|
|
Lädt alle Gerätestatus auf einmal.
|
|
|
|
```javascript
|
|
const states = await window.apiClient.getAllStates();
|
|
// {"kitchen_light": {power: true, ...}, "thermostat_1": {...}, ...}
|
|
```
|
|
|
|
#### `setDeviceState(deviceId, type, payload): Promise<void>`
|
|
Sendet einen Befehl an ein Gerät.
|
|
|
|
```javascript
|
|
// Licht einschalten
|
|
await window.apiClient.setDeviceState('kitchen_light', 'light', {
|
|
power: true,
|
|
brightness: 80
|
|
});
|
|
|
|
// Thermostat einstellen
|
|
await window.apiClient.setDeviceState('thermostat_1', 'thermostat', {
|
|
target_temp: 22.5
|
|
});
|
|
|
|
// Rollladen steuern
|
|
await window.apiClient.setDeviceState('cover_1', 'cover', {
|
|
position: 50
|
|
});
|
|
```
|
|
|
|
#### `getDeviceRoom(deviceId): Promise<{room: string}>`
|
|
Ermittelt den Raum eines Geräts.
|
|
|
|
```javascript
|
|
const { room } = await window.apiClient.getDeviceRoom('kitchen_light');
|
|
// {room: "Küche"}
|
|
```
|
|
|
|
#### `getScenes(): Promise<Scene[]>`
|
|
Lädt alle verfügbaren Szenen.
|
|
|
|
```javascript
|
|
const scenes = await window.apiClient.getScenes();
|
|
```
|
|
|
|
#### `activateScene(sceneId): Promise<void>`
|
|
Aktiviert eine Szene.
|
|
|
|
```javascript
|
|
await window.apiClient.activateScene('evening');
|
|
```
|
|
|
|
### Realtime-Updates (SSE)
|
|
|
|
#### `connectRealtime(onEvent, onError): EventSource`
|
|
Verbindet sich mit dem SSE-Stream für Live-Updates.
|
|
|
|
```javascript
|
|
window.apiClient.connectRealtime(
|
|
(event) => {
|
|
console.log('Update:', event.device_id, event.state);
|
|
// event = {device_id: "...", type: "state", state: {...}}
|
|
},
|
|
(error) => {
|
|
console.error('Connection error:', error);
|
|
}
|
|
);
|
|
```
|
|
|
|
#### `onDeviceUpdate(deviceId, callback): Function`
|
|
Registriert einen Listener für spezifische Geräte-Updates.
|
|
|
|
```javascript
|
|
// Für ein bestimmtes Gerät
|
|
const unsubscribe = window.apiClient.onDeviceUpdate('kitchen_light', (event) => {
|
|
console.log('Kitchen light changed:', event.state);
|
|
updateUI(event.state);
|
|
});
|
|
|
|
// Für alle Geräte
|
|
const unsubscribeAll = window.apiClient.onDeviceUpdate(null, (event) => {
|
|
console.log('Any device changed:', event.device_id, event.state);
|
|
});
|
|
|
|
// Später: Listener entfernen
|
|
unsubscribe();
|
|
```
|
|
|
|
#### `disconnectRealtime(): void`
|
|
Trennt die SSE-Verbindung und entfernt alle Listener.
|
|
|
|
```javascript
|
|
window.apiClient.disconnectRealtime();
|
|
```
|
|
|
|
### Helper-Methoden
|
|
|
|
#### `findDevice(devices, deviceId): Device|null`
|
|
Findet ein Gerät in einem Array.
|
|
|
|
```javascript
|
|
const devices = await window.apiClient.getDevices();
|
|
const device = window.apiClient.findDevice(devices, 'kitchen_light');
|
|
```
|
|
|
|
#### `findRoom(layout, roomName): Room|null`
|
|
Findet einen Raum im Layout.
|
|
|
|
```javascript
|
|
const layout = await window.apiClient.getLayout();
|
|
const room = window.apiClient.findRoom(layout, 'Küche');
|
|
```
|
|
|
|
#### `getDevicesForRoom(layout, devices, roomName): Device[]`
|
|
Gibt alle Geräte eines Raums zurück.
|
|
|
|
```javascript
|
|
const layout = await window.apiClient.getLayout();
|
|
const devices = await window.apiClient.getDevices();
|
|
const kitchenDevices = window.apiClient.getDevicesForRoom(layout, devices, 'Küche');
|
|
```
|
|
|
|
#### `api(path): string`
|
|
Konstruiert eine vollständige API-URL.
|
|
|
|
```javascript
|
|
const url = window.apiClient.api('/devices');
|
|
// "http://172.19.1.11:8001/devices"
|
|
```
|
|
|
|
### Backward Compatibility
|
|
|
|
Die globale `api()` Funktion ist weiterhin verfügbar:
|
|
|
|
```javascript
|
|
function api(url) {
|
|
return window.apiClient.api(url);
|
|
}
|
|
```
|
|
|
|
## Typen (JSDoc)
|
|
|
|
Die Datei `types.js` enthält JSDoc-Definitionen für alle API-Typen:
|
|
|
|
- `Room` - Raum mit Geräten
|
|
- `Layout` - Layout-Struktur
|
|
- `Device` - Gerätedaten
|
|
- `DeviceFeatures` - Geräte-Features
|
|
- `DeviceState` - Gerätestatus (Light, Thermostat, Contact, etc.)
|
|
- `RealtimeEvent` - SSE-Event-Format
|
|
- `Scene` - Szenen-Definition
|
|
- `*Payload` - Command-Payloads für verschiedene Gerätetypen
|
|
|
|
Diese ermöglichen IDE-Autocomplete und Type-Checking in modernen Editoren (VS Code, WebStorm).
|
|
|
|
## Beispiel: Vollständige Seite
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>My Page</title>
|
|
<script src="/static/types.js"></script>
|
|
<script src="/static/api-client.js"></script>
|
|
</head>
|
|
<body>
|
|
<div id="status"></div>
|
|
<button id="toggle">Toggle Light</button>
|
|
|
|
<script>
|
|
window.API_BASE = 'http://172.19.1.11:8001';
|
|
const deviceId = 'kitchen_light';
|
|
|
|
async function init() {
|
|
// Load initial state
|
|
const state = await window.apiClient.getDeviceState(deviceId);
|
|
updateUI(state);
|
|
|
|
// Listen for updates
|
|
window.apiClient.onDeviceUpdate(deviceId, (event) => {
|
|
updateUI(event.state);
|
|
});
|
|
|
|
// Connect to realtime
|
|
window.apiClient.connectRealtime((event) => {
|
|
console.log('Event:', event);
|
|
});
|
|
|
|
// Handle button clicks
|
|
document.getElementById('toggle').onclick = async () => {
|
|
const currentState = await window.apiClient.getDeviceState(deviceId);
|
|
await window.apiClient.setDeviceState(deviceId, 'light', {
|
|
power: !currentState.power
|
|
});
|
|
};
|
|
}
|
|
|
|
function updateUI(state) {
|
|
document.getElementById('status').textContent =
|
|
state.power ? 'ON' : 'OFF';
|
|
}
|
|
|
|
init();
|
|
</script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
Alle API-Methoden werfen Exceptions bei Fehlern:
|
|
|
|
```javascript
|
|
try {
|
|
const state = await window.apiClient.getDeviceState('invalid_id');
|
|
} catch (error) {
|
|
console.error('API error:', error);
|
|
showErrorMessage(error.message);
|
|
}
|
|
```
|
|
|
|
## Auto-Reconnect
|
|
|
|
Der SSE-Client versucht automatisch, nach 5 Sekunden wieder zu verbinden, wenn die Verbindung abbricht.
|
|
|
|
## Verwendete Technologien
|
|
|
|
- **Fetch API** - Für HTTP-Requests
|
|
- **EventSource** - Für Server-Sent Events
|
|
- **JSDoc** - Für Type Definitions
|
|
- **ES6+** - Modern JavaScript (Class, async/await, etc.)
|