|
1 | | -<p align="center"> |
2 | | - <img src="assets/ontrack.jpg" alt="ONTrack" width="150"/> |
3 | | -</p> |
| 1 | +# OnTrack v2 — TDS Telecom Field Route Optimizer |
4 | 2 |
|
5 | | -<h1 align="center">ONTrack</h1> |
6 | | - |
7 | | -<p align="center"> |
8 | | - <b>Route Optimizer for Folks in a Hurry</b><br/> |
9 | | - Built with Python · OR-Tools · CustomTkinter |
10 | | -</p> |
11 | | - |
12 | | -<p align="center"> |
13 | | - <img src="https://img.shields.io/badge/python-3.11+-blue?style=flat-square"/> |
14 | | - <img src="https://img.shields.io/badge/platform-Windows-informational?style=flat-square"/> |
15 | | - <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square"/> |
16 | | - <img src="https://img.shields.io/badge/status-active-brightgreen?style=flat-square"/> |
17 | | - <img src="https://img.shields.io/badge/OR--Tools-routing-orange?style=flat-square"/> |
18 | | - <img src="https://img.shields.io/badge/🚧%20WIP-not%20production%20ready-yellow?style=flat-square"/> |
19 | | -</p> |
20 | | - |
21 | | -> [!WARNING] |
22 | | -> ONTrack is a **work in progress**. Core routing logic is functional but the GUI, installer, and map preview are still being built out. Not recommended for production field use yet. |
| 3 | +Route optimization tool for TDS field service technicians. |
| 4 | +Enter addresses manually or load a CSV/Excel file, optimize the drive order, preview each stop in Street View, and launch turn-by-turn navigation in Google Maps or ArcGIS FieldMaps. |
23 | 5 |
|
24 | 6 | --- |
25 | 7 |
|
26 | | -## What It Does |
27 | | - |
28 | | -ONTrack takes a CSV or Excel file of street addresses, geocodes them, builds a real-road distance matrix, and solves the optimal drive order using Google OR-Tools — then exports the route and opens it directly in Google Maps. |
| 8 | +## Features |
| 9 | + |
| 10 | +| Feature | Desktop | Android | |
| 11 | +|---|---|---| |
| 12 | +| Manual address entry | ✓ | ✓ | |
| 13 | +| CSV / Excel import | ✓ | – | |
| 14 | +| Current location as start | ✓ (IP) | ✓ (GPS) | |
| 15 | +| Drag-to-reorder stops | ✓ | ✓ (delete/add) | |
| 16 | +| TSP route optimization | OR-Tools | Nearest-neighbor | |
| 17 | +| Distance backend: OSRM | ✓ | ✓ | |
| 18 | +| Distance backend: Google | ✓ (key) | ✓ (key) | |
| 19 | +| Street View preview | ✓ (key) | ✓ (key) | |
| 20 | +| Launch Google Maps | ✓ | ✓ | |
| 21 | +| Launch ArcGIS FieldMaps | ✓ | ✓ | |
| 22 | +| Launch Waze | ✓ | ✓ | |
| 23 | +| Add/remove stops after solve | ✓ | ✓ | |
| 24 | +| Re-optimize after edits | ✓ | ✓ | |
| 25 | +| CSV export | ✓ | – | |
29 | 26 |
|
30 | 27 | --- |
31 | 28 |
|
32 | | -## Quick Start |
| 29 | +## Setup |
33 | 30 |
|
34 | | -> [!NOTE] |
35 | | -> Requires Python 3.11+ and pip. Windows `.exe` build coming soon. |
| 31 | +### 1. Copy the example environment file |
| 32 | +```bash |
| 33 | +cp .env.example .env |
| 34 | +``` |
| 35 | +Edit `.env` and add your Google Maps API key and ArcGIS item ID. |
| 36 | +You can also set these values from the **Settings** screen inside the app. |
36 | 37 |
|
| 38 | +### 2. Install desktop dependencies |
37 | 39 | ```bash |
38 | | -git clone https://github.com/qompassai/python.git |
39 | | -cd python/ontrack |
40 | 40 | pip install -r requirements.txt |
| 41 | +``` |
| 42 | + |
| 43 | +### 3. Run on desktop |
| 44 | +```bash |
41 | 45 | python main.py |
42 | 46 | ``` |
43 | 47 |
|
44 | 48 | --- |
45 | 49 |
|
46 | | -## How It Works |
| 50 | +## Build — Desktop |
| 51 | + |
| 52 | +### Windows (one-file EXE) |
| 53 | +```powershell |
| 54 | +pip install pyinstaller |
| 55 | +pyinstaller ontrack.spec |
| 56 | +# Output: dist/OnTrack.exe |
| 57 | +``` |
47 | 58 |
|
48 | | -| Step | Module | Description | |
49 | | -|------|--------------------|-----------------------------------------------------------| |
50 | | -| 1 | `core/parser.py` | Reads CSV or Excel, extracts address column | |
51 | | -| 2 | `core/geocoder.py` | Geocodes each address to lat/lng via Nominatim or Google | |
52 | | -| 3 | `core/matrix.py` | Builds NxN real-road distance matrix via OSRM | |
53 | | -| 4 | `core/solver.py` | Solves TSP with OR-Tools, returns ordered stop list | |
54 | | -| 5 | `core/exporter.py` | Exports sorted CSV + opens Google Maps deep link | |
| 59 | +### Linux x86_64 (one-file binary) |
| 60 | +```bash |
| 61 | +pip install pyinstaller |
| 62 | +pyinstaller ontrack.spec |
| 63 | +# Output: dist/OnTrack |
| 64 | +``` |
55 | 65 |
|
56 | 66 | --- |
57 | 67 |
|
58 | | -## Configuration |
| 68 | +## Build — Android APK |
59 | 69 |
|
60 | | -ONTrack works **fully out of the box with no API keys**. All default services are free and open: |
| 70 | +**Prerequisites:** Ubuntu/Debian Linux (or WSL2), Java 17, Android SDK/NDK. |
61 | 71 |
|
62 | | -| Service | Provider | Key Required | |
63 | | -|--------------|----------------------------|--------------| |
64 | | -| Geocoding | Nominatim (OpenStreetMap) | ❌ None | |
65 | | -| Routing | OSRM public server | ❌ None | |
66 | | -| Map preview | Folium + OpenStreetMap | ❌ None | |
67 | | -| Route export | Google Maps URL | ❌ None | |
| 72 | +```bash |
| 73 | +pip install buildozer |
| 74 | + |
| 75 | +# First build (downloads Android SDK + NDK — takes 20–40 min) |
| 76 | +buildozer android debug |
| 77 | + |
| 78 | +# APK output: |
| 79 | +# bin/ontrack-2.0.0-arm64-v8a-debug.apk |
| 80 | +``` |
68 | 81 |
|
69 | | -Optionally drop a `.env` file in the project root to upgrade to Google Maps Platform for better rural accuracy: |
| 82 | +> **Note:** OR-Tools has no python-for-android recipe. |
| 83 | +> The Android build uses a pure-Python nearest-neighbor solver instead. |
| 84 | +> This gives good-quality routes for typical field routes (≤ 30 stops). |
70 | 85 |
|
| 86 | +### Sign for Play Store |
71 | 87 | ```bash |
72 | | -cp .env.example .env |
73 | | -# Then add your key: |
74 | | -# GOOGLE_MAPS_API_KEY=your_key_here |
| 88 | +# Build release AAB |
| 89 | +buildozer android release |
| 90 | +# Then sign with your keystore and upload to Google Play Console. |
75 | 91 | ``` |
76 | 92 |
|
77 | 93 | --- |
78 | 94 |
|
79 | | -## Roadmap |
| 95 | +## API Keys |
| 96 | + |
| 97 | +All keys are optional — the app works without them using free fallbacks. |
80 | 98 |
|
81 | | -- [x] Project scaffold and structure |
82 | | -- [x] CSV/Excel parser (`core/parser.py`) |
83 | | -- [x] Geocoder with Nominatim (`core/geocoder.py`) |
84 | | -- [ ] OSRM distance matrix builder |
85 | | -- [ ] OR-Tools TSP solver |
86 | | -- [ ] CustomTkinter GUI |
87 | | -- [ ] Google Maps deep link export |
88 | | -- [ ] PyInstaller `.exe` build |
89 | | -- [ ] Desktop shortcut + icon installer |
| 99 | +| Key | Used for | Get it | |
| 100 | +|---|---|---| |
| 101 | +| `GOOGLE_MAPS_API_KEY` | Street View images, Google geocoding, Google distance matrix | [console.cloud.google.com](https://console.cloud.google.com/google/maps-apis/credentials) | |
| 102 | +| `ARCGIS_ITEM_ID` | Opens correct web map in ArcGIS FieldMaps | Your ArcGIS Online map URL | |
90 | 103 |
|
91 | 104 | --- |
92 | 105 |
|
93 | | -## Project Structure |
| 106 | +## Distance Backends |
94 | 107 |
|
95 | | -``` |
96 | | -ontrack/ |
97 | | -├── main.py # Entrypoint |
98 | | -├── ontrack.spec # PyInstaller build spec |
99 | | -├── README.md |
100 | | -├── requirements.txt |
101 | | -│ |
102 | | -├── gui/ |
103 | | -│ ├── app.py # CTk root window |
104 | | -│ ├── views/ |
105 | | -│ │ ├── home.py # File picker + depot input |
106 | | -│ │ ├── results.py # Route display table |
107 | | -│ │ └── settings.py # API keys + prefs |
108 | | -│ └── components/ |
109 | | -│ ├── file_picker.py |
110 | | -│ ├── address_table.py |
111 | | -│ └── map_preview.py |
112 | | -│ |
113 | | -├── core/ |
114 | | -│ ├── parser.py # CSV/Excel → address list |
115 | | -│ ├── geocoder.py # Address → lat/lng |
116 | | -│ ├── matrix.py # Distance matrix (OSRM) |
117 | | -│ ├── solver.py # OR-Tools TSP |
118 | | -│ └── exporter.py # CSV + Maps URL |
119 | | -│ |
120 | | -├── assets/ |
121 | | -│ ├── ontrack.jpg |
122 | | -│ ├── ontrack.png |
123 | | -│ ├── ontrack.ico |
124 | | -│ └── themes/ontrack.json |
125 | | -│ |
126 | | -├── config/ |
127 | | -│ └── settings.py # dotenv API key loader |
128 | | -│ |
129 | | -└── tests/ |
130 | | - ├── test_parser.py |
131 | | - ├── test_geocoder.py |
132 | | - ├── test_solver.py |
133 | | - └── sample_addresses.csv |
134 | | -``` |
| 108 | +| Backend | Requires | Quality | |
| 109 | +|---|---|---| |
| 110 | +| `osrm` (default) | None (uses public router) | Good — real road distances | |
| 111 | +| `google` | `GOOGLE_MAPS_API_KEY` | Best — live traffic aware | |
| 112 | +| `haversine` | None | Fast — straight-line only | |
135 | 113 |
|
136 | 114 | --- |
137 | 115 |
|
138 | | -## Building the Windows `.exe` |
| 116 | +## Address File Format |
139 | 117 |
|
140 | | -```bash |
141 | | -pyinstaller --onefile --windowed \ |
142 | | - --icon=assets/ontrack.ico \ |
143 | | - --name="ONTrack" \ |
144 | | - --add-data "assets;assets" \ |
145 | | - --hidden-import ortools \ |
146 | | - main.py |
| 118 | +CSV or Excel with a column named `address`: |
| 119 | + |
| 120 | +```csv |
| 121 | +address |
| 122 | +123 Main St Spokane WA |
| 123 | +456 Elm St Coeur d'Alene ID |
| 124 | +789 Oak Ave Post Falls ID |
147 | 125 | ``` |
148 | 126 |
|
149 | | -Output: `dist/ONTrack.exe` — no Python install required on the target machine. |
| 127 | +--- |
| 128 | + |
| 129 | +## Architecture |
| 130 | + |
| 131 | +``` |
| 132 | +ontrack/ |
| 133 | +├── main.py # Entry point — detects desktop vs Android |
| 134 | +├── core/ |
| 135 | +│ ├── parser.py # CSV/Excel → address list |
| 136 | +│ ├── geocoder.py # Address → lat/lng (Nominatim or Google) |
| 137 | +│ ├── matrix.py # Distance matrix (OSRM / Google / Haversine) |
| 138 | +│ ├── solver.py # TSP optimizer (OR-Tools or nearest-neighbor) |
| 139 | +│ └── exporter.py # CSV export, Maps URL, FieldMaps URL, Street View URL |
| 140 | +├── gui/ # Desktop UI (CustomTkinter) |
| 141 | +│ ├── app.py |
| 142 | +│ └── views/ |
| 143 | +│ ├── home.py # Address input + solve |
| 144 | +│ ├── results.py # Route table + Street View + map launch |
| 145 | +│ └── settings.py # API keys + preferences |
| 146 | +├── mobile/ # Android UI (Kivy) |
| 147 | +│ ├── app.py |
| 148 | +│ └── screens/ |
| 149 | +│ ├── home.py |
| 150 | +│ ├── results.py |
| 151 | +│ └── settings.py |
| 152 | +├── config/ |
| 153 | +│ └── settings.py # Env var loader |
| 154 | +├── assets/ # Icons, splash |
| 155 | +├── buildozer.spec # Android build config |
| 156 | +├── ontrack.spec # PyInstaller desktop build config |
| 157 | +└── tests/ # pytest test suite |
| 158 | +``` |
150 | 159 |
|
151 | 160 | --- |
152 | 161 |
|
153 | | -## License |
| 162 | +## TDS Internal Notes |
154 | 163 |
|
155 | | -MIT © [Qompass AI](https://github.com/qompassai) |
| 164 | +- The app does not transmit any address data to TDS servers. All routing uses OSRM (free, no account) or the technician's own Google Maps API key. |
| 165 | +- ArcGIS FieldMaps deep links open the technician's configured web map and search for the stop address. |
| 166 | +- For enterprise deployment, set `OSRM_BASE_URL` to a self-hosted OSRM instance on TDS infrastructure for offline-capable routing. |
0 commit comments