telemetry-dashboard/README.md
2026-07-04 04:18:36 +09:00

132 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# telemetry-dashboard
Одностраничный дэшборд телеметрии стратосферного зонда. Подключается к
WebSocket бэкенда stratoflights и отображает все поля MSG_BEACON в реальном
времени. Запускается рядом с leaflet_svelte (карта — там, здесь — приборы).
## Быстрый старт
```bash
npm install
# дев-сервер
npm run dev
# type-check + продакшн-сборка (статика в ./build)
npm run check
npm run build
```
Деплой идентичен leaflet_svelte: `build/` раздаётся любым статическим
сервером, fallback — `index.html`.
## Использование
В шапке указывается полный адрес WS-эндпоинта:
```
ws://<host>/api/ws/satellite/<satellite-uuid>/telemetry/
```
Адрес сохраняется в localStorage (дефолт можно задать через
`VITE_DEFAULT_WS_URL`, см. `.env.example`). Если URL совпадает с известным
шаблоном stratoflights, перед подключением подтягивается история по REST
(`/api/<uuid>/telemetry/`); для любого другого ws-адреса дэшборд просто
слушает поток. При обрыве связи — автопереподключение с экспоненциальным
бэкоффом (до 30 с), данные не сбрасываются, плитки затемняются, возраст
последнего пакета подсвечивается (янтарный > 15 с, красный > 60 с).
## Тестовый сервер
```bash
pip install websockets
python3 test_server.py --interval 1 --speedup 20 # полный полёт за ~9 минут
python3 test_server.py --speedup 200 --start 5900 # сразу перед разрывом шара
```
Эмулирует полный профиль полёта (подъём 5 м/с → разрыв на 30 км → спуск) в
точном формате пакетов бэкенда. Подключаться на `ws://localhost:8765/`.
## Демо бок-о-бок с leaflet_svelte (через Django, как в проде)
```bash
scripts/demo-stack.sh # Django :8000 + leaflet :5173 + дэшборд :5174 + станция
scripts/demo-stack.sh restart-flight # полёт заново: рестарт станции + чистка истории в БД
scripts/demo-stack.sh stop
```
Станция летит по `mock_prediction.json` из корня репозиториев (реальный
предикт) со случайным дрейфом до ±5 км. Каждый запуск/`restart-flight`
начинает полёт с нуля; после него нажми «Отключиться/Подключиться» в обоих
окнах, чтобы сбросить старые графики. Темп: `SPEEDUP=60 scripts/demo-stack.sh`.
Скрипт также поднимает **фейковый predictor на :8080** (захардкоженный адрес
`TawhiriClient` в Django), который отдаёт тот же `mock_prediction.json`
поэтому «Рассчитать» в leaflet возвращает ровно ту траекторию, по которой
летит станция. Порядок для оверлея прогноза в слежении: `/predict`
«Рассчитать» → перейти на «Слежение» **кликом в навбаре** (результат прогноза
живёт в памяти SPA и не переживает перезагрузку страницы) → выбрать рабочую
область в «Сравнении с прогнозом». Если на :8080 уже работает настоящий
predictor — скрипт его не трогает и прогнозы идут через него.
График отклонений сопоставляет точки по времени: при ускоренном полёте
(speedup > 1) времена телеметрии и прогноза расходятся — для честного
сравнения ставь дату запуска в форме «сейчас» и `SPEEDUP=1`.
Скрипт (адаптация leaflet_svelte/scripts/run-stack.sh под новые пути) сам
создаёт спутник и токен, запускает `test_server.py --push` как наземную
станцию и печатает UUID спутника. Дальше:
- **leaflet**: http://localhost:5173/track → логин demo/demo → вставить UUID →
«Подключиться»;
- **дэшборд**: http://localhost:5174/ → адрес
`ws://localhost:8000/api/ws/satellite/<UUID>/telemetry/` → «Подключиться»
(адрес запоминается в localStorage; история за прошедший полёт подтянется
по REST автоматически).
Оба окна читают один и тот же поток из Django. Если фронты уже запущены
руками — скрипт их не трогает, просто вставь UUID в оба окна.
## Пре-флайт аудит форматов
```bash
python3 field_audit.py # из корня telemetry-dashboard
```
Исполняемая сверка всей цепочки: математика firmware против контрольных
примеров из даташитов (MS5611, SHT4x), бит-точный round-trip
beacon → PN9/CRC → Deframer → parse → webclient, совпадение ключей payload и
имён флагов с нашим парсером. 9 групп проверок; любое расхождение — assert.
## Устройство
- **SvelteKit + adapter-static** (Svelte 5 runes, TypeScript) — тот же стек и
процесс сборки, что у leaflet_svelte; тот же брендовый Bootstrap
(`static/css/bootstrap.min.css`).
- **uPlot** для графиков — им же рендерит time series Grafana; ~22 КБ gzip,
потоковые обновления через `setData()`, курсор синхронизирован между всеми
графиками (`cursor.sync`).
- `src/lib/telemetry.ts` — чистый домен: парсинг пакета, производная
вертикальная скорость (окно 30 с, как у SondeHub), колонки для uPlot с
разрывами линий при пропаже связи > 60 с.
- `src/lib/store.svelte.ts` — WebSocket + реконнект + массив сэмплов.
- Пороги (батарея, спутники, возраст пакета, быстрый спуск) — константы в
начале `src/routes/+page.svelte`.
## Выбор визуализаций (по итогам ресёрча SondeHub/SatNOGS/Grafana-практик)
| Показатель | Форма |
|---|---|
| Возраст пакета | stat-плитка, верхний левый угол, порог 15/60 с |
| Высота GPS + баро | hero-график (две серии; баро выявляет отказ MS5611) + плитка |
| Верт. скорость | производная по GPS-высоте; плитка ▲/▼ + график с нулевой линией |
| Давление | график, лог-шкала (экспонента → прямая), гПа |
| Температуры ×3 | один график, три серии с прямой подписью |
| Влажность | график с фиксированной шкалой 0100 % |
| Батарея | плитка + спарклайн, порог 3,5/3,3 В (3,3 = BATT_LOW_MV firmware) |
| Спутники | плитка + спарклайн, порог 4/6 |
| Координаты | моноширинная плитка, 5 знаков |
| 13 флагов | лампы с семантикой: OK-флаги зелёный/красный, состояния синий/серый, LOW_BATT/PYRO_ARMED — тревожные только когда взведены |
Радиальных gauge нет намеренно: ни один осмотренный боевой дэшборд
(sonik.space, SondeHub, SatNOGS) их не использует.