Metadata-Version: 2.4
Name: commute-optimizer
Version: 1.1.0
Summary: Find the best time to leave: track real drive times via the Google Routes API and report the optimal departure window
Author: Ben Kahan
License-Expression: MIT
Project-URL: Homepage, https://github.com/bkahan/commute-optimizer
Project-URL: Issues, https://github.com/bkahan/commute-optimizer/issues
Keywords: commute,traffic,google-maps,routes-api,departure-time
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# Commute Optimizer

Tracks the real drive time between two places by polling the Google Routes API
over a week, then tells you the best time to leave — with far tighter resolution
than the wide ranges Google Maps shows.

No dependencies beyond Python 3.9+.

```
pip install commute-optimizer
```

That gives you the `commute` command used below. Running from a source
checkout works too — substitute `python -m commute` for `commute`.

All data files (`config.json`, `.env`, `commute.db`, the reports, logs) live
in the directory you run `commute` from, so each tracking project can have its
own folder.

## Example output

### The report

`commute report` writes a self-contained `report.html`: one section
per direction, a chart of median commute vs. departure time (one line per
weekday), and tables ranking the best departure slot inside each rush window —
including how many minutes it saves over the worst slot.

![Example report with per-weekday commute charts and best-departure tables](docs/example-report.png)

*(Generated from synthetic demo data — regenerate with
`python docs/_gen_example.py`.)*

### The terminal

Preflight check before a long run:

```text
> commute check
[ok] config: '1600 Amphitheatre Parkway, Mountain View, CA' -> '1 Market St, San Francisco, CA'
[ok] API key found (AIzaSy...XXXX)
[ok] database writable at C:\...\commute-optimizer\commute.db (0 existing samples)
[ok] live route -> 43.6 min now (free-flow 46.3 min, 58.5 km)
[ok] live route <- 43.1 min now (free-flow 46.5 min, 58.9 km)
[ok] estimated API usage: ~938/day, ~6566/week (free tier ~10,000/month)

All checks passed - ready for a long run.
```

Polling with the auto-stop timer:

```text
> commute poll -d 7d
Polling '1600 Amphitheatre Parkway, Mountain View, CA' <-> '1 Market St, San Francisco, CA'
Rush interval 1 min, off-peak 10 min. Ctrl+C to stop.
Will stop automatically at 2026-07-12 22:59 and generate the report.
[Sun 22:59:28] -> 43.6 min (free-flow 46.3 min)
[Sun 22:59:28] <- 43.1 min (free-flow 46.5 min)
...
```

And when the report runs, it also prints the summary:

```text
1600 Amphitheatre Parkway, Mountain View, CA -> 1 Market St, San Francisco, CA
  window 07:00-10:00:
    Monday     leave 09:45-10:00 (~28.7 min; worst 51.3 min, saves 22.6)
    Tuesday    leave 09:45-10:00 (~29.4 min; worst 51.5 min, saves 22.1)
    ...
```

## Setup

1. Get a Google Maps Platform API key with the **Routes API** enabled
   (Google Cloud console → APIs & Services → enable "Routes API" → create an
   API key).

2. In the folder where you want the data to live, write the example config
   and edit your addresses:

   ```
   commute init
   ```

3. Put your API key in a `.env` file in the same folder:

   ```
   GOOGLE_MAPS_API_KEY=your-key-here
   ```

## Usage

Before a long run, verify everything works (config, API key, database, one
live API call per direction, and a quota estimate for your poll schedule):

```powershell
commute check
```

Start polling. With `-d` it stops automatically after the given duration and
generates the report; without it, it runs until Ctrl+C:

```powershell
commute poll -d 7d     # a full week, then auto-report
commute poll           # open-ended
```

Durations accept `d`/`h`/`m` and combinations: `7d`, `24h`, `90m`, `1d12h`.
Add `--no-report` to skip the automatic report at the end.

Generate the report any time mid-run (opens `report.html` in your browser;
`--no-open` to skip that):

```powershell
commute report
```

