Vollständige Next.js 15 Portfolio-Website mit: - Blog-System mit 100+ Artikeln - Supabase-Integration - Responsive Design mit Tailwind CSS - TypeScript-Konfiguration - Testing-Setup mit Vitest und Playwright Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
787 lines
21 KiB
Markdown
787 lines
21 KiB
Markdown
# Home Assistant Integration & Automation
|
|
|
|
**Meta-Description:** Smart Home Automation mit Home Assistant. WebSocket API, Node-RED Integration, Custom Automations und YAML-Konfiguration.
|
|
|
|
**Keywords:** Home Assistant, Smart Home, Automation, Node-RED, WebSocket API, YAML, IoT Platform
|
|
|
|
---
|
|
|
|
## Einführung
|
|
|
|
**Home Assistant** ist die führende Open-Source Smart Home Plattform. Mit über 2.800 Integrations, lokaler Kontrolle und einer aktiven Community bietet sie die perfekte Grundlage für jedes Smart Home Projekt.
|
|
|
|
---
|
|
|
|
## Home Assistant Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ HOME ASSISTANT ARCHITECTURE │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
│ │ Frontend │ │ Core │ │ Supervisor │ │
|
|
│ │ (React) │←──→│ (Python) │←──→│ (Docker) │ │
|
|
│ └─────────────┘ └──────┬──────┘ └─────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────────────┼─────────────────────────┐ │
|
|
│ │ Integrations │ │
|
|
│ ├─────────────────────────┼─────────────────────────┤ │
|
|
│ │ ┌────────┐ ┌────────┐ │ ┌────────┐ ┌────────┐ │ │
|
|
│ │ │ Zigbee │ │ Z-Wave │ │ │ MQTT │ │ HTTP │ │ │
|
|
│ │ └────────┘ └────────┘ │ └────────┘ └────────┘ │ │
|
|
│ │ ┌────────┐ ┌────────┐ │ ┌────────┐ ┌────────┐ │ │
|
|
│ │ │ Thread │ │ Matter │ │ │Bluetooth│ │ Cloud │ │ │
|
|
│ │ └────────┘ └────────┘ │ └────────┘ └────────┘ │ │
|
|
│ └───────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ Protocols: WebSocket, REST API, MQTT │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Installation & Setup
|
|
|
|
```bash
|
|
# Docker Installation
|
|
docker run -d \
|
|
--name homeassistant \
|
|
--privileged \
|
|
--restart=unless-stopped \
|
|
-e TZ=Europe/Berlin \
|
|
-v /path/to/config:/config \
|
|
-v /run/dbus:/run/dbus:ro \
|
|
--network=host \
|
|
ghcr.io/home-assistant/home-assistant:stable
|
|
|
|
# Oder mit Docker Compose
|
|
# docker-compose.yml
|
|
version: '3'
|
|
services:
|
|
homeassistant:
|
|
container_name: homeassistant
|
|
image: "ghcr.io/home-assistant/home-assistant:stable"
|
|
volumes:
|
|
- ./config:/config
|
|
- /etc/localtime:/etc/localtime:ro
|
|
- /run/dbus:/run/dbus:ro
|
|
restart: unless-stopped
|
|
privileged: true
|
|
network_mode: host
|
|
```
|
|
|
|
---
|
|
|
|
## WebSocket API Integration
|
|
|
|
```typescript
|
|
// lib/homeassistant-client.ts
|
|
import WebSocket from 'ws';
|
|
|
|
interface HAMessage {
|
|
id?: number;
|
|
type: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
interface HAState {
|
|
entity_id: string;
|
|
state: string;
|
|
attributes: Record<string, any>;
|
|
last_changed: string;
|
|
last_updated: string;
|
|
}
|
|
|
|
class HomeAssistantClient {
|
|
private ws: WebSocket | null = null;
|
|
private messageId = 1;
|
|
private pendingRequests: Map<number, {
|
|
resolve: (value: any) => void;
|
|
reject: (error: Error) => void;
|
|
}> = new Map();
|
|
private eventSubscribers: Map<string, Set<(data: any) => void>> = new Map();
|
|
|
|
constructor(
|
|
private url: string,
|
|
private token: string
|
|
) {}
|
|
|
|
async connect(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
this.ws = new WebSocket(this.url);
|
|
|
|
this.ws.on('open', () => {
|
|
console.log('Connected to Home Assistant');
|
|
});
|
|
|
|
this.ws.on('message', async (data) => {
|
|
const message = JSON.parse(data.toString());
|
|
await this.handleMessage(message, resolve);
|
|
});
|
|
|
|
this.ws.on('error', (error) => {
|
|
console.error('WebSocket error:', error);
|
|
reject(error);
|
|
});
|
|
|
|
this.ws.on('close', () => {
|
|
console.log('Connection closed');
|
|
this.reconnect();
|
|
});
|
|
});
|
|
}
|
|
|
|
private async handleMessage(message: any, onAuth?: (value: void) => void) {
|
|
switch (message.type) {
|
|
case 'auth_required':
|
|
this.send({ type: 'auth', access_token: this.token });
|
|
break;
|
|
|
|
case 'auth_ok':
|
|
console.log('Authenticated with Home Assistant');
|
|
onAuth?.();
|
|
break;
|
|
|
|
case 'auth_invalid':
|
|
throw new Error('Invalid authentication');
|
|
|
|
case 'result':
|
|
const pending = this.pendingRequests.get(message.id);
|
|
if (pending) {
|
|
if (message.success) {
|
|
pending.resolve(message.result);
|
|
} else {
|
|
pending.reject(new Error(message.error?.message));
|
|
}
|
|
this.pendingRequests.delete(message.id);
|
|
}
|
|
break;
|
|
|
|
case 'event':
|
|
this.handleEvent(message.event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private handleEvent(event: any) {
|
|
const eventType = event.event_type;
|
|
const subscribers = this.eventSubscribers.get(eventType);
|
|
|
|
if (subscribers) {
|
|
subscribers.forEach(callback => callback(event.data));
|
|
}
|
|
|
|
// Wildcard subscribers
|
|
const allSubscribers = this.eventSubscribers.get('*');
|
|
if (allSubscribers) {
|
|
allSubscribers.forEach(callback => callback(event));
|
|
}
|
|
}
|
|
|
|
private send(message: HAMessage) {
|
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
this.ws.send(JSON.stringify(message));
|
|
}
|
|
}
|
|
|
|
private async sendCommand<T>(message: Omit<HAMessage, 'id'>): Promise<T> {
|
|
return new Promise((resolve, reject) => {
|
|
const id = this.messageId++;
|
|
this.pendingRequests.set(id, { resolve, reject });
|
|
this.send({ ...message, id });
|
|
|
|
// Timeout nach 30 Sekunden
|
|
setTimeout(() => {
|
|
if (this.pendingRequests.has(id)) {
|
|
this.pendingRequests.delete(id);
|
|
reject(new Error('Request timeout'));
|
|
}
|
|
}, 30000);
|
|
});
|
|
}
|
|
|
|
// States abrufen
|
|
async getStates(): Promise<HAState[]> {
|
|
return this.sendCommand({ type: 'get_states' });
|
|
}
|
|
|
|
async getState(entityId: string): Promise<HAState | undefined> {
|
|
const states = await this.getStates();
|
|
return states.find(s => s.entity_id === entityId);
|
|
}
|
|
|
|
// Services aufrufen
|
|
async callService(
|
|
domain: string,
|
|
service: string,
|
|
serviceData?: Record<string, any>,
|
|
target?: { entity_id?: string | string[] }
|
|
): Promise<void> {
|
|
await this.sendCommand({
|
|
type: 'call_service',
|
|
domain,
|
|
service,
|
|
service_data: serviceData,
|
|
target
|
|
});
|
|
}
|
|
|
|
// Events abonnieren
|
|
async subscribeEvents(
|
|
eventType: string,
|
|
callback: (data: any) => void
|
|
): Promise<() => void> {
|
|
if (!this.eventSubscribers.has(eventType)) {
|
|
this.eventSubscribers.set(eventType, new Set());
|
|
|
|
// Bei HA registrieren
|
|
await this.sendCommand({
|
|
type: 'subscribe_events',
|
|
event_type: eventType === '*' ? undefined : eventType
|
|
});
|
|
}
|
|
|
|
this.eventSubscribers.get(eventType)!.add(callback);
|
|
|
|
// Unsubscribe Function
|
|
return () => {
|
|
this.eventSubscribers.get(eventType)?.delete(callback);
|
|
};
|
|
}
|
|
|
|
// Trigger State Change
|
|
async subscribeStateChanges(
|
|
entityId: string,
|
|
callback: (newState: HAState, oldState: HAState) => void
|
|
): Promise<() => void> {
|
|
return this.subscribeEvents('state_changed', (data) => {
|
|
if (data.entity_id === entityId) {
|
|
callback(data.new_state, data.old_state);
|
|
}
|
|
});
|
|
}
|
|
|
|
private reconnect() {
|
|
setTimeout(() => {
|
|
console.log('Reconnecting...');
|
|
this.connect();
|
|
}, 5000);
|
|
}
|
|
|
|
disconnect() {
|
|
this.ws?.close();
|
|
}
|
|
}
|
|
|
|
// Verwendung
|
|
const ha = new HomeAssistantClient(
|
|
'ws://homeassistant.local:8123/api/websocket',
|
|
process.env.HA_TOKEN!
|
|
);
|
|
|
|
await ha.connect();
|
|
|
|
// Alle States abrufen
|
|
const states = await ha.getStates();
|
|
console.log(`${states.length} entities found`);
|
|
|
|
// Licht einschalten
|
|
await ha.callService('light', 'turn_on', {
|
|
brightness: 255,
|
|
color_temp: 300
|
|
}, {
|
|
entity_id: 'light.wohnzimmer'
|
|
});
|
|
|
|
// State Changes beobachten
|
|
ha.subscribeStateChanges('sensor.temperature', (newState, oldState) => {
|
|
console.log(`Temperature changed: ${oldState.state} → ${newState.state}`);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## REST API Integration
|
|
|
|
```typescript
|
|
// lib/homeassistant-rest.ts
|
|
interface HARestConfig {
|
|
baseUrl: string;
|
|
token: string;
|
|
}
|
|
|
|
class HomeAssistantREST {
|
|
private baseUrl: string;
|
|
private headers: HeadersInit;
|
|
|
|
constructor(config: HARestConfig) {
|
|
this.baseUrl = config.baseUrl.replace(/\/$/, '');
|
|
this.headers = {
|
|
'Authorization': `Bearer ${config.token}`,
|
|
'Content-Type': 'application/json'
|
|
};
|
|
}
|
|
|
|
private async request<T>(
|
|
method: string,
|
|
endpoint: string,
|
|
body?: any
|
|
): Promise<T> {
|
|
const response = await fetch(`${this.baseUrl}/api${endpoint}`, {
|
|
method,
|
|
headers: this.headers,
|
|
body: body ? JSON.stringify(body) : undefined
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HA API Error: ${response.status}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
// API Status
|
|
async getApiStatus(): Promise<{ message: string }> {
|
|
return this.request('GET', '/');
|
|
}
|
|
|
|
// Config
|
|
async getConfig(): Promise<any> {
|
|
return this.request('GET', '/config');
|
|
}
|
|
|
|
// States
|
|
async getStates(): Promise<HAState[]> {
|
|
return this.request('GET', '/states');
|
|
}
|
|
|
|
async getState(entityId: string): Promise<HAState> {
|
|
return this.request('GET', `/states/${entityId}`);
|
|
}
|
|
|
|
async setState(entityId: string, state: string, attributes?: Record<string, any>): Promise<HAState> {
|
|
return this.request('POST', `/states/${entityId}`, {
|
|
state,
|
|
attributes
|
|
});
|
|
}
|
|
|
|
// Services
|
|
async getServices(): Promise<Record<string, any>> {
|
|
return this.request('GET', '/services');
|
|
}
|
|
|
|
async callService(
|
|
domain: string,
|
|
service: string,
|
|
data?: Record<string, any>
|
|
): Promise<HAState[]> {
|
|
return this.request('POST', `/services/${domain}/${service}`, data);
|
|
}
|
|
|
|
// History
|
|
async getHistory(
|
|
entityId: string,
|
|
startTime?: Date,
|
|
endTime?: Date
|
|
): Promise<HAState[][]> {
|
|
const params = new URLSearchParams();
|
|
if (startTime) params.set('start_time', startTime.toISOString());
|
|
if (endTime) params.set('end_time', endTime.toISOString());
|
|
params.set('filter_entity_id', entityId);
|
|
|
|
return this.request('GET', `/history/period?${params}`);
|
|
}
|
|
|
|
// Logbook
|
|
async getLogbook(
|
|
entityId?: string,
|
|
startTime?: Date,
|
|
endTime?: Date
|
|
): Promise<any[]> {
|
|
const params = new URLSearchParams();
|
|
if (entityId) params.set('entity', entityId);
|
|
if (startTime) params.set('start_time', startTime.toISOString());
|
|
if (endTime) params.set('end_time', endTime.toISOString());
|
|
|
|
return this.request('GET', `/logbook?${params}`);
|
|
}
|
|
|
|
// Template Rendering
|
|
async renderTemplate(template: string): Promise<string> {
|
|
const result = await this.request<{ result: string }>('POST', '/template', { template });
|
|
return result.result;
|
|
}
|
|
}
|
|
|
|
// API Route für Next.js
|
|
// app/api/home/lights/route.ts
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
const ha = new HomeAssistantREST({
|
|
baseUrl: process.env.HA_URL!,
|
|
token: process.env.HA_TOKEN!
|
|
});
|
|
|
|
export async function GET() {
|
|
const states = await ha.getStates();
|
|
const lights = states.filter(s => s.entity_id.startsWith('light.'));
|
|
|
|
return NextResponse.json(lights.map(light => ({
|
|
id: light.entity_id,
|
|
name: light.attributes.friendly_name,
|
|
state: light.state,
|
|
brightness: light.attributes.brightness,
|
|
color_temp: light.attributes.color_temp
|
|
})));
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
const { entityId, action, ...params } = await request.json();
|
|
|
|
await ha.callService('light', action, {
|
|
entity_id: entityId,
|
|
...params
|
|
});
|
|
|
|
return NextResponse.json({ success: true });
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## YAML Automations
|
|
|
|
```yaml
|
|
# automations.yaml
|
|
|
|
# Licht bei Bewegung einschalten
|
|
- id: 'motion_light_on'
|
|
alias: 'Flur Licht bei Bewegung'
|
|
description: 'Schaltet das Flur-Licht bei Bewegung ein'
|
|
trigger:
|
|
- platform: state
|
|
entity_id: binary_sensor.flur_motion
|
|
to: 'on'
|
|
condition:
|
|
- condition: state
|
|
entity_id: sun.sun
|
|
state: 'below_horizon'
|
|
- condition: state
|
|
entity_id: input_boolean.guest_mode
|
|
state: 'off'
|
|
action:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: light.flur
|
|
data:
|
|
brightness_pct: 80
|
|
transition: 2
|
|
- delay: '00:05:00'
|
|
- service: light.turn_off
|
|
target:
|
|
entity_id: light.flur
|
|
data:
|
|
transition: 5
|
|
mode: restart
|
|
|
|
# Temperatur-basierte Heizungssteuerung
|
|
- id: 'heating_control'
|
|
alias: 'Heizung Temperatur Kontrolle'
|
|
trigger:
|
|
- platform: numeric_state
|
|
entity_id: sensor.wohnzimmer_temperature
|
|
below: 20
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.heating_enabled
|
|
state: 'on'
|
|
- condition: time
|
|
after: '06:00:00'
|
|
before: '22:00:00'
|
|
action:
|
|
- service: climate.set_temperature
|
|
target:
|
|
entity_id: climate.wohnzimmer
|
|
data:
|
|
temperature: 22
|
|
hvac_mode: heat
|
|
|
|
# Guten Morgen Routine
|
|
- id: 'morning_routine'
|
|
alias: 'Guten Morgen Routine'
|
|
trigger:
|
|
- platform: time
|
|
at: input_datetime.wakeup_time
|
|
condition:
|
|
- condition: state
|
|
entity_id: input_boolean.alarm_enabled
|
|
state: 'on'
|
|
- condition: state
|
|
entity_id: person.user
|
|
state: 'home'
|
|
action:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: light.schlafzimmer
|
|
data:
|
|
brightness_pct: 10
|
|
color_temp: 500
|
|
- delay: '00:05:00'
|
|
- service: light.turn_on
|
|
data:
|
|
brightness_pct: 50
|
|
color_temp: 370
|
|
transition: 300
|
|
- service: media_player.play_media
|
|
target:
|
|
entity_id: media_player.schlafzimmer_speaker
|
|
data:
|
|
media_content_type: music
|
|
media_content_id: 'spotify:playlist:morning'
|
|
- service: notify.mobile_app
|
|
data:
|
|
message: "Guten Morgen! Es sind {{ states('sensor.outside_temperature') }}°C draußen."
|
|
```
|
|
|
|
---
|
|
|
|
## Node-RED Integration
|
|
|
|
```json
|
|
// Node-RED Flow für Home Assistant
|
|
[
|
|
{
|
|
"id": "ha-server",
|
|
"type": "server",
|
|
"name": "Home Assistant",
|
|
"addon": true
|
|
},
|
|
{
|
|
"id": "motion-trigger",
|
|
"type": "server-state-changed",
|
|
"name": "Motion Detected",
|
|
"server": "ha-server",
|
|
"entityId": "binary_sensor.motion",
|
|
"entityIdType": "exact",
|
|
"outputInitially": false,
|
|
"stateType": "str",
|
|
"ifState": "on",
|
|
"ifStateType": "str",
|
|
"outputOnlyOnStateChange": true,
|
|
"wires": [["check-conditions"]]
|
|
},
|
|
{
|
|
"id": "check-conditions",
|
|
"type": "api-current-state",
|
|
"name": "Check Sun State",
|
|
"server": "ha-server",
|
|
"entityId": "sun.sun",
|
|
"outputProperties": [
|
|
{
|
|
"property": "payload",
|
|
"propertyType": "msg",
|
|
"value": "",
|
|
"valueType": "entityState"
|
|
}
|
|
],
|
|
"wires": [["filter-night"]]
|
|
},
|
|
{
|
|
"id": "filter-night",
|
|
"type": "switch",
|
|
"name": "Night Only",
|
|
"property": "payload",
|
|
"rules": [
|
|
{ "t": "eq", "v": "below_horizon", "vt": "str" }
|
|
],
|
|
"wires": [["turn-on-light"]]
|
|
},
|
|
{
|
|
"id": "turn-on-light",
|
|
"type": "api-call-service",
|
|
"name": "Turn On Light",
|
|
"server": "ha-server",
|
|
"service_domain": "light",
|
|
"service": "turn_on",
|
|
"entityId": "light.hallway",
|
|
"data": "{\"brightness_pct\": 80, \"transition\": 2}",
|
|
"wires": [[]]
|
|
}
|
|
]
|
|
```
|
|
|
|
```typescript
|
|
// Custom Node-RED Node
|
|
import { Red, Node, NodeProperties } from 'node-red';
|
|
|
|
interface SmartLightConfig extends NodeProperties {
|
|
server: string;
|
|
entityId: string;
|
|
brightness: number;
|
|
colorTemp: number;
|
|
}
|
|
|
|
module.exports = function(RED: Red) {
|
|
function SmartLightNode(this: Node, config: SmartLightConfig) {
|
|
RED.nodes.createNode(this, config);
|
|
|
|
const server = RED.nodes.getNode(config.server) as any;
|
|
|
|
this.on('input', async (msg: any) => {
|
|
try {
|
|
const brightness = msg.brightness || config.brightness;
|
|
const colorTemp = msg.colorTemp || config.colorTemp;
|
|
|
|
await server.websocket.callService('light', 'turn_on', {
|
|
entity_id: config.entityId,
|
|
brightness_pct: brightness,
|
|
color_temp: colorTemp
|
|
});
|
|
|
|
this.status({ fill: 'green', shape: 'dot', text: 'Light on' });
|
|
this.send({ ...msg, payload: { success: true } });
|
|
} catch (error) {
|
|
this.status({ fill: 'red', shape: 'ring', text: 'Error' });
|
|
this.error(error);
|
|
}
|
|
});
|
|
}
|
|
|
|
RED.nodes.registerType('smart-light', SmartLightNode);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Custom Integration Development
|
|
|
|
```python
|
|
# custom_components/my_sensor/sensor.py
|
|
"""Custom sensor integration for Home Assistant."""
|
|
from homeassistant.components.sensor import (
|
|
SensorEntity,
|
|
SensorDeviceClass,
|
|
SensorStateClass,
|
|
)
|
|
from homeassistant.const import UnitOfTemperature
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up the sensor platform."""
|
|
async_add_entities([
|
|
MySensor(config_entry),
|
|
])
|
|
|
|
class MySensor(SensorEntity):
|
|
"""Representation of a custom sensor."""
|
|
|
|
_attr_name = "My Custom Sensor"
|
|
_attr_device_class = SensorDeviceClass.TEMPERATURE
|
|
_attr_state_class = SensorStateClass.MEASUREMENT
|
|
_attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
|
|
|
|
def __init__(self, config_entry: ConfigEntry) -> None:
|
|
"""Initialize the sensor."""
|
|
self._attr_unique_id = f"{config_entry.entry_id}_temperature"
|
|
self._attr_native_value = None
|
|
|
|
async def async_update(self) -> None:
|
|
"""Fetch new state data for the sensor."""
|
|
# API Call oder Sensor-Abfrage
|
|
self._attr_native_value = await self._fetch_temperature()
|
|
|
|
async def _fetch_temperature(self) -> float:
|
|
"""Fetch temperature from external source."""
|
|
# Implementierung
|
|
return 21.5
|
|
```
|
|
|
|
---
|
|
|
|
## Dashboard Configuration
|
|
|
|
```yaml
|
|
# ui-lovelace.yaml
|
|
title: Smart Home
|
|
views:
|
|
- title: Übersicht
|
|
path: overview
|
|
icon: mdi:home
|
|
cards:
|
|
- type: weather-forecast
|
|
entity: weather.home
|
|
|
|
- type: grid
|
|
columns: 3
|
|
cards:
|
|
- type: button
|
|
entity: light.wohnzimmer
|
|
name: Wohnzimmer
|
|
icon: mdi:sofa
|
|
tap_action:
|
|
action: toggle
|
|
|
|
- type: button
|
|
entity: light.schlafzimmer
|
|
name: Schlafzimmer
|
|
icon: mdi:bed
|
|
|
|
- type: button
|
|
entity: script.movie_mode
|
|
name: Kino Modus
|
|
icon: mdi:movie
|
|
|
|
- type: entities
|
|
title: Temperaturen
|
|
entities:
|
|
- entity: sensor.wohnzimmer_temperature
|
|
- entity: sensor.schlafzimmer_temperature
|
|
- entity: sensor.aussen_temperature
|
|
|
|
- type: history-graph
|
|
title: Temperaturverlauf
|
|
hours_to_show: 24
|
|
entities:
|
|
- entity: sensor.wohnzimmer_temperature
|
|
- entity: sensor.aussen_temperature
|
|
```
|
|
|
|
---
|
|
|
|
## Fazit
|
|
|
|
Home Assistant bietet:
|
|
|
|
1. **Lokale Kontrolle**: Keine Cloud-Abhängigkeit
|
|
2. **2800+ Integrations**: Alle Smart Home Protokolle
|
|
3. **Flexible APIs**: WebSocket, REST, MQTT
|
|
4. **Node-RED**: Visual Automation Flows
|
|
|
|
Die perfekte Plattform für Smart Home Projekte.
|
|
|
|
---
|
|
|
|
## Bildprompts
|
|
|
|
1. "Smart home dashboard with device controls, Home Assistant interface"
|
|
2. "Automation flow connecting sensors and actuators, Node-RED visual programming"
|
|
3. "Home network diagram with IoT devices, local smart home server"
|
|
|
|
---
|
|
|
|
## Quellen
|
|
|
|
- [Home Assistant Documentation](https://www.home-assistant.io/)
|
|
- [Home Assistant 2026.1 Release](https://www.home-assistant.io/blog/2026/01/07/release-20261)
|
|
- [Node-RED Home Assistant](https://flows.nodered.org/node/node-red-contrib-home-assistant)
|
|
- [Home Assistant WebSocket API](https://developers.home-assistant.io/docs/api/websocket)
|