Files
home-automation/apps/ui/static/README.md
2025-11-17 21:52:24 +01:00

7.4 KiB

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:

<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:

window.API_BASE = '{{ api_base }}';  // Jinja2 template

Verwendung

Globale Instanz

Der API-Client erstellt automatisch eine globale Instanz window.apiClient:

// 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).

const layout = await window.apiClient.getLayout();
// { rooms: [{name: "Küche", devices: ["kitchen_light", ...]}, ...] }

getDevices(): Promise<Device[]>

Lädt alle Geräte mit ihren Features.

const devices = await window.apiClient.getDevices();
// [{device_id: "...", name: "...", type: "light", features: {...}}, ...]

getDeviceState(deviceId): Promise<DeviceState>

Lädt den aktuellen Status eines Geräts.

const state = await window.apiClient.getDeviceState('kitchen_light');
// {power: true, brightness: 80, ...}

getAllStates(): Promise<Object>

Lädt alle Gerätestatus auf einmal.

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.

// 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.

const { room } = await window.apiClient.getDeviceRoom('kitchen_light');
// {room: "Küche"}

getScenes(): Promise<Scene[]>

Lädt alle verfügbaren Szenen.

const scenes = await window.apiClient.getScenes();

activateScene(sceneId): Promise<void>

Aktiviert eine Szene.

await window.apiClient.activateScene('evening');

Realtime-Updates (SSE)

connectRealtime(onEvent, onError): EventSource

Verbindet sich mit dem SSE-Stream für Live-Updates.

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.

// 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.

window.apiClient.disconnectRealtime();

Helper-Methoden

findDevice(devices, deviceId): Device|null

Findet ein Gerät in einem Array.

const devices = await window.apiClient.getDevices();
const device = window.apiClient.findDevice(devices, 'kitchen_light');

findRoom(layout, roomName): Room|null

Findet einen Raum im Layout.

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.

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.

const url = window.apiClient.api('/devices');
// "http://172.19.1.11:8001/devices"

Backward Compatibility

Die globale api() Funktion ist weiterhin verfügbar:

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

<!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:

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.)