Beispiele
Beispiel: curl
Jeden Endpunkt der API für Geräte mit curl ausprobieren, mit echten Anfragen und Antworten, und die Konfiguration nur abrufen, wenn sie sich geändert hat.
Mit curl probierst du jeden Endpunkt aus, bevor du Code schreibst, und siehst genau, was der Server antwortet. Die Beispiele gehen von Regelkreis 201 aus: T1 Kollektor, T2 Speicher unten, T3 Speicher oben, R2 Pumpe.
Vorbereitung
API=https://boilerbuddy.eu/api/v1
TOKEN=bb_live_42_... # der API-Schlüssel deines Geräts, aus dem Portal
Noch kein Schlüssel? Kopple unten oder erstelle einen im Portal: siehe Dein eigenes BoilerBuddy bauen. Mit read -rs TOKEN landet der Schlüssel nicht in deinem Shell-Verlauf.
Koppeln
Erzeuge einmalig eine UUID (Version 4) und frag nach einem Code:
UUID=$(python3 -c 'import uuid; print(uuid.uuid4())')
curl -s -X POST "$API/device/hello" \
-H "Content-Type: application/json" \
-d "{\"device_uuid\": \"$UUID\", \"firmware_version\": \"curl-test\"}"
Solange niemand das Gerät gekoppelt hat:
{"claimed":false,"pairing_code":"BB-7KQ4-M2XD","expires_at":"2026-10-16T09:30:00+00:00"}
Gib den Code auf der Geräteseite bei Mit Code koppeln ein und schick dann denselben Befehl noch einmal:
{"claimed":true,"token":"bb_live_42_Xk3..."}
Speichere den Token und nutze ihn sofort, zum Beispiel unten. Danach gibt hello nur noch zurück:
{"claimed":true}
Warum: siehe Koppeln mit hello.
Die Konfiguration abrufen
curl -s -i "$API/device/config" -H "Authorization: Bearer $TOKEN"
HTTP/2 200
content-type: application/json
etag: "9f2c1a0b7d3e4f56"
{"config_version":"9f2c1a0b7d3e4f56","device":{"id":42,"name":"Attic","mode":"live"},"intervals":{"scan_seconds":60},"controller":{"brand":"OEG","model":"KSW-E, KSW, KS2W","protocol":"modbus_ascii","connection":{"slave_address":128,"baudrate":9600,"parity":"E","bytesize":7,"stopbits":1,"timeout_ms":1000}},"sensors":[{"sensor":"T1","name":"Temperatuur zonnepaneel","type":"collector_temp","category":"temperature","unit":"\u00b0C","position":null,"address":{"register":38,"decimals":1,"signed":true,"function_code":3},"plausible_min":-50.0,"plausible_max":250.0}, ...]}
Nur die Sensorcodes, mit jq:
curl -s "$API/device/config" -H "Authorization: Bearer $TOKEN" | jq -r '.sensors[].sensor'
T1
T2
T3
R2
Nur abrufen, wenn sich etwas geändert hat
Schick das ETag in If-None-Match zurück. Hat sich nichts geändert? Dann bekommst du 304 ohne Body:
curl -s -i "$API/device/config" \
-H "Authorization: Bearer $TOKEN" \
-H 'If-None-Match: "9f2c1a0b7d3e4f56"'
HTTP/2 304
etag: "9f2c1a0b7d3e4f56"
Ersetze in einem Skript die Konfiguration und das ETag nur bei einer 200:
# Beim ersten Mal: Body und ETag aufbewahren
curl -s -D headers.txt -o config.json "$API/device/config" -H "Authorization: Bearer $TOKEN"
ETAG=$(grep -i '^etag:' headers.txt | cut -d' ' -f2 | tr -d '\r')
# Später: nur herunterladen, wenn sich etwas geändert hat
STATUS=$(curl -s -D headers.txt -o new.json -w '%{http_code}' "$API/device/config" \
-H "Authorization: Bearer $TOKEN" -H "If-None-Match: $ETAG")
if [ "$STATUS" = 200 ]; then
mv new.json config.json
ETAG=$(grep -i '^etag:' headers.txt | cut -d' ' -f2 | tr -d '\r')
fi
Messwerte senden
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
BATCH=$(python3 -c 'import uuid; print(uuid.uuid4())')
curl -s -X POST "$API/device/readings" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data @- <<EOF
{
"batch_uuid": "$BATCH",
"readings": [
{"sensor": "T1", "value": 61.4, "measured_at": "$NOW"},
{"sensor": "T2", "value": 38.0, "measured_at": "$NOW"},
{"sensor": "R2", "value": 10, "measured_at": "$NOW"}
]
}
EOF
{"accepted":3,"duplicates":0,"unmapped":[],"rejected":[]}
Genau dasselbe noch einmal (gleiches $NOW) speichert nichts doppelt:
{"accepted":0,"duplicates":3,"unmapped":[],"rejected":[]}
Ein Batch mit Fehlern
Fehler in einzelnen Messwerten bekommen trotzdem 200. Die Antwort sagt pro Messwert, was nicht stimmt:
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
curl -s -X POST "$API/device/readings" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data @- <<EOF
{
"readings": [
{"sensor": "T1", "value": 61.5, "measured_at": "$NOW"},
{"sensor": "T9", "value": 30.0, "measured_at": "$NOW"},
{"sensor": "T2", "value": "warm", "measured_at": "$NOW"},
{"sensor": "T3", "value": 55.0, "measured_at": "2030-01-01T00:00:00Z"}
]
}
EOF
{"accepted":1,"duplicates":0,"unmapped":["T9"],"rejected":[{"index":2,"reason":"invalid_value","retry":false},{"index":3,"reason":"measured_at_in_future","retry":false}]}
T9 gehört nicht zu Regelkreis 201 und ist jetzt in Quarantäne. Alle Gründe stehen in Messwerte senden.
Ein Batch, der als Ganzes ungültig ist
curl -s -X POST "$API/device/readings" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"readings": []}'
{"message":"The readings field is required.","errors":{"readings":["The readings field is required."]}}
Das ist eine 422: Noch einmal senden hilft nicht.
Einen Status senden
curl -s -i -X POST "$API/device/status" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"firmware_version": "curl-test", "uptime_s": 3600, "buffered": 0}'
HTTP/2 204
Die Geräteseite zeigt dann curl-test unter Firmware, und Zuletzt gesehen wird aktualisiert.
Fehler
Ein falscher oder ersetzter Token:
curl -s -i "$API/device/config" -H "Authorization: Bearer bb_live_42_wrong"
HTTP/2 401
www-authenticate: Bearer
content-type: application/json
{"message":"Unauthenticated."}
Zu viele Uploads in einer Minute:
HTTP/2 429
retry-after: 37
content-type: application/json
{"message":"Too Many Attempts."}
Warte die Anzahl Sekunden aus retry-after ab und schick denselben Batch noch einmal. Mehr dazu in Limits und Fehlercodes.