tescmd 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. tescmd/__init__.py +3 -0
  2. tescmd/__main__.py +5 -0
  3. tescmd/_internal/__init__.py +0 -0
  4. tescmd/_internal/async_utils.py +25 -0
  5. tescmd/_internal/permissions.py +43 -0
  6. tescmd/_internal/vin.py +44 -0
  7. tescmd/api/__init__.py +1 -0
  8. tescmd/api/charging.py +102 -0
  9. tescmd/api/client.py +189 -0
  10. tescmd/api/command.py +540 -0
  11. tescmd/api/energy.py +146 -0
  12. tescmd/api/errors.py +76 -0
  13. tescmd/api/partner.py +40 -0
  14. tescmd/api/sharing.py +65 -0
  15. tescmd/api/signed_command.py +277 -0
  16. tescmd/api/user.py +38 -0
  17. tescmd/api/vehicle.py +150 -0
  18. tescmd/auth/__init__.py +1 -0
  19. tescmd/auth/oauth.py +312 -0
  20. tescmd/auth/server.py +108 -0
  21. tescmd/auth/token_store.py +273 -0
  22. tescmd/ble/__init__.py +0 -0
  23. tescmd/cache/__init__.py +6 -0
  24. tescmd/cache/keys.py +51 -0
  25. tescmd/cache/response_cache.py +213 -0
  26. tescmd/cli/__init__.py +0 -0
  27. tescmd/cli/_client.py +603 -0
  28. tescmd/cli/_options.py +126 -0
  29. tescmd/cli/auth.py +682 -0
  30. tescmd/cli/billing.py +240 -0
  31. tescmd/cli/cache.py +85 -0
  32. tescmd/cli/charge.py +610 -0
  33. tescmd/cli/climate.py +501 -0
  34. tescmd/cli/energy.py +385 -0
  35. tescmd/cli/key.py +611 -0
  36. tescmd/cli/main.py +601 -0
  37. tescmd/cli/media.py +146 -0
  38. tescmd/cli/nav.py +242 -0
  39. tescmd/cli/partner.py +112 -0
  40. tescmd/cli/raw.py +75 -0
  41. tescmd/cli/security.py +495 -0
  42. tescmd/cli/setup.py +786 -0
  43. tescmd/cli/sharing.py +188 -0
  44. tescmd/cli/software.py +81 -0
  45. tescmd/cli/status.py +106 -0
  46. tescmd/cli/trunk.py +240 -0
  47. tescmd/cli/user.py +145 -0
  48. tescmd/cli/vehicle.py +837 -0
  49. tescmd/config/__init__.py +0 -0
  50. tescmd/crypto/__init__.py +19 -0
  51. tescmd/crypto/ecdh.py +46 -0
  52. tescmd/crypto/keys.py +122 -0
  53. tescmd/deploy/__init__.py +0 -0
  54. tescmd/deploy/github_pages.py +268 -0
  55. tescmd/models/__init__.py +85 -0
  56. tescmd/models/auth.py +108 -0
  57. tescmd/models/command.py +18 -0
  58. tescmd/models/config.py +63 -0
  59. tescmd/models/energy.py +56 -0
  60. tescmd/models/sharing.py +26 -0
  61. tescmd/models/user.py +37 -0
  62. tescmd/models/vehicle.py +185 -0
  63. tescmd/output/__init__.py +5 -0
  64. tescmd/output/formatter.py +132 -0
  65. tescmd/output/json_output.py +83 -0
  66. tescmd/output/rich_output.py +809 -0
  67. tescmd/protocol/__init__.py +23 -0
  68. tescmd/protocol/commands.py +175 -0
  69. tescmd/protocol/encoder.py +122 -0
  70. tescmd/protocol/metadata.py +116 -0
  71. tescmd/protocol/payloads.py +621 -0
  72. tescmd/protocol/protobuf/__init__.py +6 -0
  73. tescmd/protocol/protobuf/messages.py +564 -0
  74. tescmd/protocol/session.py +318 -0
  75. tescmd/protocol/signer.py +84 -0
  76. tescmd/py.typed +0 -0
  77. tescmd-0.1.2.dist-info/METADATA +458 -0
  78. tescmd-0.1.2.dist-info/RECORD +81 -0
  79. tescmd-0.1.2.dist-info/WHEEL +4 -0
  80. tescmd-0.1.2.dist-info/entry_points.txt +2 -0
  81. tescmd-0.1.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,458 @@
