API Referenz - TC100 Display
Vollständige API-Dokumentation für AWTRIX3 Display-Integration.
Übersicht
Die Display-Integration bietet zwei API-Ebenen:
- Python Display Service - High-Level Abstraktion
- AWTRIX3 HTTP API - Low-Level Direct Access
1. Python Display Service API
Initialisierung
from app.services.display_service import DisplayService
# Mit Settings
from app.config import get_settings
settings = get_settings()
display = DisplayService(
display_ip=settings.display_ip,
enabled=settings.display_enabled
)
# Manuell
display = DisplayService(
display_ip="192.168.178.48",
enabled=True
)
send_notification()
Sendet eine temporäre Notification an das Display.
Signatur
async def send_notification(
self,
text: str,
color: Optional[List[int]] = None,
icon: Optional[int] = None,
duration: int = 15,
**kwargs
) -> bool
Parameter
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
text |
str | ✅ | - | Text auf Display |
color |
List[int] | ❌ | [0,255,255] |
RGB-Farbe [R,G,B] |
icon |
int | ❌ | 4644 |
AWTRIX Icon ID |
duration |
int | ❌ | 15 |
Anzeigedauer (Sekunden) |
hold |
bool | ❌ | False |
Bleibt bis Button-Druck |
rainbow |
bool | ❌ | False |
Regenbogen-Effekt |
pushIcon |
int | ❌ | 0 |
Icon-Animation (0/1/2) |
repeat |
int | ❌ | 1 |
Wiederholungen |
Rückgabewert
True- Erfolgreich gesendetFalse- Fehler beim Senden
Beispiele
# Einfache Notification
await display.send_notification(
text="⚡ Produktion gestartet"
)
# Mit Custom-Farbe
await display.send_notification(
text="🌞 Hohe Produktion!",
color=[255, 215, 0], # Gold
duration=30
)
# Permanente Notification
await display.send_notification(
text="🚨 Wechselrichter offline!",
color=[255, 0, 0],
icon=29105,
hold=True # Bleibt bis Button-Druck
)
# Regenbogen-Effekt
await display.send_notification(
text="🎉 System gestartet",
rainbow=True,
duration=10
)
send_warning()
Sendet eine severity-basierte Warnung.
Signatur
async def send_warning(
self,
message: str,
severity: str = "warning",
title: Optional[str] = None,
icon: Optional[int] = None
) -> bool
Parameter
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
message |
str | ✅ | - | Warnungs-Text |
severity |
str | ❌ | "warning" |
info, warning, critical |
title |
str | ❌ | None |
Optionaler Titel |
icon |
int | ❌ | Auto | Auto-Select basierend auf Severity |
Severity-Mapping
| Severity | Farbe | Icon | Hold | Verwendung |
|---|---|---|---|---|
info |
🟢 Grün | 4644 | ❌ | Informationen |
warning |
🟠 Orange | 29105 | ❌ | Warnungen |
critical |
🔴 Rot | 29105 | ✅ | Kritische Fehler |
Beispiele
# Info
await display.send_warning(
message="System Update verfügbar",
severity="info"
)
# Warnung
await display.send_warning(
message="Hohe Temperatur: 85°C",
severity="warning",
title="Temperatur"
)
# Kritisch (bleibt stehen)
await display.send_warning(
message="Wechselrichter 1 offline!",
severity="critical",
title="Kritisch"
)
update_solar_status()
Aktualisiert Solar-Status am Display.
Signatur
async def update_solar_status(
self,
power_w: int,
daily_kwh: float,
online_count: int,
total_count: int,
duration: int = 0
) -> bool
Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
power_w |
int | ✅ | Aktuelle Leistung (Watt) |
daily_kwh |
float | ✅ | Tagesproduktion (kWh) |
online_count |
int | ✅ | Anzahl Online-WR |
total_count |
int | ✅ | Anzahl Gesamt-WR |
duration |
int | ❌ | Anzeigedauer (0 = permanent) |
Format
Farbe
- 🟢 Grün: Alle Wechselrichter online
- 🔴 Rot: Mindestens ein WR offline
Beispiele
# Alle online
await display.update_solar_status(
power_w=3200, # 3.2 kW
daily_kwh=8.5, # 8.5 kWh
online_count=2,
total_count=2
)
# Zeigt: "⚡3.2kW | ☀️8.5kWh heute" (Grün)
# Ein WR offline
await display.update_solar_status(
power_w=1600,
daily_kwh=8.5,
online_count=1,
total_count=2
)
# Zeigt: "⚡1.6kW | ☀️8.5kWh heute" (Rot)
set_indicator()
Steuert die 3 Status-LEDs.
Signatur
async def set_indicator(
self,
index: int,
color: Optional[List[int]] = None,
fade: int = 0,
blink: int = 0
) -> bool
Parameter
| Parameter | Typ | Pflicht | Standard | Beschreibung |
|---|---|---|---|---|
index |
int | ✅ | - | Indicator 1-3 |
color |
List[int] | ❌ | None |
RGB [R,G,B] (None = aus) |
fade |
int | ❌ | 0 |
Fade-Effekt (ms) |
blink |
int | ❌ | 0 |
Blink-Intervall (ms) |
Positionen
Display (8×32):
┌─────────────────────┐
│ 🟢 │ ← Indicator 1
│ 🟢 │ ← Indicator 2
│ ⚫ │ ← Indicator 3
└─────────────────────┘
Beispiele
# Indicator 1: Grün, pulsierend
await display.set_indicator(
index=1,
color=[0, 255, 0],
fade=1000 # 1s Fade
)
# Indicator 2: Rot, blinkend
await display.set_indicator(
index=2,
color=[255, 0, 0],
blink=500 # 500ms Intervall
)
# Indicator 3: Ausschalten
await display.set_indicator(
index=3,
color=None # Aus
)
# Alle 3 setzen
for i in [1, 2, 3]:
await display.set_indicator(
index=i,
color=[0, 255, 0],
fade=1000
)
get_stats()
Ruft Display-Status ab.
Signatur
Rückgabewert
{
"bat": 74, # Batterie %
"bat_raw": 1836, # Rohwert
"type": 1, # Display-Typ
"lux": 145, # Lichtsensor
"ldr_raw": 89, # LDR Rohwert
"ram": 168304, # Freier RAM
"bri": 150, # Helligkeit
"temp": 16, # Temperatur °C
"hum": 0, # Luftfeuchtigkeit %
"uptime": 123456, # Uptime (Sekunden)
"wifi_signal": -50, # WiFi Signal (dBm)
"messages": 0, # Anzahl Messages
"version": "0.98", # Firmware-Version
"indicator1": true, # Indicator 1 Status
"indicator2": true, # Indicator 2 Status
"indicator3": false, # Indicator 3 Status
"app": "TimeApp", # Aktive App
"uid": "abc123", # Geräte-ID
"matrix": true, # Matrix aktiv
"ip_address": "192.168.178.48"
}
Beispiel
stats = await display.get_stats()
if stats:
print(f"🔋 Batterie: {stats['bat']}%")
print(f"📶 WiFi: {stats['wifi_signal']} dBm")
print(f"🌡️ Temperatur: {stats['temp']}°C")
print(f"💡 Helligkeit: {stats['bri']}")
print(f"📦 Firmware: {stats['version']}")
2. Display Bridge API
Event-basierte Integration zwischen WebSocket und Display.
handle_inverter_update()
Verarbeitet Wechselrichter-Status-Updates.
Signatur
Input Data
{
"inverter_id": 1,
"status": "offline", # "online" | "offline"
"name": "Wechselrichter 1",
"power_w": 0,
"voltage_v": 0
}
Verhalten
- Online → Offline: Sendet kritische Warnung
- Offline → Online: Sendet Info-Notification
- Tracking: Speichert letzten Status pro WR
Beispiel
from app.services.display_bridge import handle_inverter_update
# Simuliert WR Offline
await handle_inverter_update({
"inverter_id": 1,
"status": "offline",
"name": "Wechselrichter 1"
})
# Display zeigt: "🚨 Wechselrichter 1 offline!" (Rot, Hold)
handle_production_data()
Verarbeitet Solar-Produktions-Daten.
Signatur
Input Data
{
"power_w": 3200,
"daily_kwh": 8.5,
"inverters": [
{"id": 1, "status": "online"},
{"id": 2, "status": "online"}
]
}
Verhalten
- Aktualisiert Solar-Status auf Display
- Setzt Indicators für jeden WR:
- 🟢 Grün (pulsierend) = Online
- 🔴 Rot (blinkend) = Offline
Beispiel
from app.services.display_bridge import handle_production_data
await handle_production_data({
"power_w": 3200,
"daily_kwh": 8.5,
"inverters": [
{"id": 1, "status": "online"},
{"id": 2, "status": "online"}
]
})
# Display zeigt:
# - "⚡3.2kW | ☀️8.5kWh heute" (Grün)
# - Indicators 1+2: Grün, pulsierend
handle_error()
Verarbeitet System-Fehler.
Signatur
Input Data
{
"message": "Datenbankverbindung verloren",
"severity": "critical", # "info" | "warning" | "critical"
"component": "Database",
"timestamp": "2025-01-15T10:30:00Z"
}
Verhalten
Sendet send_warning() mit entsprechender Severity.
Beispiel
from app.services.display_bridge import handle_error
await handle_error({
"message": "Datenbankverbindung verloren",
"severity": "critical",
"component": "Database"
})
# Display zeigt: "🚨 Datenbankverbindung verloren" (Rot, Hold)
3. AWTRIX3 HTTP API (Direct)
Base URL
Endpoints
POST /api/notify
Sendet eine Notification.
Request:
curl -X POST http://192.168.178.48/api/notify \
-H "Content-Type: application/json" \
-d '{
"text": "Hello World",
"color": [255, 255, 255],
"icon": 1234,
"duration": 15
}'
Response:
POST /api/custom/{name}
Erstellt/Aktualisiert Custom App.
Request:
curl -X POST http://192.168.178.48/api/custom/solar \
-H "Content-Type: application/json" \
-d '{
"text": "3.2kW",
"color": [0, 255, 0]
}'
Custom Apps
Custom Apps müssen in Display WebUI aktiviert werden!
POST /api/indicator{1|2|3}
Steuert Indicators.
Request:
curl -X POST http://192.168.178.48/api/indicator1 \
-H "Content-Type: application/json" \
-d '{
"color": [0, 255, 0],
"fade": 1000
}'
GET /api/stats
Holt Display-Status.
Request:
Response:
POST /api/power
Display ein-/ausschalten.
Request:
# Ausschalten
curl -X POST http://192.168.178.48/api/power \
-H "Content-Type: application/json" \
-d '{"power": false}'
# Einschalten
curl -X POST http://192.168.178.48/api/power \
-H "Content-Type: application/json" \
-d '{"power": true}'
POST /api/rtttl
Spielt RTTTL-Ton.
Request:
curl -X POST http://192.168.178.48/api/rtttl \
-H "Content-Type: application/json" \
-d '{
"rtttl": "two_short:d=4,o=5,b=100:16e6,16e6"
}'
4. Integration Beispiele
Produktions-Update Flow
# 1. WebSocket Manager erhält Daten
async def broadcast_production_data(self, data: dict):
# An WebSocket Clients
await self._send_message("production_data", data)
# An Display
try:
from app.services.display_bridge import handle_production_data
await handle_production_data(data)
except Exception as e:
logger.warning(f"Display failed: {e}")
# 2. Display Bridge verarbeitet
async def handle_production_data(data: dict):
settings = get_settings()
if not settings.display_enabled:
return
display = DisplayService(
display_ip=settings.display_ip,
enabled=True
)
# Solar Status
await display.update_solar_status(
power_w=data["power_w"],
daily_kwh=data["daily_kwh"],
online_count=sum(1 for inv in data["inverters"] if inv["status"] == "online"),
total_count=len(data["inverters"])
)
# Indicators
for i, inverter in enumerate(data["inverters"][:3], start=1):
if inverter["status"] == "online":
await display.set_indicator(i, color=[0, 255, 0], fade=1000)
else:
await display.set_indicator(i, color=[255, 0, 0], blink=500)
Error Handling
try:
await display.send_notification(text="Test")
except Exception as e:
logger.error(f"Display error: {e}")
# Backend läuft weiter
Batch Operations
# Mehrere Indicators gleichzeitig
async def set_all_indicators(color: List[int]):
tasks = [
display.set_indicator(i, color=color, fade=1000)
for i in [1, 2, 3]
]
await asyncio.gather(*tasks)
# Verwendung
await set_all_indicators([0, 255, 0]) # Alle grün
5. Error Codes
HTTP Status Codes
| Code | Bedeutung | Lösung |
|---|---|---|
| 200 | OK | Erfolgreich |
| 400 | Bad Request | JSON prüfen |
| 404 | Not Found | Endpoint prüfen |
| 500 | Server Error | Display neu starten |
| Timeout | Keine Antwort | IP/Netzwerk prüfen |
Python Exceptions
try:
await display.send_notification(text="Test")
except httpx.TimeoutException:
logger.error("Display timeout - IP prüfen")
except httpx.ConnectError:
logger.error("Display nicht erreichbar")
except Exception as e:
logger.error(f"Unbekannter Fehler: {e}")
6. Performance
Request Timings
| Operation | Typ | Dauer | Blocking |
|---|---|---|---|
send_notification() |
POST | ~50ms | ❌ |
update_solar_status() |
POST | ~50ms | ❌ |
set_indicator() |
POST | ~30ms | ❌ |
get_stats() |
GET | ~100ms | ❌ |
Alle Operationen sind async und blockieren Backend nicht!
Rate Limits
# Display verarbeitet ~20 Requests/Sekunde
# Empfehlung: Max 5 Updates/Sekunde
# Batch statt Loop
await asyncio.gather(
display.set_indicator(1, [0,255,0]),
display.set_indicator(2, [0,255,0]),
display.set_indicator(3, [0,255,0])
)
7. Testing
Unit Tests
import pytest
from app.services.display_service import DisplayService
@pytest.mark.asyncio
async def test_send_notification():
display = DisplayService(
display_ip="192.168.178.48",
enabled=True
)
result = await display.send_notification(text="Test")
assert result is True
@pytest.mark.asyncio
async def test_disabled_display():
display = DisplayService(
display_ip="192.168.178.48",
enabled=False
)
result = await display.send_notification(text="Test")
assert result is False # Deaktiviert
Integration Tests
# Test-Script
docker exec solarlog-backend python -c "
import asyncio
from app.services.display_service import DisplayService
async def test():
display = DisplayService('192.168.178.48', True)
# Test 1
assert await display.send_notification(text='Test 1')
await asyncio.sleep(2)
# Test 2
assert await display.update_solar_status(3200, 8.5, 2, 2)
await asyncio.sleep(2)
# Test 3
assert await display.set_indicator(1, [0,255,0])
print('✅ Alle Tests erfolgreich')
asyncio.run(test())
"
Zusammenfassung
High-Level (Python):
- send_notification() - Temporäre Nachrichten
- send_warning() - Severity-basierte Warnungen
- update_solar_status() - Live Solar-Daten
- set_indicator() - Status-LEDs
- get_stats() - Display-Status
Event-Based (Bridge):
- handle_inverter_update() - WR Status
- handle_production_data() - Solar Produktion
- handle_error() - System Fehler
Low-Level (HTTP):
- /api/notify - Notifications
- /api/custom/{name} - Custom Apps
- /api/indicator{1-3} - Indicators
- /api/stats - Status
- /api/power - Ein/Aus
Nächste Schritte:
-
Konfiguration
Detaillierte Einstellungen
-
Troubleshooting
Problemlösungen