LDS Admin API

Přehled všech dostupných REST endpointů včetně popisu použití a ukázkového requestu.

Základní URL: https://api.ldsadmin.cz  •  Autorizace: hlavička Authorization: Bearer <JWT> (kromě veřejných)  •  Interaktivní Swagger: /docs
📘 Návod: Načítání historie (Mervis server vs. naše DB) rozbalit / sbalit

Historie projektu může být uložená buď v naší DB (interní sběr, historySource: "internal"), nebo na Mervis serveru (historySource: "mervis_db"). Klient (web i iOS) nemá nic větvit — vždy volá jeden endpoint POST /api/history/unified, který sám podle nastavení projektu vybere zdroj a vrátí stejný tvar dat.

1) (volitelně) Zjisti zdroj a dostupné datapointy

Které projekty jsou Mervis a které interní – jedním voláním pro celou firmu:

curl "https://api.ldsadmin.cz/api/history/project-settings-batch?companyId=30" \
  -H "Authorization: Bearer <JWT>"
# → { "data": { "123": "mervis_db", "124": "internal" } }

Seznam datapointů (GUID + název + jednotka) pro výběr v UI – funguje pro oba zdroje:

curl "https://api.ldsadmin.cz/api/history/internal-dps/123" \
  -H "Authorization: Bearer <JWT>"
# → { "data": [ { "dpId": "<guid>", "dpName": "Napětí L1", "unit": "V", "elementKey": "..." } ] }

2) Načti historii (jeden endpoint pro Mervis i naši DB)

curl -X POST "https://api.ldsadmin.cz/api/history/unified" \
  -H "Authorization: Bearer <JWT>" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": 123,
    "dpIds": ["<mervis-guid-1>", "<mervis-guid-2>"],
    "from": "2026-06-26T00:00:00Z",
    "to":   "2026-06-27T00:00:00Z"
  }'

Odpověď – stejná struktura pro oba zdroje

Liší se jen pole source ("mervis_db" = z Mervisu, "internal" = z naší DB):

{
  "success": true,
  "source": "mervis_db",          // nebo "internal"
  "projectId": 123,
  "datapointCount": 2,
  "truncated": 50,                 // přítomno jen když jsi poslal > 50 dpIds
  "data": [
    {
      "dpId": "<guid>",
      "dpName": "Napětí L1",
      "unit": "V",
      "values": [
        { "ts": "2026-06-26T00:01:00Z", "value": 231.4 },
        { "ts": "2026-06-26T00:02:00Z", "value": 230.9 }
      ]
    }
  ]
}

iOS (Swift / URLSession) – dávkování po 50 a retry na 504

struct HistoryPoint: Decodable { let ts: String; let value: Double?; let valueText: String? }
struct HistorySeries: Decodable { let dpId: String; let dpName: String?; let unit: String?; let values: [HistoryPoint] }
struct HistoryResponse: Decodable { let success: Bool; let source: String?; let data: [HistorySeries] }

func loadHistory(projectId: Int, dpIds: [String], from: Date, to: Date,
                 token: String) async throws -> [HistorySeries] {
    let iso = ISO8601DateFormatter()
    var result: [HistorySeries] = []

    // Server limituje na 50 datapointů → posílej po dávkách.
    for chunk in stride(from: 0, to: dpIds.count, by: 50).map({ Array(dpIds[$0..<min($0+50, dpIds.count)]) }) {
        let url = URL(string: "https://api.ldsadmin.cz/api/history/unified")!
        var req = URLRequest(url: url)
        req.httpMethod = "POST"
        req.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        req.setValue("application/json", forHTTPHeaderField: "Content-Type")
        req.timeoutInterval = 120   // Mervis SOAP bývá pomalý
        req.httpBody = try JSONSerialization.data(withJSONObject: [
            "projectId": projectId,
            "dpIds": chunk,
            "from": iso.string(from: from),
            "to": iso.string(from: to)
        ])

        let (data, resp) = try await URLSession.shared.data(for: req)
        let code = (resp as? HTTPURLResponse)?.statusCode ?? 0

        // 504 = Mervis je pomalý/timeout → zkus menší rozsah (např. půlku)
        if code == 504 {
            let mid = from.addingTimeInterval(to.timeIntervalSince(from) / 2)
            result += try await loadHistory(projectId: projectId, dpIds: chunk, from: from, to: mid, token: token)
            result += try await loadHistory(projectId: projectId, dpIds: chunk, from: mid, to: to, token: token)
            continue
        }
        guard code == 200 else { throw URLError(.badServerResponse) }
        result += try JSONDecoder().decode(HistoryResponse.self, from: data).data
    }
    return result
}
💡 Doporučení: používej vždy /api/history/unified, ne /api/history/mervis ani /api/history/internal. Když admin přepne zdroj projektu, unified se přizpůsobí automaticky a klient nemusíš měnit.
⚠️ Limity: max 50 dpIds na request (přebytek se ořízne → pole truncated). Mervis SOAP má timeout 110 s – při překročení vrací HTTP 504 s { "isTimeout": true }; reaguj zmenšením časového rozsahu. Mervis data jsou downsamplovaná (≤24 h: max 5000 bodů/sérii, jinak 800). valueText (stavové/textové hodnoty) plní jen interní zdroj.

Autorizace: JWT + oprávnění view_history. Časy from/to v ISO 8601 (UTC).