Skip to content

Nightly condition push

A scheduled job that reads last night's measurements from your own source and sends one updateCondition per unit, with backoff on 429.

The job reads measurements from your own source, a placeholder here, and sends one updateCondition per unit. It needs a key with the scope condition. Run it once a night with cron, a systemd timer or your scheduler.

  • On 429 or 5xx it waits (Retry-After, otherwise exponential backoff) and sends the same body again. That is safe: values that are already stored come back in skipped as unchanged.
  • Other errors (for example 400 validation_error for a value out of range) are logged per unit, the job carries on with the next one and exits with status 1 at the end.
  • Put the time of the measurement into measured_at, not the time the job runs.
#!/usr/bin/env bash
# nightly-condition-push.sh: one updateCondition per line of readings.jsonl (needs curl and jq)
# Each line, written by your BMS export: {"battery_id": "…", "measured_at": "…", "values": {"condition.…": 81.5}}
set -uo pipefail
failed=0
while IFS= read -r line; do
  id=$(jq -r .battery_id <<<"$line")
  body=$(jq -c '{measured_at, note: "Nightly BMS export",
    values: (.values | to_entries | map({field_key: .key, value: .value}))}' <<<"$line")
  # --retry repeats 429 and 5xx answers and waits as long as Retry-After says
  status=$(curl -sS --retry 5 -o response.json -w '%{http_code}' -X PATCH \
    "$BATTERYPASS_URL/api/v1/batteries/$id/condition" \
    -H "Authorization: Bearer $BATTERYPASS_API_KEY" \
    -H "Content-Type: application/json" \
    --data "$body")
  if [ "$status" = 200 ]; then
    jq -c --arg id "$id" '{id: $id, accepted: (.accepted | length), skipped, outcome: .publication.outcome}' response.json
  else
    failed=1
    jq -c --arg id "$id" --arg status "$status" '{id: $id, status: $status, code, request_id}' response.json >&2
  fi
done < readings.jsonl
exit $failed
Output
0192a3f0-5b7c-7d21-8e4f-6a2b9c1d3e5f accepted 1, skipped 1, published

The shell version reads readings.jsonl, one JSON object per unit as shown in its header. Fields, units of measure and the rules for measured_at are explained in Push condition data. With many units, keep in mind that all keys of your organisation share 600 requests per minute.