Files
2026-08-04 17:19:11 -04:00

4.2 KiB

TDS API

Base URL on the LAN:

http://127.0.0.1:8080

Health

GET /health
GET /ready

Observation Ingestion

POST /v1/observations
x-tds-api-key: change-me
content-type: application/json

Example:

{
  "timestamp": "2026-07-21T20:10:00Z",
  "source": "synthetic",
  "sensor_id": "front-door",
  "zone_id": "entrance",
  "protocol": "ble",
  "identity_hint": "demo-ble-tag-001",
  "rssi": -48,
  "known": false,
  "metadata": { "generator": "tds.synthetic.v1" },
  "raw_payload": { "addr": "demo-ble-tag-001" }
}

Dashboard Reads

GET /v1/dashboard/summary
GET /v1/observations?source=synthetic&limit=50
GET /v1/events?zone_id=entrance&type=unknown_device_nearby&limit=50
GET /v1/sensors
GET /v1/zones
GET /v1/collectors
GET /v1/integrations
GET /v1/rules
GET /v1/state?source=unifi&kind=client&limit=50

Responses use:

{
  "items": [],
  "count": 0
}

where practical. Dashboard summary returns counts and recent events.

Current State

Collector payloads can include metadata.state_key and metadata.state_fingerprint. TDS uses those fields to maintain a current-state row and skip duplicate observation inserts when a scheduled poll returns an unchanged snapshot.

GET /v1/state
GET /v1/state?source=openwrt
GET /v1/state?source=unifi&kind=device
GET /v1/state?source=kismet
GET /v1/state?source=intercept

Current state is the preferred dashboard source for latest device/router/AP status. Observation history remains append-only and is reserved for first-seen or changed snapshots.

See docs/capture-map.md for the canonical source ownership matrix. Dashboard views should prefer source-scoped current-state reads such as:

GET /v1/state?source=openwrt
GET /v1/state?source=unifi
GET /v1/state?source=kismet
GET /v1/state?source=intercept

MQTT

Generated events publish to:

rf/events

Event payloads match the JSON returned by GET /v1/events.

OpenWrt Collector

OpenWrt is ingested through the existing observation endpoint. The collector uses authenticated ubus JSON-RPC for safe surfaces only:

  • system board
  • luci-rpc getDHCPLeases
  • luci-rpc getHostHints
  • network.interface dump
  • iwinfo devices
  • iwinfo assoclist

It intentionally avoids broad wireless config dumps because those can expose wireless credentials. See docs/openwrt.md for the read-only ACL setup.

cd /opt/tds/TDS
.venv/bin/python tools/openwrt_collect.py

Use --dry-run to inspect normalized observations without submitting them.

UniFi

UniFi Alarm Manager webhooks are accepted at:

GET /v1/webhooks/unifi/alarm
POST /v1/webhooks/unifi/alarm
x-tds-webhook-token: replace-with-long-random-token

GET query parameters or POST JSON payloads create unifi_alarm events. The UniFi poller submits client and device state through POST /v1/observations with source unifi and current-state de-dup metadata.

UniFi webhook events include normalized fields under payload.normalized while preserving the original UniFi body under payload.raw.

cd /opt/tds/TDS
.venv/bin/python tools/unifi_collect.py --dry-run

See docs/unifi.md for UDM SE API key and Alarm Manager setup.

Kismet Passive RF

Kismet passive RF observations are submitted through POST /v1/observations with source kismet.

Initial normalized kinds:

  • device for Wi-Fi and Bluetooth devices
  • aircraft for ADS-B devices
  • datasource for Kismet capture source health
  • server_status for Kismet server health
cd /opt/tds/TDS
.venv/bin/python tools/kismet_collect.py --dry-run

Intercept RF Platform

Intercept RF platform observations are submitted through POST /v1/observations with source intercept.

Initial normalized kinds:

  • server_status for Intercept process/database/counter health
  • sdr_device for RTL-SDR, HackRF, and other detected SDR devices
cd /opt/tds/TDS
.venv/bin/python tools/intercept_collect.py --dry-run

Next Adapter Phase

After backend task 10, add real source adapters in this order unless priorities change:

  1. OpenWrt infrastructure state
  2. UniFi infrastructure and Protect context
  3. Kismet passive RF observations
  4. Intercept RF observations
  5. AntiHunter RF observations