Start point for first iteration

This commit is contained in:
parent 844652c756
commit 433664dd03
16 changed files with 1476 additions and 75 deletions

356
Docs/start.md Normal file
View file

@ -0,0 +1,356 @@
# Оффлайн-карта с треком по WebSocket
**Стек:** Python (FastAPI) + WebSocket + React (Leaflet + Tauri)
**Цель:** хранить карту полностью локально на устройстве и в реальном времени отображать движение по координатам GNSS.
## 1. Цели и общие требования
### 1.1. Функциональные цели
1. Отображать карту местности **без доступа к интернету**.
2. Получать от устройства GNSS координаты в реальном времени.
3. Передавать координаты в клиентское приложение через **WebSocket**, без периодических запросов.
4. В React-приложении:
1. показывать текущую позицию на карте.
2. рисовать трек движения (историю точек).
3. при необходимости в будущем — отображать дополнительные слои (контуры поля, границы, маршруты).
### 1.2. Нефункциональные требования
1. **Полный оффлайн:**
1. ни карта, ни координаты не должны требовать внешних сервисов.
2. все файлы тайлов карты находятся локально на диске устройства.
2. **Устойчивость:**
1. временные потери GNSS-сигнала не должны ломать интерфейс.
2. разрыв WebSocket-соединения не должен ломать отображение данных с фронта.
3. **Расширяемость:**
1. добавлять новые типы данных (например, скорость, курс, высоту).
2. подключать реальные GNSS-устройства вместо генераторов.
3. добавлять слои на карту: полигоны, точки, маршруты.
4. **Простота развёртывания:**
1. backend и frontend должны запускаться стандартными командами.
2. конфигурация (путь к карте, параметры GNSS) выносится в настройки.
## 2. Архитектура решения
### 2.1. Высокоуровневая схема
Система логически делится на три части:
1. **Сервис получения GNSS-данных (внутри backend)**
- модуль в Python, который:
1. подключается к приёмнику GNSS.
2. читает сырые данные.
3. преобразует их в нормализованный формат (широта, долгота, метки времени).
2. **Backend-сервер (FastAPI)**
- HTTP-интерфейсы:
1. выдача тайлов карты по пути вида `/tiles/zoom/x/y.png`.
2. вспомогательные эндпоинты (health-check, конфигурация и т.п.).
- WebSocket-интерфейс:
1. постоянное соединение с клиентом.
2. отправка координат в режиме “push”.
- работа с файловой системой:
1. поиск нужных тайлов.
2. выдача заглушки при отсутствии тайла.
3. **Клиент (React + Leaflet)**
- модуль карты:
1. инициализацирует Leaflet-карту.
2. использует локальный URL тайлов (через backend).
- модуль трека:
1. поддерживает подключение по WebSocket.
2. хранит массив полученных точек.
3. обновляет отображение карты при получении новых данных.
#### Связи:
1. GNSS → модуль GNSS backend’а → WebSocket → React → Leaflet.
2. React → HTTP (через Leaflet) → backend → файловая система с тайлами.
### 2.2. Логические компоненты
**Backend:**
1. Модуль инициализации приложения FastAPI.
2. Модуль выдачи тайлов:
1. логика построения пути к тайлу по `{zoom}/{x}/{y}`.
2. проверка наличия файла.
3. выдача или оригинального тайла, или заглушки.
3. Модуль GNSS:
1. абстракция источника координат.
2. возможность переключить данный источник:
1. на реальное устройство.
4. Модуль WebSocket:
1. управление подключениями клиентов.
2. цикл отправки координат.
3. обработка разрывов соединения и ошибок.
**Frontend:**
5. Модуль подключения WebSocket:
1. открытие соединения.
2. обработка входящих сообщений с координатами.
3. восстановление соединения при разрыве.
6. Модуль управления треком:
1. добавление точки в список.
7. Модуль карты:
1. инициализация Leaflet-карты.
2. настройка источника тайлов на локальный backend.
3. отображение маркера последней точки.
## 3. Оффлайн-карта: концепция и хранение
### 3.1. Формат карты
В начальной версии планируется использовать **растровые тайлы**:
1. карта заранее разбивается на набор изображений (PNG или JPEG).
2. тайлы организованы в структуре каталогов по схеме:
1. уровень масштабирования (zoom).
2. координаты тайла по X и Y.
Преимущества:
3. Leaflet “из коробки” умеет работать с тайлами такого формата.
4. не требуется дополнительный сервер картографических данных — достаточно отдавать файлы по HTTP.
5. относительно просто генерировать карту для нужного региона с помощью внешних инструментов (QGIS, GDAL и др.).
### 3.2. Структура хранения тайлов
На уровне файловой системы тайлы лежат в диапазоне, например:
1. `tiles/10/567/321.png` — тайл уровня зума 10, координаты X=567, Y=321.
2. `tiles/11/1134/643.png` — тот же район на другом зуме.
Backend ничего не знает о том, как эти тайлы были созданы, он:
1. получает значение zoom, x и y из URL.
2. строит путь к файлу.
3. проверяет наличие файла.
4. отдаёт файл, если он есть.
5. если файлы нет — отдаёт заранее подготовленную картинку-заглушку.
Таким образом, карта является полностью статичной, а логика backend — максимально простой.
### 3.3. Генерация и обновление карты
Это отдельный процесс, который выполняется вне основной системы:
1. Выбирается необходимый регион (поля, районы полётов).
2. В GIS-инструменте формируется растровая подложка.
3. Эта подложка нарезается в тайлы нужных уровней масштабирования.
4. Готовый набор тайлов копируется на устройство в папку `tiles/`.
В дальнейшем можно:
1. обновлять карту, подменяя содержимое `tiles/`.
2. хранить несколько наборов карт (например, по сезонам) и включать нужный через конфиг.
## 4. Работа с координатами и GNSS
### 4.1. Источник данных
Фактически координаты приходят либо:
1. от реального GNSS-приёмника, подключённого по:
1. последовательному порту.
2. USB.
3. сетевому протоколу.
2. либо от программного симулятора, который генерирует “виртуальный маршрут”.
Задача backend — предоставить единый интерфейс, не зависящий от конкретного железа.
### 4.2. Нормализация координат
Сырые данные могут быть в формате NMEA или другом специфичном виде. Модуль GNSS:
1. парсит входные данные.
2. приводит координаты к стандартной системе:
1. широта (latitude) в градусах.
2. долгота (longitude) в градусах.
3. опционально — высота, скорость, курс.
3. добавляет метку времени (например, UNIX timestamp или ISO-строку).
4. формирует структуру, удобную для отправки на фронт.
Важно, чтобы координаты были в той системе, которую ожидает Leaflet (обычно WGS84).
### 4.3. Частота обновления
1. Модуль GNSS определяет:
1. как часто появляются новые точки.
2. как часто обновлять данные на фронте:
3. возможен вариант “как пришло — так отправили”.
4. либо накопление точек и отправка пачками (например, раз в секунду).
Частота обновления — важный параметр, влияющий на:
1. плавность трека.
2. нагрузку на канал связи.
3. нагрузку на фронт.
## 5. Потоки данных и жизненный цикл приложения
### 5.1. Запуск backend
1. При старте FastAPI:
1. инициализирует конфигурацию (настройки путей, порты, параметры GNSS).
2. проверяет наличие базовых директорий (`tiles/`, заглушка тайла).
3. при необходимости пробует подключиться к GNSS-источнику.
2. Запускается HTTP-сервер:
1. обслуживает выдачу тайлов.
2. отвечает на запросы.
### 5.2. Запуск frontend
1. React-приложение загружается в оболочке Tauri (Бинарник)
2. После инициализации:
1. открывается WebSocket-соединение с backend.
2. инициализируется карта:
1. начальный центр (по умолчанию либо по первой полученной точке).
2. указание backend-урла тайлов.
3. При успешном подключении по WebSocket:
1. приложение начинает получать координаты.
2. каждая новая точка добавляется в список.
3. карта обновляет положение маркера и линии трека.
### 5.3. Реакция на ошибки и разрывы
1. Если WebSocket-соединение закрывается:
1. фронт может попытаться переподключиться через интервалы.
2. на карте можно оставить последнюю известную позицию.
2. Если нет GNSS-данных:
1. backend может отправлять специальные сообщения о состоянии (например, “нет сигнала”).
2. фронт может отображать статичную карту без движения или соответствующее уведомление.
3. Если тайл для карты отсутствует:
1. backend отдаёт заглушку.
2. на карте вместо участка появляется условный “серый” квадрат, но интерфейс остаётся рабочим.
## 6. Основные этапы разработки
### Этап 1. Подготовка окружения и структуры проекта
1. Создать общий репозиторий с двумя основными директориями: `backend` и `frontend`.
2. Настроить базовую систему сборки и запуска:
- для backend — запуск FastAPI через Uvicorn.
- для frontend — сборщик (Vite + Tauri).
### Этап 2. Скелет backend-приложения
1. Инициализировать приложение FastAPI.
2. Добавить endpoint для проверки, что сервер поднялся.
3. Настроить CORS так, чтобы frontend мог связаться с backend в локальной разработке
На этом этапе можно убедиться, что базовая связка “frontend - backend по HTTP” работает.
### Этап 3. Механизм выдачи тайлов
1. Определить директорию хранения тайлов (`tiles/`).
2. Реализовать логику извлечения тайла по запросу вида `/tiles/{zoom}/{x}/{y}.png`.
3. Добавить заглушку для отсутствующих тайлов.
4. Прогнать простой тест: вручную запросить существующий и несуществующий тайл и убедиться, что:
1. первый отдаётся корректно.
2. второй отдаёт заглушку.
### Этап 4. Проработка GNSS-абстракции
1. Определить интерфейс модуля “источник координат”:
1. формат выдаваемых данных.
2. тип возвращаемой структуры (координаты + время).
2. На этом этапе использовать **симулятор** вместо реального устройства:
1. сделать виртуальную траекторию (линия, круг, восьмёрка и т.п.).
2. выдавать новые точки с заданным интервалом.
3. Важно: модуль должен быть реализован так, чтобы позже его можно было легко заменить реализацией, работающей с реальным железом.
### Этап 5. Добавление WebSocket-эндпоинта в backend
1. Создать WebSocket-обработчик:
1. принимать подключение от клиента.
2. при подключении запускать цикл, в котором:
1. берётся следующая точка из GNSS-источника.
2. отправляется на клиента.
2. Обработать возможные сценарии:
1. разрыв соединения клиентом.
2. ошибки в процессе отправки.
3. отключение GNSS-источника.
На этом этапе backend уже умеет:
1. выдавать тайлы.
2. в реальном времени отдавать поток координат любому подключенному клиенту по WebSocket.
### Этап 6. Скелет frontend-приложения
1. Инициализировать React-приложение.
2. Подготовить базовую структуру компонентов:
1. основной компонент приложения.
2. компонент карты.
3. будущий модуль для WebSocket.
3. Настроить запуск фронта и убедиться, что базовый “каркас” работает.
### Этап 7. Интеграция Leaflet в frontend
1. Подключить Leaflet и его React-обёртку.
2. Создать компонент карты, который:
1. инициализирует карту с некоторым стартовым центром.
2. использует URL `http://localhost:8000/tiles/{z}/{x}/{y}.png` в качестве источника тайлов.
3. Проверить:
1. что при старте приложение отображает карту (в рамках подготовленной области).
2. что при перемещении и масштабировании запросы к тайлам уходят на backend.
На этом этапе карта уже отображается локально, без участия внешних сервисов.
### Этап 8. Подключение WebSocket на frontend
1. Создать модуль, который:
1. открывает WebSocket-соединение с backend’ом по адресу `ws://localhost:8000/ws/track`.
2. слушает сообщения и добавляет новые координаты в локальное состояние приложения.
2. Реализовать простую логику:
1. хранить массив точек.
2. по каждой новой точке:
1. добавлять её в массив.
2. обновлять центр карты.
3. Связать модуль WebSocket с компонентом карты:
1. передавать массив точек как пропсы.
2. отображать:
1. маркер последней точки.
2. линию, соединяющую все точки (трек).
### Этап 9. Обработка ошибок и повышение устойчивости
1. Добавить обработку ошибок WebSocket на frontend:
1. логировать причины разрыва.
2. реализовать простую стратегию повторного подключения (например, попытка подключиться раз в несколько секунд при разрыве).
2. На backend:
1. в явном виде логировать ошибки GNSS и WebSocket.
2. при необходимости — реализовать таймауты и защиту от зависаний.
### Этап 10. Подключение реального GNSS-устройства
1. Вместо симулятора реализовать модуль чтения реальных данных:
1. добавить конфиг с параметрами подключения: порт, скорость, протокол.
2. реализовать парсинг данных.
2. Убедиться, что внешний интерфейс модуля GNSS не изменился:
1. по-прежнему выдаются координаты в ожидаемом формате.
3. Протестировать работу системы “в поле”:
1. убедиться, что карта и трек корректно отражают реальное движение.
### Этап 11. Оптимизация и подготовка к эксплуатации
1. Оптимизация производительности:
1. ограничение длины трека, если ожидается очень длинное использование без перезапуска.
2. настройка частоты обновления координат.
2. Упаковка приложения:
1. вариант 1: backend + frontend как отдельные пакеты.
2. вариант 2: объединение фронта и бека в один пакет.
3. Документация по развёртыванию:
1. пошаговое руководство по установке зависимостей.
2. инструкции по замене тайлов карты.
3. инструкции по смене GNSS-источника.
## 7. Возможные дальнейшие расширения
После того как базовый функционал будет устойчиво работать, его можно расширять:
1. **Отображение контуров полей**
1. загрузка контуров из локальных файлов (например, GeoJSON).
2. визуализация границ поля поверх карты.
2. **Планирование маршрута**
1. формирование линии проходов (полос) по ширине захвата.
2. привязка трека к этим линиям (показ отклонения).
3. **Запись и экспорт данных**
1. сохранение трека в файл (например, GeoJSON, GPX).
2. экспорт для дальнейшего анализа.
4. **Конфигурация через UI**
1. настройка масштабов карты, уровней тайлов.
2. переключение наборов карт (разные сезоны, регионы).
## 8. Итоговая сводка
Суть решения: на устройстве устанавливается локальный сервер на Python (FastAPI), который одновременно:
1. отдаёт статические файлы тайлов карты с диска,
2. и по WebSocket непрерывно передаёт координаты из приёмника ГЛОНАСС.
React-приложение с Leaflet открывает эту локальную карту (через HTTP) и подписывается на WebSocket, чтобы в реальном времени обновлять положение маркера и трек движения. Всё — от карты до координат — живёт локально, не зависит от интернета и может работать в любых условиях, где есть только устройство, приёмник и локальная сеть (или даже один компьютер).