Update tracksolidApiDocumentation.md with live implementation findings

Reflects accurate field names, behaviours, and status from production:

Polling endpoints:
- 5.1 location.list: add full response schema (direction, gpsSignal, gpsNum,
  powerValue, elecQuantity, posType, locDesc); add implementation note
  (311 calls, ~19 devices/sweep, ~200ms, missing devices silently omitted)
- 5.4 track.mileage: add maxSpeed field (BUG-03); add distance unit note
  (BUG-02 — values are km from API, corrected via migration 04)
- 5.5 track.list: add altitude/satellite fields; add POLL-01 implementation
  note (30-min schedule, 35-min lookback, source='track_list', ~137s/call)
- 5.7 parking: clarify acc_type=0 required; note durSecond vs stopSecond;
  add POLL-02 production status (60 calls, 0 rows, overnight expected)
- Rate limits: document track.list latency (~137s per call)

Alarms:
- 6.1: replace vague note with explicit poll-vs-push field name table
  (alertTypeId/alarmTypeName vs alarmType/alarmName); confirm BUG-01 fix
  verified in production (type 3 / "Vibration alert" now stored correctly)

Webhooks:
- 10.1 /pushevent: mark implemented (PUSH-01), db table
- 10.2 /pushhb: mark as not yet wired, table ready
- 10.4 /pushalarm: mark implemented, cross-ref field name table
- 10.7 /pushoil: mark implemented (PUSH-02), unit int→text note
- 10.9 /pushtem: mark implemented (PUSH-03)
- 10.10 /pushlbs: mark implemented (PUSH-04)
- 10.20 /pushobd: mark implemented, document OBD scalar extraction
- 10.21 /pushfaultinfo: mark not yet wired, table ready
- 10.22 /pushtripreport: mark implemented

Appendix B: full rewrite — split into polling and push tables with
accurate status (/⚠️/not used), call counts, and DB table references

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
David Kiania 2026-04-11 07:52:28 +03:00
parent d7ffa136a3
commit ae5bd2c960

View file