Or watch the run continuously: this regenerates `report.html` *and* a
day-by-day report (`report-daily.html` — one curve per calendar date plus a
coverage table, so you can see the data filling in before the week is done).
Run it in a second terminal alongside `poll`; refresh the browser to see
updates:

```powershell
commute watch            # updates every 15 minutes
commute watch -i 5m      # or your own interval
```

To preview the report without waiting a week, seed a synthetic week of
two-direction data (refuses to run if the DB already has samples). In an
empty folder:

```powershell
commute init
commute demo
commute report
```

### Surviving sleep and reboots

Instead of running `poll` in a terminal, register it with the OS so it stays
alive for the whole run (run this from your data folder — that's where the
scheduled poller will work):

```powershell
commute schedule install -d 7d   # poll for a week, survive anything
commute schedule status          # is the task/poller alive?
commute schedule remove          # stop and unregister
```

This relaunches the poller every 5 minutes (a lock file makes that a no-op
while one is already running) and resumes after a reboot once you log in. The
stop time is stored as an absolute timestamp, so it survives reboots too;
when it's reached, the report is generated as usual.

Per platform:

- **Windows** — a Task Scheduler task; it can also *wake the machine from
  sleep* to poll. Output goes to `poll.log` (no console window).
- **Linux** — a systemd user service + timer (`commute-poll`). Logs go to
  `journalctl --user -u commute-poll`. Runs from login onward; for
  before-login polling run `loginctl enable-linger $USER`. Linux can't wake
  itself from sleep for this; a missed tick fires right after wake.
- **macOS** — a launchd LaunchAgent (`com.commute-optimizer.poll`) logging to
  `poll.log`. macOS won't wake for it either — to poll with the lid closed,
  plug in and run `caffeinate -s`.

Don't run `schedule install` while a manually-started `poll` from an older
version is still running — stop that one first, or you'll get duplicate
samples.

If you skip all this and the machine sleeps mid-run, collected data is still
safe in `commute.db` — the report's Coverage section will show exactly which
stretches were missed.

## Config

```json
{
  "origin": "home address",
  "destination": "work address",
  "travel_mode": "DRIVE",
  "track_both_directions": true,
  "poll": {
    "active_window": ["00:00", "23:59"],
    "rush_windows": [["07:00", "10:00"], ["16:00", "19:00"]],
    "rush_interval_min": 1,
    "offpeak_interval_min": 10
  }
}
```

- `track_both_directions` — when true (the default), every tick samples both
  origin→destination and the reverse, so one run covers your morning and
  evening commutes.
- `active_window` — only poll inside this local-time range (set e.g.
  `["06:00", "20:00"]` to skip the night entirely).
- `rush_windows` — during these windows the poller samples every
  `rush_interval_min` minutes; otherwise every `offpeak_interval_min` minutes.
  The report ranks departure times *within* these windows (otherwise 3 a.m.
  always wins).

## Cost

The Routes API (traffic-aware) has ~10,000 free calls/month. The default
adaptive schedule makes roughly 470 calls/day per direction — ~6,600/week with
both directions on, still inside the free tier but without room for a second
full week in the same month. Set `track_both_directions` to false or trim
`active_window` to halve it. Run `commute check` to see the estimate
for your exact schedule.

Samples land in `commute.db` (SQLite). Transient API failures (network blips,
rate limits, 5xx) are retried with backoff (5s/15s/45s) before being recorded
as an error row; permanent failures like a bad key fail fast without retries.
The report ends each direction with a **Coverage** section flagging any
stretch where sampling stopped (sleep, reboot, repeated errors) despite the
schedule expecting data — so you know which medians to trust.

## Known limitations (v1)

- **Multi-week data blends together.** The report groups by weekday, so two
  Mondays from different weeks merge into one median curve. Intended use is a
  single week per `commute.db`; delete or rename the DB between runs.
- **Wake-from-sleep is Windows-only.** On Linux/macOS the scheduled poller
  resumes right after wake but can't wake the machine itself.
- **No automated tests.** The pieces are small and hand-verified, but there's
  no test suite yet.
