Simulates the onboard Raspberry Pi CAN reader and replays CSV/Excel logs into InfluxDB for deployment testing. This replaces the former data_replayer/ Python tool in race-profile.
Production: Firmware → Pi (can-telem-cloud) → InfluxDB → inference API
This tester: CSV / Excel / generated data → InfluxDB → inference API
npm installConfigure InfluxDB (same env vars as docker/main.py):
export INFLUXDB_URL="https://us-east-1-1.aws.cloud2.influxdata.com"
export INFLUXDB_TOKEN="your-token"
export INFLUXDB_ORG="your-org"
export INFLUXDB_BUCKET="your-bucket"See .env.example for optional settings.
| Mode | Env | Line protocol |
|---|---|---|
| production (default) | INFLUX_WRITE_MODE=production |
telemetry_snapshot,signal=soc value=85.5 <ts_ns> — matches the car |
| flat | INFLUX_WRITE_MODE=flat |
telemetry,source=sc_telemetry_tester soc=85.5,pack_power=1500 <ts_ns> — matches current docker /predict defaults |
For end-to-end inference tests against the deployment microservice, use flat mode until /predict queries the production signal tag layout.
| Mode | Command | Behavior |
|---|---|---|
| Bulk (default) | npm run batch |
Writes all rows using CSV timestamps (Var1 ms epoch if present) |
| Bulk + recent window | --shift-to-now |
Rewrites timestamps to start at now; use with /predict lookback_seconds |
| Real-time | npm start |
Sleeps --interval seconds between rows; loops by default |
From race-profile root (after git submodule update --init):
cd tools/sc-telemetry-tester
npm install
# Bulk load training CSV, shifted to current time (works with lookback_seconds)
export INFLUX_WRITE_MODE=flat
node src/replay.js \
--file ../../data_pipeline/dataProcess/testData/raw_data.csv \
--shift-to-now
# Simulate live 1 Hz telemetry from generated test data
npm start
# Custom fields (flat mode)
node src/replay.js \
--file data/test_telemetry.csv \
--fields soc,pack_power,air_temp,speed \
--realtime --interval 1 --loop
# Excel replay
node src/replay.js --file path/to/log.xlsx --shift-to-now| Flag | Description |
|---|---|
--file |
CSV or Excel path (default: data/test_telemetry.csv) |
--fields |
Comma-separated fields for flat mode |
--measurement |
Override measurement name |
--timestamp-column |
Timestamp column (auto-detects Var1, timestamp, time, _time, Time (s)) |
--interval |
Seconds between rows in realtime mode (default: 1) |
--realtime |
Sleep between rows |
--loop |
Restart from first row after file ends |
--shift-to-now |
Rewrite CSV timestamps relative to now |
--max-rows |
Cap rows written |
--start-row |
Skip leading rows (e.g. pre-race idle telemetry with speed 0) |
--route-file |
Grades/route CSV (latitude, longitude, elevation_m, distance_m) — injects lat/lon/elev into each telemetry row |
--route-mode |
distance (speed × Δt along route, default) or index (row fraction along route) |
--speed-field |
Telemetry column for speed in distance mode (default: speed) |
--speed-unit |
mph (default) or mps |
When legacy logs have missing GPS (lat/lon = 0 or -1001) but good CAN signals,
replay signals from TestDataAnalysis and inject location from BSR ASC grades CSV:
export INFLUX_WRITE_MODE=production
export INFLUXDB_MEASUREMENT=telemetry_snapshot
node src/replay.js \
--file ../../course_data/TestDataAnalysis/2024-4-7rawdata.csv \
--route-file "../../course_data/BSR ASC GPX Grades Data 1.0 2026/UofMtoSummitElmentary_grades.csv" \
--route-mode distance \
--speed-unit mph \
--start-row 31267 \
--shift-to-now \
--max-rows 60002024-4-7rawdata.csv has ~31k idle rows at speed 0 before driving starts — use --start-row 31267 so distance mode advances along the route.
--max-rows 6000 at ~20 Hz ≈ 5 minutes — enough for one strategy lookback window (300 s).
Full segment (~83k rows) without --max-rows is fine for bulk load; strategy uses the latest 300 s window.
Use --route-mode index for a quick test without integrating speed.
-
Load telemetry (terminal 1):
cd tools/sc-telemetry-tester export INFLUX_WRITE_MODE=flat node src/replay.js \ --file ../../data_pipeline/dataProcess/testData/raw_data.csv \ --shift-to-now
-
Start inference (terminal 2): see
docker/README.md -
Query (terminal 3):
curl -X POST http://127.0.0.1:8000/predict \ -H "Content-Type: application/json" \ -d '{"lookback_seconds": 300, "fields": ["soc", "pack_power", "air_temp"]}'
npm run generate # Create test_telemetry.csv from format.json
npm test # Verify Influx connection and write permissionsc-telemetry-tester/
├── data/
│ ├── data_format.json # Fallback copy of signal schema
│ └── test_telemetry.csv # Generated test drive cycle
├── src/
│ ├── influx_client.js # Influx v2 line-protocol writer
│ ├── load_replay_file.js # CSV / Excel loader
│ ├── timestamp.js # Timestamp detection and shift-to-now
│ ├── replay.js # Main replay CLI
│ ├── route_inject.js # Merge route grades CSV → lat/lon/elev
│ ├── generate_test_data.js
│ └── test_connection.js
└── package.json
Signal definitions live in sc-data-format (format.json). When cloned as a sibling under tools/ in race-profile:
tools/sc-data-format/format.json ← canonical
tools/sc-telemetry-tester/ ← this repo
Do not nest sc-data-format as a submodule inside this repo; keep them as flat siblings in race-profile.