|
|
# Triangulation Service
|
|
|
|
|
|
Сервис решает 3D-трилатерацию по 3 ресиверам:
|
|
|
- центры сфер: координаты ресиверов;
|
|
|
- радиусы сфер: расстояния, оцененные из RSSI с учетом частоты;
|
|
|
- расчет идет по одинаковым частотам, которые есть у всех 3 ресиверов;
|
|
|
- формируется таблица `frequency_table` (по каждой частоте отдельное решение);
|
|
|
- выбирается итоговая частота `selected_frequency_hz` по минимальному `rmse_m`.
|
|
|
|
|
|
## Что реализовано
|
|
|
|
|
|
- Автоматический polling 3 входных серверов (`http_sources`).
|
|
|
- Валидация входных payload с подробными ошибками.
|
|
|
- API:
|
|
|
- `GET /health`
|
|
|
- `GET /result`
|
|
|
- `GET /frequencies`
|
|
|
- `POST /refresh`
|
|
|
- `GET /config`
|
|
|
- `POST /config`
|
|
|
- UI (`/ui`) с:
|
|
|
- входными данными ресиверов;
|
|
|
- таблицей пересечений по частотам;
|
|
|
- итоговой позицией;
|
|
|
- статусом отправки на конечный сервер.
|
|
|
- Опциональный push результата на внешний сервер (`runtime.output_server`).
|
|
|
|
|
|
## Структура проекта
|
|
|
|
|
|
- [service.py](/c:/Users/snytk/triangulation/service.py) - автосервис + API + UI статик.
|
|
|
- [triangulation.py](/c:/Users/snytk/triangulation/triangulation.py) - математика.
|
|
|
- [config.template.json](/c:/Users/snytk/triangulation/config.template.json) - шаблон конфига.
|
|
|
- [web/index.html](/c:/Users/snytk/triangulation/web/index.html), [web/styles.css](/c:/Users/snytk/triangulation/web/styles.css), [web/app.js](/c:/Users/snytk/triangulation/web/app.js) - UI.
|
|
|
- [docker-compose.yml](/c:/Users/snytk/triangulation/docker-compose.yml) - test/prod профили.
|
|
|
- [docker/config.docker.test.json](/c:/Users/snytk/triangulation/docker/config.docker.test.json) - тестовый конфиг.
|
|
|
- [docker/mock_receiver.py](/c:/Users/snytk/triangulation/docker/mock_receiver.py) - mock входные сервера (random RSSI).
|
|
|
- [docker/mock_output_sink.py](/c:/Users/snytk/triangulation/docker/mock_output_sink.py) - mock конечный сервер.
|
|
|
|
|
|
## Docker Compose: test/prod режимы
|
|
|
|
|
|
`docker-compose.yml` разделен на профили:
|
|
|
|
|
|
- `test`:
|
|
|
- `triangulation-test`
|
|
|
- `receiver-r0`, `receiver-r1`, `receiver-r2`
|
|
|
- `output-sink`
|
|
|
|
|
|
- `prod`:
|
|
|
- `triangulation-prod` (читает ваш `./config.json`)
|
|
|
|
|
|
Это позволяет легко отключить тестовый режим и перейти на реальные сервера.
|
|
|
|
|
|
## Быстрый старт: Test Mode
|
|
|
|
|
|
Поднимает все контейнеры для end-to-end проверки:
|
|
|
- 3 входных mock сервера с random данными;
|
|
|
- основной сервис;
|
|
|
- output-sink, принимающий отправленные результаты.
|
|
|
|
|
|
```bash
|
|
|
docker compose --profile test up --build
|
|
|
```
|
|
|
|
|
|
Открыть:
|
|
|
- UI: `http://localhost:8081/ui`
|
|
|
- Полный результат: `http://localhost:8081/result`
|
|
|
- Частоты: `http://localhost:8081/frequencies`
|
|
|
- Полученные output-sink данные: `http://localhost:8080/latest`
|
|
|
|
|
|
Остановить:
|
|
|
```bash
|
|
|
docker compose --profile test down
|
|
|
```
|
|
|
|
|
|
## Быстрый старт: Prod Mode
|
|
|
|
|
|
1. Создайте `config.json` из шаблона:
|
|
|
```bash
|
|
|
cp config.template.json config.json
|
|
|
```
|
|
|
|
|
|
2. Заполните ваши реальные:
|
|
|
- `input.receivers[].source_url`
|
|
|
- `input.receivers[].center`
|
|
|
- `runtime.output_server`
|
|
|
|
|
|
3. Запустите:
|
|
|
```bash
|
|
|
docker compose --profile prod up --build
|
|
|
```
|
|
|
|
|
|
Остановить:
|
|
|
```bash
|
|
|
docker compose --profile prod down
|
|
|
```
|
|
|
|
|
|
## Как проверить, что данные приходят и отправляются
|
|
|
|
|
|
В UI (`/ui`) видно:
|
|
|
- блок `Ресиверы`: входящие samples;
|
|
|
- таблица `Таблица пересечений по частотам`: решения по каждой общей частоте;
|
|
|
- блок `Отправка на конечный сервер`: статус доставки (`ok/error`), HTTP-код, время, target.
|
|
|
|
|
|
Дополнительно:
|
|
|
- `GET /result` возвращает `output_delivery`.
|
|
|
- `GET /frequencies` тоже возвращает `output_delivery`.
|
|
|
- `GET http://localhost:8080/latest` показывает, что именно принял output-sink.
|
|
|
|
|
|
## Конфиг (основные поля)
|
|
|
|
|
|
Пример: [config.template.json](/c:/Users/snytk/triangulation/config.template.json)
|
|
|
|
|
|
Критичные поля:
|
|
|
- `input.mode`: только `"http_sources"` для автосервиса.
|
|
|
- `input.receivers`: ровно 3 ресивера.
|
|
|
- `input.aggregation`: `"median"` или `"mean"`.
|
|
|
- `runtime.poll_interval_s`: период опроса.
|
|
|
- `runtime.output_server.enabled`: push во внешний сервер.
|
|
|
|
|
|
## Формат входных payload
|
|
|
|
|
|
Поддержка:
|
|
|
- объект с `measurements`/`samples`/`data`;
|
|
|
- или сразу массив измерений.
|
|
|
|
|
|
Измерение:
|
|
|
- `frequency_hz` (или `freq_hz`/`frequency`/`freq`)
|
|
|
- `amplitude_dbm` (или `rssi_dbm`/`amplitude`/`rssi`)
|
|
|
|
|
|
Пример:
|
|
|
```json
|
|
|
{
|
|
|
"receiver_id": "r0",
|
|
|
"measurements": [
|
|
|
{ "frequency_hz": 433920000, "rssi_dbm": -61.5 },
|
|
|
{ "frequency_hz": 868100000, "rssi_dbm": -67.2 }
|
|
|
]
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Если `receiver_id` передан, сервис сверяет его с ожидаемым receiver из конфига.
|
|
|
|
|
|
## Валидация и ошибки некорректного контекста
|
|
|
|
|
|
Проверяется:
|
|
|
- тип payload;
|
|
|
- наличие измерений;
|
|
|
- числовые и конечные значения;
|
|
|
- `frequency_hz > 0`;
|
|
|
- соответствие `receiver_id` при наличии;
|
|
|
- наличие общих частот у всех 3 ресиверов.
|
|
|
|
|
|
Ошибки содержат:
|
|
|
- `source_url=...`
|
|
|
- номер строки `row #...`
|
|
|
- проблемное поле.
|
|
|
|
|
|
## Тесты
|
|
|
|
|
|
Запуск:
|
|
|
```bash
|
|
|
pytest -q
|
|
|
```
|
|
|
|
|
|
Покрытие:
|
|
|
- математика триангуляции;
|
|
|
- влияние частоты на RSSI->distance;
|
|
|
- интеграция `AutoService.refresh_once()`;
|
|
|
- валидационные сценарии;
|
|
|
- ошибки контекста (нет общих частот, bad field, receiver mismatch, network error, output reject).
|
|
|
|
|
|
Файл интеграционных тестов:
|
|
|
- [test_service_integration.py](/c:/Users/snytk/triangulation/test_service_integration.py)
|
|
|
|
|
|
## Локальный запуск без Docker
|
|
|
|
|
|
```bash
|
|
|
python service.py --config config.json
|
|
|
```
|
|
|
|
|
|
UI:
|
|
|
- `http://127.0.0.1:8081/ui`
|