@ -2,7 +2,7 @@
> Consolidated from official Jimi IoT documentation at [tracksolidprodocs.jimicloud.com](https://tracksolidprodocs.jimicloud.com/) and [docs.jimicloud.com](https://docs.jimicloud.com/integration/integration.html).
>
> API Spec Version: 2.7.7 | Last updated: 2026-04-08
> API Spec Version: 2.7.7 | Last updated: 2026-04-11
---
@ -81,6 +81,7 @@ Every API call includes these base parameters:
- Token acquisition (`jimi.oauth.token.get`) can be called **at most once per minute**
- `jimi.device.alarm.list` — time range limited to **1 month**, max **1000 rows** returned
- Batch endpoints accept up to **50 IMEIs** per call
- `jimi.device.track.list` — per-device endpoint (no batch); each call can be slow (~137s observed in production for a 35-minute lookback). Do not call synchronously inside a 60s scheduler loop; run on a dedicated 30-minute schedule.
---
@ -440,14 +441,26 @@ Retrieve latest positions for all devices under an account. Single API call for
|---|---|---|
| `imei` | string | Device IMEI |
| `deviceName` | string | Device name |
| `status` | string | Device status |
| `status` | string | Device status code |
| `lat` | double | Latitude |
| `lng` | double | Longitude |
| `speed` | number | Speed (km/h) |
| `direction` | number | Heading (0360 degrees) |
| `gpsTime` | string | GPS fix timestamp |
| `accStatus` | string | ACC ignition status |
| `hbTime` | string | Heartbeat/server receive time |
| `accStatus` | string | ACC ignition status (`0`=off, `1`=on) |
| `gpsSignal` | int | GPS signal quality (04) |
| `gpsNum` | int | Satellites used |
| `currentMileage` | number | Odometer reading |
| `expireFlag` | string | Expiration flag |
| `powerValue` | number | External power voltage |
| `elecQuantity` | number | Battery percentage |
| `posType` | string | Position type |
| `confidence` | int | Position confidence score |
| `expireFlag` | string | Subscription expiration flag |
| `activationFlag` | string | Activation status |
| `locDesc` | string | Reverse-geocoded address (if available) |
> **Implementation note:** This is the fleet sweep endpoint called every 60 seconds. In production it returns ~19 active devices out of 63 queried, averaging ~200ms per call. Devices without a current position are silently omitted from the response — they are not returned with null coordinates.
---
@ -532,9 +545,15 @@ Extract trip and distance records within a time period. Supports batching up to
| `imei` | string | Device IMEI |
| `startTime` | string | Trip start time |
| `endTime` | string | Trip end time |
| `distance` | number | Distance in kilometers |
| `avgSpeed` | number | Average speed (km/h) |
| `runTimeSecond` | int | Trip duration in seconds |
| `distance` | number | Distance — **stored as kilometres in DB** (see note below) |
| `avgSpeed` | number | Average speed (km/h) — field name: `avgSpeed` |
| `maxSpeed` | number | Maximum speed (km/h) — field name: `maxSpeed` |
| `runTimeSecond` | int | Driving time (seconds) |
| `idleSecond` | int | Idle time (seconds) |
> **Distance unit note (BUG-02):** The raw `distance` value returned by this endpoint is in **kilometres** as labelled. However, the value was being stored incorrectly as millimetres due to an erroneous `× 1000` multiplication in earlier code. Migration 04 corrected all historical rows: `distance_km = stored_value / 1,000,000`. Current code stores `distance` directly as `distance_km` with no further conversion. The DB column was renamed from `distance_m` to `distance_km` to reflect this.
>
> **maxSpeed note (BUG-03):** `maxSpeed` was present in the API response but not mapped in `poll_trips()`. Fixed — now stored in `tracksolid.trips.max_speed_kmh`.
---
@ -564,10 +583,14 @@ Retrieve detailed positional waypoints for a specified timeframe. **Per-device**
| `lng` | double | Longitude |
| `gpsTime` | string | Timestamp of GPS fix |
| `gpsSpeed` | int | Speed (km/h) |
| `direction` | int | Heading (0-360 degrees) |
| `direction` | int | Heading (0360 degrees) |
| `ignition` | string | Ignition state |
| `accStatus` | string | ACC status |
| `confidence` | int | Position confidence |
| `altitude` | int | Altitude (metres) — not populated by all device models |
| `satellite` | int | Satellite count |
> **Implementation note (POLL-01):** Called per-device every 30 minutes with a 35-minute lookback window. Results written to `tracksolid.position_history` with `source='track_list'` (vs `source='poll'` for the 60s sweep). Use `ON CONFLICT DO NOTHING` — duplicate fixes from overlapping windows are safely discarded. Observed: ~56 waypoints per active device per 30-min window. Altitude field is returned but not populated by X3 and GT06E devices in this fleet.
---
@ -617,7 +640,7 @@ Analyze stationary and engine-running periods.
| `end_time` | string | Yes | End time |
| `start_row` | int | Yes | Pagination offset |
| `page_size` | int | Yes | Page size |
| `acc_type` | string | Yes | ACC filter type |
| `acc_type` | string | Yes | ACC filter: **`0`** = all stops, `1` = ignition-off only |
**Response (array):**
@ -626,10 +649,12 @@ Analyze stationary and engine-running periods.
| `imei` | string | Device IMEI |
| `startTime` | string | Parking/idle start |
| `endTime` | string | Parking/idle end |
| `durSecond` | int | Total duration (seconds) |
| `durSecond` | int | Total duration (seconds) — **use this field for duration** |
| `stopSecond` | int | Stationary-only duration (seconds) — may be absent |
| `addr` | string | Address / location |
| `deviceName` | string | Device name |
| `stopSecond` | int | Stationary duration (seconds) |
> **Implementation note (POLL-02):** Pass `acc_type=0` to capture all stop events (not just ignition-off). If `acc_type` is omitted or set to an empty string the API returns 0 rows. The primary duration field is `durSecond`; `stopSecond` is a secondary field that may not be populated. In production: 60 calls logged, all successful, 0 rows — expected while fleet is overnight-parked. Will populate once vehicles complete a full stopstartstop cycle.
---
@ -690,16 +715,24 @@ Retrieve alarm events for devices within a time range.
| `imei` | string | Device IMEI |
| `model` | string | Device model |
| `account` | string | Account |
| `alertTypeId` | string | Alarm type identifier |
| `alarmTypeName` | string | Alarm type display name |
| `alertTime` | string | Alarm trigger time |
| `alertTypeId` | string | Alarm type identifier **polling field name** |
| `alarmTypeName` | string | Alarm type display name **polling field name** |
| `alertTime` | string | Alarm trigger time **polling field name** |
| `positioningTime` | string | GPS fix time at alarm |
| `lat` | double | Latitude |
| `lng` | double | Longitude |
| `speed` | number | Speed at alarm time |
| `geoid` | string | Geo-fence ID (if geofence alarm) |
> **Note:** The documented response field names (`alertTypeId`, `alertTime`) may differ from what some code examples use (`alarmType`, `alarmTime`). Always verify against actual API responses.
> **Critical field name difference — polling vs push (BUG-01):**
>
> | Data | Polling (`jimi.device.alarm.list`) | Push (`/pushalarm`) | DB column |
> |---|---|---|---|
> | Type ID | `alertTypeId` | `alarmType` | `alarm_type` |
> | Type name | `alarmTypeName` | `alarmName` | `alarm_name` |
> | Time | `alertTime` | `gateTime` | `alarm_time` |
>
> Earlier code used the push field names (`alarmType`, `alarmName`) in the polling path — these keys are never present in the polling response, so `alarm_type` and `alarm_name` were always NULL. Fixed in `ingest_events_rev.py` (FIX-E06): polling now maps `item.get('alertTypeId')``alarm_type` and `item.get('alarmTypeName')``alarm_name`. **Verified in production:** vibration alarms now store type `3` and name `"Vibration alert"` correctly.
---
@ -1217,6 +1250,8 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| Endpoint | `{YourURL}/pushevent` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented (PUSH-01) |
| **DB table** | `tracksolid.device_events` |
**`data_list` fields:**
@ -1233,6 +1268,7 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| Endpoint | `{YourURL}/pushhb` |
|---|---|
| **Handler** | Not yet implemented — DB table `tracksolid.heartbeats` exists and is ready |
**`data_list` fields (max 50 per request):**
@ -1278,6 +1314,10 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| Endpoint | `{YourURL}/pushalarm` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented |
| **DB table** | `tracksolid.alarms` |
> **Field name note:** Push uses `alarmType` and `alarmName` — different from the polling endpoint which uses `alertTypeId` and `alarmTypeName`. See Section 6.1 for the full mapping table.
**`data_list` fields (max 50 per request):**
@ -1333,6 +1373,8 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| Endpoint | `{YourURL}/pushoil` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented (PUSH-02) |
| **DB table** | `tracksolid.fuel_readings` (TimescaleDB hypertable) |
**`data_list` fields (max 50 per request):**
@ -1342,7 +1384,7 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| `path` | int | Sensor ID |
| `gateTime` | string | Reading time |
| `value` | double | Oil level (divide by 100 for actual value) |
| `unit` | int | 1=cm, 2=%, 3=V, 4=L |
| `unit` | int | `1`=cm, `2`=%, `3`=V, `4`=L — stored as text label in DB |
| `gpsTime` | string | Optional GPS time |
| `lng`, `lat` | double | Optional GPS position |
@ -1368,6 +1410,8 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| Endpoint | `{YourURL}/pushtem` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented (PUSH-03) |
| **DB table** | `tracksolid.temperature_readings` (TimescaleDB hypertable) |
**`data_list` fields:**
@ -1385,6 +1429,8 @@ You must configure your callback URL in the Tracksolid Pro platform. All push en
| Endpoint | `{YourURL}/pushlbs` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented (PUSH-04) |
| **DB table** | `tracksolid.lbs_readings` |
**`data_list` fields:**
@ -1552,8 +1598,10 @@ Called when a device finishes uploading media (photo, video, event clip) to Jimi
| Endpoint | `{YourURL}/pushobd` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented |
| **DB table** | `tracksolid.obd_readings` |
> **Important:** This is the only documented method for receiving OBD data. There is no polling/pull endpoint for OBD.
> **Important:** This is the only documented method for receiving OBD data. There is no polling/pull endpoint for OBD. The handler extracts scalar fields (`engine_rpm`, `coolant_temp_c`, `fuel_level_pct`, `battery_voltage`, `intake_pressure`, `throttle_pct`, `vehicle_speed`, `engine_load_pct`) from `obdJson` using well-known OBD PID dataID keys, and also stores the full `obdJson` in the `obd_data JSONB` column.
**`data_list` fields:**
@ -1576,6 +1624,7 @@ Called when a device finishes uploading media (photo, video, event clip) to Jimi
| Endpoint | `{YourURL}/pushfaultinfo` |
|---|---|
| **Handler** | Not yet implemented — DB table `tracksolid.fault_codes` exists and is ready |
> **Important:** This is the only documented method for receiving DTC fault codes.
@ -1598,6 +1647,8 @@ Called when a device finishes uploading media (photo, video, event clip) to Jimi
| Endpoint | `{YourURL}/pushtripreport` |
|---|---|
| **Handler** | `webhook_receiver_rev.py` — implemented |
| **DB table** | `tracksolid.trips` |
**`data_list` fields:**
@ -1647,19 +1698,39 @@ Common parameters: `deviceImei`, `proNo` (protocol number), `cmdContent` (JSON),
## Appendix B: API Coverage in This Codebase
| API Method | Pipeline | Status |
|---|---|---|
| `jimi.oauth.token.get` | `ts_shared_rev.py` | In use |
| `jimi.oauth.token.refresh` | `ts_shared_rev.py` | In use |
| `jimi.user.device.list` | `ingest_movement_rev.py` | In use |
| `jimi.track.device.detail` | `ingest_movement_rev.py` | In use |
| `jimi.user.device.location.list` | `ingest_movement_rev.py` | In use |
| `jimi.device.track.mileage` | `ingest_movement_rev.py` | In use |
| `jimi.device.alarm.list` | `ingest_events_rev.py` | In use — field mapping corrected (FIX-E06) |
| `jimi.device.obd.list` | `ingest_events_rev.py` | **Not a real endpoint** — OBD is push-only |
| `jimi.device.track.list` | `ingest_movement_rev.py` | **In use** — poll_track_list() every 30m (FIX-M14) |
| `jimi.device.location.get` | `ingest_movement_rev.py` | **In use** — get_device_locations() on-demand (FIX-M15) |
| `jimi.open.platform.report.parking` | `ingest_movement_rev.py` | **In use** — acc_type/durSecond fixed (FIX-M13) |
| `jimi.device.jimi.media.URL` | — | Not used (media catalog) |
| `jimi.device.media.event.URL` | — | Not used (alarm-triggered media) |
| All Data Push endpoints | — | Not used (webhook receiver needed) |
### Polling (Pull) Endpoints
| API Method | File | Status | Notes |
|---|---|---|---|
| `jimi.oauth.token.get` | `ts_shared_rev.py` | ✅ In use | Token auto-refreshed, cached in DB |
| `jimi.oauth.token.refresh` | `ts_shared_rev.py` | ✅ In use | |
| `jimi.user.device.list` | `ingest_movement_rev.py` | ✅ In use | Fleet sync every 5h; 2 runs, 126 devices synced |
| `jimi.track.device.detail` | `ingest_movement_rev.py` | ✅ In use | Called alongside device.list |
| `jimi.user.device.location.list` | `ingest_movement_rev.py` | ✅ In use | Every 60s; 311 calls, 5,909 upserts, 0 failures |
| `jimi.device.track.mileage` | `ingest_movement_rev.py` | ✅ In use | Trip polling; `maxSpeed` now mapped (BUG-03 fixed) |
| `jimi.device.track.list` | `ingest_movement_rev.py` | ✅ In use | `poll_track_list()` every 30m (POLL-01 / FIX-M14); 15 calls, 80 waypoints |
| `jimi.device.location.get` | `ingest_movement_rev.py` | ✅ In use | `get_device_locations()` on-demand batch refresh (POLL-03 / FIX-M15); max 50 IMEIs/call |
| `jimi.open.platform.report.parking` | `ingest_movement_rev.py` | ✅ In use | `acc_type=0`, `durSecond` corrected (POLL-02 / FIX-M13); 60 calls, 0 rows (fleet overnight) |
| `jimi.device.alarm.list` | `ingest_events_rev.py` | ✅ In use | `alertTypeId`/`alarmTypeName` mapping fixed (BUG-01 / FIX-E06); 11 calls, 11 rows |
| `jimi.device.obd.list` | — | ❌ Does not exist | OBD data is push-only via `/pushobd` |
| `jimi.device.jimi.media.URL` | — | Not used | Media file catalog |
| `jimi.device.media.event.URL` | — | Not used | Alarm-triggered media |
| All other geofence/command/media polling | — | Not used | Available when needed |
### Push (Webhook) Endpoints
| Endpoint | File | Status | DB Table |
|---|---|---|---|
| `/pushalarm` | `webhook_receiver_rev.py` | ✅ Implemented | `tracksolid.alarms` |
| `/pushtripreport` | `webhook_receiver_rev.py` | ✅ Implemented | `tracksolid.trips` |
| `/pushobd` | `webhook_receiver_rev.py` | ✅ Implemented | `tracksolid.obd_readings` |
| `/pushevent` | `webhook_receiver_rev.py` | ✅ Implemented (PUSH-01) | `tracksolid.device_events` |
| `/pushoil` | `webhook_receiver_rev.py` | ✅ Implemented (PUSH-02) | `tracksolid.fuel_readings` |
| `/pushtem` | `webhook_receiver_rev.py` | ✅ Implemented (PUSH-03) | `tracksolid.temperature_readings` |
| `/pushlbs` | `webhook_receiver_rev.py` | ✅ Implemented (PUSH-04) | `tracksolid.lbs_readings` |
| `/pushhb` | — | ⚠️ Not yet wired | `tracksolid.heartbeats` table ready |
| `/pushfaultinfo` | — | ⚠️ Not yet wired | `tracksolid.fault_codes` table ready |
| `/pushgps` | — | Not used | GPS data received via polling |
| All other push endpoints | — | Not used | |
> **Registration status:** All implemented webhook endpoints need to be registered in the Tracksolid Pro dashboard with your server's public URL before they will receive data. Tables exist and are ready; rows will be 0 until registration is complete.