Read OLT health, pull per-PON statistics, and push ONU configuration — description and VLAN — across BDCOM, VSOL and Solitine first, with Huawei MA and ZTE C3xx built in. CLI, SNMP or NETCONF underneath; identical JSON on top.
Initial support per the project brief covers BDCOM, VSOL and Solitine — both EPON and GPON. Huawei MA series and ZTE C3xx ship in the same box.
Client sends vendor, IP, username, password, port, protocol on every API request via the X-Device-Config header. No pre-registration, no stored passwords on the server. The API accepts inline credentials and uses them immediately for live mode or simulation.
# INLINE CREDENTIALS — send on EVERY request curl -X POST __API_BASE__/api/v1/devices/bdcom/credentials \ -H 'Content-Type: application/json' \ -d '{ "host": "10.0.0.11", # OLT management IP (required) "port": 22, # 22 SSH / 23 Telnet (optional) "protocol": "ssh", # ssh | telnet (optional) "username": "client_user", # CLI user (required) "password": "client_pass", # CLI pass (required) "snmp_community": "public", # optional "pon_types": ["EPON","GPON"], # optional "live_mode": true # false = simulate only }'
All data endpoints accept inline credentials: GET /olts/{vendor}, GET /pons/{vendor}, GET /onus/{vendor}, PUT/PATCH /onus/{vendor}/{onu_id}, POST /api/v1/devices/{vendor}/test.
One vendor can have many physical OLTs, each with its own username/password. Register every OLT with a unique device_id (default default); optionally bind it to a client with client_id and note the real hardware model — so every call can be validated: which device/model, which client, which credentials.
# JSON has NO comments — remove '#' notes before sending (422 otherwise) curl -X POST __API_BASE__/api/v1/devices/bdcom/credentials \ -H 'Content-Type: application/json' -H 'X-API-Token: clientA-token-67890' \ -d '{"host":"10.0.0.12","port":22,"protocol":"ssh","username":"a_user","password":"a_pass", "pon_types":["EPON","GPON"],"live_mode":true, "device_id":"hq-olt-2","client_id":"clientA","model":"P3310C"}'
Then address that OLT on any data call with the header X-Device-ID: hq-olt-2 (omit it for the default device). Devices bound to a client are only readable/writable by tokens of that client (403 otherwise). Your token's client: GET /api/v1/whoami. Full register payload fields: host, port, protocol, username, password, snmp_community, pon_types, live_mode, device_id, client_id, model. See GET /api/v1/devices for the whole per-device list (device id, client, model, host, mode).
Three core operations, one consistent schema for every vendor: overall OLT health, per-PON statistics, and ONU status with description / VLAN updates.
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/devices/{vendor}/credentials | Optional. Register credentials for stored access, or send inline via X-Device-Config header on every request. |
| GET | /api/v1/devices | Credential configuration status per vendor — shows registered devices. Inline credentials bypass registration. |
| POST | /api/v1/devices/{vendor}/test | TCP reachability test — accepts inline credentials via X-Device-Config header. |
| DELETE | /api/v1/devices/{vendor}/credentials | Remove stored credentials. Inline credentials still work without registration. |
| PATCH | /api/v1/devices/live-mode | Toggle live CLI execution globally. Can also be set per-request via X-Device-Config live_mode. |
| GET | /health | Service health, version, live-mode flag. |
| GET | /olts/{vendor} | Operation 1 — overall health: status, uptime, temperature, CPU, memory, firmware, PON types. |
| GET | /pons/{vendor} | Operation 2 — per-PON statistics: type (EPON/GPON), status, ONU count, RX/TX power, errors, distance. |
| GET | /onus/{vendor}[/{onu_id}] | Operation 3a — ONU status details. Optional filters: ?pon_id=1, ?status=online. |
| PUT PATCH | /onus/{vendor}/{onu_id} | Operation 3b — push config: {"description": "...", "vlan": 1-4094}. PUT = full, PATCH = partial. Returns the exact CLI plan. |
Fire real requests against this deployment and inspect the JSON — no setup needed. Requests run from your browser against the same origin.
Exactly what each call returns in simulation mode — the same shape you will get against real devices once credentials are registered.
{
"vendor": "bdcom",
"status": "online",
"mode": "simulation",
"model": "P3310C",
"uptime": "540h 15m",
"temperature": 41.0,
"cpu_usage": 8.0,
"memory_usage": 38.0,
"firmware_version": "V2.1.4",
"protocols": ["CLI/SSH", "SNMP"],
"pon_types": ["EPON", "GPON"],
"last_seen": "2026-09-03T19:40:00+06:00"
}
[
{
"vendor": "bdcom",
"pon_id": 1, "pon_type": "EPON",
"status": "active",
"onu_count": 16,
"rx_power": -15.3, "tx_power": -5.2,
"error_count": 0,
"distance_km": 12.5
},
{
"vendor": "bdcom",
"pon_id": 2, "pon_type": "GPON",
"status": "active",
"onu_count": 8,
"rx_power": -16.8, "tx_power": -4.9,
"error_count": 2,
"distance_km": 9.8
}
]
{
"onu": {
"vendor": "bdcom", "onu_id": 1,
"pon_id": 1,
"serial": "BDC0M1A10001",
"status": "online",
"description": "Living Room ONT",
"vlan": 100,
"rx_power": -21.2, "tx_power": -9.8,
"uptime": "120h 10m"
},
"updated": {"description": true, "vlan": true},
"push": {
"mode": "simulation",
"commands": [
"ont description 1 'Living Room ONT'",
"ont vlan 1 100",
"write memory"
],
"persist": "write memory",
"executed": false,
"detail": "simulation mode — no credentials
configured; CLI plan generated, device untouched"
}
}
The same flow in five languages: read health, list PONs, list ONUs, push a description + VLAN update. The API is plain JSON over HTTP — any language with an HTTP client works.
# 0. MANDATORY — register credentials (once per vendor) curl -X POST __API_BASE__/api/v1/devices/bdcom/credentials \ -H 'Content-Type: application/json' \ -d '{"host":"10.0.0.11","username":"client_user","password":"client_pass","live_mode":false}' # 1. Overall health curl -s __API_BASE__/olts/bdcom # 2. Per-PON statistics curl -s __API_BASE__/pons/bdcom # 3. ONU status curl -s __API_BASE__/onus/bdcom # 4. Push config — description + VLAN curl -s -X PUT __API_BASE__/onus/bdcom/1 \ -H 'Content-Type: application/json' \ -d '{"description":"Living Room ONT","vlan":100}'
import requests BASE = "__API_BASE__" # 0. MANDATORY — register credentials (once per vendor) requests.post(f"{BASE}/api/v1/devices/bdcom/credentials", json={ "host": "10.0.0.11", "username": "client_user", "password": "client_pass", "live_mode": False, }).raise_for_status() # 1. Overall health health = requests.get(f"{BASE}/olts/bdcom").json() print(health["status"], health["model"]) # 2. Per-PON statistics pons = requests.get(f"{BASE}/pons/bdcom").json() for p in pons: print(p["pon_id"], p["pon_type"], p["onu_count"]) # 3. ONU status onus = requests.get(f"{BASE}/onus/bdcom").json() # 4. Push config — description + VLAN r = requests.put(f"{BASE}/onus/bdcom/1", json={"description": "Living Room ONT", "vlan": 100}).json() print(r["updated"], r["push"]["commands"])
const BASE = "__API_BASE__"; // 0. MANDATORY — register credentials (once per vendor) await fetch(`${BASE}/api/v1/devices/bdcom/credentials`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ host: "10.0.0.11", username: "client_user", password: "client_pass", live_mode: false }), }); // 1. Overall health const health = await (await fetch(`${BASE}/olts/bdcom`)).json(); // 2. Per-PON statistics const pons = await (await fetch(`${BASE}/pons/bdcom`)).json(); // 3. ONU status const onus = await (await fetch(`${BASE}/onus/bdcom`)).json(); // 4. Push config — description + VLAN const res = await fetch(`${BASE}/onus/bdcom/1`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ description: "Living Room ONT", vlan: 100 }), }); const out = await res.json(); console.log(out.updated, out.push.commands);
package main import ( "bytes" "encoding/json" "fmt" "net/http" "io" ) func post(url string, body any) { b, _ := json.Marshal(body) resp, err := http.Post(url, "application/json", bytes.NewReader(b)) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(resp.Status, string(out)) } func main() { base := "__API_BASE__" // 0. MANDATORY — register credentials post(base+"/api/v1/devices/bdcom/credentials", map[string]any{ "host": "10.0.0.11", "username": "client_user", "password": "client_pass", "live_mode": false, }) // 1–3. GET endpoints for, path := range []string{"/olts/bdcom", "/pons/bdcom", "/onus/bdcom"} { resp, _ := http.Get(base + path) out, _ := io.ReadAll(resp.Body) resp.Body.Close() fmt.Println(path, string(out)) } // 4. Push config post(base+"/onus/bdcom/1", map[string]any{ "description": "Living Room ONT", "vlan": 100, }) }
<?php $BASE = "__API_BASE__"; function call($method, $path, $body = null) { global $BASE; $ch = curl_init($BASE . $path); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => $method, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], CURLOPT_POSTFIELDS => $body ? json_encode($body) : null, ]); return json_decode(curl_exec($ch), true); } // 0. MANDATORY — register credentials call("POST", "/api/v1/devices/bdcom/credentials", [ "host" => "10.0.0.11", "username" => "client_user", "password" => "client_pass", "live_mode" => false, ]); // 1–3. Reads $health = call("GET", "/olts/bdcom"); $pons = call("GET", "/pons/bdcom"); $onus = call("GET", "/onus/bdcom"); // 4. Push config — description + VLAN $out = call("PUT", "/onus/bdcom/1", [ "description" => "Living Room ONT", "vlan" => 100, ]); print_r($out["updated"]);
Every vendor driver maps its native CLI/SNMP/NETCONF output onto these three shapes — your integration code never changes when a new vendor is added.
Four steps from zero to a running API — locally or on any Linux server. Python 3.11+ required.
Clone the private repository or unpack the delivery package.
git clone git@github.com:dotprogrammers/olt-api.git cd olt-api
Isolated Python venv with pinned dependencies.
python3 -m venv venv source venv/bin/activate pip install -r requirements.txt
No .env editing needed — POST the client's test credentials to the credentials API, or set VENDOR_HOST / VENDOR_USER / VENDOR_PASS variables.
curl -X POST localhost:8000/api/v1/devices/bdcom/credentials \
-H 'Content-Type: application/json' \
-d '{"host":"10.0.0.11","username":"u","password":"p"}'Uvicorn for dev; systemd for production. Docs auto-mounted.
uvicorn main:app --host 0.0.0.0 --port 8000 # Swagger UI → /docs # Docs hub → / # ReDoc → /redoc
Production reference on this server: systemd unit olt-api-vendor.service behind nginx — source at /var/www/olt-api-project/, credentials store at device_credentials.json (0600).