1
+ Metadata-Version: 2.4
2
+ Name: tescmd
3
+ Version: 0.1.2
4
+ Summary: A Python CLI for querying and controlling Tesla vehicles via the Fleet API
5
+ Project-URL: Homepage, https://github.com/oceanswave/tescmd
6
+ Project-URL: Repository, https://github.com/oceanswave/tescmd
7
+ Project-URL: Issues, https://github.com/oceanswave/tescmd/issues
8
+ Project-URL: Documentation, https://github.com/oceanswave/tescmd#readme
9
+ Author: oceanswave
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,ev,fleet-api,tesla,vehicle
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: click>=8.1
26
+ Requires-Dist: cryptography>=42.0
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: keyring>=25.0
29
+ Requires-Dist: protobuf>=5.29
30
+ Requires-Dist: pydantic-settings>=2.0
31
+ Requires-Dist: pydantic>=2.0
32
+ Requires-Dist: python-dotenv>=1.0
33
+ Requires-Dist: rich>=13.0
34
+ Provides-Extra: ble
35
+ Requires-Dist: bleak>=0.22; extra == 'ble'
36
+ Provides-Extra: dev
37
+ Requires-Dist: build>=1.0; extra == 'dev'
38
+ Requires-Dist: grpcio-tools>=1.68; extra == 'dev'
39
+ Requires-Dist: mypy-protobuf>=3.6; extra == 'dev'
40
+ Requires-Dist: mypy>=1.13; extra == 'dev'
41
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
42
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
43
+ Requires-Dist: pytest-httpx>=0.34; extra == 'dev'
44
+ Requires-Dist: pytest>=8.0; extra == 'dev'
45
+ Requires-Dist: ruff>=0.8; extra == 'dev'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # tescmd
49
+
50
+ <!-- [![PyPI](https://img.shields.io/pypi/v/tescmd)](https://pypi.org/project/tescmd/) -->
51
+ <!-- [![Python](https://img.shields.io/pypi/pyversions/tescmd)](https://pypi.org/project/tescmd/) -->
52
+ [![License](https://img.shields.io/github/license/oceanswave/tescmd)](LICENSE)
53
+
54
+ A Python CLI for querying and controlling Tesla vehicles via the Fleet API — built for both human operators and AI agents.
55
+
56
+ ## Why tescmd?
57
+
58
+ Tesla's Fleet API gives developers full access to vehicle data and commands, but working with it directly means juggling OAuth2 PKCE flows, token refresh, regional endpoints, key enrollment, and raw JSON responses. tescmd wraps all of that into a single command-line tool that handles authentication, token management, and output formatting so you can focus on what you actually want to do — check your battery, find your car, or control your vehicle.
59
+
60
+ tescmd is designed to work as a tool that AI agents can invoke directly. Platforms like [OpenClaw](https://openclaw.ai/), [Claude Desktop](https://claude.ai), and other agent frameworks can call tescmd commands, parse the structured JSON output, and take actions on your behalf — "lock my car", "what's my battery at?", "start climate control". The deterministic JSON output, meaningful exit codes, cost-aware wake confirmation, and `--wake` opt-in flag make it safe for autonomous agent use without surprise billing.
61
+
62
+ ## Features
63
+
64
+ - **Vehicle state queries** — battery, range, charge status, climate, location, doors, windows, trunks, tire pressure, dashcam, sentry mode, and more
65
+ - **Vehicle commands** — charge start/stop/limit/departure scheduling, climate on/off/set temp/seats/steering wheel, lock/unlock, sentry mode, trunk/frunk, windows, HomeLink, navigation waypoints, media playback, speed limits, PIN management
66
+ - **Vehicle Command Protocol** — ECDH session management with HMAC-SHA256 signed commands via the `signed_command` endpoint; automatically used when keys are enrolled
67
+ - **Key enrollment** — `tescmd key enroll <VIN>` sends your public key to the vehicle and guides you through Tesla app approval
68
+ - **Tier enforcement** — readonly tier blocks write commands with clear guidance to upgrade
69
+ - **Energy products** — Powerwall live status, site info, backup reserve, operation mode, storm mode, time-of-use settings, charging history, calendar history, grid import/export
70
+ - **User & sharing** — account info, region, orders, feature flags, driver management, vehicle sharing invites
71
+ - **Fleet Telemetry awareness** — setup wizard highlights Fleet Telemetry streaming for up to 97% API cost reduction
72
+ - **Universal response caching** — all read commands are cached with tiered TTLs (1h for specs/warranty, 5m for fleet lists, 1m standard, 30s for location-dependent); bots can call tescmd as often as needed — within the TTL window, responses are instant and free
73
+ - **Cost-aware wake** — prompts before sending billable wake API calls; `--wake` flag for scripts that accept the cost
74
+ - **Guided OAuth2 setup** — `tescmd auth login` walks you through browser-based authentication with PKCE
75
+ - **Key management** — generate EC keys, register via Tesla Developer Portal (remote) or BLE enrollment (proximity)
76
+ - **Rich terminal output** — tables, panels, spinners powered by Rich; auto-detects TTY vs pipe
77
+ - **Configurable display units** — switch between PSI/bar, °F/°C, and mi/km (defaults to US units)
78
+ - **JSON output** — structured output for scripting and agent integration
79
+ - **Multi-profile** — switch between vehicles, accounts, and regions with named profiles
80
+ - **Agent-friendly** — deterministic JSON, meaningful exit codes, `--wake` opt-in, headless auth support
81
+
82
+ ## Quick Start
83
+
84
+ ```bash
85
+ pip install tescmd
86
+
87
+ # First-time setup (interactive wizard)
88
+ tescmd setup
89
+
90
+ # Authenticate (opens browser)
91
+ tescmd auth login
92
+
93
+ # List your vehicles
94
+ tescmd vehicle list
95
+
96
+ # Get full vehicle data snapshot
97
+ tescmd vehicle info
98
+
99
+ # Check charge status (uses cache — second call is instant)
100
+ tescmd charge status
101
+
102
+ # Start charging (auto-invalidates cache)
103
+ tescmd charge start --wake
104
+
105
+ # Climate control
106
+ tescmd climate on --wake
107
+ tescmd climate set 72
108
+
109
+ # Lock the car
110
+ tescmd security lock --wake
111
+
112
+ # Enroll your key on a vehicle (required for signed commands)
113
+ tescmd key enroll 5YJ3E1EA1NF000000
114
+
115
+ # Cache management
116
+ tescmd cache status
117
+ tescmd cache clear
118
+ ```
119
+
120
+ ## Prerequisites
121
+
122
+ The following tools should be installed and authenticated before running `tescmd setup`:
123
+
124
+ | Tool | Required | Purpose | Auth |
125
+ |------|----------|---------|------|
126
+ | **Git** | Yes | Version control, repo management | N/A |
127
+ | **GitHub CLI** (`gh`) | Recommended | Auto-creates `*.github.io` domain for key hosting | `gh auth login` |
128
+ | **Tailscale** | Optional | Secure remote access to vehicles via Fleet Telemetry | `tailscale login` |
129
+
130
+ Without the GitHub CLI, you'll need to manually host your public key at the Tesla-required `.well-known` path on your own domain. Tailscale is only needed if you plan to use Fleet Telemetry streaming for reduced API costs.
131
+
132
+ ## Installation
133
+
134
+ ### From PyPI
135
+
136
+ ```bash
137
+ pip install tescmd
138
+ ```
139
+
140
+ ### From Source
141
+
142
+ ```bash
143
+ git clone https://github.com/oceanswave/tescmd.git
144
+ cd tescmd
145
+ pip install -e ".[dev]"
146
+ ```
147
+
148
+ ## Configuration
149
+
150
+ tescmd resolves settings in this order (highest priority first):
151
+
152
+ 1. **CLI arguments** — `--vin`, `--region`, `--format`, `--units`, etc.
153
+ 2. **Environment variables** — `TESLA_VIN`, `TESLA_REGION`, etc. (`.env` files loaded automatically)
154
+ 3. **Defaults**
155
+
156
+ ### Environment Variables
157
+
158
+ Create a `.env` file in your working directory or `~/.config/tescmd/.env`:
159
+
160
+ ```dotenv
161
+ TESLA_CLIENT_ID=your-client-id
162
+ TESLA_CLIENT_SECRET=your-client-secret
163
+ TESLA_VIN=5YJ3E1EA1NF000000
164
+ TESLA_REGION=na
165
+
166
+ # Token storage (optional — defaults to OS keyring with file fallback)
167
+ TESLA_TOKEN_FILE=~/.config/tescmd/tokens.json
168
+
169
+ # Cache settings (optional)
170
+ TESLA_CACHE_ENABLED=true
171
+ TESLA_CACHE_TTL=60
172
+ TESLA_CACHE_DIR=~/.cache/tescmd
173
+
174
+ # Command protocol: auto | signed | unsigned (optional)
175
+ TESLA_COMMAND_PROTOCOL=auto
176
+
177
+ # Display units (optional — defaults to US units)
178
+ TESLA_TEMP_UNIT=F # F or C
179
+ TESLA_DISTANCE_UNIT=mi # mi or km
180
+ TESLA_PRESSURE_UNIT=psi # psi or bar
181
+ ```
182
+
183
+ ## Token Storage
184
+
185
+ By default, tescmd stores OAuth tokens in the OS keyring (macOS Keychain, GNOME Keyring, Windows Credential Manager). On headless systems where no keyring daemon is available (Docker, CI, SSH sessions), tescmd automatically falls back to a file-based store at `~/.config/tescmd/tokens.json` with restricted permissions (`0600` on Unix, owner-only ACL on Windows).
186
+
187
+ You can force file-based storage by setting `TESLA_TOKEN_FILE`:
188
+
189
+ ```bash
190
+ export TESLA_TOKEN_FILE=~/.config/tescmd/tokens.json
191
+ ```
192
+
193
+ To transfer tokens between machines, use `auth export` and `auth import`:
194
+
195
+ ```bash
196
+ # On source machine
197
+ tescmd auth export > tokens.json
198
+
199
+ # On target machine (Docker, CI, etc.)
200
+ tescmd auth import < tokens.json
201
+ ```
202
+
203
+ Check which backend is active with `tescmd status` — the output includes a `Token store` line showing `keyring` or the file path.
204
+
205
+ > **Security note:** File-based tokens are stored as plaintext JSON. The file is created with owner-only permissions, but treat it like any other credential file.
206
+
207
+ ## Commands
208
+
209
+ | Group | Commands | Description |
210
+ |---|---|---|
211
+ | `setup` | *(interactive wizard)* | First-run configuration: client ID, secret, region, domain, key enrollment |
212
+ | `auth` | `login`, `logout`, `status`, `refresh`, `register`, `export`, `import` | OAuth2 authentication lifecycle |
213
+ | `vehicle` | `list`, `get`, `info`, `data`, `location`, `wake`, `rename`, `mobile-access`, `nearby-chargers`, `alerts`, `release-notes`, `service`, `drivers`, `calendar`, `subscriptions`, `upgrades`, `options`, `specs`, `warranty`, `fleet-status`, `low-power`, `accessory-power`, `telemetry {config,create,delete,errors}` | Vehicle discovery, state queries, fleet telemetry, power management |
214
+ | `charge` | `status`, `start`, `stop`, `limit`, `limit-max`, `limit-std`, `amps`, `port-open`, `port-close`, `schedule`, `departure`, `precondition-add`, `precondition-remove`, `add-schedule`, `remove-schedule`, `clear-schedules`, `clear-preconditions`, `managed-amps`, `managed-location`, `managed-schedule` | Charge queries, control, scheduling, and fleet management |
215
+ | `billing` | `history`, `sessions`, `invoice` | Supercharger billing history and invoices |
216
+ | `climate` | `status`, `on`, `off`, `set`, `precondition`, `seat`, `seat-cool`, `wheel-heater`, `overheat`, `bioweapon`, `keeper`, `cop-temp`, `auto-seat`, `auto-wheel`, `wheel-level` | Climate, seat, and steering wheel control |
217
+ | `security` | `status`, `lock`, `auto-secure`, `unlock`, `sentry`, `valet`, `valet-reset`, `remote-start`, `flash`, `honk`, `boombox`, `speed-limit`, `pin-to-drive`, `pin-reset`, `pin-clear-admin`, `speed-clear`, `speed-clear-admin`, `guest-mode`, `erase-data` | Security, access, and PIN management |
218
+ | `trunk` | `open`, `close`, `frunk`, `window`, `sunroof`, `tonneau-open`, `tonneau-close`, `tonneau-stop` | Trunk, frunk, sunroof, tonneau, and window control |
219
+ | `media` | `play-pause`, `next-track`, `prev-track`, `next-fav`, `prev-fav`, `volume-up`, `volume-down`, `adjust-volume` | Media playback control |
220
+ | `nav` | `send`, `gps`, `supercharger`, `homelink`, `waypoints` | Navigation and HomeLink |
221
+ | `software` | `status`, `schedule`, `cancel` | Software update management |
222
+ | `energy` | `list`, `status`, `live`, `backup`, `mode`, `storm`, `tou`, `history`, `off-grid`, `grid-config`, `telemetry`, `calendar` | Energy product (Powerwall) management |
223
+ | `user` | `me`, `region`, `orders`, `features` | User account information |
224
+ | `sharing` | `add-driver`, `remove-driver`, `create-invite`, `redeem-invite`, `revoke-invite`, `list-invites` | Vehicle sharing and driver management |
225
+ | `key` | `generate`, `deploy`, `validate`, `show`, `enroll`, `unenroll` | Key management and enrollment |
226
+ | `partner` | `public-key`, `telemetry-error-vins`, `telemetry-errors` | Partner account endpoints (require client credentials) |
227
+ | `cache` | `status`, `clear` | Response cache management |
228
+ | `raw` | `get`, `post` | Arbitrary Fleet API endpoint access |
229
+
230
+ Use `tescmd <group> --help` for detailed usage on any command group. For API endpoints not yet covered by a dedicated command, use `raw get` or `raw post` as an escape hatch.
231
+
232
+ ### Global Flags
233
+
234
+ These flags can be placed at the root level or after any subcommand:
235
+
236
+ | Flag | Description |
237
+ |---|---|
238
+ | `--vin VIN` | Vehicle VIN (also accepted as a positional argument) |
239
+ | `--profile NAME` | Config profile name |
240
+ | `--format {rich,json,quiet}` | Force output format |
241
+ | `--quiet` | Suppress normal output |
242
+ | `--region {na,eu,cn}` | Tesla API region |
243
+ | `--verbose` | Enable verbose logging |
244
+ | `--no-cache` / `--fresh` | Bypass response cache for this invocation |
245
+ | `--wake` | Auto-wake vehicle without confirmation (billable) |
246
+
247
+ ## Output Formats
248
+
249
+ tescmd auto-detects the best output format:
250
+
251
+ - **Rich** (default in TTY) — formatted tables, panels, colored status indicators
252
+ - **JSON** (`--format json` or piped) — structured, parseable output
253
+ - **Quiet** (`--quiet`) — minimal output on stderr, suitable for scripts that only check exit codes
254
+
255
+ ```bash
256
+ # Human-friendly output
257
+ tescmd vehicle list
258
+
259
+ # JSON for scripting
260
+ tescmd vehicle list --format json
261
+
262
+ # Pipe-friendly (auto-switches to JSON)
263
+ tescmd vehicle list | jq '.[0].vin'
264
+
265
+ # Quiet mode (exit code only)
266
+ tescmd vehicle wake --quiet && echo "Vehicle is awake"
267
+ ```
268
+
269
+ ### Display Units
270
+
271
+ Rich output displays values in US units by default (°F, miles, PSI). Switch to metric with a single flag:
272
+
273
+ ```bash
274
+ tescmd --units metric charge status # All metric: °C, km, bar
275
+ tescmd --units us charge status # All US: °F, mi, psi (default)
276
+ ```
277
+
278
+ Or configure individual units via environment variables:
279
+
280
+ ```dotenv
281
+ TESLA_TEMP_UNIT=C # F or C
282
+ TESLA_DISTANCE_UNIT=km # mi or km
283
+ TESLA_PRESSURE_UNIT=bar # psi or bar
284
+ ```
285
+
286
+ | Dimension | US (default) | Metric | Env Variable |
287
+ |---|---|---|---|
288
+ | Temperature | °F | °C | `TESLA_TEMP_UNIT` |
289
+ | Distance | mi | km | `TESLA_DISTANCE_UNIT` |
290
+ | Pressure | psi | bar | `TESLA_PRESSURE_UNIT` |
291
+
292
+ The `--units` flag overrides all three env vars at once. The Tesla API returns Celsius, miles, and bar — conversions happen in the display layer only.
293
+
294
+ ## Tesla Fleet API Costs
295
+
296
+ Tesla's Fleet API is **pay-per-use** — every request returning a status code below 500 is billable, including 4xx errors like "vehicle asleep" (408) and rate limits (429). Wake requests are the most expensive category and are rate-limited to 3/min. There is no free tier (the $10/month credit is being discontinued).
297
+
298
+ > **Official pricing:** [Tesla Fleet API — Billing and Limits](https://developer.tesla.com/docs/fleet-api/billing-and-limits)
299
+
300
+ ### Why This Matters
301
+
302
+ A naive script that polls `vehicle_data` every 5 minutes generates **4-5 billable requests per check** (asleep error + wake + poll + data fetch). That's **1,000+ billable requests per day** from a single cron job. At roughly $1 per 500 data requests, monitoring one vehicle costs around $60/month before you even count wake requests (the most expensive tier).
303
+
304
+ ### Cost Example: Battery Check
305
+
306
+ | | Without tescmd | With tescmd |
307
+ |---|---|---|
308
+ | Vehicle asleep, check battery | 408 error (billable) + wake (billable) + poll (billable) + data (billable) = **4+ requests** | Cache miss → prompt user → user wakes via Tesla app (free) → retry → data (billable) = **1 request** |
309
+ | Check battery again 30s later | Another 4+ requests | **0 requests** (cache hit) |
310
+ | 10 checks in 1 minute | **40+ billable requests** | **1 billable request** + 9 cache hits |
311
+
312
+ ### How tescmd Reduces Costs
313
+
314
+ tescmd implements four layers of cost protection:
315
+
316
+ 1. **Universal read-command cache** — **all** read commands are cached with tiered TTLs: static data (specs, warranty) cached for 1 hour, fleet lists for 5 minutes, standard queries for 1 minute, location-dependent data for 30 seconds. Bots can call tescmd as often as needed — within the TTL, responses are instant and free.
317
+ 2. **Smart wake state** — Tracks whether the vehicle was recently confirmed online (30s TTL). Skips redundant wake attempts.
318
+ 3. **Wake confirmation prompt** — Prompts before sending billable wake calls in interactive mode. JSON/piped mode returns a structured error with `--wake` guidance.
319
+ 4. **Write-command invalidation** — write commands automatically invalidate the relevant cache scope (vehicle or energy site) so subsequent reads reflect the new state.
320
+
321
+ ```bash
322
+ # First call: hits API, caches response
323
+ tescmd charge status
324
+
325
+ # Second call within 60s: instant cache hit, no API call
326
+ tescmd charge status
327
+
328
+ # All read commands are cached — even vehicle list, user info, billing, etc.
329
+ tescmd vehicle list # cached 5 min
330
+ tescmd user me # cached 1 hour
331
+ tescmd vehicle specs # cached 1 hour
332
+ tescmd billing history # cached 1 min
333
+
334
+ # Bypass cache when you need fresh data
335
+ tescmd charge status --fresh
336
+
337
+ # Auto-wake without prompting (for scripts accepting the cost)
338
+ tescmd charge status --wake
339
+
340
+ # Manage cache
341
+ tescmd cache status # entry counts, disk usage
342
+ tescmd cache clear # clear all
343
+ tescmd cache clear --vin VIN # clear for one vehicle
344
+ tescmd cache clear --site 12345 # clear for an energy site
345
+ tescmd cache clear --scope account # clear account-level entries
346
+ ```
347
+
348
+ For the full cost breakdown with more examples, savings calculations, and Fleet Telemetry streaming comparison, see [docs/api-costs.md](docs/api-costs.md).
349
+
350
+ Configure via environment variables:
351
+
352
+ | Variable | Default | Description |
353
+ |---|---|---|
354
+ | `TESLA_CACHE_ENABLED` | `true` | Enable/disable the cache |
355
+ | `TESLA_CACHE_TTL` | `60` | Time-to-live in seconds |
356
+ | `TESLA_CACHE_DIR` | `~/.cache/tescmd` | Cache directory path |
357
+
358
+ ## Key Enrollment & Vehicle Command Protocol
359
+
360
+ Newer Tesla vehicles require commands to be signed using the [Vehicle Command Protocol](https://github.com/teslamotors/vehicle-command). tescmd handles this transparently:
361
+
362
+ 1. **Generate a key pair** — `tescmd key generate` creates an EC P-256 key pair
363
+ 2. **Enroll on vehicle** — `tescmd key enroll <VIN>` sends the public key to the vehicle; approve in the Tesla app
364
+ 3. **Commands are signed automatically** — once enrolled, tescmd uses ECDH sessions + HMAC-SHA256 to sign commands via the `signed_command` endpoint
365
+
366
+ ```bash
367
+ # Generate EC key pair
368
+ tescmd key generate
369
+
370
+ # Enroll on a vehicle (interactive approval via Tesla app)
371
+ tescmd key enroll 5YJ3E1EA1NF000000
372
+
373
+ # Commands are now signed automatically
374
+ tescmd security lock --wake
375
+ ```
376
+
377
+ The `command_protocol` setting controls routing:
378
+
379
+ | Value | Behavior |
380
+ |---|---|
381
+ | `auto` (default) | Use signed path when keys are enrolled; fall back to unsigned |
382
+ | `signed` | Require signed commands (error if no keys) |
383
+ | `unsigned` | Force legacy REST path (skip signing) |
384
+
385
+ Set via `TESLA_COMMAND_PROTOCOL` environment variable or in your config.
386
+
387
+ See [docs/vehicle-command-protocol.md](docs/vehicle-command-protocol.md) for the full protocol architecture.
388
+
389
+ ## Agent Integration
390
+
391
+ tescmd is designed for use by AI agents and automation platforms. Agents like [Claude Code](https://github.com/anthropics/claude-code), Claude Desktop, and other LLM-powered tools can invoke tescmd commands, parse the structured JSON output, and act on your behalf.
392
+
393
+ **Why tescmd works well as an agent tool:**
394
+
395
+ - **Structured JSON output** — piped/non-TTY mode automatically emits parseable JSON with consistent schema
396
+ - **Cost protection** — agents won't accidentally trigger billable wake calls without `--wake`; the default behavior is safe
397
+ - **Cache-aware** — every read command is cached; repeated queries from an agent within the TTL window cost nothing
398
+ - **Meaningful exit codes** — agents can branch on success/failure without parsing output
399
+ - **Stateless invocations** — each command is self-contained; no session state to manage
400
+ - **Signed commands** — when keys are enrolled, commands are signed transparently; no agent-side crypto needed
401
+
402
+ **Example agent workflow:**
403
+
404
+ ```bash
405
+ # Agent checks battery (cache hit if recent)
406
+ tescmd charge status --format json
407
+
408
+ # Agent decides to start charging
409
+ tescmd charge start --wake --format json
410
+
411
+ # Agent verifies the command took effect (cache was invalidated)
412
+ tescmd charge status --format json --fresh
413
+ ```
414
+
415
+ See [docs/bot-integration.md](docs/bot-integration.md) for the full JSON schema, exit code reference, and headless authentication setup.
416
+
417
+ ## Development
418
+
419
+ ```bash
420
+ # Clone and install in dev mode
421
+ git clone https://github.com/oceanswave/tescmd.git
422
+ cd tescmd
423
+ pip install -e ".[dev]"
424
+
425
+ # Run checks
426
+ ruff check src/ tests/
427
+ ruff format --check src/ tests/
428
+ mypy src/
429
+ pytest
430
+
431
+ # Run a specific test
432
+ pytest tests/cli/test_auth.py -v
433
+
434
+ # Validate API coverage against Tesla Fleet API spec
435
+ python scripts/validate_fleet_api.py
436
+ ```
437
+
438
+ ### API Coverage Validation
439
+
440
+ tescmd ships a spec-driven validation utility that compares our implementation against the Tesla Fleet API. The canonical spec lives at `spec/fleet_api_spec.json` (sourced from Tesla's docs and Go SDK), and `scripts/validate_fleet_api.py` validates all API methods, parameters, and types using AST introspection.
441
+
442
+ ```bash
443
+ python scripts/validate_fleet_api.py # Summary
444
+ python scripts/validate_fleet_api.py --verbose # All endpoints
445
+ python scripts/validate_fleet_api.py --json # Machine-readable
446
+ ```
447
+
448
+ Run this periodically or after modifying API methods to catch drift.
449
+
450
+ See [docs/development.md](docs/development.md) for detailed contribution guidelines.
451
+
452
+ ## Changelog
453
+
454
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
455
+
456
+ ## License
457
+
458
+ MIT
@@ -0,0 +1,81 @@
1
+ tescmd/__init__.py,sha256=9pBEWtaf-0va5j9CIk56XKKnJG0W0INFsj2hROYYa-I,116
2
+ tescmd/__main__.py,sha256=ecNCDo0sINhjJZiauhAcUMU67U6XUCU23ocf7vQG45E,83
3
+ tescmd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ tescmd/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ tescmd/_internal/async_utils.py,sha256=q97pYNpEFWJXJ5K5Bxh4Ph4gfEwl6C2Kwd5wuIsXmiM,619
6
+ tescmd/_internal/permissions.py,sha256=cawM9XIHJKNqi5cGYssF5iPNi_F4gONLhyLOJCbzZyI,1155
7
+ tescmd/_internal/vin.py,sha256=VlliRJzsq0in7Sny-i-ng6rMkNjCD-rJ6sIHiq3uxT8,1133
8
+ tescmd/api/__init__.py,sha256=OPKuH6YMSJU5PO4_0cuTXx5KYTmc0aR3SU8z695AZ7U,36
9
+ tescmd/api/charging.py,sha256=Se58NcLTSxCNZvpBCMJswMoI-bYhWV_MM4LHmry9_Tw,3464
10
+ tescmd/api/client.py,sha256=XKtx1ywi0CxdEUaOOnpOAh09kStF3de0iyQCLAmlN9M,6939
11
+ tescmd/api/command.py,sha256=TpVb2raih3S_cYopJmmm4bV_O0WDB1NgQQkr_yuBRNA,22402
12
+ tescmd/api/energy.py,sha256=_XOv-er9379Cza8IkE5Gjtc1FyzwsLfPdsPQR2rA1Us,5562
13
+ tescmd/api/errors.py,sha256=oyfWc3xdycGeLbBEV7uu_DCh_gCqhf78Xt3_nIV9pgc,1963
14
+ tescmd/api/partner.py,sha256=f5VWMY8V5oeiDcYduq7zxihWacdzCd6wBtPIXXwwkzY,1405
15
+ tescmd/api/sharing.py,sha256=qjlP3B8jo4hYqNOIiXiDYHxUwMHT3FAz87SLH8Y6fSM,2475
16
+ tescmd/api/signed_command.py,sha256=hMegcCnoYub0eQ3rRq0_-990tgfaWeZSWTbnQDQ_wwY,10136
17
+ tescmd/api/user.py,sha256=pz4sB9i-9pHukdIBOwGrgfRpWf4zd5gnqAqm3zAJpcA,1411
18
+ tescmd/api/vehicle.py,sha256=JYgWnK4ffissI1aAkA2uY6Jcpc-w441A5xG8_yZ1BGw,6603
19
+ tescmd/auth/__init__.py,sha256=PHsT1-mgm9b-4xft0-adq3i6fwyCSj2of4KTpMAYUhw,76
20
+ tescmd/auth/oauth.py,sha256=kgp_-Zk7zJqLIpSB9yOZLIWjXdD7WnG7nvyfZC0lKFY,9820
21
+ tescmd/auth/server.py,sha256=3h8NELWNMe9DfMu7NsfA00sc34D6mGoaFQTqPSOOdzE,3602
22
+ tescmd/auth/token_store.py,sha256=v2rx3oj3dwaMn8-yz_ge8RD22joUmfP_ZJ4rhJaUw0g,8695
23
+ tescmd/ble/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ tescmd/cache/__init__.py,sha256=V-oZyDgU4Dr6cExNVdGcsEbF6hrnOYml7VV6ZoOiyJY,249
25
+ tescmd/cache/keys.py,sha256=dcof4GM1gZEADNBx8xHtjCCIK_4ra3FxPeRVJYPoFow,1736
26
+ tescmd/cache/response_cache.py,sha256=1X-zr_-QLR5i9epH4ZobZeDO4bp482QO51YsJTI6ImE,7375
27
+ tescmd/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ tescmd/cli/_client.py,sha256=lr_ugunILZLLklPQ3syO3nGqzmyqxNh93eFQtxbVojs,21503
29
+ tescmd/cli/_options.py,sha256=lM4-lvVDLv89PahshWIRRoNUXBki4DOabt_pYaPlK-U,4175
30
+ tescmd/cli/auth.py,sha256=WqmJh1DdQnuoS7YHtSZ5s-8RlMxa1nEXtHvgOjMjN-U,22163
31
+ tescmd/cli/billing.py,sha256=BcuAI10Q2Tf6fobejoKsaO4qVN7TcOy95HSdylBn23M,7946
32
+ tescmd/cli/cache.py,sha256=LaOOfHS1ycF8LoCFdcUQfw11PYor2S__-SdWtRpA_pA,2729
33
+ tescmd/cli/charge.py,sha256=TOXRn7YGuFYj5GimBhh2bTOB_5vzU5sc86PODifHXGk,20088
34
+ tescmd/cli/climate.py,sha256=npekNHOcJ63oG1-2o-fZiTRWFmemdZ1Tl_pASWwWBlI,16890
35
+ tescmd/cli/energy.py,sha256=L7I1o3BucT71MGSsdYENN40iQKANXioNcUK19mj9wz8,11855
36
+ tescmd/cli/key.py,sha256=kMOfP4R-71T5mfj_C8q3JQV5jqvrJ3BCYDsgluk_nFQ,21666
37
+ tescmd/cli/main.py,sha256=PXMEJCnWtBlTnKON8K4I8LVkd8zmeF5kW9L6O7Qa050,20259
38
+ tescmd/cli/media.py,sha256=PQ-QJkjkIiM8IJ5CXtDOY0N1yC3DlaC5YLnebxT1nrI,4267
39
+ tescmd/cli/nav.py,sha256=22UxJDltcE9S3SfrLwtBfh51HDEm8vxun0KrQzTvZz0,7519
40
+ tescmd/cli/partner.py,sha256=0GfDCwM_Kfy5g95JwUhrrsjDFn9lSbkuNgfquIQqcSo,3488
41
+ tescmd/cli/raw.py,sha256=hj5hZs8tHHHAeXtpf7kHXewciXDvl0RlMJkPK7i3ouY,2238
42
+ tescmd/cli/security.py,sha256=laoRaF2mBda5q_jWCXyBjNCU98hsQ2Pr1a_MNWdQF3E,15713
43
+ tescmd/cli/setup.py,sha256=L8lcP7bvOxXNNLkRR89ViIm7c4r5v9fj9sAa0yYTdJw,25723
44
+ tescmd/cli/sharing.py,sha256=IIhkPlLb8sKkPmgMKVDgWTndCd5ZRvgKnZbknxYCBFc,6211
45
+ tescmd/cli/software.py,sha256=f3Jl5GRruE_wNHl3jfLbVQHEXQvQxe4y-UaNIY1j76Y,2711
46
+ tescmd/cli/status.py,sha256=T6YoG_BE24fJSmc24Uhw0IdH5mUUDySgGjn9s1LY8yc,4003
47
+ tescmd/cli/trunk.py,sha256=8ktL7_TpTXphQdrjHMUeDAP149ULB3naZvUFOoBh880,7577
48
+ tescmd/cli/user.py,sha256=eit0pQhku1l53x3Gl4um6l6c_wgFl9dU7OhyFd1g4gQ,4100
49
+ tescmd/cli/vehicle.py,sha256=q8767lw9u7XLnUpVwfaABCv3WnDtD0LI54OiGLpq_Io,27531
50
+ tescmd/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ tescmd/crypto/__init__.py,sha256=ctsVTIt0trOfAlq7SogJaGQRIyly1zxj_ImSHS7I6nM,406
52
+ tescmd/crypto/ecdh.py,sha256=2DlJcK7qxiBYRcAiWlJuj3INogid83tQeMIJ32DAb84,1366
53
+ tescmd/crypto/keys.py,sha256=jzFZwZKMYFlHGPeTSrw5pVLBwjxvLV57LzTK9d4-caM,4037
54
+ tescmd/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ tescmd/deploy/github_pages.py,sha256=8W0Xjn8XIuLAHhiEDo-Zn6KrlbgdkVAe_2wWxdDS4_Y,8150
56
+ tescmd/models/__init__.py,sha256=bHDWLA8QPxfTe6RGlr-TcOST2fqUFBxjs3l4HKzayvw,1801
57
+ tescmd/models/auth.py,sha256=5J4U8dEvSmSegkU8Dhhdo6Rr-SDssXccOL8uQDZKBsA,2815
58
+ tescmd/models/command.py,sha256=6gK9TjThXU5cKa_B3xOYpaLaGixxYp5iEhjQEMlh0Ws,388
59
+ tescmd/models/config.py,sha256=BHq7Ui2OwkYokK3hGHR1R5wCKpWXor9Oqlm0lI4ieQY,1921
60
+ tescmd/models/energy.py,sha256=u7NBa_ee3kd4C-lmPqqkRrYwZvb3g_z34EHCuGZuLHc,1429
61
+ tescmd/models/sharing.py,sha256=sJv4fCRT5AUkcqmdK8bN2Y8hpuHITEnxNp_BlbX7L4Y,609
62
+ tescmd/models/user.py,sha256=2hATFqUppheKtWDFg3axIRmxX0gmPTdwgMwZJGSQhtc,770
63
+ tescmd/models/vehicle.py,sha256=GXkQOAB406JQI4vI7xhEbWB1hK5H0SLhzwtJEXPEsTw,5733
64
+ tescmd/output/__init__.py,sha256=uFvlXwHmKHkxOIVgP8JryZlQbHLHhbhLGswGo9xuFbI,120
65
+ tescmd/output/formatter.py,sha256=pQLes-gZJbD4S32-fRwKqcLepsiXb9AIWP-Wm_H1ca0,4658
66
+ tescmd/output/json_output.py,sha256=4NFuBGn8383xoQ6NbKEgNr6MCE6bF9YaBqKydrPL_e0,2297
67
+ tescmd/output/rich_output.py,sha256=gwuAdaahaDx9CDXwuFAjCfjgyYd0itDG3OCQIhVbNM8,31579
68
+ tescmd/protocol/__init__.py,sha256=VpqeFrWNDs2DxPtFNSFmlu_d-GmioY4_PNKtNuLCqx4,545
69
+ tescmd/protocol/commands.py,sha256=_pXDyXAUZYAJyIrgsmLlxnRrBXajnFWtDB6JDuR9fPU,8657
70
+ tescmd/protocol/encoder.py,sha256=L4_qtsn1cSi3BbkDvTj1JjFuviXKIvrKtuJzlBud8XA,3543
71
+ tescmd/protocol/metadata.py,sha256=Hb9QaoGRz54z04bKIQigSD5vJKphQNLu3bcUHEW_tl8,4076
72
+ tescmd/protocol/payloads.py,sha256=l1DiJjdkDsXurs-QSfe8s-mwyCxCOrk6syZhvjei4Io,24093
73
+ tescmd/protocol/session.py,sha256=EbijNW174_ssLqt1rHmoWiU07TsYiY2xENssvWi0mI0,11405
74
+ tescmd/protocol/signer.py,sha256=L-OVqCk9XZBuFrLGeATzJSqzMm5JWfOde4hRgL8_xAs,2794
75
+ tescmd/protocol/protobuf/__init__.py,sha256=hAvTsN4tkJMoKhLsjnrO_XepHbhrK7PfymBCpah9hUg,291
76
+ tescmd/protocol/protobuf/messages.py,sha256=8vBH8i-1--FrR5ydSJFAn9UwNMIrSkm6henqWkOMXxU,21124
77
+ tescmd-0.1.2.dist-info/METADATA,sha256=LKAwyRI-f8vO9mAwSuZCXRkz0vh-7FCxGBY2gIFPzpA,21608
78
+ tescmd-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
79
+ tescmd-0.1.2.dist-info/entry_points.txt,sha256=e-Uk81_gfLu4XzJl9bv6-bUIodJbnxAgfR5ugFyeD2E,48
80
+ tescmd-0.1.2.dist-info/licenses/LICENSE,sha256=gFEbRZ5xHSPxkT3OgbLFhDWVUxZv80kFDnv0t3G1E7M,1070
81
+ tescmd-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ tescmd = tescmd.cli.main:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sean McLellan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.